diff --git a/vcx/ci/Jenkinsfile b/vcx/ci/Jenkinsfile index 88237da5..2b2f0b77 100644 --- a/vcx/ci/Jenkinsfile +++ b/vcx/ci/Jenkinsfile @@ -249,9 +249,9 @@ def buildAndroid(arch) { android.inside { ANDROID_SCRIPT_PATH = 'vcx/ci/scripts/androidBuild.sh' - LIBINDY_BRANCH="stable" - LIBINDY_VERSION="1.6.8" - LIBINDY_TAG="" + LIBINDY_BRANCH="master" + LIBINDY_VERSION="1.7.0" + LIBINDY_TAG="934" sh 'sudo ./vcx/ci/scripts/installCert.sh' sh "LIBINDY_BRANCH=${LIBINDY_BRANCH} LIBINDY_VERSION=${LIBINDY_VERSION} LIBINDY_TAG=${LIBINDY_TAG} ./${ANDROID_SCRIPT_PATH} ${arch}" @@ -275,7 +275,8 @@ def buildAndroid(arch) { } def packageAndroid(android) { - all_archs = ["arm", "arm64", "armv7", "x86", "x86_64"] + //all_archs = ["arm", "arm64", "armv7", "x86", "x86_64"] + all_archs = ["x86"] for (arch in all_archs) { dir("runtime_android_build/libvcx_${arch}") { unstash name: "libvcx_${arch}" diff --git a/vcx/ci/libindy.dockerfile b/vcx/ci/libindy.dockerfile index f94b2eda..34579e56 100644 --- a/vcx/ci/libindy.dockerfile +++ b/vcx/ci/libindy.dockerfile @@ -22,7 +22,7 @@ RUN apt-get update -y && apt-get install -y \ curl \ libffi-dev \ ruby \ - ruby-dev \ + ruby-dev \ sudo \ rubygems \ libzmq5 \ @@ -36,17 +36,17 @@ RUN apt-get update -y && apt-get install -y \ unzip \ vim -# Install Nodejs +# Install Nodejs RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - \ && apt-get install -y nodejs # Install Rust -ARG RUST_VER="1.27.0" +ARG RUST_VER="1.31.1" ENV RUST_ARCHIVE=rust-${RUST_VER}-x86_64-unknown-linux-gnu.tar.gz ENV RUST_DOWNLOAD_URL=https://static.rust-lang.org/dist/$RUST_ARCHIVE # Install Gradle -RUN wget https://services.gradle.org/distributions/gradle-3.4.1-bin.zip +RUN wget -q https://services.gradle.org/distributions/gradle-3.4.1-bin.zip RUN mkdir /opt/gradle RUN unzip -d /opt/gradle gradle-3.4.1-bin.zip @@ -66,8 +66,8 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 68DB5E88 && \ add-apt-repository 'deb https://repo.corp.evernym.com/deb evernym-agency-dev-ubuntu main' && \ curl https://repo.corp.evernym.com/repo.corp.evenym.com-sig.key | apt-key add - -ARG LIBINDY_VER="1.6.8" -ARG LIBNULL_VER="1.6.8" +ARG LIBINDY_VER="1.7.0" +ARG LIBNULL_VER="1.7.0" ARG LIBSOVTOKEN_VER="0.9.6" RUN apt-get update && apt-get install -y \ diff --git a/vcx/ci/libvcx.dockerfile b/vcx/ci/libvcx.dockerfile index c40823f0..03cf4bda 100644 --- a/vcx/ci/libvcx.dockerfile +++ b/vcx/ci/libvcx.dockerfile @@ -4,7 +4,7 @@ ARG uid=1000 RUN useradd -ms /bin/bash -u $uid vcx USER vcx -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.27.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.31.1 ENV PATH /home/vcx/.cargo/bin:$PATH WORKDIR /home/vcx ENV PATH /home/vcx:$PATH diff --git a/vcx/ci/scripts/androidBuild.sh b/vcx/ci/scripts/androidBuild.sh index 0b5028d3..4a8e0406 100755 --- a/vcx/ci/scripts/androidBuild.sh +++ b/vcx/ci/scripts/androidBuild.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + setup() { echo "Working Directory: ${PWD}" set -e @@ -94,9 +96,9 @@ get_libindy() { if [ ! -d "libindy_${ARCH}" ]; then if [ "$LIBINDY_BRANCH" = "stable" ]; then - wget https://repo.sovrin.org/android/libindy/${LIBINDY_BRANCH}/${LIBINDY_VERSION}/libindy_android_${ARCH}_${LIBINDY_VERSION}.zip + wget -q https://repo.sovrin.org/android/libindy/${LIBINDY_BRANCH}/${LIBINDY_VERSION}/libindy_android_${ARCH}_${LIBINDY_VERSION}.zip else - wget https://repo.sovrin.org/android/libindy/${LIBINDY_BRANCH}/${LIBINDY_VERSION}-${LIBINDY_TAG}/libindy_android_${ARCH}_${LIBINDY_VERSION}.zip + wget -q https://repo.sovrin.org/android/libindy/${LIBINDY_BRANCH}/${LIBINDY_VERSION}-${LIBINDY_TAG}/libindy_android_${ARCH}_${LIBINDY_VERSION}.zip fi unzip libindy_android_${ARCH}_${LIBINDY_VERSION}.zip @@ -114,7 +116,7 @@ get_libsovtoken() { LIBSOVTOKEN_ZIP=libsovtoken_0.9.6-201811211720-4901e95_all.zip if [ ! -d "libsovtoken" ]; then echo "retrieving libsovtoken prebuilt library" - wget ${SOVRIN_REPO}/${LIBSOVTOKEN_ZIP} + wget -q ${SOVRIN_REPO}/${LIBSOVTOKEN_ZIP} unzip ${LIBSOVTOKEN_ZIP} fi export LIBSOVTOKEN_DIR="${PWD}/libsovtoken/${TRIPLET}" diff --git a/vcx/libvcx/Cargo.lock b/vcx/libvcx/Cargo.lock deleted file mode 100644 index e3cf66c2..00000000 --- a/vcx/libvcx/Cargo.lock +++ /dev/null @@ -1,1785 +0,0 @@ -[[package]] -name = "adler32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "aho-corasick" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "android_log-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "android_logger" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "android_log-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "antidote" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arrayvec" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "build_const" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bytes" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "chrono" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation-sys" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crossbeam-deque" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "dtoa" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "encoding_rs" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "env_logger" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "flate2" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fnv" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "httparse" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "humantime" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hyper" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hyper-tls" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "indy" -version = "1.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "indy-sys 1.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "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)", - "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "indy-sys" -version = "1.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "iovec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "itoa" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "json" -version = "0.11.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazycell" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.41" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libflate" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libvcx" -version = "0.1.2097319" -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)", - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "indy 1.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "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)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rmp 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rmp-serde 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rmpv 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-base58 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lock_api" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log-mdc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log-panics" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log4rs" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.1.1 (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)", - "log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde-value 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memchr" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memoffset" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "mime" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime_guess" -version = "2.0.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mime 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz-sys" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide_c_api" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 0.6.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.5 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "native-tls" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "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)", - "openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "net2" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "nodrop" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-complex" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-derive" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-iter" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-rational" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num_cpus" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "openssl" -version = "0.9.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "openssl" -version = "0.10.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "openssl-sys" -version = "0.9.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "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)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ordered-float" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "owning_ref" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "phf" -version = "0.7.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_shared 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_codegen" -version = "0.7.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_generator 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_generator" -version = "0.7.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_shared 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_shared" -version = "0.7.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pkg-config" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "proc-macro2" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_syscall" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "relay" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "reqwest" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libflate 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rmp" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rmp-serde" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rmp 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rmpv" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rmp 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rust-base58" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ryu" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "safemem" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "safemem" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "schannel" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scoped-tls" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "security-framework" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "security-framework-sys" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.80" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde-value" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive" -version = "1.0.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_urlencoded" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_yaml" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "siphasher" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slab" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "smallvec" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "stable_deref_trait" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "syn" -version = "0.15.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termcolor" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread-id" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-codec" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-core" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-fs" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-io" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-service" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tls" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-udp" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "toml" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "try-lock" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "typemap" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ucd-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicase" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicase" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unsafe-any" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "url" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "uuid" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "vcpkg" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "want" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wincolor" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "yaml-rust" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a" -"checksum android_log-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e" -"checksum android_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86983875e7c3a202e31471cc6d60fcc18f30e194f1729cfff3bfb43d646ffced" -"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" -"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c4a342b450b268e1be8036311e2c613d7f8a7ed31214dff1cc3b60852a3168d" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" -"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" -"checksum bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0ce55bd354b095246fc34caf4e9e242f5297a7fd938b090cadfea6eee614aa62" -"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" -"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" -"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" -"checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" -"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" -"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" -"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" -"checksum encoding_rs 0.8.10 (registry+https://github.com/rust-lang/crates.io-index)" = "065f4d0c826fdaef059ac45487169d918558e3cf86c9d89f6e81cf52369126e5" -"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" -"checksum flate2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3b0c7353385f92079524de3b7116cf99d73947c08a7472774e9b3b04bff3b901" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" -"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" -"checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7" -"checksum hyper-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffb1bd5e518d3065840ab315dbbf44e4420e5f7d80e2cb93fa6ffffc50522378" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum indy 1.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "82f721a2d29f4b384ae9b7d35eee3f2f22f7838bb29a7a556fccc992e57ae639" -"checksum indy-sys 1.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2283efa24927118f670edd325f7350c6ef3326bc1e28d39ed2de684f8bf503c2" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" -"checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" -"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" -"checksum libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)" = "ac8ebf8343a981e2fa97042b14768f02ed3e1d602eac06cae6166df3c8ced206" -"checksum libflate 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "21138fc6669f438ed7ae3559d5789a5f0ba32f28c1f0608d1e452b0bb06ee936" -"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" -"checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a" -"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" -"checksum log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" -"checksum log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae0136257df209261daa18d6c16394757c63e032e27aafd8b07788b051082bef" -"checksum log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25e0fc8737a634116a2deb38d821e4400ed16ce9dcb0d628a978d399260f5902" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b3629fe9fdbff6daa6c33b90f7c08355c1aca05a3d01fa8063b822fcf185f3b" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum mime 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0a907b83e7b9e987032439a387e187119cddafc92d5c2aaeb1d92580a793f630" -"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" -"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" -"checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c" -"checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e" -"checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f74dbadc8b43df7864539cedb7bc91345e532fdd913cfdc23ad94f4d2d40fbc0" -"checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" -"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" -"checksum num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eceac7784c5dc97c2d6edf30259b4e153e6e2b42b3c85e9a6e9f45d06caef6e" -"checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8" -"checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d" -"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" -"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" -"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "5e1309181cdcbdb51bc3b6bedb33dfac2a83b3d585033d3f6d9e22e8c1928613" -"checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" -"checksum openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)" = "278c1ad40a89aa1e741a1eed089a2f60b18fab8089c3139b542140fc7d674106" -"checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" -"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum phf 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "cec29da322b242f4c3098852c77a0ca261c9c01b806cae85a5572a1eb94db9a6" -"checksum phf_codegen 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "7d187f00cd98d5afbcd8898f6cf181743a449162aeb329dcd2f3849009e605ad" -"checksum phf_generator 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "03dc191feb9b08b0dc1330d6549b795b9d81aec19efe6b4a45aec8d4caee0c4b" -"checksum phf_shared 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "b539898d22d4273ded07f64a05737649dc69095d92cb87c7097ec68e3f150b93" -"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" -"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" -"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" -"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" -"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2069749032ea3ec200ca51e4a31df41759190a88edca0d2d86ee8bedf7073341" -"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" -"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum reqwest 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)" = "738769ec83daf6c1929dc9dae7d69ed3779b55ae5c356e989dcd3aa677d8486e" -"checksum rmp 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a3d45d7afc9b132b34a2479648863aa95c5c88e98b32285326a6ebadc80ec5c9" -"checksum rmp-serde 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "011e1d58446e9fa3af7cdc1fb91295b10621d3ac4cb3a85cc86385ee9ca50cd3" -"checksum rmpv 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29af0205707de955a396a1d3c657677c65f791ebabb63c0596c0b2fec0bf6325" -"checksum rust-base58 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b313b91fcdc6719ad41fa2dad2b7e810b03833fae4bf911950e15529a5f04439" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" -"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" -"checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" -"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" -"checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef" -"checksum serde-value 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52903ade2290cbd61a0937a66a268f26cebf246e3ddd7964a8babb297111fb0d" -"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c" -"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce" -"checksum serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aaed41d9fb1e2f587201b863356590c90c1157495d811430a0c0325fe8169650" -"checksum serde_yaml 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "980f5cc4e92ba24ba471b6a7b3df17d5b7b2c16fb1900a1aa0a79062320b16c4" -"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" -"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" -"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum syn 0.15.14 (registry+https://github.com/rust-lang/crates.io-index)" = "baaba45c6bf60fe29aaf241fa33306c0b75c801edea8378263a8f043b09a5634" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" -"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee337e5f4e501fc32966fec6fe0ca0cc1c237b0b1b14a335f8bfe3c5f06e286" -"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" -"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde" -"checksum tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "60ae25f6b17d25116d2cba342083abe5255d3c2c79cb21ea11aa049c53bf7c75" -"checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21" -"checksum tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4b26fd37f1125738b2170c80b551f69ff6fecb277e6e5ca885e53eec2b005018" -"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" -"checksum tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad235e9dadd126b2d47f6736f65aa1fdcd6420e66ca63f44177bc78df89f912" -"checksum tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3929aee321c9220ed838ed6c3928be7f9b69986b0e3c22c972a66dbf8a298c68" -"checksum tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3a52f00c97fedb6d535d27f65cccb7181c8dd4c6edc3eda9ea93f6d45d05168e" -"checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" -"checksum tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da941144b816d0dcda4db3a1ba87596e4df5e860a72b70783fe435891f80601c" -"checksum toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2" -"checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" -"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" -"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -"checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" -"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" -"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4" -"checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" -"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e" diff --git a/vcx/libvcx/Cargo.toml b/vcx/libvcx/Cargo.toml index 99d3d6fa..3c3aa435 100644 --- a/vcx/libvcx/Cargo.toml +++ b/vcx/libvcx/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libvcx" -version = "0.1.2097319" +version = "0.2.0" authors = [ "Evernym Inc." ] publish = false description = "This is the official SDK for Evernym's VCX" @@ -18,6 +18,8 @@ pool_tests = [] nullpay = [] sovtoken = [] agency = [] +# Causes the build to fail on all warnings +#fatal_warnings = [] # turn on release versioning ci = [] @@ -27,6 +29,7 @@ env_logger = "0.5.10" log = "0.4" log4rs = "0.8.0" chrono = "0.4" +time = "0.1.36" lazy_static = "0.2" libc = "=0.2.41" rand = "0.3" @@ -35,7 +38,7 @@ serde_json = "1.0" json = "*" serde_derive = "1.0" url = "1.5.1" -reqwest = "0.8.5" +reqwest = "0.9.5" rust-base58 = "0.0.4" rmpv = "0.4.0" rmp = "0.8" @@ -43,10 +46,12 @@ rmp-serde = "0.13.7" base64 = "0.8.0" openssl = "0.10" num-traits = "0.2.0" -indy = "1.6.8" +indy = { version = "1.7.0", path = "../../wrappers/rust/" } +indy-sys = { version = "1.7.0", path = "../../wrappers/rust/indy-sys/" } log-panics = "2.0.0" tokio-threadpool = "0.1.6" futures = "0.1.23" +libloading = "0.5.0" [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.5" @@ -60,11 +65,12 @@ serde_derive = "1.0" [dev-dependencies] tempfile = "2.2" +dirs = "1.0.4" [package.metadata.deb] maintainer = "Evernym, Inc." copyright = "2018, Evernym Inc." -depends = "$auto, libindy (=1.6.8), libsovtoken (=0.9.6)" +depends = "$auto, libindy (=1.7.0), libsovtoken (=0.9.6)" extended-description = """\ This is Evernym's SDK for managing Verifiable Credential eXchange against an Indy network. For specific instructions on building see the README in the corresponding github repo https://github.com/evernym/sdk""" section = "admin" diff --git a/vcx/libvcx/build.rs b/vcx/libvcx/build.rs index 924b9cbc..91cac950 100644 --- a/vcx/libvcx/build.rs +++ b/vcx/libvcx/build.rs @@ -1,4 +1,5 @@ use std::env; +use std::fs; use std::io::prelude::*; use std::fs::File; use std::path::Path; @@ -121,6 +122,29 @@ fn main() { } else if cfg!(feature = "sovtoken") { println!("cargo:rustc-link-lib=sovtoken"); } + }else if target.contains("-windows-") { + println!("cargo:rustc-link-lib=indy.dll"); + + let profile = env::var("PROFILE").unwrap(); + println!("profile={}", profile); + + let output_dir = env::var("OUT_DIR").unwrap(); + println!("output_dir={}", output_dir); + let output_dir = Path::new(output_dir.as_str()); + + let indy_dir = env::var("INDY_DIR").unwrap_or(format!("..\\..\\libindy\\target\\{}", profile)); + println!("indy_dir={}", indy_dir); + let indy_dir = Path::new(indy_dir.as_str()); + + let dst = output_dir.join("..\\..\\..\\.."); + println!("cargo:rustc-flags=-L {}", indy_dir.as_os_str().to_str().unwrap()); + + let files = vec!["indy.dll", "libeay32md.dll", "libsodium.dll", "libzmq.dll", "ssleay32md.dll"]; + for f in files.iter() { + if let Ok(_) = fs::copy(&indy_dir.join(f), &dst.join(f)) { + println!("copy {} -> {}", &indy_dir.join(f).display(), &dst.join(f).display()); + } + } } match env::var("CARGO_FEATURE_CI") { diff --git a/vcx/libvcx/build_scripts/android/mac/mac.build.libz.sh b/vcx/libvcx/build_scripts/android/mac/mac.build.libz.sh index 0ff2a02c..d9b998bc 100755 --- a/vcx/libvcx/build_scripts/android/mac/mac.build.libz.sh +++ b/vcx/libvcx/build_scripts/android/mac/mac.build.libz.sh @@ -14,13 +14,13 @@ mkdir -p $WORK_DIR/libz-android/zlib/include ZLIB_DIR=$WORK_DIR/libz-android/zlib-1.2.11 cd $WORK_DIR/libz-android if [ ! -f zlib-1.2.11.tar.gz ]; then - wget https://zlib.net/zlib-1.2.11.tar.gz + wget -q https://zlib.net/zlib-1.2.11.tar.gz fi if [ ! -d $ZLIB_DIR ]; then tar -zxf zlib-1.2.11.tar.gz fi cd $ZLIB_DIR -cp zconf.h $WORK_DIR/libz-android/zlib/include/ +cp zconf.h $WORK_DIR/libz-android/zlib/include/ cp zlib.h $WORK_DIR/libz-android/zlib/include/ diff --git a/vcx/libvcx/build_scripts/android/vcx/build.nondocker.sh b/vcx/libvcx/build_scripts/android/vcx/build.nondocker.sh index 83b41051..71986a0c 100755 --- a/vcx/libvcx/build_scripts/android/vcx/build.nondocker.sh +++ b/vcx/libvcx/build_scripts/android/vcx/build.nondocker.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +set -e + WORKDIR=${PWD} TARGET_ARCH=$1 TARGET_API=$2 diff --git a/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh b/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh index 1806c6ea..6882b929 100755 --- a/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh +++ b/vcx/libvcx/build_scripts/ios/mac/mac.01.libindy.setup.sh @@ -44,7 +44,7 @@ fi if [[ $RUSTUP_VERSION =~ ^'rustup ' ]]; then rustup update - rustup default 1.27.0 + rustup default 1.31.1 rustup component add rls-preview rust-analysis rust-src echo "Using rustc version $(rustc --version)" rustup target remove aarch64-linux-android armv7-linux-androideabi arm-linux-androideabi i686-linux-android x86_64-linux-android diff --git a/vcx/libvcx/build_scripts/ios/mac/shared.functions.sh b/vcx/libvcx/build_scripts/ios/mac/shared.functions.sh index d8ebb597..fa50310b 100644 --- a/vcx/libvcx/build_scripts/ios/mac/shared.functions.sh +++ b/vcx/libvcx/build_scripts/ios/mac/shared.functions.sh @@ -1,7 +1,10 @@ #!/bin/sh +set -e + export LIBSOVTOKEN_IOS_BUILD_URL="https://repo.sovrin.org/ios/libsovtoken/stable/libsovtoken_0.9.6-201811211710-4901e95_all.zip" -export LIBINDY_IOS_BUILD_URL="https://repo.sovrin.org/ios/libindy/stable/libindy-core/1.6.8/libindy.tar.gz" +#export LIBINDY_IOS_BUILD_URL="https://repo.sovrin.org/ios/libindy/stable/libindy-core/1.7.0/libindy.tar.gz" +export LIBINDY_IOS_BUILD_URL="https://repo.sovrin.org/ios/libindy/master/libindy-core/1.7.0-934/libindy.tar.gz" # export LIBINDY_IOS_BUILD_URL="https://repo.sovrin.org/ios/libindy/rc/libindy-core/1.6.6-28/libindy.tar.gz" export LIBSOVTOKEN_FILE=$(basename ${LIBSOVTOKEN_IOS_BUILD_URL}) diff --git a/vcx/libvcx/include/vcx.h b/vcx/libvcx/include/vcx.h index 9f7f1ca4..4b4680b1 100644 --- a/vcx/libvcx/include/vcx.h +++ b/vcx/libvcx/include/vcx.h @@ -19,6 +19,7 @@ typedef unsigned int vcx_wallet_search_handle_t; typedef unsigned int vcx_bool_t; typedef unsigned int count_t; typedef unsigned long vcx_price_t; +typedef unsigned int vcx_u32_t; typedef enum { @@ -1577,6 +1578,33 @@ vcx_error_t vcx_wallet_validate_payment_address(int32_t command_handle, const char *payment_address, void (*cb)(int32_t, vcx_error_t)); + +vcx_error_t vcx_set_default_logger( const char * pattern ); +vcx_error_t vcx_set_logger( const void* context, + vcx_bool_t (*enabledFn)(const void* context, + vcx_u32_t level, + const char* target), + void (*logFn)(const void* context, + vcx_u32_t level, + const char* target, + const char* message, + const char* module_path, + const char* file, + vcx_u32_t line), + void (*flushFn)(const void* context)); +vcx_error_t vcx_get_logger(const void* vcx_get_logger, + vcx_bool_t (**enabledFn)(const void* context, + vcx_u32_t level, + const char* target), + void (**logFn)(const void* context, + vcx_u32_t level, + const char* target, + const char* message, + const char* module_path, + const char* file, + vcx_u32_t line), + void (**flushFn)(const void* context) ); + #ifdef __cplusplus } // extern "C" #endif diff --git a/vcx/libvcx/install_toolchains.sh b/vcx/libvcx/install_toolchains.sh index a2f54ed0..5d99f8b1 100644 --- a/vcx/libvcx/install_toolchains.sh +++ b/vcx/libvcx/install_toolchains.sh @@ -10,11 +10,11 @@ cd /tmp/NDK if [ "$(uname)" == "Darwin" ]; then echo "Downloading NDK for OSX" - wget https://dl.google.com/android/repository/android-ndk-r16b-darwin-x86_64.zip + wget -q https://dl.google.com/android/repository/android-ndk-r16b-darwin-x86_64.zip unzip android-ndk-r16b-darwin-x86_64.zip elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then echo "Downloading NDK for Linux" - wget https://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip + wget -q https://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip unzip android-ndk-r16b-linux-x86_64.zip fi diff --git a/vcx/libvcx/sample_config/config.json b/vcx/libvcx/sample_config/config.json index fc17e928..5df6f1dd 100644 --- a/vcx/libvcx/sample_config/config.json +++ b/vcx/libvcx/sample_config/config.json @@ -1,7 +1,7 @@ { - "agency_did": "L5nbFwXJRmdnJVYhCsy52j", - "agency_verkey": "BQEgx9PJ7JJgt1LadyP45a7JrWdyqkrzrCBGRZ9QVrvL", - "agency_endpoint": "https://cagency.pdev.evernym.com", + "agency_did": "VsKV7grR1BUE29mG2Fm2kX", + "agency_verkey": "Hezce2UWMZ3wUhVkh2LfKSs8nDzWwzs2Win7EzNN3YaR", + "agency_endpoint": "http://localhost:8080", "genesis_path":"/var/lib/indy/verity-staging/pool_transactions_genesis", "institution_name": "institution", "institution_logo_url": "http://robohash.org/234", @@ -10,5 +10,7 @@ "remote_to_sdk_did": "EtfeMFytvYTKnWwqTScp9D", "remote_to_sdk_verkey": "8a7hZDyJK1nNCizRCKMr4H4QbDm8Gg2vcbDRab8SVfsi", "sdk_to_remote_did": "KacwZ2ndG6396KXJ9NDDw6", - "sdk_to_remote_verkey": "B8LgZGxEPcpTJfZkeqXuKNLihM1Awm8yidqsNwYi5QGc" + "sdk_to_remote_verkey": "B8LgZGxEPcpTJfZkeqXuKNLihM1Awm8yidqsNwYi5QGc", + "payment_method": "null" } + diff --git a/vcx/libvcx/scripts/provision_agent_keys.py b/vcx/libvcx/scripts/provision_agent_keys.py index d488233c..ddb62344 100755 --- a/vcx/libvcx/scripts/provision_agent_keys.py +++ b/vcx/libvcx/scripts/provision_agent_keys.py @@ -14,6 +14,7 @@ def parse_args(): parser.add_argument("AGENCY_URL") parser.add_argument("WALLET_KEY") parser.add_argument("--wallet-name", help="optional name for libindy wallet") + parser.add_argument("--wallet-type", help="optional type of libindy wallet") parser.add_argument("--agent-seed", help="optional seed used to create enterprise->agent DID/VK") parser.add_argument("--enterprise-seed", help="optional seed used to create enterprise DID/VK") parser.add_argument("--verbose", action="store_true") @@ -56,6 +57,7 @@ def register_agent(args): 'agency_verkey':agency_info['verKey'], 'wallet_key':args.WALLET_KEY, 'wallet_name':args.wallet_name, + 'wallet_type':args.wallet_type, 'agent_seed':args.agent_seed, 'enterprise_seed':args.enterprise_seed}) diff --git a/vcx/libvcx/src/api/connection.rs b/vcx/libvcx/src/api/connection.rs index 60ee07eb..8be66d0c 100644 --- a/vcx/libvcx/src/api/connection.rs +++ b/vcx/libvcx/src/api/connection.rs @@ -8,7 +8,7 @@ use utils::threadpool::spawn; use std::ptr; use error::ToErrorCode; use error::connection::ConnectionError; -use connection::{get_source_id, build_connection, build_connection_with_invite, connect, to_string, get_state, release, is_valid_handle, update_state, from_string, get_invite_details, delete_connection}; +use connection::{get_source_id, create_connection, create_connection_with_invite, connect, to_string, get_state, release, is_valid_handle, update_state, from_string, get_invite_details, delete_connection}; /// Delete a Connection object and release its handle /// @@ -28,19 +28,21 @@ pub extern fn vcx_connection_delete_connection(command_handle: u32, cb: Option) -> u32 { + info!("vcx_delete_connection >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); if !is_valid_handle(connection_handle) { return ConnectionError::InvalidHandle().to_error_code() } - info!("vcx_connection_delete_connection(command_handle: {}, connection_handle: {})", command_handle, connection_handle); + trace!("vcx_connection_delete_connection(command_handle: {}, connection_handle: {})", command_handle, connection_handle); spawn(move|| { match delete_connection(connection_handle) { Ok(_) => { - info!("vcx_connection_delete_connection_cb(command_handle: {}, rc: {})", command_handle, 0); + trace!("vcx_connection_delete_connection_cb(command_handle: {}, rc: {})", command_handle, 0); cb(command_handle, error::SUCCESS.code_num); }, Err(e) => { - info!("vcx_connection_delete_connection_cb(command_handle: {}, rc: {})", command_handle, e); + trace!("vcx_connection_delete_connection_cb(command_handle: {}, rc: {})", command_handle, e); cb(command_handle, e.to_error_code()); }, } @@ -67,13 +69,15 @@ pub extern fn vcx_connection_delete_connection(command_handle: u32, pub extern fn vcx_connection_create(command_handle: u32, source_id: *const c_char, cb: Option) -> u32 { + info!("vcx_connection_create >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); - info!("vcx_connection_create(command_handle: {}, source_id: {})", command_handle, source_id); + trace!("vcx_connection_create(command_handle: {}, source_id: {})", command_handle, source_id); spawn(move|| { - match build_connection(&source_id) { + match create_connection(&source_id) { Ok(handle) => { - info!("vcx_connection_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", + trace!("vcx_connection_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", command_handle, error_string(0), handle, source_id); cb(command_handle, error::SUCCESS.code_num, handle); }, @@ -108,15 +112,16 @@ pub extern fn vcx_connection_create_with_invite(command_handle: u32, source_id: *const c_char, invite_details: *const c_char, cb: Option) -> u32 { + info!("vcx_connection_create_with_invite >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); check_useful_c_str!(invite_details, error::INVALID_OPTION.code_num); - info!("vcx_connection_create_with_invite(command_handle: {}, source_id: {})", command_handle, source_id); + trace!("vcx_connection_create_with_invite(command_handle: {}, source_id: {})", command_handle, source_id); spawn(move|| { - match build_connection_with_invite(&source_id, &invite_details) { + match create_connection_with_invite(&source_id, &invite_details) { Ok(handle) => { - info!("vcx_connection_create_with_invite_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", + trace!("vcx_connection_create_with_invite_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", command_handle, error_string(0), handle, source_id); cb(command_handle, error::SUCCESS.code_num, handle); }, @@ -142,7 +147,7 @@ pub extern fn vcx_connection_create_with_invite(command_handle: u32, /// /// connection_options: Provides details indicating if the connection will be established by text or QR Code /// -/// # Examples connection_options -> "{"connection_type":"SMS","phone":"123"}" OR: "{"connection_type":"QR","phone":""}" +/// # Examples connection_options -> "{"connection_type":"SMS","phone":"123","use_public_did":true}" OR: "{"connection_type":"QR","phone":"","use_public_did":false}" /// /// cb: Callback that provides error status of request /// @@ -153,6 +158,7 @@ pub extern fn vcx_connection_connect(command_handle:u32, connection_handle: u32, connection_options: *const c_char, cb: Option) -> u32 { + info!("vcx_connection_connect >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -170,7 +176,7 @@ pub extern fn vcx_connection_connect(command_handle:u32, }; let source_id = get_source_id(connection_handle).unwrap_or_default(); - info!("vcx_connection_connect(command_handle: {}, connection_handle: {}, connection_options: {:?}), source_id: {:?}", + trace!("vcx_connection_connect(command_handle: {}, connection_handle: {}, connection_options: {:?}), source_id: {:?}", command_handle, connection_handle, options, source_id); spawn(move|| { @@ -178,7 +184,7 @@ pub extern fn vcx_connection_connect(command_handle:u32, Ok(_) => { match get_invite_details(connection_handle,true) { Ok(x) => { - info!("vcx_connection_connect_cb(command_handle: {}, connection_handle: {}, rc: {}, details: {}), source_id: {:?}", + trace!("vcx_connection_connect_cb(command_handle: {}, connection_handle: {}, rc: {}, details: {}), source_id: {:?}", command_handle, connection_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -218,11 +224,12 @@ pub extern fn vcx_connection_connect(command_handle:u32, pub extern fn vcx_connection_serialize(command_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_connection_serialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = get_source_id(connection_handle).unwrap_or_default(); - info!("vcx_connection_serialize(command_handle: {}, connection_handle: {}), source_id: {:?}", + trace!("vcx_connection_serialize(command_handle: {}, connection_handle: {}), source_id: {:?}", command_handle, connection_handle, source_id); if !is_valid_handle(connection_handle) { @@ -233,7 +240,7 @@ pub extern fn vcx_connection_serialize(command_handle: u32, spawn(move|| { match to_string(connection_handle) { Ok(json) => { - info!("vcx_connection_serialize_cb(command_handle: {}, connection_handle: {}, rc: {}, state: {}), source_id: {:?}", + trace!("vcx_connection_serialize_cb(command_handle: {}, connection_handle: {}, rc: {}, state: {}), source_id: {:?}", command_handle, connection_handle, error_string(0), json, source_id); let msg = CStringUtils::string_to_cstring(json); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -266,17 +273,18 @@ pub extern fn vcx_connection_serialize(command_handle: u32, pub extern fn vcx_connection_deserialize(command_handle: u32, connection_data: *const c_char, cb: Option) -> u32 { + info!("vcx_connection_deserialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(connection_data, error::INVALID_OPTION.code_num); - info!("vcx_connection_deserialize(command_handle: {}, connection_data: {})", command_handle, connection_data); + trace!("vcx_connection_deserialize(command_handle: {}, connection_data: {})", command_handle, connection_data); spawn(move|| { let (rc, handle) = match from_string(&connection_data) { Ok(x) => { let source_id = get_source_id(x).unwrap_or_default(); - info!("vcx_connection_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {:?}", + trace!("vcx_connection_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {:?}", command_handle, error_string(0), x, source_id); (error::SUCCESS.code_num, x) }, @@ -311,11 +319,12 @@ pub extern fn vcx_connection_deserialize(command_handle: u32, pub extern fn vcx_connection_update_state(command_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_connection_update_state >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = get_source_id(connection_handle).unwrap_or_default(); - info!("vcx_connection_update_state(command_handle: {}, connection_handle: {}), source_id: {:?}", + trace!("vcx_connection_update_state(command_handle: {}, connection_handle: {}), source_id: {:?}", command_handle, connection_handle, source_id); if !is_valid_handle(connection_handle) { @@ -326,7 +335,7 @@ pub extern fn vcx_connection_update_state(command_handle: u32, spawn(move|| { let rc = match update_state(connection_handle) { Ok(x) => { - info!("vcx_connection_update_state_cb(command_handle: {}, rc: {}, connection_handle: {}, state: {}), source_id: {:?}", + trace!("vcx_connection_update_state_cb(command_handle: {}, rc: {}, connection_handle: {}, state: {}), source_id: {:?}", command_handle, error_string(0), connection_handle, get_state(connection_handle), source_id); x }, @@ -360,11 +369,12 @@ pub extern fn vcx_connection_update_state(command_handle: u32, pub extern fn vcx_connection_get_state(command_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_connection_get_state >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = get_source_id(connection_handle).unwrap_or_default(); - info!("vcx_connection_get_state(command_handle: {}, connection_handle: {}), source_id: {:?}", + trace!("vcx_connection_get_state(command_handle: {}, connection_handle: {}), source_id: {:?}", command_handle, connection_handle, source_id); if !is_valid_handle(connection_handle) { @@ -373,7 +383,7 @@ pub extern fn vcx_connection_get_state(command_handle: u32, } spawn(move|| { - info!("vcx_connection_get_state_cb(command_handle: {}, rc: {}, connection_handle: {}, state: {}), source_id: {:?}", + trace!("vcx_connection_get_state_cb(command_handle: {}, rc: {}, connection_handle: {}, state: {}), source_id: {:?}", command_handle, error_string(0), connection_handle, get_state(connection_handle), source_id); cb(command_handle, error::SUCCESS.code_num, get_state(connection_handle)); @@ -401,11 +411,12 @@ pub extern fn vcx_connection_invite_details(command_handle: u32, connection_handle: u32, abbreviated: bool, cb: Option) -> u32 { + info!("vcx_connection_invite_details >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = get_source_id(connection_handle).unwrap_or_default(); - info!("vcx_connection_invite_details(command_handle: {}, connection_handle: {}, abbreviated: {}), source_id: {:?}", + trace!("vcx_connection_invite_details(command_handle: {}, connection_handle: {}, abbreviated: {}), source_id: {:?}", command_handle, connection_handle, abbreviated, source_id); if !is_valid_handle(connection_handle) { @@ -416,7 +427,7 @@ pub extern fn vcx_connection_invite_details(command_handle: u32, spawn(move|| { match get_invite_details(connection_handle, abbreviated){ Ok(str) => { - info!("vcx_connection_invite_details_cb(command_handle: {}, connection_handle: {}, rc: {}, details: {}), source_id: {:?}", + trace!("vcx_connection_invite_details_cb(command_handle: {}, connection_handle: {}, rc: {}, details: {}), source_id: {:?}", command_handle, connection_handle, error_string(0), str, source_id); let msg = CStringUtils::string_to_cstring(str); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -443,9 +454,11 @@ pub extern fn vcx_connection_invite_details(command_handle: u32, /// Success #[no_mangle] pub extern fn vcx_connection_release(connection_handle: u32) -> u32 { + info!("vcx_connection_release >>>"); + let source_id = get_source_id(connection_handle).unwrap_or_default(); match release(connection_handle) { - Ok(_) => info!("vcx_connection_release(connection_handle: {}, rc: {}), source_id: {:?}", + Ok(_) => trace!("vcx_connection_release(connection_handle: {}, rc: {}), source_id: {:?}", connection_handle, error_string(0), source_id), Err(e) => warn!("vcx_connection_release(connection_handle: {}), rc: {}), source_id: {:?}", connection_handle, error_string(e.to_error_code()), source_id), @@ -459,12 +472,12 @@ mod tests { use super::*; use std::ffi::CString; use std::ptr; + use connection::tests::build_test_connection; use utils::error; use std::time::Duration; - use api::VcxStateType; + use api::{return_types_u32, VcxStateType}; use utils::httpclient; use utils::constants::GET_MESSAGES_RESPONSE; - use utils::libindy::return_types_u32; use utils::error::SUCCESS; #[test] @@ -498,7 +511,7 @@ mod tests { let cb = return_types_u32::Return_U32_STR::new().unwrap(); let rc = vcx_connection_connect(cb.command_handle, 0, CString::new("{}").unwrap().into_raw(),Some(cb.get_callback())); assert_eq!(rc, error::INVALID_CONNECTION_HANDLE.code_num); - let handle = build_connection("test_vcx_connection_connect").unwrap(); + let handle = build_test_connection(); assert!(handle > 0); let cb = return_types_u32::Return_U32_STR::new().unwrap(); let rc = vcx_connection_connect(cb.command_handle,handle, CString::new("{}").unwrap().into_raw(),Some(cb.get_callback())); @@ -510,8 +523,9 @@ mod tests { #[test] fn test_vcx_connection_update_state() { init!("true"); - let handle = build_connection("test_vcx_connection_update_state").unwrap(); + let handle = build_test_connection(); assert!(handle > 0); + connect(handle,None).unwrap(); let cb = return_types_u32::Return_U32_U32::new().unwrap(); httpclient::set_next_u8_response(GET_MESSAGES_RESPONSE.to_vec()); let rc = vcx_connection_update_state(cb.command_handle,handle,Some(cb.get_callback())); @@ -529,7 +543,7 @@ mod tests { #[test] fn test_vcx_connection_serialize() { init!("true"); - let handle = build_connection("test_vcx_connection_get_data").unwrap(); + let handle = build_test_connection(); assert!(handle > 0); let cb = return_types_u32::Return_U32_STR::new().unwrap(); @@ -543,7 +557,7 @@ mod tests { #[test] fn test_vcx_connection_release() { init!("true"); - let handle = build_connection("test_vcx_connection_release").unwrap(); + let handle = build_test_connection(); assert!(handle > 0); let rc = vcx_connection_release(handle); @@ -569,9 +583,10 @@ mod tests { #[test] fn test_vcx_connection_get_state() { init!("true"); - let handle = build_connection("test_vcx_connection_get_state").unwrap(); + let handle = build_test_connection(); assert!(handle > 0); let cb = return_types_u32::Return_U32_U32::new().unwrap(); + connect(handle, None).unwrap(); httpclient::set_next_u8_response(GET_MESSAGES_RESPONSE.to_vec()); let rc = vcx_connection_update_state(cb.command_handle,handle,Some(cb.get_callback())); assert_eq!(cb.receive(Some(Duration::from_secs(10))).unwrap(), VcxStateType::VcxStateAccepted as u32); @@ -584,10 +599,10 @@ mod tests { #[test] fn test_vcx_connection_delete_connection() { init!("true"); - let test_name = "test_vcx_connection_delete_connection"; - let connection_handle = build_connection(test_name).unwrap(); - let command_handle = 0; + let connection_handle = build_test_connection(); + connect(connection_handle, Some("{}".to_string())).unwrap(); let cb = return_types_u32::Return_U32::new().unwrap(); - assert_eq!(0, vcx_connection_delete_connection(command_handle, connection_handle, Some(cb.get_callback()))); + assert_eq!(vcx_connection_delete_connection(cb.command_handle, connection_handle, Some(cb.get_callback())), error::SUCCESS.code_num); + cb.receive(Some(Duration::from_secs(10))).unwrap(); } } diff --git a/vcx/libvcx/src/api/credential.rs b/vcx/libvcx/src/api/credential.rs index 9972b816..d86e9a53 100644 --- a/vcx/libvcx/src/api/credential.rs +++ b/vcx/libvcx/src/api/credential.rs @@ -28,6 +28,8 @@ use utils::threadpool::spawn; pub extern fn vcx_credential_get_payment_info(command_handle: u32, credential_handle: u32, cb: Option) -> u32 { + info!("vcx_credential_get_payment_info >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); spawn(move|| { match credential::get_payment_information(credential_handle) { @@ -35,13 +37,13 @@ pub extern fn vcx_credential_get_payment_info(command_handle: u32, match p { Some(p) => { let info = p.to_string().unwrap_or("{}".to_string()); - info!("vcx_credential_get_payment_info(command_handle: {}, rc: {}, msg: {})", command_handle, error::SUCCESS.code_num, info.clone()); + trace!("vcx_credential_get_payment_info(command_handle: {}, rc: {}, msg: {})", command_handle, error::SUCCESS.code_num, info.clone()); let msg = CStringUtils::string_to_cstring(info); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, None => { let msg = CStringUtils::string_to_cstring(format!("{{}}")); - info!("vcx_credential_get_payment_info(command_handle: {}, rc: {}, msg: {})", command_handle, error::SUCCESS.code_num, "{}"); + trace!("vcx_credential_get_payment_info(command_handle: {}, rc: {}, msg: {})", command_handle, error::SUCCESS.code_num, "{}"); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); } } @@ -82,18 +84,19 @@ pub extern fn vcx_credential_create_with_offer(command_handle: u32, source_id: *const c_char, offer: *const c_char, cb: Option) -> u32 { + info!("vcx_credential_create_with_offer >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); check_useful_c_str!(offer, error::INVALID_OPTION.code_num); - info!("vcx_credential_create_with_offer(command_handle: {}, source_id: {}, offer: {})", + trace!("vcx_credential_create_with_offer(command_handle: {}, source_id: {}, offer: {})", command_handle, source_id, offer); spawn(move|| { match credential::credential_create_with_offer(&source_id, &offer) { Ok(x) => { - info!("vcx_credential_create_with_offer_cb(command_handle: {}, source_id: {}, rc: {}, handle: {})", + trace!("vcx_credential_create_with_offer_cb(command_handle: {}, source_id: {}, rc: {}, handle: {})", command_handle, source_id, error_string(0), x); cb(command_handle, error::SUCCESS.code_num, x) }, @@ -127,19 +130,21 @@ pub extern fn vcx_credential_create_with_offer(command_handle: u32, pub extern fn vcx_get_credential(command_handle: u32, credential_handle: u32, cb: Option) -> u32 { + info!("vcx_get_credential >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); if !credential::is_valid_handle(credential_handle) { return CredentialError::InvalidHandle().to_error_code(); } let source_id = credential::get_source_id(credential_handle).unwrap_or_default(); - info!("vcx_get_credential(command_handle: {}, credential_handle: {}) source_id: {})", + trace!("vcx_get_credential(command_handle: {}, credential_handle: {}) source_id: {})", command_handle, credential_handle, source_id); spawn(move|| { match credential::get_credential(credential_handle) { Ok(s) => { - info!("vcx_get_credential_cb(commmand_handle: {}, rc: {}, msg: {}) source_id: {}", + trace!("vcx_get_credential_cb(commmand_handle: {}, rc: {}, msg: {}) source_id: {}", command_handle, error::SUCCESS.code_num, s, source_id); let msg = CStringUtils::string_to_cstring(s); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -180,12 +185,13 @@ pub extern fn vcx_credential_create_with_msgid(command_handle: u32, connection_handle: u32, msg_id: *const c_char, cb: Option) -> u32 { + info!("vcx_credential_create_with_msgid >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); check_useful_c_str!(msg_id, error::INVALID_OPTION.code_num); - info!("vcx_credential_create_with_msgid(command_handle: {}, source_id: {}, connection_handle: {}, msg_id: {})", + trace!("vcx_credential_create_with_msgid(command_handle: {}, source_id: {}, connection_handle: {}, msg_id: {})", command_handle, source_id, connection_handle, msg_id); spawn(move|| { @@ -198,7 +204,7 @@ pub extern fn vcx_credential_create_with_msgid(command_handle: u32, Err(_) => offer, }; let c_offer = CStringUtils::string_to_cstring(offer_string); - info!("vcx_credential_create_with_offer_cb(command_handle: {}, source_id: {}, rc: {}, handle: {}) source_id: {}", + trace!("vcx_credential_create_with_offer_cb(command_handle: {}, source_id: {}, rc: {}, handle: {}) source_id: {}", command_handle, source_id, error_string(0), handle, source_id); cb(command_handle, error::SUCCESS.code_num, handle, c_offer.as_ptr()) }, @@ -238,6 +244,7 @@ pub extern fn vcx_credential_send_request(command_handle: u32, connection_handle: u32, payment_handle: u32, cb: Option) -> u32 { + info!("vcx_credential_send_request >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -250,13 +257,13 @@ pub extern fn vcx_credential_send_request(command_handle: u32, } let source_id = credential::get_source_id(credential_handle).unwrap_or_default(); - info!("vcx_credential_send_request(command_handle: {}, credential_handle: {}, connection_handle: {}), source_id: {:?}", + trace!("vcx_credential_send_request(command_handle: {}, credential_handle: {}, connection_handle: {}), source_id: {:?}", command_handle, credential_handle, connection_handle, source_id); spawn(move|| { match credential::send_credential_request(credential_handle, connection_handle) { Ok(x) => { - info!("vcx_credential_send_request_cb(command_handle: {}, rc: {}) source_id: {}", + trace!("vcx_credential_send_request_cb(command_handle: {}, rc: {}) source_id: {}", command_handle, x.to_string(), source_id); cb(command_handle,x); }, @@ -289,6 +296,7 @@ pub extern fn vcx_credential_send_request(command_handle: u32, pub extern fn vcx_credential_get_offers(command_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_credential_get_offers >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -296,13 +304,13 @@ pub extern fn vcx_credential_get_offers(command_handle: u32, return error::INVALID_CONNECTION_HANDLE.code_num; } - info!("vcx_credential_get_offers(command_handle: {}, connection_handle: {})", + trace!("vcx_credential_get_offers(command_handle: {}, connection_handle: {})", command_handle, connection_handle); spawn(move|| { match credential::get_credential_offer_messages(connection_handle) { Ok(x) => { - info!("vcx_credential_get_offers_cb(command_handle: {}, rc: {}, msg: {})", + trace!("vcx_credential_get_offers_cb(command_handle: {}, rc: {}, msg: {})", command_handle, x.to_string(), x); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -337,6 +345,7 @@ pub extern fn vcx_credential_get_offers(command_handle: u32, pub extern fn vcx_credential_update_state(command_handle: u32, credential_handle: u32, cb: Option) -> u32 { + info!("vcx_credential_update_state >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -345,7 +354,7 @@ pub extern fn vcx_credential_update_state(command_handle: u32, } let source_id = credential::get_source_id(credential_handle).unwrap_or_default(); - info!("vcx_credential_update_state(command_handle: {}, credential_handle: {}), source_id: {:?}", + trace!("vcx_credential_update_state(command_handle: {}, credential_handle: {}), source_id: {:?}", command_handle, credential_handle, source_id); spawn(move|| { @@ -360,7 +369,7 @@ pub extern fn vcx_credential_update_state(command_handle: u32, let state = match credential::get_state(credential_handle) { Ok(s) => { - info!("vcx_credential_update_state_cb(command_handle: {}, rc: {}, state: {}), source_id: {:?}", + trace!("vcx_credential_update_state_cb(command_handle: {}, rc: {}, state: {}), source_id: {:?}", command_handle, error_string(0), s, source_id); cb(command_handle, error::SUCCESS.code_num, s) }, @@ -391,6 +400,8 @@ pub extern fn vcx_credential_update_state(command_handle: u32, pub extern fn vcx_credential_get_state(command_handle: u32, handle: u32, cb: Option) -> u32 { + info!("vcx_credential_get_state >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); if !credential::is_valid_handle(handle) { @@ -398,13 +409,13 @@ pub extern fn vcx_credential_get_state(command_handle: u32, } let source_id = credential::get_source_id(handle).unwrap_or_default(); - info!("vcx_credential_get_state(command_handle: {}, credential_handle: {}), source_id: {:?}", + trace!("vcx_credential_get_state(command_handle: {}, credential_handle: {}), source_id: {:?}", command_handle, handle, source_id); spawn(move|| { match credential::get_state(handle) { Ok(s) => { - info!("vcx_credential_get_state_cb(command_handle: {}, rc: {}, state: {}), source_id: {:?}", + trace!("vcx_credential_get_state_cb(command_handle: {}, rc: {}, state: {}), source_id: {:?}", command_handle, error_string(0), s, source_id); cb(command_handle, error::SUCCESS.code_num, s) }, @@ -437,6 +448,7 @@ pub extern fn vcx_credential_get_state(command_handle: u32, pub extern fn vcx_credential_serialize(command_handle: u32, handle: u32, cb: Option) -> u32 { + info!("vcx_credential_serialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -445,13 +457,13 @@ pub extern fn vcx_credential_serialize(command_handle: u32, } let source_id = credential::get_source_id(handle).unwrap_or_default(); - info!("vcx_credential_serialize(command_handle: {}, credential_handle: {}), source_id: {:?}", + trace!("vcx_credential_serialize(command_handle: {}, credential_handle: {}), source_id: {:?}", command_handle, handle, source_id); spawn(move|| { match credential::to_string(handle) { Ok(x) => { - info!("vcx_credential_serialize_cb(command_handle: {}, rc: {}, data: {}), source_id: {:?}", + trace!("vcx_credential_serialize_cb(command_handle: {}, rc: {}, data: {}), source_id: {:?}", command_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -485,17 +497,18 @@ pub extern fn vcx_credential_serialize(command_handle: u32, pub extern fn vcx_credential_deserialize(command_handle: u32, credential_data: *const c_char, cb: Option) -> u32 { + info!("vcx_credential_deserialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(credential_data, error::INVALID_OPTION.code_num); - info!("vcx_credential_deserialize(command_handle: {}, credential_data: {})", + trace!("vcx_credential_deserialize(command_handle: {}, credential_data: {})", command_handle, credential_data); spawn(move|| { match credential::from_string(&credential_data) { Ok(x) => { - info!("vcx_credential_deserialize_cb(command_handle: {}, rc: {}, credential_handle: {}) source_id: {}", + trace!("vcx_credential_deserialize_cb(command_handle: {}, rc: {}, credential_handle: {}) source_id: {}", command_handle, error_string(0), x, credential::get_source_id(x).unwrap_or_default()); cb(command_handle, 0, x); @@ -522,9 +535,11 @@ pub extern fn vcx_credential_deserialize(command_handle: u32, /// Success #[no_mangle] pub extern fn vcx_credential_release(handle: u32) -> u32 { + info!("vcx_credential_release >>>"); + let source_id = credential::get_source_id(handle).unwrap_or_default(); match credential::release(handle) { - Ok(_) => info!("vcx_credential_release(handle: {}, rc: {}), source_id: {:?}", + Ok(_) => trace!("vcx_credential_release(handle: {}, rc: {}), source_id: {:?}", handle, error_string(0), source_id), Err(e) => error!("vcx_credential_release(handle: {}, rc: {}), source_id: {:?}", handle, error_string(e.to_error_code()), source_id), @@ -554,18 +569,19 @@ pub extern fn vcx_credential_release(handle: u32) -> u32 { pub extern fn vcx_credential_get_payment_txn(command_handle: u32, handle: u32, cb: Option) -> u32 { + info!("vcx_credential_get_payment_txn >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = credential::get_source_id(handle).unwrap_or_default(); - info!("vcx_credential_get_payment_txn(command_handle: {}) source_id: {}", command_handle, source_id); + trace!("vcx_credential_get_payment_txn(command_handle: {}) source_id: {}", command_handle, source_id); spawn(move|| { match credential::get_payment_txn(handle) { Ok(x) => { match serde_json::to_string(&x) { Ok(x) => { - info!("vcx_credential_get_payment_txn_cb(command_handle: {}, rc: {}, : {}), source_id: {}", + trace!("vcx_credential_get_payment_txn_cb(command_handle: {}, rc: {}, : {}), source_id: {}", command_handle, error_string(0), x, credential::get_source_id(handle).unwrap_or_default()); let msg = CStringUtils::string_to_cstring(x); @@ -599,7 +615,7 @@ mod tests { use std::time::Duration; use connection; use api::VcxStateType; - use utils::libindy::return_types_u32; + use api::return_types_u32; use serde_json::Value; use utils::constants::{DEFAULT_SERIALIZED_CREDENTIAL, DEFAULT_SERIALIZE_VERSION}; @@ -652,7 +668,7 @@ mod tests { let handle = credential::credential_create_with_offer("test_send_request",::utils::constants::CREDENTIAL_OFFER_JSON).unwrap(); assert_eq!(credential::get_state(handle).unwrap(),VcxStateType::VcxStateRequestReceived as u32); - let connection_handle = connection::build_connection("test_send_credential_offer").unwrap(); + let connection_handle = connection::tests::build_test_connection(); let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_credential_send_request(cb.command_handle,handle,connection_handle,0, Some(cb.get_callback())), error::SUCCESS.code_num); cb.receive(Some(Duration::from_secs(10))).unwrap(); @@ -661,7 +677,7 @@ mod tests { #[test] fn test_vcx_credential_get_new_offers(){ init!("true"); - let cxn = ::connection::build_connection("test_get_new_offers").unwrap(); + let cxn = ::connection::tests::build_test_connection(); let cb = return_types_u32::Return_U32_STR::new().unwrap(); assert_eq!(vcx_credential_get_offers(cb.command_handle, cxn, @@ -673,7 +689,7 @@ mod tests { #[test] fn test_vcx_credential_create() { init!("true"); - let cxn = ::connection::build_connection("test_vcx_credential_create").unwrap(); + let cxn = ::connection::tests::build_test_connection(); let cb = return_types_u32::Return_U32_U32_STR::new().unwrap(); assert_eq!(vcx_credential_create_with_msgid(cb.command_handle, CString::new("test_vcx_credential_create").unwrap().into_raw(), @@ -697,7 +713,8 @@ mod tests { #[test] fn test_vcx_credential_update_state() { init!("true"); - let cxn = ::connection::build_connection("test_credential_update_state").unwrap(); + let cxn = ::connection::tests::build_test_connection(); + ::connection::connect(cxn,None).unwrap(); let handle = credential::from_string(DEFAULT_SERIALIZED_CREDENTIAL).unwrap(); ::utils::httpclient::set_next_u8_response(::utils::constants::NEW_CREDENTIAL_OFFER_RESPONSE.to_vec()); let cb = return_types_u32::Return_U32_U32::new().unwrap(); diff --git a/vcx/libvcx/src/api/credential_def.rs b/vcx/libvcx/src/api/credential_def.rs index 1b11fda4..5b5e3565 100644 --- a/vcx/libvcx/src/api/credential_def.rs +++ b/vcx/libvcx/src/api/credential_def.rs @@ -26,9 +26,12 @@ use utils::threadpool::spawn; /// /// tag: way to create a unique credential def with the same schema and issuer did. /// -//Todo: Provide more info about the config -/// config: revocation info -/// +/// revocation details: type-specific configuration of credential definition revocation +/// TODO: Currently supports ISSUANCE BY DEFAULT, support for ISSUANCE ON DEMAND will be added as part of ticket: IS-1074 +/// support_revocation: true|false - Optional, by default its false +/// tails_file: path to tails file - Optional if support_revocation is false +/// max_creds: size of tails file - Optional if support_revocation is false +/// # Examples config -> "{}" | "{"support_revocation":false}" | "{"support_revocation":true, "tails_file": "/tmp/tailsfile.txt", "max_creds": 1}" /// cb: Callback that provides CredentialDef handle and error status of request. /// /// payment_handle: future use (currently uses any address in wallet) @@ -42,15 +45,17 @@ pub extern fn vcx_credentialdef_create(command_handle: u32, schema_id: *const c_char, issuer_did: *const c_char, tag: *const c_char, - config: *const c_char, + revocation_details: *const c_char, payment_handle: u32, cb: Option) -> u32 { + info!("vcx_credentialdef_create >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(credentialdef_name, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); check_useful_c_str!(schema_id, error::INVALID_OPTION.code_num); check_useful_c_str!(tag, error::INVALID_OPTION.code_num); - check_useful_c_str!(config, error::INVALID_OPTION.code_num); + check_useful_c_str!(revocation_details, error::INVALID_OPTION.code_num); let issuer_did: String = if !issuer_did.is_null() { check_useful_c_str!(issuer_did, error::INVALID_OPTION.code_num); @@ -61,24 +66,25 @@ pub extern fn vcx_credentialdef_create(command_handle: u32, Err(x) => return x } }; - info!("vcx_credential_def_create(command_handle: {}, source_id: {}, credentialdef_name: {} schema_id: {}, issuer_did: {}, tag: {}, config: {})", + + trace!("vcx_credential_def_create(command_handle: {}, source_id: {}, credentialdef_name: {} schema_id: {}, issuer_did: {}, tag: {}, revocation_details: {:?})", command_handle, source_id, credentialdef_name, schema_id, issuer_did, tag, - config); + revocation_details); spawn(move|| { let ( rc, handle) = match credential_def::create_new_credentialdef(source_id, - credentialdef_name, - issuer_did, - schema_id, - tag, - config) { + credentialdef_name, + issuer_did, + schema_id, + tag, + revocation_details) { Ok(x) => { - info!("vcx_credential_def_create_cb(command_handle: {}, rc: {}, credentialdef_handle: {}), source_id: {:?}", + trace!("vcx_credential_def_create_cb(command_handle: {}, rc: {}, credentialdef_handle: {}), source_id: {:?}", command_handle, error_string(0), x, credential_def::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, @@ -111,11 +117,12 @@ pub extern fn vcx_credentialdef_create(command_handle: u32, pub extern fn vcx_credentialdef_serialize(command_handle: u32, credentialdef_handle: u32, cb: Option) -> u32 { + info!("vcx_credentialdef_serialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = credential_def::get_source_id(credentialdef_handle).unwrap_or_default(); - info!("vcx_credentialdef_serialize(command_handle: {}, credentialdef_handle: {}), source_id: {:?}", + trace!("vcx_credentialdef_serialize(command_handle: {}, credentialdef_handle: {}), source_id: {:?}", command_handle, credentialdef_handle, source_id); if !credential_def::is_valid_handle(credentialdef_handle) { @@ -125,7 +132,7 @@ pub extern fn vcx_credentialdef_serialize(command_handle: u32, spawn(move|| { match credential_def::to_string(credentialdef_handle) { Ok(x) => { - info!("vcx_credentialdef_serialize_cb(command_handle: {}, credentialdef_handle: {}, rc: {}, state: {}), source_id: {:?}", + trace!("vcx_credentialdef_serialize_cb(command_handle: {}, credentialdef_handle: {}, rc: {}, state: {}), source_id: {:?}", command_handle, credentialdef_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -158,16 +165,17 @@ pub extern fn vcx_credentialdef_serialize(command_handle: u32, pub extern fn vcx_credentialdef_deserialize(command_handle: u32, credentialdef_data: *const c_char, cb: Option) -> u32 { + info!("vcx_credentialdef_deserialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(credentialdef_data, error::INVALID_OPTION.code_num); - info!("vcx_credentialdef_deserialize(command_handle: {}, credentialdef_data: {})", command_handle, credentialdef_data); + trace!("vcx_credentialdef_deserialize(command_handle: {}, credentialdef_data: {})", command_handle, credentialdef_data); spawn(move|| { let (rc, handle) = match credential_def::from_string(&credentialdef_data) { Ok(x) => { - info!("vcx_credentialdef_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", + trace!("vcx_credentialdef_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", command_handle, error_string(0), x, credential_def::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, @@ -199,10 +207,12 @@ pub extern fn vcx_credentialdef_deserialize(command_handle: u32, pub extern fn vcx_credentialdef_get_cred_def_id(command_handle: u32, cred_def_handle: u32, cb: Option) -> u32 { + info!("vcx_credentialdef_get_cred_def_id >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = credential_def::get_source_id(cred_def_handle).unwrap_or_default(); - info!("vcx_credentialdef_get_cred_def_id(command_handle: {}, cred_def_handle: {}) source_id: {}", command_handle, cred_def_handle, source_id); + trace!("vcx_credentialdef_get_cred_def_id(command_handle: {}, cred_def_handle: {}) source_id: {}", command_handle, cred_def_handle, source_id); if !credential_def::is_valid_handle(cred_def_handle) { return error::INVALID_CREDENTIAL_DEF_HANDLE.code_num; } @@ -210,7 +220,7 @@ pub extern fn vcx_credentialdef_get_cred_def_id(command_handle: u32, spawn(move|| { match credential_def::get_cred_def_id(cred_def_handle) { Ok(x) => { - info!("vcx_credentialdef_get_cred_def_id(command_handle: {}, cred_def_handle: {}, rc: {}, cred_def_id: {}) source_id: {}", + trace!("vcx_credentialdef_get_cred_def_id(command_handle: {}, cred_def_handle: {}, rc: {}, cred_def_id: {}) source_id: {}", command_handle, cred_def_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -250,18 +260,19 @@ pub extern fn vcx_credentialdef_get_cred_def_id(command_handle: u32, pub extern fn vcx_credentialdef_get_payment_txn(command_handle: u32, handle: u32, cb: Option) -> u32 { + info!("vcx_credentialdef_get_payment_txn >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = credential_def::get_source_id(handle).unwrap_or_default(); - info!("vcx_credentialdef_get_payment_txn(command_handle: {}) source_id: {}", command_handle, source_id); + trace!("vcx_credentialdef_get_payment_txn(command_handle: {}) source_id: {}", command_handle, source_id); spawn(move|| { - match credential_def::get_payment_txn(handle) { + match credential_def::get_cred_def_payment_txn(handle) { Ok(x) => { match serde_json::to_string(&x) { Ok(x) => { - info!("vcx_credentialdef_get_payment_txn_cb(command_handle: {}, rc: {}, : {}), source_id: {}", + trace!("vcx_credentialdef_get_payment_txn_cb(command_handle: {}, rc: {}, : {}), source_id: {}", command_handle, error_string(0), x, credential_def::get_source_id(handle).unwrap_or_default()); let msg = CStringUtils::string_to_cstring(x); @@ -296,9 +307,11 @@ pub extern fn vcx_credentialdef_get_payment_txn(command_handle: u32, /// Success #[no_mangle] pub extern fn vcx_credentialdef_release(credentialdef_handle: u32) -> u32 { + info!("vcx_credentialdef_release >>>"); + let source_id = credential_def::get_source_id(credentialdef_handle).unwrap_or_default(); match credential_def::release(credentialdef_handle) { - Ok(_) => info!("vcx_credentialdef_release(credentialdef_handle: {}, rc: {}), source_id: {}", + Ok(_) => trace!("vcx_credentialdef_release(credentialdef_handle: {}, rc: {}), source_id: {}", credentialdef_handle, error_string(0), source_id), Err(x) => warn!("vcx_credentialdef_release(credentialdef_handle: {}, rc: {}), source_id: {}", credentialdef_handle, x.to_string(), source_id), @@ -314,7 +327,7 @@ mod tests { use std::ffi::CString; use std::time::Duration; use settings; - use utils::libindy::return_types_u32; + use api::return_types_u32; use utils::constants::{SCHEMA_ID}; #[test] @@ -367,14 +380,16 @@ mod tests { let handle = cb.receive(Some(Duration::from_secs(10))).unwrap(); let cb = return_types_u32::Return_U32_STR::new().unwrap(); assert_eq!(vcx_credentialdef_serialize(cb.command_handle, handle, Some(cb.get_callback())), error::SUCCESS.code_num); - assert!(cb.receive(Some(Duration::from_secs(10))).is_ok()); + let cred = cb.receive(Some(Duration::from_secs(10))).unwrap(); + assert!(cred.is_some()); } #[test] fn test_vcx_credentialdef_deserialize_succeeds() { init!("true"); let cb = return_types_u32::Return_U32_U32::new().unwrap(); - let original = r#"{"version":"1.0", "data": {"id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1697","tag":"tag","name":"Test Credential Definition","source_id":"SourceId"}}"#; + + let original = r#"{"version":"1.0", "data": {"id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1697","issuer_did":"2hoqvcwupRTUNkXn6ArYzs","tag":"tag","name":"Test Credential Definition","rev_ref_def":null,"rev_reg_entry":null,"rev_reg_id":null,"source_id":"SourceId"}}"#; assert_eq!(vcx_credentialdef_deserialize(cb.command_handle, CString::new(original).unwrap().into_raw(), Some(cb.get_callback())), error::SUCCESS.code_num); @@ -410,7 +425,8 @@ mod tests { let handle = credential_def::create_new_credentialdef("sid".to_string(), "name".to_string(), did,SCHEMA_ID.to_string(), - "tag".to_string(),"{}".to_string()).unwrap(); + "tag".to_string(), + "{}".to_string()).unwrap(); let cb = return_types_u32::Return_U32_STR::new().unwrap(); let rc = vcx_credentialdef_get_payment_txn(cb.command_handle, handle, Some(cb.get_callback())); cb.receive(Some(Duration::from_secs(10))).unwrap(); diff --git a/vcx/libvcx/src/api/disclosed_proof.rs b/vcx/libvcx/src/api/disclosed_proof.rs index 3c8ec80c..98d9f888 100644 --- a/vcx/libvcx/src/api/disclosed_proof.rs +++ b/vcx/libvcx/src/api/disclosed_proof.rs @@ -30,18 +30,19 @@ pub extern fn vcx_disclosed_proof_create_with_request(command_handle: u32, source_id: *const c_char, proof_req: *const c_char, cb: Option) -> u32 { + info!("vcx_disclosed_proof_create_with_request >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); check_useful_c_str!(proof_req, error::INVALID_OPTION.code_num); - info!("vcx_disclosed_proof_create_with_request(command_handle: {}, source_id: {}, proof_req: {})", + trace!("vcx_disclosed_proof_create_with_request(command_handle: {}, source_id: {}, proof_req: {})", command_handle, source_id, proof_req); spawn(move|| { match disclosed_proof::create_proof(&source_id, &proof_req){ Ok(x) => { - info!("vcx_disclosed_proof_create_with_request_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", + trace!("vcx_disclosed_proof_create_with_request_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", command_handle, error_string(0), x, source_id); cb(command_handle, 0, x); }, @@ -82,12 +83,13 @@ pub extern fn vcx_disclosed_proof_create_with_msgid(command_handle: u32, connection_handle: u32, msg_id: *const c_char, cb: Option) -> u32 { + info!("vcx_disclosed_proof_create_with_msgid >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); check_useful_c_str!(msg_id, error::INVALID_OPTION.code_num); - info!("vcx_disclosed_proof_create_with_msgid(command_handle: {}, source_id: {}, connection_handle: {}, msg_id: {})", + trace!("vcx_disclosed_proof_create_with_msgid(command_handle: {}, source_id: {}, connection_handle: {}, msg_id: {})", command_handle, source_id, connection_handle, msg_id); spawn(move|| { @@ -95,7 +97,7 @@ pub extern fn vcx_disclosed_proof_create_with_msgid(command_handle: u32, Ok(request) => { match disclosed_proof::create_proof(&source_id, &request) { Ok(handle) => { - info!("vcx_disclosed_proof_create_with_msgid_cb(command_handle: {}, rc: {}, handle: {}, proof_req: {}) source_id: {}", + trace!("vcx_disclosed_proof_create_with_msgid_cb(command_handle: {}, rc: {}, handle: {}, proof_req: {}) source_id: {}", command_handle, error_string(0), handle, request, source_id); let msg = CStringUtils::string_to_cstring(request); cb(command_handle, error::SUCCESS.code_num, handle, msg.as_ptr()) @@ -136,6 +138,7 @@ pub extern fn vcx_disclosed_proof_send_proof(command_handle: u32, proof_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_disclosed_proof_send_proof >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -148,13 +151,13 @@ pub extern fn vcx_disclosed_proof_send_proof(command_handle: u32, } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_disclosed_proof_send_proof(command_handle: {}, proof_handle: {}, connection_handle: {}) source_id: {}", + trace!("vcx_disclosed_proof_send_proof(command_handle: {}, proof_handle: {}, connection_handle: {}) source_id: {}", command_handle, proof_handle, connection_handle, source_id); spawn(move|| { let err = match disclosed_proof::send_proof(proof_handle, connection_handle) { Ok(x) => { - info!("vcx_disclosed_proof_send_proof_cb(command_handle: {}, rc: {}) source_id: {}", + trace!("vcx_disclosed_proof_send_proof_cb(command_handle: {}, rc: {}) source_id: {}", command_handle, error_string(0), source_id); cb(command_handle,x); }, @@ -187,6 +190,7 @@ pub extern fn vcx_disclosed_proof_send_proof(command_handle: u32, pub extern fn vcx_disclosed_proof_get_requests(command_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_disclosed_proof_get_requests >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -194,13 +198,13 @@ pub extern fn vcx_disclosed_proof_get_requests(command_handle: u32, return error::INVALID_CONNECTION_HANDLE.code_num; } - info!("vcx_disclosed_proof_get_requests(command_handle: {}, connection_handle: {})", + trace!("vcx_disclosed_proof_get_requests(command_handle: {}, connection_handle: {})", command_handle, connection_handle); spawn(move|| { match disclosed_proof::get_proof_request_messages(connection_handle, None) { Ok(x) => { - info!("vcx_disclosed_proof_get_requests_cb(command_handle: {}, rc: {}, msg: {})", + trace!("vcx_disclosed_proof_get_requests_cb(command_handle: {}, rc: {}, msg: {})", command_handle, error_string(0), x); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -233,6 +237,7 @@ pub extern fn vcx_disclosed_proof_get_requests(command_handle: u32, pub extern fn vcx_disclosed_proof_get_state(command_handle: u32, proof_handle: u32, cb: Option) -> u32 { + info!("vcx_disclosed_proof_get_state >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -241,13 +246,13 @@ pub extern fn vcx_disclosed_proof_get_state(command_handle: u32, } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_disclosed_proof_get_state(command_handle: {}, proof_handle: {}), source_id: {:?}", + trace!("vcx_disclosed_proof_get_state(command_handle: {}, proof_handle: {}), source_id: {:?}", command_handle, proof_handle, source_id); spawn(move|| { match disclosed_proof::get_state(proof_handle) { Ok(s) => { - info!("vcx_disclosed_proof_get_state_cb(command_handle: {}, rc: {}, state: {}) source_id: {}", + trace!("vcx_disclosed_proof_get_state_cb(command_handle: {}, rc: {}, state: {}) source_id: {}", command_handle, error_string(0), s, source_id); cb(command_handle, error::SUCCESS.code_num, s) }, @@ -279,6 +284,7 @@ pub extern fn vcx_disclosed_proof_get_state(command_handle: u32, pub extern fn vcx_disclosed_proof_update_state(command_handle: u32, proof_handle: u32, cb: Option) -> u32 { + info!("vcx_disclosed_proof_update_state >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -287,13 +293,13 @@ pub extern fn vcx_disclosed_proof_update_state(command_handle: u32, } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_disclosed_proof_update_state(command_handle: {}, proof_handle: {}) source_id: {}", + trace!("vcx_disclosed_proof_update_state(command_handle: {}, proof_handle: {}) source_id: {}", command_handle, proof_handle, source_id); spawn(move|| { match disclosed_proof::update_state(proof_handle) { Ok(s) => { - info!("vcx_disclosed_proof_update_state_cb(command_handle: {}, rc: {}, state: {}) source_id: {}", + trace!("vcx_disclosed_proof_update_state_cb(command_handle: {}, rc: {}, state: {}) source_id: {}", command_handle, error_string(0), s, source_id); cb(command_handle, error::SUCCESS.code_num, s) }, @@ -325,6 +331,7 @@ pub extern fn vcx_disclosed_proof_update_state(command_handle: u32, pub extern fn vcx_disclosed_proof_serialize(command_handle: u32, proof_handle: u32, cb: Option) -> u32 { + info!("vcx_disclosed_proof_serialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -333,13 +340,13 @@ pub extern fn vcx_disclosed_proof_serialize(command_handle: u32, } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_disclosed_proof_serialize(command_handle: {}, proof_handle: {}) source_id: {}", + trace!("vcx_disclosed_proof_serialize(command_handle: {}, proof_handle: {}) source_id: {}", command_handle, proof_handle, source_id); spawn(move|| { match disclosed_proof::to_string(proof_handle) { Ok(x) => { - info!("vcx_disclosed_proof_serialize_cb(command_handle: {}, rc: {}, data: {}) source_id: {}", + trace!("vcx_disclosed_proof_serialize_cb(command_handle: {}, rc: {}, data: {}) source_id: {}", command_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num,msg.as_ptr()); @@ -373,17 +380,18 @@ pub extern fn vcx_disclosed_proof_serialize(command_handle: u32, pub extern fn vcx_disclosed_proof_deserialize(command_handle: u32, proof_data: *const c_char, cb: Option) -> u32 { + info!("vcx_disclosed_proof_deserialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(proof_data, error::INVALID_OPTION.code_num); - info!("vcx_disclosed_proof_deserialize(command_handle: {}, proof_data: {})", + trace!("vcx_disclosed_proof_deserialize(command_handle: {}, proof_data: {})", command_handle, proof_data); spawn(move|| { match disclosed_proof::from_string(&proof_data) { Ok(x) => { - info!("vcx_disclosed_proof_deserialize_cb(command_handle: {}, rc: {}, proof_handle: {}) source_id: {}", + trace!("vcx_disclosed_proof_deserialize_cb(command_handle: {}, rc: {}, proof_handle: {}) source_id: {}", command_handle, error_string(0), x, disclosed_proof::get_source_id(x).unwrap_or_default()); cb(command_handle, 0, x); @@ -416,6 +424,7 @@ pub extern fn vcx_disclosed_proof_deserialize(command_handle: u32, pub extern fn vcx_disclosed_proof_retrieve_credentials(command_handle: u32, proof_handle: u32, cb: Option) -> u32 { + info!("vcx_disclosed_proof_retrieve_credentials >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -424,13 +433,13 @@ pub extern fn vcx_disclosed_proof_retrieve_credentials(command_handle: u32, } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_disclosed_proof_retrieve_credentials(command_handle: {}, proof_handle: {}) source_id: {}", + trace!("vcx_disclosed_proof_retrieve_credentials(command_handle: {}, proof_handle: {}) source_id: {}", command_handle, proof_handle, source_id); spawn(move|| { match disclosed_proof::retrieve_credentials(proof_handle) { Ok(x) => { - info!("vcx_disclosed_proof_retrieve_credentials(command_handle: {}, rc: {}, data: {}) source_id: {}", + trace!("vcx_disclosed_proof_retrieve_credentials(command_handle: {}, rc: {}, data: {}) source_id: {}", command_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num,msg.as_ptr()); @@ -457,11 +466,32 @@ pub extern fn vcx_disclosed_proof_retrieve_credentials(command_handle: u32, /// handle: Proof handle that was provided during creation. Used to identify the disclosed proof object /// /// selected_credentials: a json string with a credential for each proof request attribute. -/// List of possible credentials for each attribute is returned from vcx_disclosed_proof_retrieve_credentials -/// # Examples selected_credential -> "{"req_attr_0":cred_info}" Where cred_info is returned from retrieve credentials +/// List of possible credentials for each attribute is returned from vcx_disclosed_proof_retrieve_credentials, +/// (user needs to select specific credential to use from list of credentials) +/// { +/// "attrs":{ +/// String:{// Attribute key: This may not be the same as the attr name ex. "age_1" where attribute name is "age" +/// "credential": { +/// "cred_info":{ +/// "referent":String, +/// "attrs":{ String: String }, // ex. {"age": "111", "name": "Bob"} +/// "schema_id": String, +/// "cred_def_id": String, +/// "rev_reg_id":Option, +/// "cred_rev_id":Option, +/// }, +/// "interval":Option<{to: Option, from:: Option}> +/// }, // This is the exact credential information selected from list of +/// // credentials returned from vcx_disclosed_proof_retrieve_credentials +/// "tails_file": Option<"String">, // Path to tails file for this credential +/// }, +/// }, +/// "predicates":{ TODO: will be implemented as part of IS-1095 ticket. } +/// } +/// // selected_credentials can be empty "{}" if the proof only contains self_attested_attrs /// /// self_attested_attrs: a json string with attributes self attested by user -/// # Examples self_attested_attrs -> "{"self_attested_attr_0":"attested_val"}" +/// # Examples self_attested_attrs -> "{"self_attested_attr_0":"attested_val"}" | "{}" /// /// cb: Callback that returns error status /// @@ -473,6 +503,7 @@ pub extern fn vcx_disclosed_proof_generate_proof(command_handle: u32, selected_credentials: *const c_char, self_attested_attrs: *const c_char, cb: Option) -> u32 { + info!("vcx_disclosed_proof_generate_proof >>>"); check_useful_c_str!(selected_credentials, error::INVALID_OPTION.code_num); check_useful_c_str!(self_attested_attrs, error::INVALID_OPTION.code_num); @@ -483,13 +514,13 @@ pub extern fn vcx_disclosed_proof_generate_proof(command_handle: u32, } let source_id = disclosed_proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_disclosed_proof_generate_proof(command_handle: {}, proof_handle: {}, selected_credentials: {}, self_attested_attrs: {}) source_id: {}", + trace!("vcx_disclosed_proof_generate_proof(command_handle: {}, proof_handle: {}, selected_credentials: {}, self_attested_attrs: {}) source_id: {}", command_handle, proof_handle, selected_credentials, self_attested_attrs, source_id); spawn(move|| { match disclosed_proof::generate_proof(proof_handle, selected_credentials, self_attested_attrs) { Ok(_) => { - info!("vcx_disclosed_proof_generate_proof(command_handle: {}, rc: {}) source_id: {}", + trace!("vcx_disclosed_proof_generate_proof(command_handle: {}, rc: {}) source_id: {}", command_handle, error::SUCCESS.code_num, source_id); cb(command_handle, error::SUCCESS.code_num); }, @@ -516,9 +547,11 @@ pub extern fn vcx_disclosed_proof_generate_proof(command_handle: u32, /// Success #[no_mangle] pub extern fn vcx_disclosed_proof_release(handle: u32) -> u32 { + info!("vcx_disclosed_proof_release >>>"); + let source_id = disclosed_proof::get_source_id(handle).unwrap_or_default(); match disclosed_proof::release(handle) { - Ok(_) => info!("vcx_disclosed_proof_release(handle: {}, rc: {}), source_id: {:?}", + Ok(_) => trace!("vcx_disclosed_proof_release(handle: {}, rc: {}), source_id: {:?}", handle, error_string(0), source_id), Err(e) => error!("vcx_disclosed_proof_release(handle: {}, rc: {}), source_id: {:?}", handle, error_string(e), source_id), @@ -535,7 +568,7 @@ mod tests { use connection; use api::VcxStateType; use utils::constants::DEFAULT_SERIALIZE_VERSION; - use utils::libindy::return_types_u32; + use api::return_types_u32; use serde_json::Value; pub const BAD_PROOF_REQUEST: &str = r#"{"version": "0.1","to_did": "LtMgSjtFcyPwenK9SHCyb8","from_did": "LtMgSjtFcyPwenK9SHCyb8","claim": {"account_num": ["8BEaoLf8TBmK4BUyX8WWnA"],"name_on_account": ["Alice"]},"schema_seq_no": 48,"issuer_did": "Pd4fnFtRBcMKRVC2go5w3j","claim_name": "Account Certificate","claim_id": "3675417066","msg_ref_id": "ymy5nth"}"#; @@ -566,7 +599,7 @@ mod tests { #[test] fn test_create_with_msgid() { init!("true"); - let cxn = ::connection::build_connection("test_create_with_msgid").unwrap(); + let cxn = ::connection::tests::build_test_connection(); ::utils::httpclient::set_next_u8_response(::utils::constants::NEW_PROOF_REQUEST_RESPONSE.to_vec()); let cb = return_types_u32::Return_U32_U32_STR::new().unwrap(); assert_eq!(vcx_disclosed_proof_create_with_msgid(cb.command_handle, @@ -607,7 +640,7 @@ mod tests { let handle = disclosed_proof::create_proof("1",::utils::constants::PROOF_REQUEST_JSON).unwrap(); assert_eq!(disclosed_proof::get_state(handle).unwrap(),VcxStateType::VcxStateRequestReceived as u32); - let connection_handle = connection::build_connection("test_send_proof").unwrap(); + let connection_handle = connection::tests::build_test_connection(); let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_disclosed_proof_send_proof(cb.command_handle,handle,connection_handle,Some(cb.get_callback())), error::SUCCESS.code_num); @@ -617,7 +650,7 @@ mod tests { #[test] fn test_vcx_proof_get_requests(){ init!("true"); - let cxn = ::connection::build_connection("test_get_new_requests").unwrap(); + let cxn = ::connection::tests::build_test_connection(); ::utils::httpclient::set_next_u8_response(::utils::constants::NEW_PROOF_REQUEST_RESPONSE.to_vec()); let cb = return_types_u32::Return_U32_STR::new().unwrap(); assert_eq!(vcx_disclosed_proof_get_requests(cb.command_handle, cxn, Some(cb.get_callback())),error::SUCCESS.code_num as u32); diff --git a/vcx/libvcx/src/api/issuer_credential.rs b/vcx/libvcx/src/api/issuer_credential.rs index 88c76dfc..9c3eb6b1 100644 --- a/vcx/libvcx/src/api/issuer_credential.rs +++ b/vcx/libvcx/src/api/issuer_credential.rs @@ -35,24 +35,25 @@ use utils::threadpool::spawn; /// #Returns /// Error code as a u32 /// -/// # Example credential_data -> "{"state":["UT"]}" +/// # Example crendetial_data -> "{"state":"UT"}" +/// # Example credential_data -> "{"state":["UT"]}" please note: this format is deprecated #[no_mangle] #[allow(unused_variables, unused_mut)] pub extern fn vcx_issuer_create_credential(command_handle: u32, source_id: *const c_char, - cred_def_id: *const c_char, + cred_def_handle: u32, issuer_did: *const c_char, credential_data: *const c_char, credential_name: *const c_char, price: *const c_char, cb: Option) -> u32 { + info!("vcx_issuer_create_credential >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(credential_data, error::INVALID_OPTION.code_num); check_useful_c_str!(credential_name, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); check_useful_c_str!(price, error::INVALID_OPTION.code_num); - check_useful_c_str!(cred_def_id, error::INVALID_OPTION.code_num); let issuer_did: String = if !issuer_did.is_null() { check_useful_c_str!(issuer_did, error::INVALID_OPTION.code_num); @@ -69,18 +70,22 @@ pub extern fn vcx_issuer_create_credential(command_handle: u32, Err(_) => return error::INVALID_OPTION.code_num, }; - info!("vcx_issuer_create_credential(command_handle: {}, source_id: {}, cred_def_id: {}, issuer_did: {}, credential_data: {}, credential_name: {})", + if !::credential_def::is_valid_handle(cred_def_handle) { + return error::INVALID_CREDENTIAL_DEF_HANDLE.code_num; + } + + trace!("vcx_issuer_create_credential(command_handle: {}, source_id: {}, cred_def_handle: {}, issuer_did: {}, credential_data: {}, credential_name: {})", command_handle, source_id, - cred_def_id, + cred_def_handle, issuer_did, credential_data, credential_name); spawn(move|| { - let (rc, handle) = match issuer_credential::issuer_credential_create(cred_def_id, source_id, issuer_did, credential_name, credential_data, price) { + let (rc, handle) = match issuer_credential::issuer_credential_create(cred_def_handle, source_id, issuer_did, credential_name, credential_data, price) { Ok(x) => { - info!("vcx_issuer_create_credential_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", + trace!("vcx_issuer_create_credential_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", command_handle, error_string(0), x, issuer_credential::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, @@ -117,11 +122,12 @@ pub extern fn vcx_issuer_send_credential_offer(command_handle: u32, credential_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_issuer_send_credential_offer >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); - info!("vcx_issuer_send_credential(command_handle: {}, credential_handle: {}, connection_handle: {}) source_id: {}", + trace!("vcx_issuer_send_credential(command_handle: {}, credential_handle: {}, connection_handle: {}) source_id: {}", command_handle, credential_handle, connection_handle, source_id); if !issuer_credential::is_valid_handle(credential_handle) { @@ -135,7 +141,7 @@ pub extern fn vcx_issuer_send_credential_offer(command_handle: u32, spawn(move|| { let err = match issuer_credential::send_credential_offer(credential_handle, connection_handle) { Ok(x) => { - info!("vcx_issuer_send_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", + trace!("vcx_issuer_send_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", command_handle, credential_handle, error_string(x), source_id); x }, @@ -169,11 +175,12 @@ pub extern fn vcx_issuer_send_credential_offer(command_handle: u32, pub extern fn vcx_issuer_credential_update_state(command_handle: u32, credential_handle: u32, cb: Option) -> u32 { + info!("vcx_issuer_credential_update_state >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); - info!("vcx_issuer_credential_update_state(command_handle: {}, credential_handle: {}) source_id: {}", + trace!("vcx_issuer_credential_update_state(command_handle: {}, credential_handle: {}) source_id: {}", command_handle, credential_handle, source_id); if !issuer_credential::is_valid_handle(credential_handle) { @@ -183,7 +190,7 @@ pub extern fn vcx_issuer_credential_update_state(command_handle: u32, spawn(move|| { match issuer_credential::update_state(credential_handle) { Ok(x) => { - info!("vcx_issuer_credential_update_state_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", + trace!("vcx_issuer_credential_update_state_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", command_handle, credential_handle, error_string(0), x, source_id); cb(command_handle, error::SUCCESS.code_num, x); }, @@ -216,11 +223,12 @@ pub extern fn vcx_issuer_credential_update_state(command_handle: u32, pub extern fn vcx_issuer_credential_get_state(command_handle: u32, credential_handle: u32, cb: Option) -> u32 { + info!("vcx_issuer_credential_get_state >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); - info!("vcx_issuer_credential_get_state(command_handle: {}, credential_handle: {}) source_id: {}", + trace!("vcx_issuer_credential_get_state(command_handle: {}, credential_handle: {}) source_id: {}", command_handle, credential_handle, source_id); if !issuer_credential::is_valid_handle(credential_handle) { @@ -230,7 +238,7 @@ pub extern fn vcx_issuer_credential_get_state(command_handle: u32, spawn(move|| { match issuer_credential::get_state(credential_handle) { Ok(x) => { - info!("vcx_issuer_credential_get_state_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", + trace!("vcx_issuer_credential_get_state_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", command_handle, credential_handle, error_string(0), x, source_id); cb(command_handle, error::SUCCESS.code_num, x); }, @@ -248,9 +256,15 @@ pub extern fn vcx_issuer_credential_get_state(command_handle: u32, } #[allow(unused_variables, unused_mut)] -pub extern fn vcx_issuer_get_credential_request(credential_handle: u32, credential_request: *mut c_char) -> u32 { error::SUCCESS.code_num } +pub extern fn vcx_issuer_get_credential_request(credential_handle: u32, credential_request: *mut c_char) -> u32 { + info!("vcx_issuer_get_credential_request >>>"); + error::SUCCESS.code_num +} #[allow(unused_variables, unused_mut)] -pub extern fn vcx_issuer_accept_credential(credential_handle: u32) -> u32 { error::SUCCESS.code_num } +pub extern fn vcx_issuer_accept_credential(credential_handle: u32) -> u32 { + info!("vcx_issuer_accept_credential >>>"); + error::SUCCESS.code_num +} /// Send Credential that was requested by user /// @@ -270,6 +284,7 @@ pub extern fn vcx_issuer_send_credential(command_handle: u32, credential_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_issuer_send_credential >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -282,12 +297,12 @@ pub extern fn vcx_issuer_send_credential(command_handle: u32, } let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); - info!("vcx_issuer_send_credential(command_handle: {}, credential_handle: {}, connection_handle: {}) source_id: {}", + trace!("vcx_issuer_send_credential(command_handle: {}, credential_handle: {}, connection_handle: {}) source_id: {}", command_handle, credential_handle, connection_handle, source_id); spawn(move|| { let err = match issuer_credential::send_credential(credential_handle, connection_handle) { Ok(x) => { - info!("vcx_issuer_send_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", + trace!("vcx_issuer_send_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", command_handle, credential_handle, error_string(x), source_id); x }, @@ -307,7 +322,10 @@ pub extern fn vcx_issuer_send_credential(command_handle: u32, } #[allow(unused_variables)] -pub extern fn vcx_issuer_terminate_credential(credential_handle: u32, termination_type: u32, msg: *const c_char) -> u32 { error::SUCCESS.code_num } +pub extern fn vcx_issuer_terminate_credential(credential_handle: u32, termination_type: u32, msg: *const c_char) -> u32 { + info!("vcx_issuer_terminate_credential >>>"); + error::SUCCESS.code_num +} /// Takes the credential object and returns a json string of all its attributes /// @@ -324,6 +342,7 @@ pub extern fn vcx_issuer_terminate_credential(credential_handle: u32, terminatio pub extern fn vcx_issuer_credential_serialize(command_handle: u32, credential_handle: u32, cb: Option) -> u32 { + info!("vcx_issuer_credential_serialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -332,18 +351,18 @@ pub extern fn vcx_issuer_credential_serialize(command_handle: u32, } let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); - info!("vcx_issuer_credential_serialize(credential_serialize(command_handle: {}, credential_handle: {}), source_id: {}", + trace!("vcx_issuer_credential_serialize(credential_serialize(command_handle: {}, credential_handle: {}), source_id: {}", command_handle, credential_handle, source_id); spawn(move|| { match issuer_credential::to_string(credential_handle) { Ok(x) => { - info!("vcx_issuer_credential_serialize_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", + trace!("vcx_issuer_credential_serialize_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {}", command_handle, credential_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num,msg.as_ptr()); }, Err(x) => { - info!("vcx_issuer_credential_serialize_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {})", + trace!("vcx_issuer_credential_serialize_cb(command_handle: {}, credential_handle: {}, rc: {}, state: {}) source_id: {})", command_handle, credential_handle, error_string(x.to_error_code()), "null", source_id); cb(command_handle,x.to_error_code(),ptr::null_mut()); }, @@ -370,16 +389,17 @@ pub extern fn vcx_issuer_credential_serialize(command_handle: u32, pub extern fn vcx_issuer_credential_deserialize(command_handle: u32, credential_data: *const c_char, cb: Option) -> u32 { + info!("vcx_issuer_credential_deserialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(credential_data, error::INVALID_OPTION.code_num); - info!("vcx_issuer_credential_deserialize(command_handle: {}, credential_data: {})", command_handle, credential_data); + trace!("vcx_issuer_credential_deserialize(command_handle: {}, credential_data: {})", command_handle, credential_data); spawn(move|| { let (rc, handle) = match issuer_credential::from_string(&credential_data) { Ok(x) => { - info!("vcx_issuer_credential_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", + trace!("vcx_issuer_credential_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", command_handle, error_string(0), x, issuer_credential::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, @@ -407,9 +427,10 @@ pub extern fn vcx_issuer_credential_deserialize(command_handle: u32, /// Success #[no_mangle] pub extern fn vcx_issuer_credential_release(credential_handle: u32) -> u32 { + info!("vcx_issuer_credential_release >>>"); let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); match issuer_credential::release(credential_handle) { - Ok(_) => info!("(vcx_issuer_credential_release credential_handle: {}, rc: {}), source_id: {}", + Ok(_) => trace!("(vcx_issuer_credential_release credential_handle: {}, rc: {}), source_id: {}", credential_handle, error_string(0), source_id), Err(e) => warn!("(vcx_issuer_credential_release credential_handle: {}, rc: {}), source_id: {}", credential_handle, error_string(e.to_error_code()), source_id), @@ -439,18 +460,19 @@ pub extern fn vcx_issuer_credential_release(credential_handle: u32) -> u32 { pub extern fn vcx_issuer_credential_get_payment_txn(command_handle: u32, handle: u32, cb: Option) -> u32 { + info!("vcx_issuer_credential_get_payment_txn >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = issuer_credential::get_source_id(handle).unwrap_or_default(); - info!("vcx_issuer_credential_get_payment_txn(command_handle: {}) source_id: {}", command_handle, source_id); + trace!("vcx_issuer_credential_get_payment_txn(command_handle: {}) source_id: {}", command_handle, source_id); spawn(move|| { match issuer_credential::get_payment_txn(handle) { Ok(x) => { match serde_json::to_string(&x) { Ok(x) => { - info!("vcx_issuer_credential_get_payment_txn_cb(command_handle: {}, rc: {}, : {}) source_id: {}", + trace!("vcx_issuer_credential_get_payment_txn_cb(command_handle: {}, rc: {}, : {}) source_id: {}", command_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); @@ -476,6 +498,54 @@ pub extern fn vcx_issuer_credential_get_payment_txn(command_handle: u32, error::SUCCESS.code_num } +/// Revoke Credential +/// +/// #Params +/// command_handle: command handle to map callback to user context. +/// +/// credential_handle: Credential handle that was provided during creation. Used to identify credential object +/// +/// cb: Callback that provides error status of sending the credential +/// +/// #Returns +/// Error code as a u32 +#[no_mangle] +pub extern fn vcx_issuer_revoke_credential(command_handle: u32, + credential_handle: u32, + cb: Option) -> u32 { + + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + + if !issuer_credential::is_valid_handle(credential_handle) { + return error::INVALID_ISSUER_CREDENTIAL_HANDLE.code_num; + } + + let source_id = issuer_credential::get_source_id(credential_handle).unwrap_or_default(); + info!("vcx_issuer_revoke_credential(command_handle: {}, credential_handle: {}) source_id: {}", + command_handle, credential_handle, source_id); + + spawn(move|| { + let err = match issuer_credential::revoke_credential(credential_handle) { + Ok(_) => { + info!("vcx_issuer_revoke_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", + command_handle, credential_handle, error_string(error::SUCCESS.code_num), source_id); + error::SUCCESS.code_num + }, + Err(x) => { + warn!("vcx_issuer_revoke_credential_cb(command_handle: {}, credential_handle: {}, rc: {}) source_id: {}", + command_handle, credential_handle, error_string(x), source_id); + x + }, + }; + + cb(command_handle,err); + + Ok(()) + }); + + error::SUCCESS.code_num +} + #[cfg(test)] mod tests { extern crate serde_json; @@ -485,15 +555,75 @@ mod tests { use std::time::Duration; use settings; use connection; - use api::VcxStateType; - use utils::constants::{CRED_DEF_ID, DEFAULT_SERIALIZED_ISSUER_CREDENTIAL}; - use utils::libindy::return_types_u32; + use utils::{ + constants::{DEFAULT_SERIALIZED_ISSUER_CREDENTIAL}, + get_temp_dir_path + }; + use api::{return_types_u32, VcxStateType}; static DEFAULT_CREDENTIAL_NAME: &str = "Credential Name Default"; static DEFAULT_DID: &str = "8XFh8yBzrpJQmNyZzgoTqB"; static DEFAULT_ATTR: &str = "{\"attr\":\"value\"}"; static DEFAULT_SCHEMA_SEQ_NO: u32 = 32; - static ISSUER_CREDENTIAL_STATE_ACCEPTED: &str = r#"{"version": "1.0", "data": {"source_id":"standard_credential","credential_attributes":"{\"address2\":[\"101 Wilson Lane\"],\n \"zip\":[\"87121\"],\n \"state\":[\"UT\"],\n \"city\":[\"SLC\"],\n \"address1\":[\"101 Tela Lane\"]\n }","msg_uid":"1234","schema_seq_no":32,"issuer_did":"QTrbV4raAcND4DWWzBmdsh","state":3,"credential_request":{"libindy_cred_req":"{\"prover_did\":\"2hoqvcwupRTUNkXn6ArYzs\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"blinded_ms\":{\"u\":\"8732071602357015307810566138808197234658312581785137109788113302982640059349967050965447489217593298616209988826723701562661343443517589847218013366407845073616266391756009264980040238952349445643778936575656535779015458023493903785780518101975701982901383514030208868847307622362696880263163343848494510595690307613204277848599695882210459126941797459019913953592724097855109613611647709745072773427626720401442235193011557232562555622244156336806151662441234847773393387649719209243455960347563274791229126202016215550120934775060992031280966045894859557271641817491943416048075445449722000591059568013176905304195\",\"ur\":null},\"blinded_ms_correctness_proof\":{\"c\":\"26530740026507431379491385424781000855170637402280225419270466226736067904512\",\"v_dash_cap\":\"143142764256221649591394190756594263575252787336888260277569702754606119430149731374696604981582865909586330696038557351486556018124278706293019764236792379930773289730781387402321307275066512629558473696520197393762713894449968058415758200647216768004242460019909604733610794104180629190082978779757591726666340720737832809779281945323437475154340615798778337960748836468199407007775031657682302038533398039806427675709453395148841959462470861915712789403465722659960342165041260269463103782446132475688821810775202828210979373826636650138063942962121467854349698464501455098258293105554402435773328031261630390919907379686173528652481917022556931483089035786146580024468924714494948737711000361399753716101561779590\",\"ms_cap\":\"6713785684292289748157544902063599004332363811033155861083956757033688921010462943169460951559595511857618896433311745591610892377735569122165958960965808330552472093346163460366\"},\"nonce\":\"1154549882365416803296713\"}","libindy_cred_req_meta":"{\"master_secret_blinding_data\":{\"v_prime\":\"5395355128172250143169068089431956784792642542761864362402228480600989694874966075941384260155648520933482583695015613159862636260075389615716222159662546164168786411292929058350829109114076583253317335067228793239648602609298582418017531463540043998240957993320093249294158252626231822371040785324638542033761124918129739329505169470758613520824786030494489920230941474441127178440612550463476183902911947132651422614577934309909240587823495239211344374406789215531181787691051240041033304085509402896936138071991158258582839272399829973882057207073602788766808713962858580770439194397272070900372124998541828707590819468056588985228490934\",\"vr_prime\":null},\"nonce\":\"1154549882365416803296713\",\"master_secret_name\":\"main\"}","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766","tid":"cCanHnpFAD","to_did":"BnRXf8yDMUwGyZVDkSENeq","from_did":"GxtnGN6ypZYgEqcftSQFnC","version":"0.1","mid":"","msg_ref_id":"12345"},"credential_offer":{"msg_type":"CRED_OFFER","version":"0.1","to_did":"8XFh8yBzrpJQmNyZzgoTqB","from_did":"8XFh8yBzrpJQmNyZzgoTqB","libindy_offer":"{\"schema_id\":\"2hoqvcwupRTUNkXn6ArYzs:2:schema_name:0.0.11\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"key_correctness_proof\":{\"c\":\"81455034389059130581506970475392033040313255495112570189348030990050944959723\",\"xz_cap\":\"313645697267968767252234073635675430449902008059550004460259716107399731378591839990019486954341409015811398444145390509019258403747288031702507727573872041899321045924287139508392740014051146807378366748171039375722083582850094590251566094137198468729226768809401256609008814847622114541957109991869490323195581928533376835343922482073783968747913611549869005687592623346914265913612170394649557294382253996246104002213172081216651539025706643350612557508228429410997102814965307308636524874409734625285377555470610010065029649043789306111101285927931757335536116856245613021564584847709796772325323716389295248332887528840195072737364278387101996545501723112970168561425282691953586374723401\",\"xr_cap\":{\"age\":\"882754630824080045376337358848444600715931719237593270810742883245639461185815851876695993155364347227577960272007297643455666310248109151421699898719086697252758726897984721300131927517824869533193272729923436764134176057310403382007926964744387461941410106739551156849252510593074993038770740497381973934250838808938096281745915721201706218145129356389886319652075267352853728443472451999347485331725183791798330085570375973775830893185375873153450320600510970851511952771344003741169784422212142610068911032856394030732377780807267819554991221318614567131747542069695452212861957610989952712388162117309870024706736915145245688230386906705817571265829695877232812698581971245658766976413035\",\"height\":\"987637616420540109240639213457114631238834322455397854134075974962516028070241761486895351636137675737583463907200584608953198912009428606796987435233170230262246507002244616435810064614719873830573727071246389627645604379157359983051337498205555868770767724876429776832782322071025598605854225056296405802351270140259313942108556513054492873024197036931111152136704979025907027537437514085689067466225661223523070057146052814725207863140129032189711026590245299845102901392525049014890473357388530510591717159458757929233202259332009161834669583439224425159885860519286698297401104830776447810193871233628235105641793685350321428066559473844839135685992587694149460959649026855973744322255314\",\"name\":\"1546639434545851623074023662485597065284112939224695559955181790271051962463722945049040324831863838273446566781589598791986646525127962031342679728936610678403807319789934638790962870799709103831307094501191346766422178361730723105585107221227683700136793784629414737866344469139276697568820727798174438114746109084012381033673759358527018948810066386903378176283974585934466197449653414224049202874335628877153172622300824161652402616917051692229112366954543190460604470158025596786552965425465904108943932508335616457348969058666355825158659883154681844070175331759147881082936624886840666700175491257446990494466033687900546604556189308597860524376648979247121908124398665458633017197827236\",\"sex\":\"716474787042335984121980741678479956610893721743783933016481046646620232719875607171626872246169633453851120125820240948330986140162546620706675695953306343625792456607323180362022779776451183315417053730047607706403536921566872327898942782065882640264019040337889347226013768331343768976174940163847488834059250858062959921604207705933170308295671034308248661208253191415678118624962846251281290296191433330052514696549137940098226268222146864337521249047457556625050919427268119508782974114298993324181252788789806496387982332099887944556949042187369539832351477275159404450154234059063271817130338030393531532967222197942953924825232879558249711884940237537025210406407183892784259089230597\"}},\"nonce\":\"161126724054910446992163\"}","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766","credential_attrs":{"address1":["101 Tela Lane"],"address2":["101 Wilson Lane"],"city":["SLC"],"state":["UT"],"zip":["87121"]},"schema_seq_no":1487,"claim_name":"Credential","claim_id":"defaultCredentialId","msg_ref_id":"abcd"},"credential_name":"Credential","credential_id":"defaultCredentialId","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766","price":0,"ref_msg_id":null,"agent_did":"FhrSrYtQcw3p9xwf7NYemf","agent_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE","issued_did":"8XFh8yBzrpJQmNyZzgoTqB","issued_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE","remote_did":"FhrSrYtQcw3p9xwf7NYemf","remote_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE"}}"#; + + fn issuer_credential_state_accepted() -> String { + json!({ + "version": "1.0", + "data": { + "cred_def_handle":1, + "tails_file": get_temp_dir_path(Some("tails")).to_str().unwrap(), + "rev_reg_id": "123", + "cred_rev_id": "456", + "source_id": "standard_credential", + "credential_attributes": "{\"address2\":[\"101 Wilson Lane\"],\n \"zip\":[\"87121\"],\n \"state\":[\"UT\"],\n \"city\":[\"SLC\"],\n \"address1\":[\"101 Tela Lane\"]\n }", + "msg_uid": "1234", + "schema_seq_no": 32, + "issuer_did": "QTrbV4raAcND4DWWzBmdsh", + "state": 3, + "credential_request": { + "libindy_cred_req": "{\"prover_did\":\"2hoqvcwupRTUNkXn6ArYzs\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"blinded_ms\":{\"u\":\"8732071602357015307810566138808197234658312581785137109788113302982640059349967050965447489217593298616209988826723701562661343443517589847218013366407845073616266391756009264980040238952349445643778936575656535779015458023493903785780518101975701982901383514030208868847307622362696880263163343848494510595690307613204277848599695882210459126941797459019913953592724097855109613611647709745072773427626720401442235193011557232562555622244156336806151662441234847773393387649719209243455960347563274791229126202016215550120934775060992031280966045894859557271641817491943416048075445449722000591059568013176905304195\",\"ur\":null},\"blinded_ms_correctness_proof\":{\"c\":\"26530740026507431379491385424781000855170637402280225419270466226736067904512\",\"v_dash_cap\":\"143142764256221649591394190756594263575252787336888260277569702754606119430149731374696604981582865909586330696038557351486556018124278706293019764236792379930773289730781387402321307275066512629558473696520197393762713894449968058415758200647216768004242460019909604733610794104180629190082978779757591726666340720737832809779281945323437475154340615798778337960748836468199407007775031657682302038533398039806427675709453395148841959462470861915712789403465722659960342165041260269463103782446132475688821810775202828210979373826636650138063942962121467854349698464501455098258293105554402435773328031261630390919907379686173528652481917022556931483089035786146580024468924714494948737711000361399753716101561779590\",\"ms_cap\":\"6713785684292289748157544902063599004332363811033155861083956757033688921010462943169460951559595511857618896433311745591610892377735569122165958960965808330552472093346163460366\"},\"nonce\":\"1154549882365416803296713\"}", + "libindy_cred_req_meta": "{\"master_secret_blinding_data\":{\"v_prime\":\"5395355128172250143169068089431956784792642542761864362402228480600989694874966075941384260155648520933482583695015613159862636260075389615716222159662546164168786411292929058350829109114076583253317335067228793239648602609298582418017531463540043998240957993320093249294158252626231822371040785324638542033761124918129739329505169470758613520824786030494489920230941474441127178440612550463476183902911947132651422614577934309909240587823495239211344374406789215531181787691051240041033304085509402896936138071991158258582839272399829973882057207073602788766808713962858580770439194397272070900372124998541828707590819468056588985228490934\",\"vr_prime\":null},\"nonce\":\"1154549882365416803296713\",\"master_secret_name\":\"main\"}", + "cred_def_id": "2hoqvcwupRTUNkXn6ArYzs:3:CL:1766", + "tid": "cCanHnpFAD", + "to_did": "BnRXf8yDMUwGyZVDkSENeq", + "from_did": "GxtnGN6ypZYgEqcftSQFnC", + "version": "0.1", + "mid": "", + "msg_ref_id": "12345" + }, + "credential_offer": { + "msg_type": "CRED_OFFER", + "version": "0.1", + "to_did": "8XFh8yBzrpJQmNyZzgoTqB", + "from_did": "8XFh8yBzrpJQmNyZzgoTqB", + "libindy_offer": "{\"schema_id\":\"2hoqvcwupRTUNkXn6ArYzs:2:schema_name:0.0.11\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"key_correctness_proof\":{\"c\":\"81455034389059130581506970475392033040313255495112570189348030990050944959723\",\"xz_cap\":\"313645697267968767252234073635675430449902008059550004460259716107399731378591839990019486954341409015811398444145390509019258403747288031702507727573872041899321045924287139508392740014051146807378366748171039375722083582850094590251566094137198468729226768809401256609008814847622114541957109991869490323195581928533376835343922482073783968747913611549869005687592623346914265913612170394649557294382253996246104002213172081216651539025706643350612557508228429410997102814965307308636524874409734625285377555470610010065029649043789306111101285927931757335536116856245613021564584847709796772325323716389295248332887528840195072737364278387101996545501723112970168561425282691953586374723401\",\"xr_cap\":{\"age\":\"882754630824080045376337358848444600715931719237593270810742883245639461185815851876695993155364347227577960272007297643455666310248109151421699898719086697252758726897984721300131927517824869533193272729923436764134176057310403382007926964744387461941410106739551156849252510593074993038770740497381973934250838808938096281745915721201706218145129356389886319652075267352853728443472451999347485331725183791798330085570375973775830893185375873153450320600510970851511952771344003741169784422212142610068911032856394030732377780807267819554991221318614567131747542069695452212861957610989952712388162117309870024706736915145245688230386906705817571265829695877232812698581971245658766976413035\",\"height\":\"987637616420540109240639213457114631238834322455397854134075974962516028070241761486895351636137675737583463907200584608953198912009428606796987435233170230262246507002244616435810064614719873830573727071246389627645604379157359983051337498205555868770767724876429776832782322071025598605854225056296405802351270140259313942108556513054492873024197036931111152136704979025907027537437514085689067466225661223523070057146052814725207863140129032189711026590245299845102901392525049014890473357388530510591717159458757929233202259332009161834669583439224425159885860519286698297401104830776447810193871233628235105641793685350321428066559473844839135685992587694149460959649026855973744322255314\",\"name\":\"1546639434545851623074023662485597065284112939224695559955181790271051962463722945049040324831863838273446566781589598791986646525127962031342679728936610678403807319789934638790962870799709103831307094501191346766422178361730723105585107221227683700136793784629414737866344469139276697568820727798174438114746109084012381033673759358527018948810066386903378176283974585934466197449653414224049202874335628877153172622300824161652402616917051692229112366954543190460604470158025596786552965425465904108943932508335616457348969058666355825158659883154681844070175331759147881082936624886840666700175491257446990494466033687900546604556189308597860524376648979247121908124398665458633017197827236\",\"sex\":\"716474787042335984121980741678479956610893721743783933016481046646620232719875607171626872246169633453851120125820240948330986140162546620706675695953306343625792456607323180362022779776451183315417053730047607706403536921566872327898942782065882640264019040337889347226013768331343768976174940163847488834059250858062959921604207705933170308295671034308248661208253191415678118624962846251281290296191433330052514696549137940098226268222146864337521249047457556625050919427268119508782974114298993324181252788789806496387982332099887944556949042187369539832351477275159404450154234059063271817130338030393531532967222197942953924825232879558249711884940237537025210406407183892784259089230597\"}},\"nonce\":\"161126724054910446992163\"}", + "cred_def_id": "2hoqvcwupRTUNkXn6ArYzs:3:CL:1766", + "credential_attrs": { + "address1":["101 Tela Lane"], + "address2":["101 Wilson Lane"], + "city":["SLC"], + "state":["UT"], + "zip":["87121"] + }, + "schema_seq_no":1487, + "claim_name":"Credential", + "claim_id":"defaultCredentialId", + "msg_ref_id":"abcd" + }, + "credential_name":"Credential", + "credential_id":"defaultCredentialId", + "cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766", + "price":0, + "ref_msg_id":"null", + "agent_did":"FhrSrYtQcw3p9xwf7NYemf", + "agent_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", + "issued_did":"8XFh8yBzrpJQmNyZzgoTqB", + "issued_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", + "remote_did":"FhrSrYtQcw3p9xwf7NYemf", + "remote_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE" + } + }).to_string() + } #[test] fn test_vcx_issuer_create_credential_success() { @@ -501,7 +631,7 @@ mod tests { let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_issuer_create_credential(cb.command_handle, CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - CString::new(CRED_DEF_ID).unwrap().into_raw(), + ::credential_def::tests::create_cred_def_fake(), ptr::null(), CString::new(DEFAULT_ATTR).unwrap().into_raw(), CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), @@ -516,7 +646,7 @@ mod tests { let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_issuer_create_credential(cb.command_handle, CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - CString::new(CRED_DEF_ID).unwrap().into_raw(), + ::credential_def::tests::create_cred_def_fake(), ptr::null(), ptr::null(), CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), @@ -533,7 +663,7 @@ mod tests { let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_issuer_create_credential(cb.command_handle, CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - CString::new(CRED_DEF_ID).unwrap().into_raw(), + ::credential_def::tests::create_cred_def_fake(), CString::new(DEFAULT_DID).unwrap().into_raw(), CString::new(DEFAULT_ATTR).unwrap().into_raw(), CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), @@ -561,7 +691,8 @@ mod tests { let handle = issuer_credential::from_string(DEFAULT_SERIALIZED_ISSUER_CREDENTIAL).unwrap(); assert_eq!(issuer_credential::get_state(handle).unwrap(),VcxStateType::VcxStateInitialized as u32); - let connection_handle = connection::build_connection("test_send_credential_offer").unwrap(); + let connection_handle = ::connection::tests::build_test_connection(); + connection::connect(connection_handle,None).unwrap(); let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_issuer_send_credential_offer(cb.command_handle, @@ -576,12 +707,12 @@ mod tests { fn test_vcx_issuer_send_a_credential() { init!("true"); settings::set_config_value(settings::CONFIG_INSTITUTION_DID, DEFAULT_DID); - let serialized_credential = ISSUER_CREDENTIAL_STATE_ACCEPTED; let test_name = "test_vcx_issuer_send_a_credential"; - let handle = issuer_credential::from_string(ISSUER_CREDENTIAL_STATE_ACCEPTED).unwrap(); + let handle = issuer_credential::from_string(&issuer_credential_state_accepted()).unwrap(); // create connection - let connection_handle = connection::build_connection("test_send_credential").unwrap(); + let connection_handle = ::connection::tests::build_test_connection(); + connection::connect(connection_handle,None).unwrap(); // send the credential let cb = return_types_u32::Return_U32::new().unwrap(); @@ -600,7 +731,7 @@ mod tests { let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_issuer_create_credential(cb.command_handle, CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - CString::new(CRED_DEF_ID).unwrap().into_raw(), + ::credential_def::tests::create_cred_def_fake(), CString::new(DEFAULT_DID).unwrap().into_raw(), CString::new(DEFAULT_ATTR).unwrap().into_raw(), CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), @@ -624,7 +755,7 @@ mod tests { let cb = return_types_u32::Return_U32_U32::new().unwrap(); assert_eq!(vcx_issuer_create_credential(cb.command_handle, CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), - CString::new(CRED_DEF_ID).unwrap().into_raw(), + ::credential_def::tests::create_cred_def_fake(), CString::new(DEFAULT_DID).unwrap().into_raw(), CString::new(DEFAULT_ATTR).unwrap().into_raw(), CString::new(DEFAULT_CREDENTIAL_NAME).unwrap().into_raw(), @@ -658,4 +789,19 @@ mod tests { vcx_issuer_credential_get_payment_txn(cb.command_handle, handle, Some(cb.get_callback())); cb.receive(Some(Duration::from_secs(10))).unwrap(); } + + #[test] + fn test_vcx_issuer_revoke_credential() { + init!("true"); + settings::set_config_value(settings::CONFIG_INSTITUTION_DID, DEFAULT_DID); + let handle = issuer_credential::from_string(&issuer_credential_state_accepted()).unwrap(); + + // send the credential + let cb = return_types_u32::Return_U32::new().unwrap(); + assert_eq!(vcx_issuer_revoke_credential(cb.command_handle, + handle, + Some(cb.get_callback())), + error::SUCCESS.code_num); + cb.receive(Some(Duration::from_secs(10))).unwrap(); + } } diff --git a/vcx/libvcx/src/api/logger.rs b/vcx/libvcx/src/api/logger.rs new file mode 100644 index 00000000..4d24322e --- /dev/null +++ b/vcx/libvcx/src/api/logger.rs @@ -0,0 +1,113 @@ +extern crate libc; +extern crate indy_sys; +use utils::logger::{ EnabledCB, FlushCB, LibvcxLogger, LibvcxDefaultLogger, LogCB, LOGGER_STATE, CVoid }; +use utils::cstring::CStringUtils; +use self::libc::{c_char}; + +use utils::error::{ INVALID_CONFIGURATION, SUCCESS }; + +/// Set default logger implementation. +/// +/// Allows library user use `env_logger` logger as default implementation. +/// More details about `env_logger` and its customization can be found here: https://crates.io/crates/env_logger +/// +/// #Params +/// pattern: (optional) pattern that corresponds with the log messages to show. +/// +/// NOTE: You should specify either `pattern` parameter or `RUST_LOG` environment variable to init logger. +/// +/// #Returns +/// u32 error code +#[no_mangle] +pub extern fn vcx_set_default_logger(pattern: *const c_char) -> u32 { + info!("vcx_set_default_logger >>>"); + + check_useful_opt_c_str!(pattern, INVALID_CONFIGURATION.code_num); + + trace!("vcx_set_default_logger(pattern: {:?})", pattern); + + match LibvcxDefaultLogger::init(pattern) { + Ok(_) => { + debug!("Logger Successfully Initialized"); + SUCCESS.code_num + }, + Err(ec) => { + error!("Logger Failed To Initialize: {}", ec); + ec + }, + } +} + +/// Set custom logger implementation. +/// +/// Allows library user to provide custom logger implementation as set of handlers. +/// +/// #Params +/// context: pointer to some logger context that will be available in logger handlers. +/// enabled: (optional) "enabled" operation handler - calls to determines if a log record would be logged. (false positive if not specified) +/// log: "log" operation handler - calls to logs a record. +/// flush: (optional) "flush" operation handler - calls to flushes buffered records (in case of crash or signal). +/// +/// #Returns +/// u32 Error Code +#[no_mangle] +pub extern fn vcx_set_logger(context: *const CVoid, + enabled: Option, + log: Option, + flush: Option) -> u32 { + info!("vcx_set_logger >>>"); + + trace!("vcx_set_logger( context: {:?}, enabled: {:?}, log: {:?}, flush: {:?}", + context, enabled, log, flush); + check_useful_c_callback!(log, SUCCESS.code_num); + let res = LibvcxLogger::init(context, enabled, log, flush); + match res { + Ok(_) => { + debug!("Logger Successfully Initialized"); + SUCCESS.code_num + }, + Err(ec) => { + error!("Logger Failed To Initialize: {}", ec); + ec + }, + } +} + +/// Get the currently used logger. +/// +/// NOTE: if logger is not set dummy implementation would be returned. +/// +/// #Params +/// `context_p` - Reference that will contain logger context. +/// `enabled_cb_p` - Reference that will contain pointer to enable operation handler. +/// `log_cb_p` - Reference that will contain pointer to log operation handler. +/// `flush_cb_p` - Reference that will contain pointer to flush operation handler. +/// +/// #Returns +/// Error code +/// +/// This is tested in wrapper tests (python3) +#[no_mangle] +pub extern fn vcx_get_logger(context_p: *mut *const CVoid, + enabled_cb_p: *mut Option, + log_cb_p: *mut Option, + flush_cb_p: *mut Option) -> u32 { + info!("vcx_get_logger >>>"); + + trace!("vcx_get_logger >>> context_p: {:?}, enabled_cb_p: {:?}, log_cb_p: {:?}, flush_cb_p: {:?}", context_p, enabled_cb_p, log_cb_p, flush_cb_p); + + unsafe { + let (context, enabled_cb, log_cb, flush_cb) = LOGGER_STATE.get(); + *context_p = context; + *enabled_cb_p = enabled_cb; + *log_cb_p = log_cb; + *flush_cb_p = flush_cb; + } + + let res = SUCCESS.code_num; + trace!("vcx_get_logger: <<< res: {:?}", res); + res +} + + + diff --git a/vcx/libvcx/src/api/mod.rs b/vcx/libvcx/src/api/mod.rs index 0c900877..47d34dc6 100644 --- a/vcx/libvcx/src/api/mod.rs +++ b/vcx/libvcx/src/api/mod.rs @@ -10,6 +10,8 @@ pub mod schema; pub mod credential; pub mod disclosed_proof; pub mod wallet; +pub mod logger; +pub mod return_types_u32; use std::fmt; @@ -97,9 +99,9 @@ enum_number!(ProofStateType #[repr(C)] pub struct VcxStatus { - pub handle: ::std::os::raw::c_int, - pub status: ::std::os::raw::c_int, - pub msg: *mut ::std::os::raw::c_char, + pub handle: libc::c_int, + pub status: libc::c_int, + pub msg: *mut libc::c_char, } diff --git a/vcx/libvcx/src/api/proof.rs b/vcx/libvcx/src/api/proof.rs index b205d1f9..f190a364 100644 --- a/vcx/libvcx/src/api/proof.rs +++ b/vcx/libvcx/src/api/proof.rs @@ -17,14 +17,51 @@ use utils::threadpool::spawn; /// /// source_id: Enterprise's personal identification for the user. /// -/// requested_attrs: attributes/claims prover must provide in proof +/// requested_attrs: Describes requested attribute +/// { +/// "name": string, // attribute name, (case insensitive and ignore spaces) +/// "restrictions": (filter_json) { +/// "schema_id": string, (Optional) +/// "schema_issuer_did": string, (Optional) +/// "schema_name": string, (Optional) +/// "schema_version": string, (Optional) +/// "issuer_did": string, (Optional) +/// "cred_def_id": string, (Optional) +/// }, +/// "non_revoked": { +/// "from": Optional<(u64)> Requested time represented as a total number of seconds from Unix Epoch, Optional +/// "to": Optional<(u64)> +/// //Requested time represented as a total number of seconds from Unix Epoch, Optional +/// } +/// } /// /// # Example requested_attrs -> "[{"name":"attrName","restrictions":["issuer_did":"did","schema_id":"id","schema_issuer_did":"did","schema_name":"name","schema_version":"1.1.1","cred_def_id":"id"}]]" /// /// requested_predicates: predicate specifications prover must provide claim for +/// { // set of requested predicates +/// "name": attribute name, (case insensitive and ignore spaces) +/// "p_type": predicate type (Currently ">=" only) +/// "p_value": int predicate value +/// "restrictions": Optional, // see above +/// "non_revoked": Optional<{ +/// "from": Optional<(u64)> Requested time represented as a total number of seconds from Unix Epoch, Optional +/// "to": Optional<(u64)> Requested time represented as a total number of seconds from Unix Epoch, Optional +/// }> +/// }, /// /// # Example requested_predicates -> "[{"name":"attrName","p_type":"GE","p_value":9,"restrictions":["issuer_did":"did","schema_id":"id","schema_issuer_did":"did","schema_name":"name","schema_version":"1.1.1","cred_def_id":"id"}]]" /// +/// revocation_interval: Optional<>, // see below, +/// // If specified, prover must proof non-revocation +/// // for date in this interval for each attribute +/// // (can be overridden on attribute level) +/// from: Optional // timestamp of interval beginning +/// to: Optional // timestamp of interval beginning +/// // Requested time represented as a total number of seconds from Unix Epoch, Optional +/// # Examples config -> "{}" | "{"to": 123} | "{"from": 100, "to": 123}" +/// +/// +/// /// /// cb: Callback that provides proof handle and error status of request. /// @@ -35,22 +72,25 @@ pub extern fn vcx_proof_create(command_handle: u32, source_id: *const c_char, requested_attrs: *const c_char, requested_predicates: *const c_char, + revocation_interval: *const c_char, name: *const c_char, cb: Option) -> u32 { + info!("vcx_proof_create >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(requested_attrs, error::INVALID_OPTION.code_num); check_useful_c_str!(requested_predicates, error::INVALID_OPTION.code_num); check_useful_c_str!(name, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); + check_useful_c_str!(revocation_interval, error::INVALID_OPTION.code_num); - info!("vcx_proof_create(command_handle: {}, source_id: {}, requested_attrs: {}, requested_predicates: {}, name: {})", - command_handle, source_id, requested_attrs, requested_predicates, name); + trace!("vcx_proof_create(command_handle: {}, source_id: {}, requested_attrs: {}, requested_predicates: {}, revocation_interval: {}, name: {})", + command_handle, source_id, requested_attrs, requested_predicates, revocation_interval, name); spawn(move|| { - let ( rc, handle) = match proof::create_proof(source_id, requested_attrs, requested_predicates, name) { + let ( rc, handle) = match proof::create_proof(source_id, requested_attrs, requested_predicates, revocation_interval, name) { Ok(x) => { - info!("vcx_proof_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", + trace!("vcx_proof_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", command_handle, error_string(0), x, proof::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, @@ -83,10 +123,12 @@ pub extern fn vcx_proof_create(command_handle: u32, pub extern fn vcx_proof_update_state(command_handle: u32, proof_handle: u32, cb: Option) -> u32 { + info!("vcx_proof_update_state >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_proof_update_state(command_handle: {}, proof_handle: {}) source_id: {}", + trace!("vcx_proof_update_state(command_handle: {}, proof_handle: {}) source_id: {}", command_handle, proof_handle, source_id); if !proof::is_valid_handle(proof_handle) { @@ -96,7 +138,7 @@ pub extern fn vcx_proof_update_state(command_handle: u32, spawn(move|| { match proof::update_state(proof_handle) { Ok(x) => { - info!("vcx_proof_update_state_cb(command_handle: {}, rc: {}, proof_handle: {}, state: {}) source_id: {}", + trace!("vcx_proof_update_state_cb(command_handle: {}, rc: {}, proof_handle: {}, state: {}) source_id: {}", command_handle, error_string(0), proof_handle, x, source_id); cb(command_handle, error::SUCCESS.code_num, x); }, @@ -128,10 +170,12 @@ pub extern fn vcx_proof_update_state(command_handle: u32, pub extern fn vcx_proof_get_state(command_handle: u32, proof_handle: u32, cb: Option) -> u32 { + info!("vcx_proof_get_state >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_proof_get_state(command_handle: {}, proof_handle: {}), source_id: {}", + trace!("vcx_proof_get_state(command_handle: {}, proof_handle: {}), source_id: {}", command_handle, proof_handle, source_id); if !proof::is_valid_handle(proof_handle) { @@ -141,7 +185,7 @@ pub extern fn vcx_proof_get_state(command_handle: u32, spawn(move|| { match proof::get_state(proof_handle) { Ok(x) => { - info!("vcx_proof_get_state_cb(command_handle: {}, rc: {}, proof_handle: {}, state: {}) source_id: {}", + trace!("vcx_proof_get_state_cb(command_handle: {}, rc: {}, proof_handle: {}, state: {}) source_id: {}", command_handle, error_string(0), proof_handle, x, source_id); cb(command_handle, error::SUCCESS.code_num, x); }, @@ -173,11 +217,12 @@ pub extern fn vcx_proof_get_state(command_handle: u32, pub extern fn vcx_proof_serialize(command_handle: u32, proof_handle: u32, cb: Option) -> u32 { + info!("vcx_proof_serialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_proof_serialize(command_handle: {}, proof_handle: {}) source_id: {}", command_handle, proof_handle, source_id); + trace!("vcx_proof_serialize(command_handle: {}, proof_handle: {}) source_id: {}", command_handle, proof_handle, source_id); if !proof::is_valid_handle(proof_handle) { return error::INVALID_PROOF_HANDLE.code_num; @@ -186,7 +231,7 @@ pub extern fn vcx_proof_serialize(command_handle: u32, spawn(move|| { match proof::to_string(proof_handle) { Ok(x) => { - info!("vcx_proof_serialize_cb(command_handle: {}, proof_handle: {}, rc: {}, state: {}) source_id: {}", + trace!("vcx_proof_serialize_cb(command_handle: {}, proof_handle: {}, rc: {}, state: {}) source_id: {}", command_handle, proof_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -219,17 +264,18 @@ pub extern fn vcx_proof_serialize(command_handle: u32, pub extern fn vcx_proof_deserialize(command_handle: u32, proof_data: *const c_char, cb: Option) -> u32 { + info!("vcx_proof_deserialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(proof_data, error::INVALID_OPTION.code_num); - info!("vcx_proof_deserialize(command_handle: {}, proof_data: {})", + trace!("vcx_proof_deserialize(command_handle: {}, proof_data: {})", command_handle, proof_data); spawn(move|| { let (rc, handle) = match proof::from_string(&proof_data) { Ok(x) => { - info!("vcx_proof_deserialize_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", + trace!("vcx_proof_deserialize_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", command_handle, error_string(0), x, proof::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, @@ -256,9 +302,11 @@ pub extern fn vcx_proof_deserialize(command_handle: u32, /// Success #[no_mangle] pub extern fn vcx_proof_release(proof_handle: u32) -> u32 { + info!("vcx_proof_release >>>"); + let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); match proof::release(proof_handle) { - Ok(x) => info!("vcx_proof_release(proof_handle: {}, rc: {}), source_id: {}", + Ok(x) => trace!("vcx_proof_release(proof_handle: {}, rc: {}), source_id: {}", proof_handle, error_string(0), source_id), Err(e) => warn!("vcx_proof_release(proof_handle: {}, rc: {}), source_id: {}", proof_handle, error_string(e.to_error_code()), source_id), @@ -284,11 +332,12 @@ pub extern fn vcx_proof_send_request(command_handle: u32, proof_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_proof_send_request >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_proof_send_request(command_handle: {}, proof_handle: {}, connection_handle: {}) source_id: {}", + trace!("vcx_proof_send_request(command_handle: {}, proof_handle: {}, connection_handle: {}) source_id: {}", command_handle, proof_handle, connection_handle, source_id); if !proof::is_valid_handle(proof_handle) { return error::INVALID_PROOF_HANDLE.code_num; @@ -301,7 +350,7 @@ pub extern fn vcx_proof_send_request(command_handle: u32, spawn(move|| { let err = match proof::send_proof_request(proof_handle, connection_handle) { Ok(x) => { - info!("vcx_proof_send_request_cb(command_handle: {}, rc: {}, proof_handle: {}) source_id: {}", + trace!("vcx_proof_send_request_cb(command_handle: {}, rc: {}, proof_handle: {}) source_id: {}", command_handle, 0, proof_handle, source_id); x }, @@ -338,10 +387,12 @@ pub extern fn vcx_get_proof(command_handle: u32, proof_handle: u32, connection_handle: u32, cb: Option) -> u32 { + info!("vcx_get_proof >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = proof::get_source_id(proof_handle).unwrap_or_default(); - info!("vcx_get_proof(command_handle: {}, proof_handle: {}, connection_handle: {}) source_id: {}", + trace!("vcx_get_proof(command_handle: {}, proof_handle: {}, connection_handle: {}) source_id: {}", command_handle, proof_handle, connection_handle, source_id); if !proof::is_valid_handle(proof_handle) { return error::INVALID_PROOF_HANDLE.code_num; @@ -360,7 +411,7 @@ pub extern fn vcx_get_proof(command_handle: u32, match proof::get_proof(proof_handle) { Ok(x) => { - info!("vcx_get_proof_cb(command_handle: {}, proof_handle: {}, rc: {}, proof: {}) source_id: {}", command_handle, proof_handle, 0, x, source_id); + trace!("vcx_get_proof_cb(command_handle: {}, proof_handle: {}, rc: {}, proof: {}) source_id: {}", command_handle, proof_handle, 0, x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, proof::get_proof_state(proof_handle).unwrap_or(0), msg.as_ptr()); }, @@ -378,7 +429,10 @@ pub extern fn vcx_get_proof(command_handle: u32, #[allow(unused_variables)] -pub extern fn vcx_proof_accepted(proof_handle: u32, response_data: *const c_char) -> u32 { error::SUCCESS.code_num } +pub extern fn vcx_proof_accepted(proof_handle: u32, response_data: *const c_char) -> u32 { + info!("vcx_proof_accepted >>>"); + error::SUCCESS.code_num +} #[cfg(test)] @@ -390,11 +444,9 @@ mod tests { use std::time::Duration; use std::thread; use proof; - use api::VcxStateType; use connection; - use api::{ ProofStateType }; + use api::{ ProofStateType, return_types_u32, VcxStateType }; use utils::constants::*; - use utils::libindy::return_types_u32; static DEFAULT_PROOF_NAME: &'static str = "PROOF_NAME"; @@ -404,6 +456,7 @@ mod tests { CString::new(DEFAULT_PROOF_NAME).unwrap().into_raw(), CString::new(REQUESTED_ATTRS).unwrap().into_raw(), CString::new(REQUESTED_PREDICATES).unwrap().into_raw(), + CString::new(r#"{"support_revocation":false}"#).unwrap().into_raw(), CString::new("optional").unwrap().into_raw(), Some(cb.get_callback())); (cb, rc) @@ -425,6 +478,7 @@ mod tests { ptr::null(), ptr::null(), ptr::null(), + CString::new(r#"{"support_revocation":false}"#).unwrap().into_raw(), ptr::null(), None), error::INVALID_OPTION.code_num); @@ -448,7 +502,7 @@ mod tests { fn test_vcx_proof_deserialize_succeeds() { init!("true"); let cb = return_types_u32::Return_U32_U32::new().unwrap(); - let original = r#"{"nonce":"123456","version":"1.0","handle":1,"msg_uid":"","ref_msg_id":"","name":"Name Data","prover_vk":"","agent_did":"","agent_vk":"","remote_did":"","remote_vk":"","prover_did":"8XFh8yBzrpJQmNyZzgoTqB","requested_attrs":"{\"attrs\":[{\"name\":\"person name\"},{\"schema_seq_no\":1,\"name\":\"address_1\"},{\"schema_seq_no\":2,\"issuer_did\":\"ISSUER_DID2\",\"name\":\"address_2\"},{\"schema_seq_no\":1,\"name\":\"city\"},{\"schema_seq_no\":1,\"name\":\"state\"},{\"schema_seq_no\":1,\"name\":\"zip\"}]}","requested_predicates":"{\"attr_name\":\"age\",\"p_type\":\"GE\",\"value\":18,\"schema_seq_no\":1,\"issuer_did\":\"DID1\"}","source_id":"source id","state":2,"proof_state":0,"proof":null,"proof_request":null}"#; + let original = r#"{"nonce":"123456","version":"1.0","handle":1,"msg_uid":"","ref_msg_id":"","name":"Name Data","prover_vk":"","agent_did":"","agent_vk":"","remote_did":"","remote_vk":"","prover_did":"8XFh8yBzrpJQmNyZzgoTqB","requested_attrs":"{\"attrs\":[{\"name\":\"person name\"},{\"schema_seq_no\":1,\"name\":\"address_1\"},{\"schema_seq_no\":2,\"issuer_did\":\"ISSUER_DID2\",\"name\":\"address_2\"},{\"schema_seq_no\":1,\"name\":\"city\"},{\"schema_seq_no\":1,\"name\":\"state\"},{\"schema_seq_no\":1,\"name\":\"zip\"}]}","requested_predicates":"{\"attr_name\":\"age\",\"p_type\":\"GE\",\"value\":18,\"schema_seq_no\":1,\"issuer_did\":\"DID1\"}","source_id":"source id","state":2,"proof_state":0,"proof":null,"proof_request":null,"revocation_interval":{}}"#; assert_eq!(vcx_proof_deserialize(cb.command_handle, CString::new(PROOF_OFFER_SENT).unwrap().into_raw(), Some(cb.get_callback())), @@ -483,7 +537,7 @@ mod tests { let proof_handle = cb.receive(Some(Duration::from_secs(10))).unwrap(); assert_eq!(proof::get_state(proof_handle).unwrap(),VcxStateType::VcxStateInitialized as u32); - let connection_handle = connection::build_connection("test_send_proof_request").unwrap(); + let connection_handle = ::connection::tests::build_test_connection(); let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_proof_send_request(cb.command_handle, proof_handle, @@ -501,7 +555,7 @@ mod tests { let (cb, rc) = create_proof_util(); assert_eq!(rc, error::SUCCESS.code_num); let proof_handle = cb.receive(Some(Duration::from_secs(10))).unwrap(); - let connection_handle = connection::build_connection("test_get_proof_fails_when_not_ready_with_proof").unwrap(); + let connection_handle = connection::tests::build_test_connection(); connection::set_pw_did(connection_handle, "XXFh7yBzrpJQmNyZzgoTqB").unwrap(); thread::sleep(Duration::from_millis(300)); @@ -517,7 +571,7 @@ mod tests { #[test] fn test_get_proof_returns_proof_with_proof_state_invalid() { init!("true"); - let connection_handle = connection::build_connection("test_get_proof_returns_proof_with_proof_state_invalid").unwrap(); + let connection_handle = connection::tests::build_test_connection(); connection::set_pw_did(connection_handle, "XXFh7yBzrpJQmNyZzgoTqB").unwrap(); let proof_handle = proof::from_string(PROOF_WITH_INVALID_STATE).unwrap(); let cb = return_types_u32::Return_U32_U32_STR::new().unwrap(); diff --git a/vcx/libvcx/src/utils/libindy/return_types_u32.rs b/vcx/libvcx/src/api/return_types_u32.rs similarity index 99% rename from vcx/libvcx/src/utils/libindy/return_types_u32.rs rename to vcx/libvcx/src/api/return_types_u32.rs index 31685d7b..2d6460bc 100644 --- a/vcx/libvcx/src/utils/libindy/return_types_u32.rs +++ b/vcx/libvcx/src/api/return_types_u32.rs @@ -36,7 +36,7 @@ pub fn receive(receiver: &Receiver, timeout: Option) -> Result Ok(t), Err(e) => match e { RecvTimeoutError::Timeout => { - warn!("Timed Out waiting for libindy to call back"); + warn!("Timed Out waiting for call back"); Err(error::TIMEOUT_LIBINDY_ERROR.code_num) }, RecvTimeoutError::Disconnected => { diff --git a/vcx/libvcx/src/api/schema.rs b/vcx/libvcx/src/api/schema.rs index 8022e034..af67f83c 100644 --- a/vcx/libvcx/src/api/schema.rs +++ b/vcx/libvcx/src/api/schema.rs @@ -22,7 +22,7 @@ use utils::threadpool::spawn; /// /// version: version of schema /// -/// schema_data: list of attributes that will make up the schema +/// schema_data: list of attributes that will make up the schema (the number of attributes should be less or equal than 125) /// /// # Example schema_data -> "["attr1", "attr2", "attr3"]" /// @@ -40,6 +40,8 @@ pub extern fn vcx_schema_create(command_handle: u32, schema_data: *const c_char, payment_handle: u32, cb: Option) -> u32 { + info!("vcx_schema_create >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(schema_name, error::INVALID_OPTION.code_num); check_useful_c_str!(version, error::INVALID_OPTION.code_num); @@ -50,7 +52,7 @@ pub extern fn vcx_schema_create(command_handle: u32, Ok(x) => x, Err(x) => return x }; - info!(target:"vcx","vcx_schema_create(command_handle: {}, source_id: {}, schema_name: {}, schema_data: {})", + trace!(target:"vcx","vcx_schema_create(command_handle: {}, source_id: {}, schema_name: {}, schema_data: {})", command_handle, source_id, schema_name, schema_data); spawn(move|| { @@ -60,7 +62,7 @@ pub extern fn vcx_schema_create(command_handle: u32, version, schema_data) { Ok(x) => { - info!(target:"vcx", "vcx_schema_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", + trace!(target:"vcx", "vcx_schema_create_cb(command_handle: {}, rc: {}, handle: {}) source_id: {}", command_handle, error_string(0), x, source_id); (error::SUCCESS.code_num, x) }, @@ -94,11 +96,12 @@ pub extern fn vcx_schema_create(command_handle: u32, pub extern fn vcx_schema_serialize(command_handle: u32, schema_handle: u32, cb: Option) -> u32 { + info!("vcx_schema_serialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let source_id = schema::get_source_id(schema_handle).unwrap_or_default(); - info!("vcx_schema_serialize(command_handle: {}, schema_handle: {}) source_id: {}", + trace!("vcx_schema_serialize(command_handle: {}, schema_handle: {}) source_id: {}", command_handle, schema_handle, source_id); if !schema::is_valid_handle(schema_handle) { @@ -108,7 +111,7 @@ pub extern fn vcx_schema_serialize(command_handle: u32, spawn(move|| { match schema::to_string(schema_handle) { Ok(x) => { - info!("vcx_schema_serialize_cb(command_handle: {}, schema_handle: {}, rc: {}, state: {}) source_id: {}", + trace!("vcx_schema_serialize_cb(command_handle: {}, schema_handle: {}, rc: {}, state: {}) source_id: {}", command_handle, schema_handle, error_string(0), x, source_id); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -141,15 +144,16 @@ pub extern fn vcx_schema_serialize(command_handle: u32, pub extern fn vcx_schema_deserialize(command_handle: u32, schema_data: *const c_char, cb: Option) -> u32 { + info!("vcx_schema_deserialize >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(schema_data, error::INVALID_OPTION.code_num); - info!("vcx_schema_deserialize(command_handle: {}, schema_data: {})", command_handle, schema_data); + trace!("vcx_schema_deserialize(command_handle: {}, schema_data: {})", command_handle, schema_data); spawn(move|| { let (rc, handle) = match schema::from_string(&schema_data) { Ok(x) => { - info!("vcx_schema_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", + trace!("vcx_schema_deserialize_cb(command_handle: {}, rc: {}, handle: {}), source_id: {}", command_handle, error_string(0), x, schema::get_source_id(x).unwrap_or_default()); (error::SUCCESS.code_num, x) }, @@ -176,9 +180,11 @@ pub extern fn vcx_schema_deserialize(command_handle: u32, /// Success #[no_mangle] pub extern fn vcx_schema_release(schema_handle: u32) -> u32 { + info!("vcx_schema_release >>>"); + let source_id = schema::get_source_id(schema_handle).unwrap_or_default(); match schema::release(schema_handle) { - Ok(x) => info!("vcx_schema_release(schema_handle: {}, rc: {}), source_id: {}", + Ok(x) => trace!("vcx_schema_release(schema_handle: {}, rc: {}), source_id: {}", schema_handle, error_string(0), source_id), Err(e) => warn!("vcx_schema_release(schema_handle: {}, rc: {}), source_id: {}", schema_handle, error_string(e.to_error_code()), source_id), @@ -199,9 +205,11 @@ pub extern fn vcx_schema_release(schema_handle: u32) -> u32 { pub extern fn vcx_schema_get_schema_id(command_handle: u32, schema_handle: u32, cb: Option) -> u32 { + info!("vcx_schema_get_schema_id >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - info!("vcx_schema_get_schema_id(command_handle: {}, schema_handle: {})", command_handle, schema_handle); + trace!("vcx_schema_get_schema_id(command_handle: {}, schema_handle: {})", command_handle, schema_handle); if !schema::is_valid_handle(schema_handle) { return error::INVALID_SCHEMA_HANDLE.code_num; } @@ -209,7 +217,7 @@ pub extern fn vcx_schema_get_schema_id(command_handle: u32, spawn(move|| { match schema::get_schema_id(schema_handle) { Ok(x) => { - info!("vcx_schema_get_schema_id(command_handle: {}, schema_handle: {}, rc: {}, schema_seq_no: {})", + trace!("vcx_schema_get_schema_id(command_handle: {}, schema_handle: {}, rc: {}, schema_seq_no: {})", command_handle, schema_handle, error_string(0), x); let msg = CStringUtils::string_to_cstring(x); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); @@ -245,10 +253,12 @@ pub extern fn vcx_schema_get_attributes(command_handle: u32, source_id: *const c_char, schema_id: *const c_char, cb: Option) -> u32 { + info!("vcx_schema_get_attributes >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(source_id, error::INVALID_OPTION.code_num); check_useful_c_str!(schema_id, error::INVALID_OPTION.code_num); - info!("vcx_schema_get_attributes(command_handle: {}, source_id: {}, schema_id: {})", + trace!("vcx_schema_get_attributes(command_handle: {}, source_id: {}, schema_id: {})", command_handle, source_id, schema_id); spawn(move|| { @@ -256,7 +266,7 @@ pub extern fn vcx_schema_get_attributes(command_handle: u32, Ok((handle, data)) => { let data:serde_json::Value = serde_json::from_str(&data).unwrap(); let data = data["data"].clone(); - info!("vcx_schema_get_attributes_cb(command_handle: {}, rc: {}, handle: {}, attrs: {})", + trace!("vcx_schema_get_attributes_cb(command_handle: {}, rc: {}, handle: {}, attrs: {})", command_handle, error_string(0), handle, data); let msg = CStringUtils::string_to_cstring(data.to_string()); cb(command_handle, error::SUCCESS.code_num, handle, msg.as_ptr()); @@ -296,17 +306,18 @@ pub extern fn vcx_schema_get_attributes(command_handle: u32, pub extern fn vcx_schema_get_payment_txn(command_handle: u32, handle: u32, cb: Option) -> u32 { + info!("vcx_schema_get_payment_txn >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - info!("vcx_schema_get_payment_txn(command_handle: {})", command_handle); + trace!("vcx_schema_get_payment_txn(command_handle: {})", command_handle); spawn(move|| { match schema::get_payment_txn(handle) { Ok(x) => { match serde_json::to_string(&x) { Ok(x) => { - info!("vcx_schema_get_payment_txn_cb(command_handle: {}, rc: {}, : {}), source_id: {:?}", + trace!("vcx_schema_get_payment_txn_cb(command_handle: {}, rc: {}, : {}), source_id: {:?}", command_handle, error_string(0), x, schema::get_source_id(handle).unwrap_or_default()); let msg = CStringUtils::string_to_cstring(x); @@ -346,7 +357,7 @@ mod tests { use settings; #[allow(unused_imports)] use utils::constants::{ SCHEMA_ID, SCHEMA_WITH_VERSION, DEFAULT_SCHEMA_ATTRS, DEFAULT_SCHEMA_ID, DEFAULT_SCHEMA_NAME }; - use utils::libindy::return_types_u32; + use api::return_types_u32; #[test] fn test_vcx_create_schema_success() { diff --git a/vcx/libvcx/src/api/utils.rs b/vcx/libvcx/src/api/utils.rs index a0172b7e..83916d91 100644 --- a/vcx/libvcx/src/api/utils.rs +++ b/vcx/libvcx/src/api/utils.rs @@ -29,12 +29,14 @@ pub struct UpdateAgentInfo { #[no_mangle] pub extern fn vcx_provision_agent(config: *const c_char) -> *mut c_char { + info!("vcx_provision_agent >>>"); + check_useful_c_str!(config, ptr::null_mut()); + trace!("vcx_provision_agent(config: {})", config); + match messages::agent_utils::connect_register_provision(&config) { Err(e) => { - // Ensure state of libvcx is clean - ::api::vcx::vcx_shutdown(false); error!("Provision Agent Error {}.", e); return ptr::null_mut(); }, @@ -64,22 +66,22 @@ pub extern fn vcx_provision_agent(config: *const c_char) -> *mut c_char { pub extern fn vcx_agent_provision_async(command_handle : u32, config: *const c_char, cb: Option) -> u32 { + info!("vcx_agent_provision_async >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(config, error::INVALID_OPTION.code_num); - info!("vcx_agent_provision_async(command_handle: {}, json: {})", + trace!("vcx_agent_provision_async(command_handle: {}, json: {})", command_handle, config); thread::spawn(move|| { match messages::agent_utils::connect_register_provision(&config) { Err(e) => { - // Ensure state of libvcx is clean - ::api::vcx::vcx_shutdown(false); error!("vcx_agent_provision_async_cb(command_handle: {}, rc: {}, config: NULL", command_handle, error_string(e)); cb(command_handle, e, ptr::null_mut()); }, Ok(s) => { - info!("vcx_agent_provision_async_cb(command_handle: {}, rc: {}, config: {})", + trace!("vcx_agent_provision_async_cb(command_handle: {}, rc: {}, config: {})", command_handle, error_string(0), s); let msg = CStringUtils::string_to_cstring(s); cb(command_handle, 0, msg.as_ptr()); @@ -106,11 +108,12 @@ pub extern fn vcx_agent_provision_async(command_handle : u32, pub extern fn vcx_agent_update_info(command_handle: u32, json: *const c_char, cb: Option) -> u32 { + info!("vcx_agent_update_info >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(json, error::INVALID_OPTION.code_num); - info!("vcx_agent_update_info(command_handle: {}, json: {})", + trace!("vcx_agent_update_info(command_handle: {}, json: {})", command_handle, json); let agent_info: UpdateAgentInfo = match serde_json::from_str(&json) { @@ -123,7 +126,7 @@ pub extern fn vcx_agent_update_info(command_handle: u32, spawn(move|| { match messages::agent_utils::update_agent_info(&agent_info.id, &agent_info.value){ Ok(x) => { - info!("vcx_agent_update_info_cb(command_handle: {}, rc: {})", + trace!("vcx_agent_update_info_cb(command_handle: {}, rc: {})", command_handle, error::error_string(0)); cb(command_handle, error::SUCCESS.code_num); }, @@ -153,15 +156,16 @@ pub extern fn vcx_agent_update_info(command_handle: u32, #[no_mangle] pub extern fn vcx_ledger_get_fees(command_handle: u32, cb: Option) -> u32 { + info!("vcx_ledger_get_fees >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - info!("vcx_ledger_get_fees(command_handle: {})", + trace!("vcx_ledger_get_fees(command_handle: {})", command_handle); spawn(move|| { match ::utils::libindy::payments::get_ledger_fees() { Ok(x) => { - info!("vcx_ledger_get_fees_cb(command_handle: {}, rc: {}, fees: {})", + trace!("vcx_ledger_get_fees_cb(command_handle: {}, rc: {}, fees: {})", command_handle, error::error_string(0), x); let msg = CStringUtils::string_to_cstring(x); @@ -183,6 +187,8 @@ pub extern fn vcx_ledger_get_fees(command_handle: u32, #[no_mangle] pub extern fn vcx_set_next_agency_response(message_index: u32) { + info!("vcx_set_next_agency_response >>>"); + let message = match message_index { 1 => CREATE_KEYS_RESPONSE.to_vec(), 2 => UPDATE_PROFILE_RESPONSE.to_vec(), @@ -219,6 +225,7 @@ pub extern fn vcx_messages_download(command_handle: u32, uids: *const c_char, pw_dids: *const c_char, cb: Option) -> u32 { + info!("vcx_messages_download >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); @@ -249,7 +256,7 @@ pub extern fn vcx_messages_download(command_handle: u32, None }; - info!("vcx_messages_download(command_handle: {}, message_status: {:?}, uids: {:?})", + trace!("vcx_messages_download(command_handle: {}, message_status: {:?}, uids: {:?})", command_handle, message_status, uids); spawn(move|| { @@ -257,7 +264,7 @@ pub extern fn vcx_messages_download(command_handle: u32, Ok(x) => { match serde_json::to_string(&x) { Ok(x) => { - info!("vcx_messages_download_cb(command_handle: {}, rc: {}, messages: {})", + trace!("vcx_messages_download_cb(command_handle: {}, rc: {}, messages: {})", command_handle, error::error_string(0), x); let msg = CStringUtils::string_to_cstring(x); @@ -305,18 +312,19 @@ pub extern fn vcx_messages_update_status(command_handle: u32, message_status: *const c_char, msg_json: *const c_char, cb: Option) -> u32 { + info!("vcx_messages_update_status >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(message_status, error::INVALID_OPTION.code_num); check_useful_c_str!(msg_json, error::INVALID_OPTION.code_num); - info!("vcx_messages_set_status(command_handle: {}, message_status: {:?}, uids: {:?})", + trace!("vcx_messages_set_status(command_handle: {}, message_status: {:?}, uids: {:?})", command_handle, message_status, msg_json); spawn(move|| { match ::messages::update_message::update_agency_messages(&message_status, &msg_json) { Ok(_) => { - info!("vcx_messages_set_status_cb(command_handle: {}, rc: {})", + trace!("vcx_messages_set_status_cb(command_handle: {}, rc: {})", command_handle, error::error_string(0)); cb(command_handle, error::SUCCESS.code_num); @@ -341,7 +349,8 @@ mod tests { use super::*; use std::ffi::CString; use std::time::Duration; - use utils::libindy::return_types_u32; + use api::return_types_u32; + use utils::timeout::TimeoutUtils; #[test] fn test_provision_agent() { @@ -362,7 +371,6 @@ mod tests { let json_string = r#"{"agency_url":"https://enym-eagency.pdev.evernym.com","agency_did":"Ab8TvZa3Q19VNkQVzAWVL7","agency_verkey":"5LXaR43B1aQyeh94VBP8LG1Sgvjk7aNfqiksBCSjwqbf","wallet_name":"test_provision_agent","agent_seed":null,"enterprise_seed":null,"wallet_key":"key"}"#; let c_json = CString::new(json_string).unwrap().into_raw(); - use utils::libindy::return_types_u32; let cb = return_types_u32::Return_U32_STR::new().unwrap(); let result = vcx_agent_provision_async(cb.command_handle, c_json, Some(cb.get_callback())); assert_eq!(0, result); @@ -384,6 +392,28 @@ mod tests { assert_eq!(result, Err(error::INVALID_CONFIGURATION.code_num)); } + #[test] + fn test_create_agent_fails_for_unknown_wallet_type() { + init!("false"); + + let config = json!({ + "agency_url":"https://enym-eagency.pdev.evernym.com", + "agency_did":"Ab8TvZa3Q19VNkQVzAWVL7", + "agency_verkey":"5LXaR43B1aQyeh94VBP8LG1Sgvjk7aNfqiksBCSjwqbf", + "wallet_name":"test_provision_agent", + "wallet_key":"key", + "wallet_type":"UNKNOWN_WALLET_TYPE" + }).to_string(); + + let c_config = CString::new(config).unwrap().into_raw(); + + let cb = return_types_u32::Return_U32_STR::new().unwrap(); + let result = vcx_agent_provision_async(cb.command_handle, c_config, Some(cb.get_callback())); + assert_eq!(0, result); + let result = cb.receive(Some(TimeoutUtils::medium_timeout())); + assert_eq!(result, Err(error::INVALID_WALLET_CREATION.code_num)); + } + #[test] fn test_update_agent_info() { init!("true"); diff --git a/vcx/libvcx/src/api/vcx.rs b/vcx/libvcx/src/api/vcx.rs index cf53695c..ea93e9a9 100644 --- a/vcx/libvcx/src/api/vcx.rs +++ b/vcx/libvcx/src/api/vcx.rs @@ -28,17 +28,20 @@ use utils::threadpool::spawn; pub extern fn vcx_init_with_config(command_handle: u32, config: *const c_char, cb: Option) -> u32 { + info!("vcx_init_with_config >>>"); + check_useful_c_str!(config,error::INVALID_OPTION.code_num); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + trace!("vcx_init(command_handle: {}, config: {:?})", + command_handle, config); + if config == "ENABLE_TEST_MODE" { settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE,"true"); settings::set_defaults(); } else { match settings::process_config_string(&config) { Err(e) => { - // Ensure state of libvcx is clean - vcx_shutdown(false); error!("Invalid configuration specified: {}", e); return e; }, @@ -66,9 +69,14 @@ pub extern fn vcx_init_with_config(command_handle: u32, pub extern fn vcx_init (command_handle: u32, config_path:*const c_char, cb: Option) -> u32 { + info!("vcx_init >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + trace!("vcx_init(command_handle: {}, config_path: {:?})", + command_handle, config_path); + + if !config_path.is_null() { check_useful_c_str!(config_path,error::INVALID_OPTION.code_num); @@ -78,12 +86,14 @@ pub extern fn vcx_init (command_handle: u32, } else { match settings::process_config_file(&config_path) { Err(e) => { - // Ensure state of libvcx is clean - vcx_shutdown(false); - println!("Invalid configuration specified: {}", e); return error::INVALID_CONFIGURATION.code_num; }, - Ok(_) => (), + Ok(_) => { + match settings::validate_payment_method() { + Ok(_) => (), + Err(e) => return e + } + }, }; } } else { @@ -95,15 +105,9 @@ pub extern fn vcx_init (command_handle: u32, } fn _finish_init(command_handle: u32, cb: extern fn(xcommand_handle: u32, err: u32)) -> u32 { - ::utils::logger::LoggerUtils::init(); ::utils::threadpool::init(); - match ::utils::libindy::payments::init_payments() { - Ok(_) => (), - Err(x) => return x, - }; - settings::log_settings(); if wallet::get_wallet_handle() > 0 { @@ -114,13 +118,15 @@ fn _finish_init(command_handle: u32, cb: extern fn(xcommand_handle: u32, err: u3 let wallet_name = match settings::get_config_value(settings::CONFIG_WALLET_NAME) { Ok(x) => x, Err(_) => { - info!("Using default wallet: {}", settings::DEFAULT_WALLET_NAME.to_string()); + trace!("Using default wallet: {}", settings::DEFAULT_WALLET_NAME.to_string()); settings::set_config_value(settings::CONFIG_WALLET_NAME, settings::DEFAULT_WALLET_NAME); settings::DEFAULT_WALLET_NAME.to_string() } }; - info!("libvcx version: {}{}", version_constants::VERSION, version_constants::REVISION); + let wallet_type = settings::get_config_value(settings::CONFIG_WALLET_TYPE).ok(); + + trace!("libvcx version: {}{}", version_constants::VERSION, version_constants::REVISION); spawn(move|| { if settings::get_config_value(settings::CONFIG_GENESIS_PATH).is_ok() { @@ -133,7 +139,7 @@ fn _finish_init(command_handle: u32, cb: extern fn(xcommand_handle: u32, err: u3 } } - match wallet::open_wallet(&wallet_name) { + match wallet::open_wallet(&wallet_name, wallet_type.as_ref().map(String::as_str)) { Ok(_) => { debug!("Init Wallet Successful"); cb(command_handle, error::SUCCESS.code_num); @@ -155,6 +161,7 @@ lazy_static!{ #[no_mangle] pub extern fn vcx_version() -> *const c_char { + info!("vcx_version >>>"); VERSION_STRING.as_ptr() } @@ -169,6 +176,8 @@ pub extern fn vcx_version() -> *const c_char { /// Success #[no_mangle] pub extern fn vcx_shutdown(delete: bool) -> u32 { + info!("vcx_shutdown >>>"); + trace!("vcx_shutdown(delete: {})", delete); match wallet::close_wallet() { Ok(_) => {}, @@ -195,7 +204,9 @@ pub extern fn vcx_shutdown(delete: bool) -> u32 { let wallet_name = settings::get_config_value(settings::CONFIG_WALLET_NAME) .unwrap_or(settings::DEFAULT_WALLET_NAME.to_string()); - match wallet::delete_wallet(&wallet_name) { + let wallet_type = settings::get_config_value(settings::CONFIG_WALLET_TYPE).ok(); + + match wallet::delete_wallet(&wallet_name, wallet_type.as_ref().map(String::as_str)) { Ok(_) => (), Err(_) => (), }; @@ -207,21 +218,24 @@ pub extern fn vcx_shutdown(delete: bool) -> u32 { } settings::clear_config(); - info!("vcx_shutdown(delete: {})", delete); + trace!("vcx_shutdown(delete: {})", delete); error::SUCCESS.code_num } #[no_mangle] pub extern fn vcx_error_c_message(error_code: u32) -> *const c_char { - info!("vcx_error_message(error_code: {})", error_code); + info!("vcx_error_c_message >>>"); + trace!("vcx_error_message(error_code: {})", error_code); error::error_c_message(&error_code).as_ptr() } #[no_mangle] pub extern fn vcx_update_institution_info(name: *const c_char, logo_url: *const c_char) -> u32 { + info!("vcx_update_institution_info >>>"); + check_useful_c_str!(name, error::INVALID_CONFIGURATION.code_num); check_useful_c_str!(logo_url, error::INVALID_CONFIGURATION.code_num); - info!("vcx_update_institution_info(name: {}, logo_url: {})", name, logo_url); + trace!("vcx_update_institution_info(name: {}, logo_url: {})", name, logo_url); settings::set_config_value(::settings::CONFIG_INSTITUTION_NAME, &name); settings::set_config_value(::settings::CONFIG_INSTITUTION_LOGO_URL, &logo_url); @@ -231,6 +245,7 @@ pub extern fn vcx_update_institution_info(name: *const c_char, logo_url: *const #[no_mangle] pub extern fn vcx_mint_tokens(seed: *const c_char, fees: *const c_char) { + info!("vcx_mint_tokens >>>"); let seed = if !seed.is_null() { check_useful_opt_c_str!(seed, ()); @@ -247,6 +262,7 @@ pub extern fn vcx_mint_tokens(seed: *const c_char, fees: *const c_char) { else { None }; + trace!("vcx_mint_tokens(seed: {:?}, fees: {:?})", seed, fees); ::utils::libindy::payments::mint_tokens_and_set_fees(None, None, fees, seed).unwrap_or_default(); } @@ -258,18 +274,25 @@ mod tests { use std::time::Duration; use std::ptr; use std::thread; - use utils::libindy::wallet::{import, tests::export_test_wallet, tests::delete_import_wallet_path}; - use utils::libindy::{ pool::get_pool_handle, return_types_u32 }; + use utils::{ + libindy::{ + wallet::{import, tests::export_test_wallet, tests::delete_import_wallet_path}, + pool::get_pool_handle + }, + get_temp_dir_path + }; + use api::return_types_u32; - fn create_config_util() -> String { + fn create_config_util(logging: Option<&str>) -> String { json!({"agency_did" : "72x8p4HubxzUK1dwxcc5FU", - "remote_to_sdk_did" : "UJGjM6Cea2YVixjWwHN9wq", - "sdk_to_remote_did" : "AB3JM851T4EQmhh8CdagSP", - "sdk_to_remote_verkey" : "888MFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", - "institution_name" : "evernym enterprise", - "agency_verkey" : "91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", - "remote_to_sdk_verkey" : "91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", - "genesis_path":"/tmp/pool1.txn"}).to_string() + "remote_to_sdk_did" : "UJGjM6Cea2YVixjWwHN9wq", + "sdk_to_remote_did" : "AB3JM851T4EQmhh8CdagSP", + "sdk_to_remote_verkey" : "888MFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", + "institution_name" : "evernym enterprise", + "agency_verkey" : "91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", + "remote_to_sdk_verkey" : "91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", + "genesis_path": get_temp_dir_path(Some("pool1.txn")).to_str().unwrap(), + "payment_method": "null"}).to_string() } #[cfg(feature = "agency")] @@ -280,8 +303,9 @@ mod tests { wallet::close_wallet().unwrap(); pool::close().unwrap(); - let config_path = "/tmp/test_init.json"; - let content = create_config_util(); + let config_path_buf = get_temp_dir_path(Some("test_init.json")); + let config_path = config_path_buf.to_str().unwrap(); + let content = create_config_util(Some("true")); settings::write_config_to_file(&content, config_path).unwrap(); let cb = return_types_u32::Return_U32::new().unwrap(); @@ -294,6 +318,30 @@ mod tests { assert_ne!(get_pool_handle().unwrap(), 0); } + #[cfg(feature = "agency")] + #[cfg(feature = "pool_tests")] + #[test] + fn test_init_with_file_no_payment_method() { + init!("false"); + settings::clear_config(); + + let config_path_buf = get_temp_dir_path(Some("test_init.json")); + let config_path = config_path_buf.to_str().unwrap(); + let content = json!({ + "wallet_name": settings::DEFAULT_WALLET_NAME, + "wallet_key": settings::DEFAULT_WALLET_KEY, + "wallet_key_derivation": settings::DEFAULT_WALLET_KEY_DERIVATION, + }).to_string(); + + settings::write_config_to_file(&content, config_path).unwrap(); + + let cb = return_types_u32::Return_U32::new().unwrap(); + assert_eq!(vcx_init(cb.command_handle, + CString::new(config_path).unwrap().into_raw(), + Some(cb.get_callback())), + error::MISSING_PAYMENT_METHOD.code_num); + } + #[cfg(feature = "agency")] #[cfg(feature = "pool_tests")] #[test] @@ -302,7 +350,7 @@ mod tests { wallet::close_wallet().unwrap(); pool::close().unwrap(); - let content = create_config_util(); + let content = create_config_util(None); let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_init_with_config(cb.command_handle, @@ -325,15 +373,15 @@ mod tests { settings::set_config_value(settings::CONFIG_WALLET_KEY,settings::DEFAULT_WALLET_KEY); // Write invalid genesis.txn - let mut f = fs::File::create(::utils::constants::GENESIS_PATH).unwrap(); + let mut f = fs::File::create(get_temp_dir_path(Some(::utils::constants::GENESIS_PATH)).to_str().unwrap()).unwrap(); f.write_all("{}".as_bytes()).unwrap(); f.flush().unwrap(); f.sync_all().unwrap(); let wallet_name = "test_init_fails_when_open_pool_fails"; - wallet::create_wallet(wallet_name).unwrap(); + wallet::create_wallet(wallet_name, None).unwrap(); - let content = create_config_util(); + let content = create_config_util(None); let cb = return_types_u32::Return_U32::new().unwrap(); assert_eq!(vcx_init_with_config(cb.command_handle, @@ -345,7 +393,7 @@ mod tests { assert!(rc.is_err()); assert_eq!(get_pool_handle(), Err(error::NO_POOL_OPEN.code_num)); assert_eq!(wallet::get_wallet_handle(), 0); - wallet::delete_wallet(wallet_name).unwrap(); + wallet::delete_wallet(wallet_name, None).unwrap(); } #[test] @@ -355,7 +403,8 @@ mod tests { let content = json!({ "wallet_name": settings::DEFAULT_WALLET_NAME, - "wallet_key": settings::DEFAULT_WALLET_KEY + "wallet_key": settings::DEFAULT_WALLET_KEY, + "wallet_key_derivation": settings::DEFAULT_WALLET_KEY_DERIVATION, }).to_string(); let cb = return_types_u32::Return_U32::new().unwrap(); @@ -490,8 +539,9 @@ mod tests { fn test_init_fails_with_open_wallet() { init!("ledger"); - let config_path = "/tmp/test_init.json"; - let content = create_config_util(); + let config_path_buf = get_temp_dir_path(Some("test_init.json")); + let config_path = config_path_buf.to_str().unwrap(); + let content = create_config_util(None); settings::write_config_to_file(&content, config_path).unwrap(); let cb = return_types_u32::Return_U32::new().unwrap(); @@ -505,22 +555,24 @@ mod tests { fn test_init_after_importing_wallet_success() { settings::set_defaults(); teardown!("false"); - let exported_path = format!(r#"/tmp/{}"#, settings::DEFAULT_WALLET_NAME); - let dir = export_test_wallet(); + let export_path = export_test_wallet(); + vcx_shutdown(true); let import_config = json!({ settings::CONFIG_WALLET_NAME: settings::DEFAULT_WALLET_NAME, settings::CONFIG_WALLET_KEY: settings::DEFAULT_WALLET_KEY, - settings::CONFIG_EXPORTED_WALLET_PATH: exported_path, + settings::CONFIG_WALLET_KEY_DERIVATION: settings::DEFAULT_WALLET_KEY_DERIVATION, settings::CONFIG_WALLET_BACKUP_KEY: settings::DEFAULT_WALLET_BACKUP_KEY, + settings::CONFIG_EXPORTED_WALLET_PATH: export_path, }).to_string(); import(&import_config).unwrap(); let content = json!({ "wallet_name": settings::DEFAULT_WALLET_NAME, "wallet_key": settings::DEFAULT_WALLET_KEY, + "wallet_key_derivation": settings::DEFAULT_WALLET_KEY_DERIVATION, }).to_string(); let cb = return_types_u32::Return_U32::new().unwrap(); @@ -530,7 +582,7 @@ mod tests { error::SUCCESS.code_num); cb.receive(Some(Duration::from_secs(10))).unwrap(); - delete_import_wallet_path(dir); + delete_import_wallet_path(export_path); vcx_shutdown(true); } @@ -538,22 +590,24 @@ mod tests { fn test_init_with_imported_wallet_fails_with_different_params() { settings::set_defaults(); teardown!("false"); - let exported_path = format!(r#"/tmp/{}"#, settings::DEFAULT_WALLET_NAME); - let dir = export_test_wallet(); + let export_path = export_test_wallet(); + vcx_shutdown(true); let import_config = json!({ settings::CONFIG_WALLET_NAME: settings::DEFAULT_WALLET_NAME, settings::CONFIG_WALLET_KEY: settings::DEFAULT_WALLET_KEY, - settings::CONFIG_EXPORTED_WALLET_PATH: exported_path, + settings::CONFIG_WALLET_KEY_DERIVATION: settings::DEFAULT_WALLET_KEY_DERIVATION, + settings::CONFIG_EXPORTED_WALLET_PATH: export_path, settings::CONFIG_WALLET_BACKUP_KEY: settings::DEFAULT_WALLET_BACKUP_KEY, }).to_string(); import(&import_config).unwrap(); let content = json!({ "wallet_name": "different_wallet_name", - "wallet_key": settings::DEFAULT_WALLET_KEY + "wallet_key": settings::DEFAULT_WALLET_KEY, + "wallet_key_derivation": settings::DEFAULT_WALLET_KEY_DERIVATION, }).to_string(); let cb = return_types_u32::Return_U32::new().unwrap(); @@ -563,7 +617,7 @@ mod tests { error::SUCCESS.code_num); assert_eq!(cb.receive(Some(Duration::from_secs(10))).err(), Some(error::WALLET_NOT_FOUND.code_num)); - delete_import_wallet_path(dir); + delete_import_wallet_path(export_path); settings::set_config_value(settings::CONFIG_WALLET_NAME,settings::DEFAULT_WALLET_NAME); vcx_shutdown(true); } @@ -572,13 +626,15 @@ mod tests { fn test_import_after_init_fails() { settings::set_defaults(); teardown!("false"); - let exported_path = format!(r#"/tmp/{}"#, settings::DEFAULT_WALLET_NAME); - let dir = export_test_wallet(); + + let export_path = export_test_wallet(); + vcx_shutdown(false); let content = json!({ "wallet_name": settings::DEFAULT_WALLET_NAME, "wallet_key": settings::DEFAULT_WALLET_KEY, + "wallet_key_derivation": settings::DEFAULT_WALLET_KEY_DERIVATION, }).to_string(); let cb = return_types_u32::Return_U32::new().unwrap(); @@ -591,12 +647,12 @@ mod tests { let import_config = json!({ settings::CONFIG_WALLET_NAME: settings::DEFAULT_WALLET_NAME, settings::CONFIG_WALLET_KEY: settings::DEFAULT_WALLET_KEY, - settings::CONFIG_EXPORTED_WALLET_PATH: exported_path, + settings::CONFIG_EXPORTED_WALLET_PATH: export_path, settings::CONFIG_WALLET_BACKUP_KEY: settings::DEFAULT_WALLET_BACKUP_KEY, }).to_string(); assert_eq!(import(&import_config), Err(::error::wallet::WalletError::CommonError(error::WALLET_ALREADY_EXISTS.code_num))); - delete_import_wallet_path(dir); + delete_import_wallet_path(export_path); vcx_shutdown(true); } @@ -639,10 +695,10 @@ mod tests { init!("true"); let data = r#"["name","male"]"#; - let connection = ::connection::build_connection("h1").unwrap(); - let issuer_credential = ::issuer_credential::issuer_credential_create("cred_id".to_string(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(), 1).unwrap(); - let proof = ::proof::create_proof("1".to_string(),"[]".to_string(), "[]".to_string(),"Optional".to_owned()).unwrap(); + let connection = ::connection::tests::build_test_connection(); let credentialdef = ::credential_def::create_new_credentialdef("SID".to_string(),"NAME".to_string(),"4fUDR9R7fjwELRvH9JT6HH".to_string(), "id".to_string(), "tag".to_string(),"{}".to_string() ).unwrap(); + let issuer_credential = ::issuer_credential::issuer_credential_create(credentialdef,"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(), 1).unwrap(); + let proof = ::proof::create_proof("1".to_string(),"[]".to_string(), "[]".to_string(),r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); let schema = ::schema::create_new_schema("5", "VsKV7grR1BUE29mG2Fm2kX".to_string(),"name".to_string(), "0.1".to_string(), data.to_string()).unwrap(); let disclosed_proof = ::disclosed_proof::create_proof("id",::utils::constants::PROOF_REQUEST_JSON).unwrap(); let credential = ::credential::credential_create_with_offer("name", ::utils::constants::CREDENTIAL_OFFER_JSON).unwrap(); @@ -695,4 +751,25 @@ mod tests { assert_eq!(new_url, &settings::get_config_value(::settings::CONFIG_INSTITUTION_LOGO_URL).unwrap()); ::settings::set_defaults(); } + + // This test is ignored because it sets up logging, which can only be done + // once per process. + #[ignore] + #[cfg(feature = "agency")] + #[cfg(feature = "pool_tests")] + #[test] + fn test_init_with_logging_config() { + init!("ledger"); + wallet::close_wallet().unwrap(); + pool::close().unwrap(); + let content = create_config_util(Some("debug")); + let cb = return_types_u32::Return_U32::new().unwrap(); + assert_eq!(vcx_init_with_config(cb.command_handle, + CString::new(content).unwrap().into_raw(), + Some(cb.get_callback())), + error::SUCCESS.code_num); + cb.receive(Some(Duration::from_secs(10))).unwrap(); + assert_ne!(get_pool_handle().unwrap(), 0); + debug!("This statement should log"); + } } diff --git a/vcx/libvcx/src/api/wallet.rs b/vcx/libvcx/src/api/wallet.rs index c0df2d3a..9a749921 100644 --- a/vcx/libvcx/src/api/wallet.rs +++ b/vcx/libvcx/src/api/wallet.rs @@ -12,35 +12,6 @@ use std::path::Path; use utils::threadpool::spawn; use std::thread; -extern { - pub fn indy_add_wallet_record(command_handle: i32, - wallet_handle: i32, - type_: *const c_char, - id: *const c_char, - value: *const c_char, - tags_json: *const c_char, - cb: Option) -> i32; - - pub fn indy_get_wallet_record(command_handle: i32, - wallet_handle: i32, - type_: *const c_char, - id: *const c_char, - options_json: *const c_char, - cb: Option) -> i32; - - pub fn indy_update_wallet_record_value(command_handle: i32, - wallet_handle: i32, - type_: *const c_char, - id: *const c_char, - value: *const c_char, - cb: Option) -> i32; - - pub fn indy_delete_wallet_record(command_handle: i32, - wallet_handle: i32, - type_: *const c_char, - id: *const c_char, - cb: Option) -> i32; -} /// Get the total balance from all addresses contained in the configured wallet /// @@ -59,15 +30,16 @@ extern { pub extern fn vcx_wallet_get_token_info(command_handle: u32, payment_handle: u32, cb: Option) -> u32 { + info!("vcx_wallet_get_token_info >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - info!("vcx_wallet_get_token_info(command_handle: {}, payment_handle: {})", + trace!("vcx_wallet_get_token_info(command_handle: {}, payment_handle: {})", command_handle, payment_handle); spawn(move|| { match get_wallet_token_info() { Ok(x) => { - info!("vcx_wallet_get_token_info_cb(command_handle: {}, rc: {}, info: {})", + trace!("vcx_wallet_get_token_info_cb(command_handle: {}, rc: {}, info: {})", command_handle, error_string(0), x.to_string()); let msg = CStringUtils::string_to_cstring(x.to_string()); @@ -101,6 +73,7 @@ pub extern fn vcx_wallet_get_token_info(command_handle: u32, pub extern fn vcx_wallet_create_payment_address(command_handle: u32, seed: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_create_payment_address >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); let seed = if !seed.is_null() { @@ -110,13 +83,13 @@ pub extern fn vcx_wallet_create_payment_address(command_handle: u32, None }; - info!("vcx_wallet_create_payment_address(command_handle: {})", + trace!("vcx_wallet_create_payment_address(command_handle: {})", command_handle); spawn(move|| { match create_address(seed) { Ok(x) => { - info!("vcx_wallet_create_payment_address_cb(command_handle: {}, rc: {}, address: {})", + trace!("vcx_wallet_create_payment_address_cb(command_handle: {}, rc: {}, address: {})", command_handle, error_string(0), x); let msg = CStringUtils::string_to_cstring(x); @@ -173,26 +146,27 @@ pub extern fn vcx_wallet_add_record(command_handle: u32, value: *const c_char, tags_json: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_add_record >>>"); + check_useful_c_str!(type_, error::INVALID_OPTION.code_num); check_useful_c_str!(id, error::INVALID_OPTION.code_num); check_useful_c_str!(value, error::INVALID_OPTION.code_num); check_useful_c_str!(tags_json, error::INVALID_OPTION.code_num); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - - info!("vcx_wallet_add_record(command_handle: {}, type_: {}, id: {}, value: {}, tags_json: {})", + trace!("vcx_wallet_add_record(command_handle: {}, type_: {}, id: {}, value: {}, tags_json: {})", command_handle, type_, id, value, tags_json); spawn(move|| { - match wallet::add_record(&type_, &id, &value, &tags_json) { + match wallet::add_record(&type_, &id, &value, Some(&tags_json)) { Ok(x) => { - info!("vcx_wallet_add_record(command_handle: {}, rc: {})", + trace!("vcx_wallet_add_record(command_handle: {}, rc: {})", command_handle, error_string(0)); cb(command_handle, error::SUCCESS.code_num); }, Err(x) => { - info!("vcx_wallet_add_record(command_handle: {}, rc: {})", + trace!("vcx_wallet_add_record(command_handle: {}, rc: {})", command_handle, error_string(x)); cb(command_handle, x); @@ -229,24 +203,26 @@ pub extern fn vcx_wallet_update_record_value(command_handle: u32, id: *const c_char, value: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_update_record_value >>>"); + check_useful_c_str!(type_, error::INVALID_OPTION.code_num); check_useful_c_str!(id, error::INVALID_OPTION.code_num); check_useful_c_str!(value, error::INVALID_OPTION.code_num); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - info!("vcx_wallet_update_record_value(command_handle: {}, type_: {}, id: {}, value: {})", + trace!("vcx_wallet_update_record_value(command_handle: {}, type_: {}, id: {}, value: {})", command_handle, type_, id, value); spawn(move|| { match wallet::update_record_value(&type_, &id, &value) { Ok(x) => { - info!("vcx_wallet_update_record_value(command_handle: {}, rc: {})", + trace!("vcx_wallet_update_record_value(command_handle: {}, rc: {})", command_handle, error_string(0)); cb(command_handle, error::SUCCESS.code_num); }, Err(x) => { - info!("vcx_wallet_update_record_value(command_handle: {}, rc: {})", + trace!("vcx_wallet_update_record_value(command_handle: {}, rc: {})", command_handle, error_string(x)); cb(command_handle, x); @@ -283,10 +259,16 @@ pub extern fn vcx_wallet_update_record_tags(command_handle: u32, id: *const c_char, tags: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_update_record_tags >>>"); + check_useful_c_str!(type_, error::INVALID_OPTION.code_num); check_useful_c_str!(id, error::INVALID_OPTION.code_num); check_useful_c_str!(tags, error::INVALID_OPTION.code_num); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + + trace!("vcx_wallet_update_record_tags(command_handle: {}, type_: {}, id: {}, tags: {})", + command_handle, type_, id, tags); + spawn(move|| { cb(command_handle, error::SUCCESS.code_num); @@ -320,10 +302,16 @@ pub extern fn vcx_wallet_add_record_tags(command_handle: u32, id: *const c_char, tags: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_add_record_tags >>>"); + check_useful_c_str!(type_, error::INVALID_OPTION.code_num); check_useful_c_str!(id, error::INVALID_OPTION.code_num); check_useful_c_str!(tags, error::INVALID_OPTION.code_num); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + + trace!("vcx_wallet_add_record_tags(command_handle: {}, type_: {}, id: {}, tags: {})", + command_handle, type_, id, tags); + spawn(move|| { cb(command_handle, error::SUCCESS.code_num); Ok(()) @@ -356,10 +344,16 @@ pub extern fn vcx_wallet_delete_record_tags(command_handle: u32, id: *const c_char, tags: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_delete_record_tags >>>"); + check_useful_c_str!(type_, error::INVALID_OPTION.code_num); check_useful_c_str!(id, error::INVALID_OPTION.code_num); check_useful_c_str!(tags, error::INVALID_OPTION.code_num); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + + trace!("vcx_wallet_delete_record_tags(command_handle: {}, type_: {}, id: {}, tags: {})", + command_handle, type_, id, tags); + spawn(move|| { cb(command_handle, error::SUCCESS.code_num); Ok(()) @@ -391,19 +385,20 @@ pub extern fn vcx_wallet_get_record(command_handle: u32, id: *const c_char, options_json: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_get_record >>>"); check_useful_c_str!(type_, error::INVALID_OPTION.code_num); check_useful_c_str!(id, error::INVALID_OPTION.code_num); check_useful_c_str!(options_json, error::INVALID_OPTION.code_num); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - info!("vcx_wallet_get_record(command_handle: {}, type_: {}, id: {}, options: {})", + trace!("vcx_wallet_get_record(command_handle: {}, type_: {}, id: {}, options: {})", command_handle, type_, id, options_json); spawn(move|| { match wallet::get_record(&type_, &id, &options_json) { Ok(x) => { - info!("vcx_wallet_get_record(command_handle: {}, rc: {}, record_json: {})", + trace!("vcx_wallet_get_record(command_handle: {}, rc: {}, record_json: {})", command_handle, error_string(0), x); let msg = CStringUtils::string_to_cstring(x); @@ -411,7 +406,7 @@ pub extern fn vcx_wallet_get_record(command_handle: u32, cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(x) => { - info!("vcx_wallet_get_record(command_handle: {}, rc: {}, record_json: {})", + trace!("vcx_wallet_get_record(command_handle: {}, rc: {}, record_json: {})", command_handle, error_string(x), "null"); let msg = CStringUtils::string_to_cstring("".to_string()); @@ -447,23 +442,25 @@ pub extern fn vcx_wallet_delete_record(command_handle: u32, type_: *const c_char, id: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_delete_record >>>"); + check_useful_c_str!(type_, error::INVALID_OPTION.code_num); check_useful_c_str!(id, error::INVALID_OPTION.code_num); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - info!("vcx_wallet_delete_record(command_handle: {}, type_: {}, id: {})", + trace!("vcx_wallet_delete_record(command_handle: {}, type_: {}, id: {})", command_handle, type_, id); spawn(move|| { match wallet::delete_record(&type_, &id) { Ok(x) => { - info!("vcx_wallet_delete_record(command_handle: {}, rc: {})", + trace!("vcx_wallet_delete_record(command_handle: {}, rc: {})", command_handle, error_string(0)); cb(command_handle, error::SUCCESS.code_num); }, Err(x) => { - info!("vcx_wallet_delete_record(command_handle: {}, rc: {})", + trace!("vcx_wallet_delete_record(command_handle: {}, rc: {})", command_handle, error_string(x)); cb(command_handle, x); @@ -500,6 +497,7 @@ pub extern fn vcx_wallet_send_tokens(command_handle: u32, tokens: *const c_char, recipient: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_send_tokens >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(recipient, error::INVALID_OPTION.code_num); @@ -509,20 +507,20 @@ pub extern fn vcx_wallet_send_tokens(command_handle: u32, Ok(x) => x, Err(_) => return error::INVALID_OPTION.code_num, }; - info!("vcx_wallet_send_tokens(command_handle: {}, payment_handle: {}, tokens: {}, recipient: {})", + trace!("vcx_wallet_send_tokens(command_handle: {}, payment_handle: {}, tokens: {}, recipient: {})", command_handle, payment_handle, tokens, recipient); spawn(move|| { match pay_a_payee(tokens, &recipient) { Ok((payment, msg)) => { - info!("vcx_wallet_send_tokens_cb(command_handle: {}, rc: {}, receipt: {})", + trace!("vcx_wallet_send_tokens_cb(command_handle: {}, rc: {}, receipt: {})", command_handle, error_string(0), msg); let msg = CStringUtils::string_to_cstring(msg); cb(command_handle, error::SUCCESS.code_num, msg.as_ptr()); }, Err(e) => { let msg = "Failed to send tokens".to_string(); - info!("vcx_wallet_send_tokens_cb(command_handle: {}, rc: {}, reciept: {})", command_handle, e.to_error_code(), msg); + trace!("vcx_wallet_send_tokens_cb(command_handle: {}, rc: {}, reciept: {})", command_handle, e.to_error_code(), msg); let msg = CStringUtils::string_to_cstring("".to_string()); cb(command_handle, e.to_error_code(), msg.as_ptr()); }, @@ -569,7 +567,10 @@ pub extern fn vcx_wallet_open_search(command_handle: i32, options_json: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_open_search >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + use utils::constants::DEFAULT_SEARCH_HANDLE; spawn(move|| { cb(command_handle, error::SUCCESS.code_num, DEFAULT_SEARCH_HANDLE as i32); @@ -605,7 +606,13 @@ pub extern fn vcx_wallet_search_next_records(command_handle: i32, count: usize, cb: Option) -> u32 { + info!("vcx_wallet_search_next_records >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + + trace!("vcx_wallet_search_next_records(command_handle: {}, wallet_search_handle: {})", + command_handle, wallet_search_handle); + spawn(move|| { use utils::constants::DEFAULT_SEARCH_RECORD; let msg = CStringUtils::string_to_cstring(DEFAULT_SEARCH_RECORD.to_string()); @@ -633,13 +640,14 @@ pub extern fn vcx_wallet_search_next_records(command_handle: i32, pub extern fn vcx_wallet_close_search(command_handle: u32, search_handle: u32, cb: Option) -> u32 { + info!("vcx_wallet_close_search >>>"); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); - info!("vcx_wallet_close_search(command_handle: {}, search_handle: {})", + trace!("vcx_wallet_close_search(command_handle: {}, search_handle: {})", command_handle, search_handle); spawn(move|| { - info!("vcx_wallet_close_search(command_handle: {}, rc: {})", + trace!("vcx_wallet_close_search(command_handle: {}, rc: {})", command_handle, error_string(0)); cb(command_handle, error::SUCCESS.code_num); Ok(()) @@ -668,16 +676,23 @@ pub extern fn vcx_wallet_export(command_handle: u32, backup_key: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_export >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(path, error::INVALID_OPTION.code_num); check_useful_c_str!(backup_key, error::INVALID_OPTION.code_num); + + trace!("vcx_wallet_export(command_handle: {}, path: {}, backup_key: ****)", + command_handle, path); + + spawn(move|| { let path = Path::new(&path); - info!("vcx_wallet_export(command_handle: {}, path: {:?}, backup_key: ****)", command_handle, path); + trace!("vcx_wallet_export(command_handle: {}, path: {:?}, backup_key: ****)", command_handle, path); match export(get_wallet_handle(), &path, &backup_key) { Ok(_) => { let return_code = error::SUCCESS.code_num; - info!("vcx_wallet_export(command_handle: {}, rc: {})", command_handle, return_code); + trace!("vcx_wallet_export(command_handle: {}, rc: {})", command_handle, return_code); cb(command_handle, return_code); } Err(e) => { @@ -703,7 +718,7 @@ pub extern fn vcx_wallet_export(command_handle: u32, /// config: "{"wallet_name":"","wallet_key":"","exported_wallet_path":"","backup_key":"","key_derivation":""}" /// exported_wallet_path: Path of the file that contains exported wallet content /// backup_key: Key used when creating the backup of the wallet (For encryption/decrption) -/// Optional: method of key derivation used by libindy +/// Optional: method of key derivation used by libindy. By default, libvcx uses ARGON2I_INT /// cb: Callback that provides the success/failure of the api call. /// #Returns /// Error code - success indicates that the api call was successfully created and execution @@ -713,15 +728,20 @@ pub extern fn vcx_wallet_import(command_handle: u32, config: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_import >>>"); + check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); check_useful_c_str!(config, error::INVALID_OPTION.code_num); - thread::spawn(move|| { - info!("vcx_wallet_import(command_handle: {}, config: ****)", command_handle); + trace!("vcx_wallet_import(command_handle: {}, config: ****)", + command_handle); + + thread::spawn(move|| { + trace!("vcx_wallet_import(command_handle: {}, config: ****)", command_handle); match import(&config) { Ok(_) => { let return_code = error::SUCCESS.code_num; - info!("vcx_wallet_import(command_handle: {}, rc: {})", command_handle, return_code); + trace!("vcx_wallet_import(command_handle: {}, rc: {})", command_handle, return_code); cb(command_handle, return_code); } Err(e) => { @@ -752,8 +772,14 @@ pub extern fn vcx_wallet_import(command_handle: u32, pub extern fn vcx_wallet_validate_payment_address(command_handle: i32, payment_address: *const c_char, cb: Option) -> u32 { + info!("vcx_wallet_validate_payment_address >>>"); + check_useful_c_str!(payment_address, error::INVALID_OPTION.code_num); check_useful_c_callback!(cb, error::INVALID_OPTION.code_num); + + trace!("vcx_wallet_validate_payment_address(command_handle: {}, payment_address: {})", + command_handle, payment_address); + spawn(move|| { cb(command_handle, error::SUCCESS.code_num); Ok(()) @@ -767,10 +793,13 @@ pub mod tests { extern crate serde_json; use super::*; + use api::return_types_u32; use std::ptr; use std::ffi::CString; use std::time::Duration; - use utils::libindy::{ return_types_u32, wallet::delete_wallet}; + use utils::libindy::wallet::delete_wallet; + #[cfg(feature = "pool_tests")] + use utils::libindy::payments::build_test_address; #[test] fn test_get_token_info() { @@ -811,7 +840,7 @@ pub mod tests { #[test] fn test_send_payment() { init!("ledger"); - let recipient = CStringUtils::string_to_cstring(::utils::constants::PAYMENT_ADDRESS.to_string()); + let recipient = CStringUtils::string_to_cstring(build_test_address("2ZrAm5Jc3sP4NAXMQbaWzDxEa12xxJW3VgWjbbPtMPQCoznJyS")); println!("sending payment to {:?}", recipient); let balance = ::utils::libindy::payments::get_wallet_token_info().unwrap().get_balance(); let tokens = 5; @@ -1031,7 +1060,6 @@ pub mod tests { use std::env; use std::fs; use std::path::Path; - use utils::libindy::return_types_u32; use std::time::Duration; use settings; @@ -1055,9 +1083,9 @@ pub mod tests { dir_c_str.as_ptr(), backup_key_c_str.as_ptr(), Some(cb.get_callback())), error::SUCCESS.code_num); - cb.receive(Some(Duration::from_secs(5))).unwrap(); + cb.receive(Some(Duration::from_secs(50))).unwrap(); - delete_wallet(&wallet_name).unwrap(); + delete_wallet(&wallet_name, None).unwrap(); let cb = return_types_u32::Return_U32::new().unwrap(); let exported_path = dir.to_str().unwrap(); @@ -1071,11 +1099,11 @@ pub mod tests { assert_eq!(vcx_wallet_import(cb.command_handle, import_config_c.as_ptr(), Some(cb.get_callback())), error::SUCCESS.code_num); - cb.receive(Some(Duration::from_secs(5))).unwrap(); + cb.receive(Some(Duration::from_secs(50))).unwrap(); let handle = setup_wallet_env(&wallet_name).unwrap(); - delete_wallet(&wallet_name).unwrap(); + delete_wallet(&wallet_name, None).unwrap(); fs::remove_file(Path::new(&dir)).unwrap(); assert!(!Path::new(&dir).exists()); } diff --git a/vcx/libvcx/src/connection.rs b/vcx/libvcx/src/connection.rs index 35b4d4ac..f4be89a6 100644 --- a/vcx/libvcx/src/connection.rs +++ b/vcx/libvcx/src/connection.rs @@ -4,7 +4,6 @@ extern crate rmp_serde; extern crate serde; extern crate libc; -use utils::libindy::wallet; use utils::error; use utils::libindy::signus::create_and_store_my_did; use utils::libindy::crypto; @@ -17,7 +16,7 @@ use messages::invite::{InviteDetail, SenderDetail}; use messages::get_message::Message; use serde::Deserialize; use self::rmp_serde::{encode, Deserializer}; -use messages::MessageResponseCode::{ MessageAccepted }; +use messages::MessageResponseCode::MessageAccepted; use serde_json::Value; use utils::json::KeyMatch; use error::connection::ConnectionError; @@ -29,15 +28,16 @@ lazy_static! { static ref CONNECTION_MAP: ObjectCache = Default::default(); } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] struct ConnectionOptions { #[serde(default)] connection_type: Option, #[serde(default)] phone: Option, + use_public_did: Option, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] struct Connection { source_id: String, pw_did: String, @@ -52,47 +52,29 @@ struct Connection { agent_vk: String, their_pw_did: String, their_pw_verkey: String, // used by proofs/credentials when sending to edge device + public_did: Option, + their_public_did: Option, } + + impl Connection { - fn _connect_send_invite(&mut self, options: Option) -> Result { + fn _connect_send_invite(&mut self, options: &ConnectionOptions) -> Result { debug!("sending invite for connection {}", self.source_id); - let options_obj: ConnectionOptions = match options { - Some(opt) => { - match opt.trim().is_empty() { - true => ConnectionOptions { - connection_type: None, - phone: None - }, - false => match serde_json::from_str(opt.trim()) { - Ok(val) => val, - // TODO: Refactor Error -// TODO: Implement Correct Error -// Err(_) => return Err(error::INVALID_OPTION.code_num), - Err(_) => return Err(ConnectionError::GeneralConnectionError()), - } - } - }, - None => { - ConnectionOptions { - connection_type: None, - phone: None - } - } - }; match messages::send_invite() .to(&self.pw_did) .to_vk(&self.pw_verkey) - .phone_number(&options_obj.phone) + .phone_number(&options.phone) .agent_did(&self.agent_did) .agent_vk(&self.agent_vk) + .public_did(self.public_did.clone()) .send_secure() { Err(ec) => { // TODO: Refactor Error // TODO: Implement Correct Error - return Err(ConnectionError::CommonError(ec)) - }, + return Err(ConnectionError::CommonError(ec)); + } Ok(response) => { self.state = VcxStateType::VcxStateOfferSent; self.invite_detail = match parse_invite_detail(&response[0]) { @@ -101,8 +83,8 @@ impl Connection { error!("error when sending invite for connection {}: {}", self.source_id, x); // TODO: Refactor Error // TODO: Implement Correct Error - return Err(ConnectionError::GeneralConnectionError()) - }, + return Err(ConnectionError::GeneralConnectionError()); + } }; self.invite_url = Some(response[1].clone()); Ok(error::SUCCESS.code_num) @@ -110,6 +92,8 @@ impl Connection { } } pub fn delete_connection(&mut self) -> Result { + trace!("Connection::delete_connection >>>"); + match messages::delete_connection() .to(&self.pw_did) .to_vk(&self.pw_verkey) @@ -117,17 +101,16 @@ impl Connection { .agent_vk(&self.agent_vk) .send_secure() { Err(ec) => { - return Err(ConnectionError::CannotDeleteConnection()) - }, + return Err(ConnectionError::CannotDeleteConnection()); + } Ok(response) => { self.state = VcxStateType::VcxStateNone; Ok(error::SUCCESS.code_num) } } - } - fn _connect_accept_invite(&mut self, options: Option) -> Result { + fn _connect_accept_invite(&mut self) -> Result { debug!("accepting invite for connection {}", self.source_id); if let Some(ref details) = self.invite_detail { @@ -145,14 +128,13 @@ impl Connection { // TODO: Refactor Error // TODO: Implement Correct Error Err(ConnectionError::GeneralConnectionError()) - }, + } Ok(response) => { self.state = VcxStateType::VcxStateAccepted; Ok(error::SUCCESS.code_num) } } - } - else{ + } else { warn!("{} can not connect without invite details", self.source_id); // TODO: Refactor Error // TODO: Implement Correct Error @@ -160,14 +142,14 @@ impl Connection { } } - - fn connect(&mut self, options: Option) -> Result { + fn connect(&mut self, options: &ConnectionOptions) -> Result { + trace!("Connection::connect >>> options: {:?}", options); match self.state { VcxStateType::VcxStateInitialized | VcxStateType::VcxStateOfferSent => self._connect_send_invite(options), - VcxStateType::VcxStateRequestReceived => self._connect_accept_invite(options), + VcxStateType::VcxStateRequestReceived => self._connect_accept_invite(), _ => { - warn!("connection {} in state {} not ready to connect",self.source_id, self.state as u32); + warn!("connection {} in state {} not ready to connect", self.source_id, self.state as u32); // TODO: Refactor Error // TODO: Implement Correct Error Err(ConnectionError::GeneralConnectionError()) @@ -175,8 +157,14 @@ impl Connection { } } - fn get_state(&self) -> u32 { self.state as u32 } - fn set_state(&mut self, state: VcxStateType) { self.state = state; } + fn get_state(&self) -> u32 { + trace!("Connection::get_state >>>"); + self.state as u32 + } + fn set_state(&mut self, state: VcxStateType) { + trace!("Connection::set_state >>> state: {:?}", state); + self.state = state; + } fn get_pw_did(&self) -> &String { &self.pw_did } fn set_pw_did(&mut self, did: &str) { self.pw_did = did.to_string(); } @@ -184,6 +172,9 @@ impl Connection { fn get_their_pw_did(&self) -> &String { &self.their_pw_did } fn set_their_pw_did(&mut self, did: &str) { self.their_pw_did = did.to_string(); } + fn set_their_public_did(&mut self, did: &str) { self.their_public_did = Some(did.to_string()); } + fn get_their_public_did(&self) -> Option { self.their_public_did.clone() } + fn get_agent_did(&self) -> &String { &self.agent_did } fn set_agent_did(&mut self, did: &str) { self.agent_did = did.to_string(); } @@ -216,7 +207,7 @@ impl Connection { } fn from_str(s: &str) -> Result { - let s:Value = serde_json::from_str(&s) + let s: Value = serde_json::from_str(&s) .or(Err(ConnectionError::InvalidJson()))?; let connection: Connection = serde_json::from_value(s["data"].clone()) .or(Err(ConnectionError::InvalidJson()))?; @@ -229,6 +220,39 @@ impl Connection { "data": json!(self), }).to_string() } + + fn create_agent_pairwise(&mut self) -> Result { + debug!("creating pairwise keys on agent for connection {}", self.source_id); + + let result = messages::create_keys() + .for_did(&self.pw_did) + .for_verkey(&self.pw_verkey) + .send_secure() + .map_err(|e|ConnectionError::CommonError(e))?; + debug!("create key for connection: {} with did/vk: {:?}", self.source_id, result); + self.set_agent_did(&result[0]); + self.set_agent_verkey(&result[1]); + Ok(error::SUCCESS.code_num) + } + + fn update_agent_profile(&mut self, options: &ConnectionOptions) -> Result { + debug!("updating agent config for connection {}", self.source_id); + if let Some(true) = options.use_public_did { + self.public_did = Some(settings::get_config_value(settings::CONFIG_INSTITUTION_DID).map_err(|e|ConnectionError::CommonError(e))?); + }; + + if let Ok(name) = settings::get_config_value(settings::CONFIG_INSTITUTION_NAME) { + match messages::update_data() + .to(&self.pw_did) + .name(&name) + .logo_url(&settings::get_config_value(settings::CONFIG_INSTITUTION_LOGO_URL).map_err(|e| ConnectionError::CommonError(e))?) + .use_public_did(&self.public_did) + .send_secure() { + Ok(_) => Ok(error::SUCCESS.code_num), + Err(ec) => Err(ConnectionError::CommonError(ec)), + } + } else { Ok(error::SUCCESS.code_num) } + } } pub fn is_valid_handle(handle: u32) -> bool { @@ -267,13 +291,26 @@ pub fn get_their_pw_did(handle: u32) -> Result { }).or(Err(ConnectionError::InvalidHandle())) } -pub fn set_their_pw_did(handle: u32, did: &str) -> Result<(), ConnectionError>{ +pub fn set_their_pw_did(handle: u32, did: &str) -> Result<(), ConnectionError> { CONNECTION_MAP.get_mut(handle, |cxn| { cxn.set_their_pw_did(did); Ok(()) }).or(Err(ConnectionError::InvalidHandle())) } +pub fn set_their_public_did(handle: u32, did: &str) -> Result<(), ConnectionError> { + CONNECTION_MAP.get_mut(handle, |cxn| { + cxn.set_their_public_did(did); + Ok(()) + }).or(Err(ConnectionError::InvalidHandle())) +} + +pub fn get_their_public_did(handle: u32) -> Result, ConnectionError> { + CONNECTION_MAP.get(handle, |cxn| { + Ok(cxn.get_their_public_did().clone()) + }).or(Err(ConnectionError::InvalidHandle())) +} + pub fn get_their_pw_verkey(handle: u32) -> Result { CONNECTION_MAP.get(handle, |cxn| { Ok(cxn.get_their_pw_verkey().clone()) @@ -281,7 +318,10 @@ pub fn get_their_pw_verkey(handle: u32) -> Result { } pub fn set_their_pw_verkey(handle: u32, did: &str) -> Result<(), ConnectionError> { - CONNECTION_MAP.get_mut(handle, |cxn| { cxn.set_their_pw_verkey(did); Ok(()) }).map_err(|e| { + CONNECTION_MAP.get_mut(handle, |cxn| { + cxn.set_their_pw_verkey(did); + Ok(()) + }).map_err(|e| { ConnectionError::InvalidHandle() }) } @@ -319,7 +359,7 @@ pub fn get_agent_verkey(handle: u32) -> Result { }).or(Err(ConnectionError::InvalidHandle())) } -pub fn set_agent_verkey(handle: u32, verkey: &str) -> Result<(), ConnectionError>{ +pub fn set_agent_verkey(handle: u32, verkey: &str) -> Result<(), ConnectionError> { CONNECTION_MAP.get_mut(handle, |cxn| { cxn.set_agent_verkey(verkey); Ok(()) @@ -341,6 +381,8 @@ pub fn set_pw_verkey(handle: u32, verkey: &str) -> Result<(), ConnectionError> { pub fn get_state(handle: u32) -> u32 { match CONNECTION_MAP.get(handle, |cxn| { + debug!("get state for connection {}", cxn.get_source_id()); + Ok(cxn.get_state().clone()) }) { Ok(s) => s, @@ -361,50 +403,17 @@ pub fn get_source_id(handle: u32) -> Result { }).or(Err(ConnectionError::InvalidHandle())) } -pub fn create_agent_pairwise(handle: u32) -> Result { - debug!("creating pairwise keys on agent for connection {}", get_source_id(handle).unwrap_or_default()); - let pw_did = get_pw_did(handle)?; - let pw_verkey = get_pw_verkey(handle)?; - - let result = messages::create_keys() - .for_did(&pw_did) - .for_verkey(&pw_verkey) - .send_secure() - .or(Err(ConnectionError::InvalidWalletSetup()))?; // Throw a context specific error - debug!("create key for connection: {} with did/vk: {:?}", get_source_id(handle).unwrap_or_default(), result); - set_agent_did(handle,&result[0]).err(); - set_agent_verkey(handle,&result[1]).err(); - Ok(error::SUCCESS.code_num) -} - -pub fn update_agent_profile(handle: u32) -> Result { - debug!("updating agent config for connection {}", get_source_id(handle).unwrap_or_default()); - let pw_did = get_pw_did(handle)?; - if let Ok(name) = settings::get_config_value(settings::CONFIG_INSTITUTION_NAME) { - match messages::update_data() - .to(&pw_did) - .name(&name) - .logo_url(&settings::get_config_value(settings::CONFIG_INSTITUTION_LOGO_URL).map_err(|e| ConnectionError::CommonError(e))?) - .send_secure() { - Ok(_) => Ok(error::SUCCESS.code_num), - Err(ec) => Err(ConnectionError::CommonError(ec)), - } - } else { Ok(error::SUCCESS.code_num) } -} +pub fn create_connection(source_id: &str) -> Result { + trace!("create_connection >>> source_id: {}", source_id); + let (pw_did, pw_verkey) = create_and_store_my_did(None).map_err(|ec|ConnectionError::CommonError(ec))?; -// -// NOTE: build_connection and create_connection are broken up to make it easier to create connections in tests -// you can call create_connection without test_mode and you don't have to build a wallet or -// mock the agency during the connection phase -// -fn create_connection(source_id: &str) -> Result { - // This is a new connection + debug!("did: {} verkey: {}, source id: {}", pw_did, pw_verkey, source_id); let c = Connection { source_id: source_id.to_string(), - pw_did: String::new(), - pw_verkey: String::new(), - state: VcxStateType::VcxStateNone, + pw_did, + pw_verkey, + state: VcxStateType::VcxStateInitialized, uuid: String::new(), endpoint: String::new(), invite_detail: None, @@ -413,69 +422,21 @@ fn create_connection(source_id: &str) -> Result { agent_vk: String::new(), their_pw_did: String::new(), their_pw_verkey: String::new(), + public_did: None, + their_public_did: None, }; - let new_handle = CONNECTION_MAP.add(c).map_err(|key| ConnectionError::CreateError(key))?; - debug!("creating connection: {} {}", new_handle, source_id); - Ok(new_handle) - -} - -fn init_connection(handle: u32) -> Result { - let (my_did, my_verkey) = match create_and_store_my_did(None) { - Ok(y) => y, - Err(x) => { - error!("{} could not create DID/VK: {}", get_source_id(handle).unwrap_or_default(), x); - return Err(ConnectionError::CommonError(x)) - }, - }; - - debug!("handle: {} did: {} verkey: {}, source id: {}", handle, my_did, my_verkey, get_source_id(handle)?); - set_pw_did(handle, &my_did).err(); - set_pw_verkey(handle, &my_verkey).err(); - - match create_agent_pairwise(handle) { - Err(err) => { - error!("Error while Creating Agent Pairwise: {}", err); - release(handle)?; - return Err(err) - }, - Ok(_) => debug!("created pairwise key on agent"), - }; - - match update_agent_profile(handle) { - Err(x) => { - error!("could not update profile on agent: {}", x); - release(handle)?; - return Err(x) - }, - Ok(_) => debug!("updated profile on agent"), - }; - - set_state(handle, VcxStateType::VcxStateInitialized).err(); - Ok(error::SUCCESS.code_num) -} - -pub fn build_connection(source_id: &str) -> Result { - let new_handle = create_connection(source_id)?; - - match init_connection(new_handle) { - Ok(_) => Ok(new_handle), - Err(x) => { - release(new_handle)?; - return Err(x) - } - } + Ok(new_handle) } -pub fn build_connection_with_invite(source_id: &str, details: &str) -> Result { - debug!("using invite to create connection {}", source_id); +pub fn create_connection_with_invite(source_id: &str, details: &str) -> Result { + debug!("create connection {} with invite {}", source_id, details); - let details:Value = serde_json::from_str(&details) + let details: Value = serde_json::from_str(&details) .or(Err(ConnectionError::CommonError(error::INVALID_JSON.code_num)))?; - let invite_details:InviteDetail = match serde_json::from_value(details.clone()) { + let invite_details: InviteDetail = match serde_json::from_value(details.clone()) { Ok(x) => x, Err(x) => { // Try converting to abbreviated @@ -486,23 +447,17 @@ pub fn build_connection_with_invite(source_id: &str, details: &str) -> Result return Err(ConnectionError::CommonError(error::INVALID_JSON.code_num)), } - }, + } }; let new_handle = create_connection(source_id)?; - match init_connection(new_handle){ - Ok(_) => (), - Err(x) => { - release(new_handle)?; - return Err(x); - } - }; - + set_invite_details(new_handle, &invite_details).err(); set_their_pw_did(new_handle, invite_details.sender_detail.did.as_str()).err(); set_their_pw_verkey(new_handle, invite_details.sender_detail.verkey.as_str()).err(); - - set_invite_details(new_handle, invite_details).err(); + if let Some(did) = invite_details.sender_detail.public_did { + set_their_public_did(new_handle, &did).err(); + } set_state(new_handle, VcxStateType::VcxStateRequestReceived).err(); @@ -514,11 +469,11 @@ pub fn parse_acceptance_details(handle: u32, message: &Message) -> Result Result x, Err(x) => { error!("Could not parse outer msg: {}", x); - return Err(ConnectionError::CommonError(error::INVALID_MSGPACK.code_num)) - }, + return Err(ConnectionError::CommonError(error::INVALID_MSGPACK.code_num)); + } }; let payload = messages::to_u8(&response.msg); // TODO: Refactor Error - let details = messages::invite::parse_invitation_acceptance_details(payload).map_err(|e| {ConnectionError::CommonError(e)})?; + let details = messages::invite::parse_invitation_acceptance_details(payload).map_err(|e| { ConnectionError::CommonError(e) })?; Ok(details) } pub fn update_state(handle: u32) -> Result { debug!("updating state for connection {}", get_source_id(handle).unwrap_or_default()); + let state = get_state(handle); + + if state == VcxStateType::VcxStateInitialized as u32 || state == VcxStateType::VcxStateAccepted as u32 { + return Ok(error::SUCCESS.code_num) + } + // TODO: Refactor Error let pw_did = get_pw_did(handle)?; let pw_vk = get_pw_verkey(handle)?; @@ -553,47 +514,75 @@ pub fn update_state(handle: u32) -> Result { .agent_vk(&agent_vk) .send_secure() { Err(x) => { - error!("could not update state for handle {}: {}", handle, x); + error!("could not update state for handle {}: {}", handle, x); // TODO: Refactor Error Err(ConnectionError::CommonError(error::POST_MSG_FAILURE.code_num)) } Ok(response) => { debug!("connection {} update state response: {:?}", get_source_id(handle).unwrap_or_default(), response); - if get_state(handle) == VcxStateType::VcxStateOfferSent as u32 || get_state(handle) == VcxStateType::VcxStateInitialized as u32{ - for i in response { - if i.status_code == MessageAccepted.as_string() && i.msg_type == "connReqAnswer" { - // TODO: Refactor Error - let details = parse_acceptance_details(handle, &i)?; - set_their_pw_did(handle, &details.did).ok(); - set_their_pw_verkey(handle, &details.verkey).ok(); - set_state(handle, VcxStateType::VcxStateAccepted).ok(); - } - } + if get_state(handle) == VcxStateType::VcxStateOfferSent as u32 || get_state(handle) == VcxStateType::VcxStateInitialized as u32 { + for i in response { + if i.status_code == MessageAccepted.as_string() && i.msg_type == "connReqAnswer" { + // TODO: Refactor Error + let details = parse_acceptance_details(handle, &i)?; + set_their_pw_did(handle, &details.did).ok(); + set_their_pw_verkey(handle, &details.verkey).ok(); + set_state(handle, VcxStateType::VcxStateAccepted).ok(); + } + } }; Ok(error::SUCCESS.code_num) //TODO: add expiration handling - }, + } } } -pub fn delete_connection(handle:u32) -> Result { + +pub fn delete_connection(handle: u32) -> Result { CONNECTION_MAP.get_mut(handle, |t| { + debug!("delete connection: {}", t.get_source_id()); match t.delete_connection() { Ok(x) => Ok(x), Err(e) => { - return Err(e.to_error_code()) - }, + return Err(e.to_error_code()); + } } }).or(Err(ConnectionError::CannotDeleteConnection())).and(release(handle)) } pub fn connect(handle: u32, options: Option) -> Result { + let options_obj: ConnectionOptions = match options { + Some(opt) => { + match opt.trim().is_empty() { + true => ConnectionOptions { + connection_type: None, + phone: None, + use_public_did: None + }, + false => match serde_json::from_str(opt.trim()) { + Ok(val) => val, + Err(_) => return Err(ConnectionError::CommonError(error::INVALID_OPTION.code_num)), + } + } + }, + None => { + ConnectionOptions { + connection_type: None, + phone: None, + use_public_did: None + } + } + }; + CONNECTION_MAP.get_mut(handle, |t| { - t.connect(options.clone()).map_err(|ec| ec.to_error_code()) + debug!("establish connection {}", t.get_source_id()); + t.create_agent_pairwise().map_err(|ec|ec.to_error_code())?; + t.update_agent_profile(&options_obj).map_err(|ec|ec.to_error_code())?; + t.connect(&options_obj).map_err(|ec| ec.to_error_code()) }).map_err(|ec| ConnectionError::CommonError(ec)) } -pub fn to_string(handle: u32) -> Result { +pub fn to_string(handle: u32) -> Result { CONNECTION_MAP.get(handle, |t| { // TODO: Make this an error.to_error_code and back again? Ok(Connection::to_string(&t)) @@ -613,7 +602,7 @@ pub fn from_string(connection_data: &str) -> Result { Ok(new_handle) } -pub fn release(handle: u32) -> Result< u32, ConnectionError> { +pub fn release(handle: u32) -> Result { match CONNECTION_MAP.release(handle) { Ok(_) => Ok(ConnectionError::CommonError(error::SUCCESS.code_num).to_error_code()), Err(_) => Err(ConnectionError::InvalidHandle()) @@ -628,39 +617,39 @@ pub fn release_all() { }; } -pub fn get_invite_details(handle: u32, abbreviated:bool) -> Result { +pub fn get_invite_details(handle: u32, abbreviated: bool) -> Result { + debug!("get invite details for connection {}", get_source_id(handle).unwrap_or_default()); + CONNECTION_MAP.get(handle, |t| { match abbreviated { false => { Ok(serde_json::to_string(&t.invite_detail) .or(Err(ConnectionError::InviteDetailError()))) - }, + } true => { let details = serde_json::to_value(&t.invite_detail).or(Err(ConnectionError::InviteDetailError().to_error_code()))?; let abbr = abbrv_event_detail(details)?; Ok(serde_json::to_string(&abbr).or(Err(ConnectionError::InviteDetailError()))) - }, + } } }).or(Err(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num)))? - } -pub fn set_invite_details(handle: u32, invite_detail: InviteDetail) -> Result<(), ConnectionError>{ +pub fn set_invite_details(handle: u32, invite_detail: &InviteDetail) -> Result<(), ConnectionError>{ CONNECTION_MAP.get_mut(handle, |cxn| { cxn.set_invite_detail(invite_detail.clone()); -// TODO: Verify that this is ok to do...seems not rusty. + // TODO: Verify that this is ok to do...seems not rusty. Ok(()) }).or(Err(ConnectionError::InvalidHandle())) } pub fn parse_invite_detail(response: &str) -> Result { - let details: InviteDetail = match serde_json::from_str(response) { Ok(x) => x, Err(x) => { debug!("Connect called without a valid response from server: {}", x); return Err(ConnectionError::InviteDetailError()); - }, + } }; Ok(details) @@ -672,7 +661,7 @@ pub fn parse_invite_detail(response: &str) -> Result Result, ConnectionError> { let my_payload = messages::Payload { - msg_info: messages::MsgInfo { name: msg_type.to_string(), ver: "1.0".to_string(), fmt: "json".to_string(), }, + msg_info: messages::MsgInfo { name: msg_type.to_string(), ver: "1.0".to_string(), fmt: "json".to_string() }, msg: data.to_string(), }; let bytes = match encode::to_vec_named(&my_payload) { @@ -680,20 +669,19 @@ pub fn generate_encrypted_payload(my_vk: &str, their_vk: &str, data: &str, msg_t Err(x) => { error!("could not encode create_keys msg: {}", x); return Err(ConnectionError::InvalidMessagePack()); - }, + } }; trace!("Sending payload: {:?}", bytes); - crypto::prep_msg(wallet::get_wallet_handle(),&my_vk, &their_vk, &bytes).map_err(|ec| ConnectionError::CommonError(ec)) + crypto::prep_msg(&my_vk, &their_vk, &bytes).map_err(|ec| ConnectionError::CommonError(ec)) } - //********** // Code to convert InviteDetails to Abbreviated String //********** -impl KeyMatch for (String,Option){ +impl KeyMatch for (String, Option) { fn matches(&self, key: &String, context: &Vec) -> bool { if key.eq(&self.0) { match context.last() { @@ -701,7 +689,7 @@ impl KeyMatch for (String,Option){ if let Some(ref expected_parent) = self.1 { return parent.eq(expected_parent); } - }, + } None => { return self.1.is_none(); } @@ -712,7 +700,7 @@ impl KeyMatch for (String,Option){ } -lazy_static!{ +lazy_static! { static ref ABBREVIATIONS: Vec<(String, String)> = { vec![ ("statusCode".to_string(), "sc".to_string()), @@ -734,7 +722,7 @@ lazy_static!{ }; } -lazy_static!{ +lazy_static! { static ref UNABBREVIATIONS: Vec<((String, Option), String)> = { vec![ (("sc".to_string(), None), "statusCode".to_string()), @@ -767,7 +755,6 @@ fn unabbrv_event_detail(val: Value) -> Result { } - #[cfg(test)] pub mod tests { use utils::constants::*; @@ -779,15 +766,25 @@ pub mod tests { use super::*; use rand::Rng; + pub fn build_test_connection() -> u32 { + let handle = create_connection("alice").unwrap(); + connect(handle, Some("{}".to_string())).unwrap(); + handle + } + pub fn create_connected_connections() -> (u32, u32) { - let alice = build_connection("alice").unwrap(); - connect(alice, Some("{}".to_string())).unwrap(); + let alice = create_connection("alice").unwrap(); + let my_public_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + let options = json!({"use_public_did": true}).to_string(); + connect(alice, Some(options)).unwrap(); let details = get_invite_details(alice, false).unwrap(); //BE CONSUMER AND ACCEPT INVITE FROM INSTITUTION ::utils::devsetup::tests::set_consumer(); - let faber = build_connection_with_invite("faber", &details).unwrap(); + let faber = create_connection_with_invite("faber", &details).unwrap(); assert_eq!(VcxStateType::VcxStateRequestReceived as u32, get_state(faber)); connect(faber, Some("{}".to_string())).unwrap(); + let public_did = get_their_public_did(faber).unwrap().unwrap(); + assert_eq!(my_public_did, public_did); //BE INSTITUTION AND CHECK THAT INVITE WAS ACCEPTED ::utils::devsetup::tests::set_institution(); thread::sleep(Duration::from_millis(2000)); @@ -797,17 +794,27 @@ pub mod tests { } #[test] - fn test_build_connection_failures(){ + fn test_build_connection_failures() { init!("true"); settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE,"false"); - assert_eq!(build_connection("This Should Fail").err(), + assert_eq!(create_connection("This Should Fail").err(), Some(ConnectionError::CommonError(error::INVALID_WALLET_HANDLE.code_num))); - assert!(build_connection_with_invite("This Should Fail", "BadDetailsFoobar").is_err()); + assert!(create_connection_with_invite("This Should Fail", "BadDetailsFoobar").is_err()); + } + + #[test] + fn test_create_connection_agency_failure() { + init!("indy"); + ::utils::httpclient::set_next_u8_response(vec![]); + let handle = create_connection("invalid").unwrap(); + let rc = connect(handle, None); + assert_eq!(rc.unwrap_err(),ConnectionError::CommonError(error::POST_MSG_FAILURE.code_num)); } + #[test] fn test_create_connection() { init!("true"); - let handle = build_connection("test_create_connection").unwrap(); + let handle = create_connection("test_create_connection").unwrap(); assert!(handle > 0); assert!(!get_pw_did(handle).unwrap().is_empty()); assert!(!get_pw_verkey(handle).unwrap().is_empty()); @@ -821,10 +828,10 @@ pub mod tests { #[test] fn test_create_drop_create() { init!("true"); - let handle = build_connection("test_create_drop_create").unwrap(); + let handle = create_connection("test_create_drop_create").unwrap(); let did1 = get_pw_did(handle).unwrap(); assert!(release(handle).is_ok()); - let handle2 = build_connection("test_create_drop_create").unwrap(); + let handle2 = create_connection("test_create_drop_create").unwrap(); assert_ne!(handle,handle2); let did2 = get_pw_did(handle2).unwrap(); assert_eq!(did1, did2); @@ -847,15 +854,15 @@ pub mod tests { #[test] fn test_get_string_fails() { match to_string(0) { - Ok(_) => assert_eq!(1,0), //fail if we get here - Err(_) => assert_eq!(0,0), + Ok(_) => assert_eq!(1, 0), //fail if we get here + Err(_) => assert_eq!(0, 0), }; } #[test] fn test_parse_invite_details() { let invite = parse_invite_detail(INVITE_DETAIL_STRING).unwrap(); - assert_eq!(invite.sender_detail.verkey,"ESE6MnqAyjRigduPG454vfLvKhMbmaZjy9vqxCnSKQnp"); + assert_eq!(invite.sender_detail.verkey, "ESE6MnqAyjRigduPG454vfLvKhMbmaZjy9vqxCnSKQnp"); assert_eq!(parse_invite_detail(BAD_INVITE_DETAIL_STRING).err(), Some(ConnectionError::InviteDetailError())); } @@ -876,6 +883,8 @@ pub mod tests { agent_vk: "EkVTa7SCJ5SntpYyX7CSb2pcBhiVGT9kWSagA8a9T69A".to_string(), their_pw_did: String::new(), their_pw_verkey: String::new(), + public_did: None, + their_public_did: None, }; let handle = CONNECTION_MAP.add(c).unwrap(); @@ -892,34 +901,34 @@ pub mod tests { #[test] fn test_serialize_deserialize() { init!("true"); - let handle = build_connection("test_serialize_deserialize").unwrap(); + let handle = create_connection("test_serialize_deserialize").unwrap(); assert!(handle > 0); let first_string = to_string(handle).unwrap(); assert!(release(handle).is_ok()); let handle = from_string(&first_string).unwrap(); let second_string = to_string(handle).unwrap(); assert!(release(handle).is_ok()); - assert_eq!(first_string,second_string); + assert_eq!(first_string, second_string); } #[test] fn test_deserialize_existing() { init!("true"); - let handle = build_connection("test_serialize_deserialize").unwrap(); + let handle = create_connection("test_serialize_deserialize").unwrap(); assert!(handle > 0); let first_string = to_string(handle).unwrap(); let handle = from_string(&first_string).unwrap(); let second_string = to_string(handle).unwrap(); - assert_eq!(first_string,second_string); + assert_eq!(first_string, second_string); } #[test] fn test_retry_connection() { init!("true"); - let handle = build_connection("test_serialize_deserialize").unwrap(); + let handle = create_connection("test_serialize_deserialize").unwrap(); assert!(handle > 0); assert_eq!(get_state(handle), VcxStateType::VcxStateInitialized as u32); - connect(handle,Some(String::new())).unwrap(); + connect(handle, Some(String::new())).unwrap(); connect(handle, Some(String::new())).unwrap(); } @@ -927,7 +936,7 @@ pub mod tests { fn test_bad_wallet_connection_fails() { init!("true"); settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE,"false"); - assert_eq!(build_connection("test_bad_wallet_connection_fails").unwrap_err().to_error_code(),error::INVALID_WALLET_HANDLE.code_num); + assert_eq!(create_connection("test_bad_wallet_connection_fails").unwrap_err().to_error_code(),error::INVALID_WALLET_HANDLE.code_num); } #[test] @@ -960,6 +969,8 @@ pub mod tests { agent_vk: "EkVTa7SCJ5SntpYyX7CSb2pcBhiVGT9kWSagA8a9T69A".to_string(), their_pw_did: String::new(), their_pw_verkey: String::new(), + public_did: None, + their_public_did: None, }; let handle = CONNECTION_MAP.add(c).unwrap(); @@ -969,7 +980,8 @@ pub mod tests { // test that it fails let bad_response = Message { status_code: MessageAccepted.as_string(), - payload: None, // This will cause an error + payload: None, + // This will cause an error sender_did: "H4FBkUidRG8WLsWa7M6P38".to_string(), uid: "yzjjywu".to_string(), msg_type: "connReqAnswer".to_string(), @@ -979,7 +991,7 @@ pub mod tests { }; match parse_acceptance_details(handle, &bad_response) { - Ok(_) => assert_eq!(0,1), // we should not receive this + Ok(_) => assert_eq!(0, 1), // we should not receive this // TODO: Refactor Error // TODO: Fix this test to be a correct Error Type Err(e) => assert_eq!(e, ConnectionError::CommonError(1019)), @@ -988,7 +1000,7 @@ pub mod tests { #[test] fn test_invite_detail_abbr() { - let invite_detail:Value = serde_json::from_str(INVITE_DETAIL_STRING).unwrap(); + let invite_detail: Value = serde_json::from_str(INVITE_DETAIL_STRING).unwrap(); let abbr = abbrv_event_detail(invite_detail).unwrap(); let abbr_obj = abbr.as_object().unwrap(); @@ -1052,17 +1064,17 @@ pub mod tests { #[test] fn test_release_all() { init!("true"); - let h1 = build_connection("rel1").unwrap(); - let h2 = build_connection("rel2").unwrap(); - let h3 = build_connection("rel3").unwrap(); - let h4 = build_connection("rel4").unwrap(); - let h5 = build_connection("rel5").unwrap(); + let h1 = create_connection("rel1").unwrap(); + let h2 = create_connection("rel2").unwrap(); + let h3 = create_connection("rel3").unwrap(); + let h4 = create_connection("rel4").unwrap(); + let h5 = create_connection("rel5").unwrap(); release_all(); - assert_eq!(release(h1).err(),Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - assert_eq!(release(h2).err(),Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - assert_eq!(release(h3).err(),Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - assert_eq!(release(h4).err(),Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - assert_eq!(release(h5).err(),Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); + assert_eq!(release(h1).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); + assert_eq!(release(h2).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); + assert_eq!(release(h3).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); + assert_eq!(release(h4).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); + assert_eq!(release(h5).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); } #[test] @@ -1073,20 +1085,20 @@ pub mod tests { let unabbrv_details = unabbrv_event_detail(serde_json::from_str(details).unwrap()).unwrap(); let details = serde_json::to_string(&unabbrv_details).unwrap(); - let handle = build_connection_with_invite("alice",&details).unwrap(); + let handle = create_connection_with_invite("alice",&details).unwrap(); - connect(handle,Some("{}".to_string())).unwrap(); + connect(handle, Some("{}".to_string())).unwrap(); - let handle_2 = build_connection_with_invite("alice",&details).unwrap(); + let handle_2 = create_connection_with_invite("alice",&details).unwrap(); - connect(handle_2,Some("{}".to_string())).unwrap(); + connect(handle_2, Some("{}".to_string())).unwrap(); } #[test] fn test_create_with_invalid_invite_details() { init!("true"); let bad_details = r#"{"id":"mtfjmda","s":{"d":"abc"},"l":"abc","n":"Evernym","v":"avc"},"sa":{"d":"abc","e":"abc","v":"abc"},"sc":"MS-101","sm":"message created","t":"there"}"#; - match build_connection_with_invite("alice",&bad_details) { + match create_connection_with_invite("alice",&bad_details) { Ok(_) => panic!("should have failed"), Err(x) => assert_eq!(x, ConnectionError::CommonError(error::INVALID_JSON.code_num)), }; @@ -1111,6 +1123,8 @@ pub mod tests { agent_vk: "EkVTa7SCJ5SntpYyX7CSb2pcBhiVGT9kWSagA8a9T69A".to_string(), their_pw_did: String::new(), their_pw_verkey: String::new(), + public_did: None, + their_public_did: None, }; let handle = CONNECTION_MAP.add(c).unwrap(); @@ -1123,20 +1137,19 @@ pub mod tests { // release throws a connection Error assert_eq!(release(1234).err(), Some(ConnectionError::CommonError(error::INVALID_CONNECTION_HANDLE.code_num))); - } #[test] - fn test_void_functions_actually_have_results(){ + fn test_void_functions_actually_have_results() { assert_eq!(set_their_pw_verkey(1, "blah").err(), Some(ConnectionError::InvalidHandle())); assert_eq!(set_state(1, VcxStateType::VcxStateNone).err(), Some(ConnectionError::InvalidHandle())); assert_eq!(set_pw_did(1, "blah").err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_their_pw_did(1,"blah").err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_uuid(1,"blah").err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_endpoint(1,"blah").err(), Some(ConnectionError::InvalidHandle())); - assert_eq!(set_agent_verkey(1,"blah").err(), Some(ConnectionError::InvalidHandle())); + assert_eq!(set_their_pw_did(1, "blah").err(), Some(ConnectionError::InvalidHandle())); + assert_eq!(set_uuid(1, "blah").err(), Some(ConnectionError::InvalidHandle())); + assert_eq!(set_endpoint(1, "blah").err(), Some(ConnectionError::InvalidHandle())); + assert_eq!(set_agent_verkey(1, "blah").err(), Some(ConnectionError::InvalidHandle())); let details: InviteDetail = serde_json::from_str(INVITE_DETAIL_STRING).unwrap(); - assert_eq!(set_invite_details(1, details).err(), Some(ConnectionError::InvalidHandle())); + assert_eq!(set_invite_details(1, &details).err(), Some(ConnectionError::InvalidHandle())); assert_eq!(set_pw_verkey(1, "blah").err(), Some(ConnectionError::InvalidHandle())); } } diff --git a/vcx/libvcx/src/credential.rs b/vcx/libvcx/src/credential.rs index 6340744b..6c4f1c45 100644 --- a/vcx/libvcx/src/credential.rs +++ b/vcx/libvcx/src/credential.rs @@ -19,9 +19,9 @@ use messages::extract_json_payload; use utils::libindy::anoncreds::{libindy_prover_create_credential_req, libindy_prover_store_credential}; use utils::libindy::crypto; +use utils::libindy::anoncreds; use utils::libindy::payments::{pay_a_payee, PaymentTxn}; -use credential_def::retrieve_credential_def; use connection; use settings; @@ -84,13 +84,15 @@ pub struct Credential { impl Credential { pub fn build_request(&self, my_did: &str, their_did: &str) -> Result { + trace!("Credential::build_request >>> my_did: {}, their_did: {}", my_did, their_did); + if self.state != VcxStateType::VcxStateRequestReceived { return Err(CredentialError::NotReady())} let prover_did = self.my_did.as_ref().ok_or(CredentialError::CommonError(error::INVALID_DID.code_num))?; let credential_offer = self.credential_offer.as_ref().ok_or(CredentialError::InvalidCredentialJson())?; - let (cred_def_id, cred_def_json) = retrieve_credential_def(&credential_offer.cred_def_id) - .map_err(|err| CredentialError::CommonError(err.to_error_code()))?; + let (cred_def_id, cred_def_json) = anoncreds::get_cred_def_json(&credential_offer.cred_def_id) + .map_err(|err| CredentialError::CommonError(err))?; /* debug!("storing credential offer: {}", credential_offer); @@ -116,6 +118,8 @@ impl Credential { } fn send_request(&mut self, connection_handle: u32) -> Result { + trace!("Credential::send_request >>> connection_handle: {}", connection_handle); + debug!("sending credential request {} via connection: {}", self.source_id, connection::get_source_id(connection_handle).unwrap_or_default()); self.my_did = Some(connection::get_pw_did(connection_handle).map_err(|ec| CredentialError::CommonError(ec.to_error_code()))?); self.my_vk = Some(connection::get_pw_verkey(connection_handle).map_err(|ec| CredentialError::CommonError(ec.to_error_code()))?); @@ -190,22 +194,24 @@ impl Credential { let cred_req: &CredentialRequest = self.credential_request.as_ref() .ok_or(CredentialError::InvalidCredentialJson().to_error_code())?; - let (_, cred_def_json) = ::credential_def::retrieve_credential_def(&cred_req.cred_def_id) - .map_err(|err| CredentialError::CommonError(err.to_error_code()).to_error_code())?; + let (_, cred_def_json) = anoncreds::get_cred_def_json(&cred_req.cred_def_id)?; self.credential = Some(credential); self.cred_id = Some(libindy_prover_store_credential(None, &cred_req.libindy_cred_req_meta, &credential_msg.libindy_cred, &cred_def_json, - None)?); + match credential_msg.rev_reg_def_json.len() { + 0 => None, + _ => Some(credential_msg.rev_reg_def_json), + })?); self.state = VcxStateType::VcxStateAccepted; Ok(()) } fn update_state(&mut self) { - debug!("updating state for credential {} with msg_id {:?}", self.source_id, self.msg_uid); + trace!("Credential::update_state >>>"); match self.state { VcxStateType::VcxStateOfferSent => { //Check for messages @@ -221,11 +227,13 @@ impl Credential { } fn get_state(&self) -> u32 { + trace!("Credential::get_state >>>"); let state = self.state as u32; state } fn get_credential(&self) -> Result { + trace!("Credential::get_credential >>>"); if self.state == VcxStateType::VcxStateAccepted { match self.credential { Some(ref x) => Ok(self.to_cred_string(x)), @@ -238,6 +246,7 @@ impl Credential { } fn get_credential_offer(&self) -> Result { + trace!("Credential::get_credential_offer >>>"); if self.state == VcxStateType::VcxStateRequestReceived { match self.credential_offer { Some(ref x) => match serde_json::to_string(x) { @@ -278,6 +287,7 @@ impl Credential { fn get_source_id(&self) -> &String {&self.source_id} fn get_payment_txn(&self) -> Result { + trace!("Credential::get_payment_txn >>>"); match self.payment_txn { Some(ref payment_txn) if self.payment_info.is_some() => Ok(payment_txn.clone()), _ => Err(error::NO_PAYMENT_INFORMATION.code_num) @@ -306,6 +316,7 @@ impl Credential { } fn get_payment_info(&self) -> Result, CredentialError> { + trace!("Credential::get_payment_info >>>"); Ok(self.payment_info.clone()) } @@ -338,6 +349,8 @@ fn handle_err(code_num: u32) -> CredentialError { } pub fn credential_create_with_offer(source_id: &str, offer: &str) -> Result { + trace!("credential_create_with_offer >>> source_id: {}, offer: {}", source_id, offer); + let mut new_credential = _credential_create(source_id); let (offer, payment_info) = parse_json_offer(offer)?; @@ -362,6 +375,7 @@ fn _credential_create(source_id: &str) -> Credential { pub fn update_state(handle: u32) -> Result { HANDLE_MAP.get_mut(handle, |obj|{ + debug!("updating state for credential {} with msg_id {:?}", obj.source_id, obj.msg_uid); obj.update_state(); Ok(error::SUCCESS.code_num) }) @@ -370,6 +384,7 @@ pub fn update_state(handle: u32) -> Result { pub fn get_credential(handle: u32) -> Result { HANDLE_MAP.get(handle, |obj| { + debug!("getting credential {}", obj.get_source_id()); obj.get_credential().map_err(|e| e.to_error_code()) }).map_err(|ec| CredentialError::CommonError(ec)) } @@ -382,6 +397,7 @@ pub fn get_payment_txn(handle: u32) -> Result { pub fn get_credential_offer(handle: u32) -> Result { HANDLE_MAP.get(handle, |obj| { + debug!("getting credential offer {}", obj.source_id); obj.get_credential_offer().map_err(|e| e.to_error_code()) }).map_err(|ec| CredentialError::CommonError(ec)) } @@ -405,6 +421,8 @@ pub fn send_credential_request(handle: u32, connection_handle: u32) -> Result Result { + trace!("get_credential_offer_msg >>> connection_handle: {}, msg_id: {}", connection_handle, msg_id); + let my_did = connection::get_pw_did(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; let my_vk = connection::get_pw_verkey(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; let agent_did = connection::get_agent_did(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; @@ -442,6 +460,8 @@ pub fn get_credential_offer_msg(connection_handle: u32, msg_id: &str) -> Result< } pub fn get_credential_offer_messages(connection_handle: u32) -> Result { + trace!("Credential::get_credential_offer_messages >>> connection_handle: {}", connection_handle); + debug!("checking agent for credential offers from connection {}", connection::get_source_id(connection_handle).unwrap_or_default()); let my_did = connection::get_pw_did(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; let my_vk = connection::get_pw_verkey(connection_handle).map_err(|e| CredentialError::CommonError(e.to_error_code()))?; @@ -573,6 +593,7 @@ pub mod tests { pub const BAD_CREDENTIAL_OFFER: &str = r#"{"version": "0.1","to_did": "LtMgSjtFcyPwenK9SHCyb8","from_did": "LtMgSjtFcyPwenK9SHCyb8","claim": {"account_num": ["8BEaoLf8TBmK4BUyX8WWnA"],"name_on_account": ["Alice"]},"schema_seq_no": 48,"issuer_did": "Pd4fnFtRBcMKRVC2go5w3j","claim_name": "Account Certificate","claim_id": "3675417066","msg_ref_id": "ymy5nth"}"#; use utils::constants::{DEFAULT_SERIALIZED_CREDENTIAL, DEFAULT_SERIALIZED_CREDENTIAL_PAYMENT_REQUIRED}; + use utils::libindy::payments::build_test_address; pub fn create_credential(offer: &str) -> Credential { let mut credential = _credential_create("source_id"); @@ -588,7 +609,7 @@ pub mod tests { let mut cred: Credential = Credential::from_str(DEFAULT_SERIALIZED_CREDENTIAL).unwrap(); cred.payment_info = Some(PaymentInfo { payment_required: "one-time".to_string(), - payment_addr: "pov:null:OsdjtGKavZDBuG2xFw2QunVwwGs5IB3j".to_string(), + payment_addr: build_test_address("OsdjtGKavZDBuG2xFw2QunVwwGs5IB3j"), price, }); cred @@ -635,7 +656,7 @@ pub mod tests { fn full_credential_test(){ init!("true"); - let connection_h = connection::build_connection("test_send_credential_offer").unwrap(); + let connection_h = connection::tests::build_test_connection(); let offers = get_credential_offer_messages(connection_h).unwrap(); let offers:Value = serde_json::from_str(&offers).unwrap(); let offers = serde_json::to_string(&offers[0]).unwrap(); @@ -654,13 +675,12 @@ pub mod tests { assert_eq!(get_credential_id(c_h).unwrap(), "cred_id"); // this is set in test mode assert!(get_credential(c_h).unwrap().len() > 100); let serialized = to_string(c_h).unwrap(); - println!("{}", serialized); } #[test] fn test_get_credential_offer() { init!("true"); - let connection_h = connection::build_connection("test_get_credential_offer").unwrap(); + let connection_h = connection::tests::build_test_connection(); let offer = get_credential_offer_messages(connection_h).unwrap(); let o: serde_json::Value = serde_json::from_str(&offer).unwrap(); let credential_offer: CredentialOffer = serde_json::from_str(&o[0][0].to_string()).unwrap(); diff --git a/vcx/libvcx/src/credential_def.rs b/vcx/libvcx/src/credential_def.rs index 0f810d91..f039da05 100644 --- a/vcx/libvcx/src/credential_def.rs +++ b/vcx/libvcx/src/credential_def.rs @@ -3,16 +3,8 @@ extern crate rand; extern crate libc; use utils::error; -use settings; -use schema::LedgerSchema; -use utils::constants::{ CRED_DEF_ID, CRED_DEF_JSON, CRED_DEF_TXN_TYPE }; -use utils::libindy::payments::{pay_for_txn, PaymentTxn}; -use utils::libindy::anoncreds::{libindy_create_and_store_credential_def}; -use utils::libindy::ledger::{libindy_submit_request, - libindy_build_get_credential_def_txn, - libindy_build_create_credential_def_txn, - libindy_parse_get_cred_def_response}; -use error::ToErrorCode; +use utils::libindy::payments::{PaymentTxn}; +use utils::libindy::anoncreds; use error::cred_def::CredDefError; use object_cache::ObjectCache; @@ -26,7 +18,21 @@ pub struct CredentialDef { tag: String, name: String, source_id: String, - payment_txn: Option, + issuer_did: String, + cred_def_payment_txn: Option, + rev_reg_def_payment_txn: Option, + rev_reg_delta_payment_txn: Option, + rev_reg_id: Option, + rev_reg_def: Option, + rev_reg_entry: Option, + tails_file: Option, +} + +#[derive(Deserialize, Debug, Serialize)] +pub struct RevocationDetails { + pub support_revocation: Option, + pub tails_file: Option, + pub max_creds: Option, } impl Default for CredentialDef { @@ -36,7 +42,14 @@ impl Default for CredentialDef { tag: String::new(), name: String::new(), source_id: String::new(), - payment_txn: None, + issuer_did: String::new(), + cred_def_payment_txn: None, + rev_reg_def_payment_txn: None, + rev_reg_delta_payment_txn: None, + rev_reg_id: None, + rev_reg_def: None, + rev_reg_entry: None, + tails_file: None, } } } @@ -47,19 +60,27 @@ impl CredentialDef { CredentialDef::from_string_with_version(&input).or(Err(CredDefError::CreateCredDefError())) } - pub fn to_string(&self) -> String { - self.to_string_with_version() - } + pub fn to_string(&self) -> String { self.to_string_with_version() } pub fn get_source_id(&self) -> &String { &self.source_id } + pub fn get_rev_reg_id(&self) -> Option { self.rev_reg_id.clone() } + + pub fn get_tails_file(&self) -> Option {self.tails_file.clone() } + + pub fn get_rev_reg_def(&self) -> Option { self.rev_reg_def.clone() } + pub fn get_cred_def_id(&self) -> &String { &self.id } pub fn set_name(&mut self, name: String) { self.name = name.clone(); } pub fn set_source_id(&mut self, source_id: String) { self.source_id = source_id.clone(); } - fn get_payment_txn(&self) -> Result { Ok(self.payment_txn.clone().ok_or(error::NOT_READY.code_num)?) } + fn get_cred_def_payment_txn(&self) -> Result { Ok(self.cred_def_payment_txn.clone().ok_or(error::NOT_READY.code_num)?) } + + fn get_rev_reg_def_payment_txn(&self) -> Option { self.rev_reg_def_payment_txn.clone() } + + fn get_rev_reg_delta_payment_txn(&self) -> Option { self.rev_reg_delta_payment_txn.clone() } fn to_string_with_version(&self) -> String { json!({ @@ -81,23 +102,71 @@ pub fn create_new_credentialdef(source_id: String, issuer_did: String, schema_id: String, tag: String, - config_json: String) -> Result { - let schema_json = LedgerSchema::new_from_ledger(&schema_id) - .map_err(|x| CredDefError::CommonError(x.to_error_code()))?.schema_json; + revocation_details: String) -> Result { + trace!("create_new_credentialdef >>> source_id: {}, name: {}, issuer_did: {}, schema_id: {}, revocation_details: {}", + source_id, name, issuer_did, schema_id, revocation_details); + + let revocation_details: RevocationDetails = serde_json::from_str(&revocation_details) + .or(Err(CredDefError::InvalidRevocationDetails()))?; + + let (_, schema_json) = anoncreds::get_schema_json(&schema_id) + .map_err(|x| CredDefError::CommonError(x))?; + + // Creates Credential Definition in both wallet and on ledger + let (id, cred_def_payment_txn) = anoncreds::create_cred_def(&issuer_did, + &schema_json, + &tag, + None, + revocation_details.support_revocation) + .map_err(|err| { + if err == error::CREDENTIAL_DEF_ALREADY_CREATED.code_num { + error!("Credential Definition for issuer_did {} already in wallet", issuer_did); + CredDefError::CredDefAlreadyCreatedError() + } else { + error!("{} with: {}", error::CREATE_CREDENTIAL_DEF_ERR.message, err); + CredDefError::CreateCredDefError() + } + })?; + + // Creates Revocation Definition in wallet and on ledger + // Posts Revocation Delta to Ledger + let (rev_reg_id, rev_reg_def, rev_reg_entry, rev_def_payment, rev_delta_payment) + = match revocation_details.support_revocation { + Some(true) => { + let tails_file = revocation_details + .tails_file + .as_ref() + .ok_or(CredDefError::InvalidRevocationDetails())?; + + let max_creds = revocation_details + .max_creds + .ok_or(CredDefError::InvalidRevocationDetails())?; + + let (rev_reg_id, rev_reg_def, rev_reg_entry, rev_def_payment) = + anoncreds::create_rev_reg_def(&issuer_did, &id, &tails_file, max_creds) + .or(Err(CredDefError::CreateRevRegDefError()))?; - debug!("creating credentialdef with source_id: {}, name: {}, issuer_did: {}, schema_id: {}", source_id, name, issuer_did, schema_id); - let (id, payment_txn) = _create_and_store_credential_def( &issuer_did, - &schema_json, - &tag, - None, - &config_json)?; + let (delta_payment, _) = anoncreds::post_rev_reg_delta(&issuer_did, &rev_reg_id, &rev_reg_entry) + .or(Err(CredDefError::InvalidRevocationEntry()))?; + + (Some(rev_reg_id), Some(rev_reg_def), Some(rev_reg_entry), rev_def_payment, delta_payment) + } + _ => (None, None, None, None, None), + }; let new_cred_def = CredentialDef { source_id, name, tag, id, - payment_txn, + issuer_did, + cred_def_payment_txn, + rev_reg_def_payment_txn: rev_def_payment, + rev_reg_delta_payment_txn: rev_delta_payment, + rev_reg_id, + rev_reg_def, + rev_reg_entry, + tails_file: revocation_details.tails_file, }; let new_handle = CREDENTIALDEF_MAP.add(new_cred_def).map_err(|key|CredDefError::CreateCredDefError())?; @@ -105,58 +174,6 @@ pub fn create_new_credentialdef(source_id: String, Ok(new_handle) } -//Todo: possibly move _create_and_store_credential_def and retrieve_cred_def to a common trait -fn _create_and_store_credential_def(issuer_did: &str, - schema_json: &str, - tag: &str, - sig_type: Option<&str>, - config_json: &str) -> Result<(String, Option), CredDefError> { - if settings::test_indy_mode_enabled() { - return Ok((CRED_DEF_ID.to_string(), Some(PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap()))); - } - - let (id, cred_def_json) = libindy_create_and_store_credential_def(issuer_did, - schema_json, - tag, - sig_type, - config_json) - .map_err(|err| { - match err { - //Todo: Find out how to match on Cred...code_num - x if x == error::CREDENTIAL_DEF_ALREADY_CREATED.code_num => { - error!("cred_def for issuer_did {} already in wallet", issuer_did); - CredDefError::CredDefAlreadyCreatedError() - }, - _ => { - error!("{} with: {}", error::CREATE_CREDENTIAL_DEF_ERR.message, err); - CredDefError::CreateCredDefError() - } - } - })?; - - - let cred_def_req = libindy_build_create_credential_def_txn(issuer_did, &cred_def_json) - .or(Err(CredDefError::CreateCredDefError()))?; - - let (payment, response) = pay_for_txn(&cred_def_req, CRED_DEF_TXN_TYPE) - .map_err(|err| CredDefError::CommonError(err))?; - - Ok((id, payment)) -} - -pub fn retrieve_credential_def(cred_def_id: &str) -> Result<(String, String), CredDefError> { - if settings::test_indy_mode_enabled() { return Ok((CRED_DEF_ID.to_string(), CRED_DEF_JSON.to_string())); } - - let get_cred_def_req = libindy_build_get_credential_def_txn(cred_def_id) - .or(Err(CredDefError::BuildCredDefRequestError()))?; - - let get_cred_def_response = libindy_submit_request(&get_cred_def_req) - .map_err(|err| CredDefError::CommonError(err))?; - - libindy_parse_get_cred_def_response(&get_cred_def_response) - .or(Err(CredDefError::RetrieveCredDefError())) -} - pub fn is_valid_handle(handle: u32) -> bool { CREDENTIALDEF_MAP.has_handle(handle) } @@ -181,9 +198,9 @@ pub fn get_source_id(handle: u32) -> Result { }).map_err(|ec|CredDefError::CommonError(ec)) } -pub fn get_payment_txn(handle: u32) -> Result { +pub fn get_cred_def_payment_txn(handle: u32) -> Result { CREDENTIALDEF_MAP.get(handle,|c| { - c.get_payment_txn() + c.get_cred_def_payment_txn() }).or(Err(CredDefError::NoPaymentInformation())) } @@ -193,6 +210,37 @@ pub fn get_cred_def_id(handle: u32) -> Result { }).map_err(|ec|CredDefError::CommonError(ec)) } +pub fn get_rev_reg_id(handle: u32) -> Result, CredDefError> { + CREDENTIALDEF_MAP.get(handle,|c| { + Ok(c.get_rev_reg_id().clone()) + }).map_err(|ec|CredDefError::CommonError(ec)) +} + +pub fn get_tails_file(handle: u32) -> Result, CredDefError> { + CREDENTIALDEF_MAP.get(handle,|c| { + Ok(c.get_tails_file().clone()) + }).map_err(|ec|CredDefError::CommonError(ec)) +} + +pub fn get_rev_reg_def(handle: u32) -> Result, CredDefError> { + CREDENTIALDEF_MAP.get(handle,|c| { + Ok(c.get_rev_reg_def().clone()) + }).map_err(|ec|CredDefError::CommonError(ec)) +} + +pub fn get_rev_reg_def_payment_txn(handle: u32) -> Result, CredDefError> { + CREDENTIALDEF_MAP.get(handle,|c| { + Ok(c.get_rev_reg_def_payment_txn()) + }).map_err(|ec|CredDefError::CommonError(ec)) +} + + +pub fn get_rev_reg_delta_payment_txn(handle: u32) -> Result, CredDefError> { + CREDENTIALDEF_MAP.get(handle,|c| { + Ok(c.get_rev_reg_delta_payment_txn()) + }).map_err(|ec|CredDefError::CommonError(ec)) +} + pub fn release(handle: u32) -> Result<(), CredDefError> { match CREDENTIALDEF_MAP.release(handle) { Ok(_) => Ok(()), @@ -200,6 +248,20 @@ pub fn release(handle: u32) -> Result<(), CredDefError> { } } +pub fn find_handle(cred_def_id: &str) -> Result { + let mut handles = Vec::new(); + + for handle in CREDENTIALDEF_MAP.store.lock().unwrap().iter() { + handles.push(handle.0.clone()); + } + for handle in handles.iter() { + let id = get_cred_def_id(*handle).unwrap(); + println!("id: {}", id); + } + + Ok(error::SUCCESS.code_num) +} + pub fn release_all() { match CREDENTIALDEF_MAP.drain() { Ok(_) => (), @@ -209,36 +271,87 @@ pub fn release_all() { #[cfg(test)] pub mod tests { - use utils::constants::{SCHEMA_ID, SCHEMAS_JSON}; + use utils::{ + constants::{SCHEMA_ID, CRED_DEF_ID}, + get_temp_dir_path + }; use super::*; + use settings; + use std::{ + thread::sleep, + time::Duration + }; static CREDENTIAL_DEF_NAME: &str = "Test Credential Definition"; static ISSUER_DID: &str = "4fUDR9R7fjwELRvH9JT6HH"; + pub fn create_cred_def_real(revoc: bool) -> (u32, u32) { + let schema_handle = ::schema::tests::create_schema_real(); + let schema_id = ::schema::get_schema_id(schema_handle).unwrap(); + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + let mut revocation_details = json!({"support_revocation":revoc}); + if revoc { + revocation_details["tails_file"] = json!(get_temp_dir_path(Some("tails_file.txt")).to_str().unwrap()); + revocation_details["max_creds"] = json!(10); + } + sleep(Duration::from_secs(2)); + let cred_def_handle = create_new_credentialdef("1".to_string(), + CREDENTIAL_DEF_NAME.to_string(), + did, + schema_id, + "tag_1".to_string(), + revocation_details.to_string()).unwrap(); + + (schema_handle, cred_def_handle) + } + + pub fn create_cred_def_fake() -> u32 { + create_new_credentialdef("SourceId".to_string(), + CREDENTIAL_DEF_NAME.to_string(), + ISSUER_DID.to_string(), + SCHEMA_ID.to_string(), + "tag".to_string(), + "{}".to_string()).unwrap() + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_create_cred_def_without_rev_will_have_no_rev_id() { + init!("ledger"); + let (_, handle) = create_cred_def_real(false); + let rev_reg_id = get_rev_reg_id(handle).unwrap(); + assert!(rev_reg_id.is_none()); + + let (_, handle) = create_cred_def_real(true); + let rev_reg_id = get_rev_reg_id(handle).unwrap(); + assert!(rev_reg_id.is_some()); + } + #[test] fn test_get_cred_def() { init!("true"); + let (_, handle) = create_cred_def_real(false); - let (id, cred_def_json) = retrieve_credential_def(CRED_DEF_ID).unwrap(); - assert_eq!(&id, CRED_DEF_ID); - assert_eq!(&cred_def_json, CRED_DEF_JSON); - } + let payment = serde_json::to_string(&get_cred_def_payment_txn(handle).unwrap()).unwrap(); + assert!(payment.len() > 0); + find_handle("123").unwrap(); +} #[test] fn test_get_credential_def_by_send_request_fails() { settings::clear_config(); settings::set_defaults(); settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "false"); - assert!(retrieve_credential_def(CRED_DEF_ID).is_err()); + assert!(::utils::libindy::anoncreds::get_cred_def_json(CRED_DEF_ID).is_err()); } #[cfg(feature = "pool_tests")] #[test] fn test_get_credential_def() { init!("ledger"); - let (_, _, cred_def_id, cred_def_json) = ::utils::libindy::anoncreds::tests::create_and_store_credential_def(::utils::constants::DEFAULT_SCHEMA_ATTRS); + let (_, _, cred_def_id, cred_def_json, _, _) = ::utils::libindy::anoncreds::tests::create_and_store_credential_def(::utils::constants::DEFAULT_SCHEMA_ATTRS, false); - let (id, r_cred_def_json) = retrieve_credential_def(&cred_def_id).unwrap(); + let (id, r_cred_def_json) = ::utils::libindy::anoncreds::get_cred_def_json(&cred_def_id).unwrap(); assert_eq!(id, cred_def_id); let def1: serde_json::Value = serde_json::from_str(&cred_def_json).unwrap(); @@ -248,7 +361,8 @@ pub mod tests { #[cfg(feature = "pool_tests")] #[test] - fn test_create_credential_def_real() { + fn test_create_revocable_fails_with_no_tails_file() { + let wallet_name = "test_create_revocable_fails_with_no_tails_file"; init!("ledger"); let data = r#"["address1","address2","zip","city","state"]"#.to_string(); @@ -256,21 +370,45 @@ pub mod tests { let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let rc = create_new_credentialdef("1".to_string(), - "name".to_string(), - did, - schema_id, - "tag_1".to_string(), - r#"{"support_revocation":false}"#.to_string()).unwrap(); + wallet_name.to_string(), + did, + schema_id, + "tag_1".to_string(), + r#"{"support_revocation":true}"#.to_string()); + assert_eq!(rc, Err(CredDefError::InvalidRevocationDetails())); + } - let payment = serde_json::to_string(&get_payment_txn(rc).unwrap()).unwrap(); - assert!(payment.len() > 0); + #[cfg(feature = "pool_tests")] + #[test] + fn test_create_revocable_cred_def_with_payments() { + let wallet_name = "test_create_revocable_cred_def"; + init!("ledger"); + + let data = r#"["address1","address2","zip","city","state"]"#.to_string(); + let (schema_id, _) = ::utils::libindy::anoncreds::tests::create_and_write_test_schema(::utils::constants::DEFAULT_SCHEMA_ATTRS); + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + + let revocation_details = json!({"support_revocation": true, "tails_file": get_temp_dir_path(Some("tails.txt")).to_str().unwrap(), "max_creds": 2}).to_string(); + let handle = create_new_credentialdef("1".to_string(), + wallet_name.to_string(), + did, + schema_id, + "tag_1".to_string(), + revocation_details).unwrap(); + + assert!(get_rev_reg_def(handle).unwrap().is_some()); + assert!(get_rev_reg_id(handle).unwrap().is_some()); + assert!(get_rev_reg_def_payment_txn(handle).unwrap().is_some()); + assert!(get_rev_reg_delta_payment_txn(handle).unwrap().is_some()); + let cred_id = get_cred_def_id(handle).unwrap(); + let (_, json) = ::utils::libindy::anoncreds::get_cred_def_json(&cred_id).unwrap(); + println!("cred_def_json: {:?}", json); } #[cfg(feature = "pool_tests")] #[test] - fn test_create_credential_def_no_fees_real() { + fn test_create_credential_def_real() { init!("ledger"); - ::utils::libindy::payments::mint_tokens_and_set_fees(Some(0),Some(0),Some(r#"{"101":0, "102":0}"#.to_string()), None).unwrap(); let data = r#"["address1","address2","zip","city","state"]"#.to_string(); let (schema_id, _) = ::utils::libindy::anoncreds::tests::create_and_write_test_schema(::utils::constants::DEFAULT_SCHEMA_ATTRS); @@ -282,14 +420,17 @@ pub mod tests { schema_id, "tag_1".to_string(), r#"{"support_revocation":false}"#.to_string()).unwrap(); + + let payment = serde_json::to_string(&get_cred_def_payment_txn(rc).unwrap()).unwrap(); + assert!(payment.len() > 0); } + #[cfg(feature = "pool_tests")] #[test] - fn test_create_credential_def_and_store_in_wallet() { - init!("true"); - let config = r#"{"support_revocation":false}"#; - let (id, _) = _create_and_store_credential_def(SCHEMAS_JSON, ISSUER_DID, "tag_1",None, config).unwrap(); - assert_eq!(id, CRED_DEF_ID); + fn test_create_credential_def_no_fees_real() { + init!("ledger"); + + let rc = create_cred_def_real(false); } #[cfg(feature = "pool_tests")] @@ -319,24 +460,14 @@ pub mod tests { #[test] fn test_create_credentialdef_success() { init!("true"); - let handle = create_new_credentialdef("SourceId".to_string(), - CREDENTIAL_DEF_NAME.to_string(), - ISSUER_DID.to_string(), - SCHEMA_ID.to_string(), - "tag".to_string(), - "{}".to_string()).unwrap(); + let handle = create_cred_def_fake(); assert!(handle > 0); } #[test] fn test_to_string_succeeds() { init!("true"); - let handle = create_new_credentialdef("SourceId".to_string(), - CREDENTIAL_DEF_NAME.to_string(), - ISSUER_DID.to_string(), - SCHEMA_ID.to_string(), - "tag".to_string(), - "{}".to_string()).unwrap(); + let handle = create_cred_def_fake(); let credential_string = to_string(handle).unwrap(); let credential_values: serde_json::Value = serde_json::from_str(&credential_string).unwrap(); assert_eq!(credential_values["version"].clone(), "1.0"); @@ -345,12 +476,7 @@ pub mod tests { #[test] fn test_from_string_succeeds() { init!("true"); - let handle = create_new_credentialdef("SourceId".to_string(), - CREDENTIAL_DEF_NAME.to_string(), - ISSUER_DID.to_string(), - SCHEMA_ID.to_string(), - "tag".to_string(), - "{}".to_string()).unwrap(); + let handle = create_cred_def_fake(); let credentialdef_data = to_string(handle).unwrap(); assert!(!credentialdef_data.is_empty()); release(handle).unwrap(); @@ -377,4 +503,10 @@ pub mod tests { assert_eq!(release(h4),Err(CredDefError::InvalidHandle())); assert_eq!(release(h5),Err(CredDefError::InvalidHandle())); } + + #[test] + fn test_map_serde() { + let serde_v = json!({"max_creds": 22, "tails_file": "abc.txt"}); + println!("none: {:?}", serde_v.get("n")); + } } diff --git a/vcx/libvcx/src/disclosed_proof.rs b/vcx/libvcx/src/disclosed_proof.rs index fad011be..77cba54a 100644 --- a/vcx/libvcx/src/disclosed_proof.rs +++ b/vcx/libvcx/src/disclosed_proof.rs @@ -8,20 +8,19 @@ use connection; use messages; use messages::GeneralMessage; use messages::proofs::proof_message::{ProofMessage }; -use messages::proofs::proof_request::{ ProofRequestMessage }; +use messages::proofs::proof_request::{ ProofRequestMessage, ProofRequestData, NonRevokedInterval }; use messages::extract_json_payload; use messages::to_u8; - -use credential_def::{ retrieve_credential_def }; -use schema::{ LedgerSchema }; +use time; use utils::libindy::anoncreds; use utils::libindy::crypto; -use utils::serde_utils; +use utils::libindy::anoncreds::{ get_rev_reg_def_json, get_rev_reg_delta_json }; use settings; use utils::httpclient; use utils::constants::{ DEFAULT_SERIALIZE_VERSION, CREDS_FROM_PROOF_REQ, DEFAULT_GENERATED_PROOF }; +use utils::libindy::cache::{get_rev_reg_cache, set_rev_reg_cache, RevRegCache, RevState}; use serde_json::{Value}; @@ -75,99 +74,258 @@ pub struct RequestedCreds { #[derive(Debug, Deserialize, Serialize, PartialEq)] pub struct CredInfo { + pub requested_attr: String, pub referent: String, pub schema_id: String, pub cred_def_id: String, + pub rev_reg_id: Option, + pub cred_rev_id: Option, + pub revocation_interval: Option, + pub tails_file: Option, + pub timestamp: Option } -fn credential_def_identifiers(credentials: &str) -> Result, ProofError> { +fn credential_def_identifiers(credentials: &str, proof_req: &ProofRequestData) + -> Result, ProofError> { + let mut rtn = Vec::new(); let credentials: Value = serde_json::from_str(credentials) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; + .or(Err(ProofError::InvalidJson()))?; if let Value::Object(ref attrs) = credentials["attrs"] { for (requested_attr, value) in attrs { - if let Some(ref attr_obj) = value.get("cred_info") { - rtn.push(( - requested_attr.to_string(), - serde_utils::get_value_to_string("referent", attr_obj) - .map_err(|e| ProofError::CommonError(e))?, - serde_utils::get_value_to_string("schema_id", attr_obj) - .map_err(|e| ProofError::CommonError(e))?, - serde_utils::get_value_to_string("cred_def_id", attr_obj) - .map_err(|e| ProofError::CommonError(e))? - )); - } + if let (Some(referent), Some(schema_id), Some(cred_def_id)) = + (value["credential"]["cred_info"]["referent"].as_str(), + value["credential"]["cred_info"]["schema_id"].as_str(), + value["credential"]["cred_info"]["cred_def_id"].as_str()) { + + let rev_reg_id = value["credential"]["cred_info"]["rev_reg_id"] + .as_str() + .map(|x| x.to_string()); + + let cred_rev_id = value["credential"]["cred_info"]["cred_rev_id"] + .as_str() + .map(|x| x.to_string()); + + let tails_file = value["tails_file"] + .as_str() + .map(|x| x.to_string()); + + rtn.push( + CredInfo { + requested_attr: requested_attr.to_string(), + referent: referent.to_string(), + schema_id: schema_id.to_string(), + cred_def_id: cred_def_id.to_string(), + revocation_interval: _get_revocation_interval(&requested_attr, &proof_req)?, + timestamp: None, + rev_reg_id, + cred_rev_id, + tails_file, + } + ); + } else { return Err(ProofError::InvalidCredData()) } } } + Ok(rtn) } +fn _get_revocation_interval(attr_name: &str, proof_req: &ProofRequestData) + -> Result, ProofError> { + + if let Some(ref attr) = proof_req.requested_attributes.get(attr_name) { + + if let Some(ref interval) = attr.non_revoked { + return Ok(Some(NonRevokedInterval {from: interval.from, to: interval.to})) + } + else if let Some(ref interval) = proof_req.non_revoked { + return Ok(Some(NonRevokedInterval { from: interval.from, to: interval.to })) + } + + return Ok(None) + } + // Todo: Handle case for predicates + + Err(ProofError::InvalidCredData()) +} + +// Also updates timestamp in credentials_identifiers +fn build_rev_states_json(credentials_identifiers: &mut Vec) -> Result { + let mut rtn: Value = json!({}); + let mut timestamps: HashMap = HashMap::new(); + + for cred_info in credentials_identifiers.iter_mut() { + if let (Some(rev_reg_id), Some(cred_rev_id), Some(tails_file)) = + (&cred_info.rev_reg_id, &cred_info.cred_rev_id, &cred_info.tails_file) { + + if rtn.get(&rev_reg_id).is_none() { + let (from, to) = if let Some(ref interval) = cred_info.revocation_interval + { (interval.from, interval.to) } + else { (None, None )}; + +// let from = from.unwrap_or(0); +// let to = to.unwrap_or(time::get_time().sec as u64); + let cache = get_rev_reg_cache(&rev_reg_id); + + let (rev_state_json, timestamp) = if let Some(cached_rev_state) = cache.rev_state { + if cached_rev_state.timestamp >= from.unwrap_or(0) + && cached_rev_state.timestamp <= to.unwrap_or(time::get_time().sec as u64) { + (cached_rev_state.value, cached_rev_state.timestamp) + } else { + let from = match from { + Some(from) if from >= cached_rev_state.timestamp => { + Some(cached_rev_state.timestamp) + }, + _ => None + }; + + let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id) + .map_err(|e| ProofError::CommonError(e))?; + + let (rev_reg_id, rev_reg_delta_json, timestamp) = get_rev_reg_delta_json( + &rev_reg_id, + from, + to + ).map_err(|e| ProofError::CommonError(e))?; + + let rev_state_json = anoncreds::libindy_prover_update_revocation_state( + &rev_reg_def_json, + &cached_rev_state.value, + &rev_reg_delta_json, + &cred_rev_id, + &tails_file + ).map_err(|e| ProofError::CommonError(e))?; + + if timestamp > cached_rev_state.timestamp { + let new_cache = RevRegCache { + rev_state: Some(RevState { + timestamp: timestamp, + value: rev_state_json.clone() + }) + }; + set_rev_reg_cache(&rev_reg_id, &new_cache); + } + + (rev_state_json, timestamp) + } + } else { + let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id) + .map_err(|e| ProofError::CommonError(e))?; + + let (rev_reg_id, rev_reg_delta_json, timestamp) = get_rev_reg_delta_json( + &rev_reg_id, + None, + to + ).map_err(|e| ProofError::CommonError(e))?; + + let rev_state_json = anoncreds::libindy_prover_create_revocation_state( + &rev_reg_def_json, + &rev_reg_delta_json, + &cred_rev_id, + &tails_file + ).map_err(|e| ProofError::CommonError(e))?; + + let new_cache = RevRegCache { + rev_state: Some(RevState { + timestamp: timestamp, + value: rev_state_json.clone() + }) + }; + set_rev_reg_cache(&rev_reg_id, &new_cache); + + (rev_state_json, timestamp) + }; + + let rev_state_json: Value = serde_json::from_str(&rev_state_json) + .or(Err(ProofError::InvalidJson()))?; + + // TODO: proover should be able to create multiple states of same revocation policy for different timestamps + // see ticket IS-1108 + rtn[rev_reg_id.to_string()] = json!({timestamp.to_string(): rev_state_json}); + cred_info.timestamp = Some(timestamp); + + // Cache timestamp for future attributes that have the same rev_reg_id + timestamps.insert(rev_reg_id.to_string(), timestamp); + } + + // If the rev_reg_id is already in the map, timestamp may not be updated on cred_info + if cred_info.timestamp.is_none() { + cred_info.timestamp = timestamps.get(rev_reg_id).map(|x| x.clone()); + } + } + } + + Ok(rtn.to_string()) + +} + impl DisclosedProof { fn set_proof_request(&mut self, req: ProofRequestMessage) {self.proof_request = Some(req)} - fn get_state(&self) -> u32 {self.state as u32} - fn set_state(&mut self, state: VcxStateType) {self.state = state} + fn get_state(&self) -> u32 { + trace!("DisclosedProof::get_state >>>"); + self.state as u32 + } + fn set_state(&mut self, state: VcxStateType) { + trace!("DisclosedProof::set_state >>> state: {:?}", state); + self.state = state + } fn retrieve_credentials(&self) -> Result { + trace!("DisclosedProof::set_state >>>"); if settings::test_indy_mode_enabled() {return Ok(CREDS_FROM_PROOF_REQ.to_string())} - let proof_req = self.proof_request.as_ref().ok_or(ProofError::ProofNotReadyError())?; + let proof_req = self.proof_request + .as_ref() + .ok_or(ProofError::ProofNotReadyError())?; + let indy_proof_req = serde_json::to_string(&proof_req.proof_request_data) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; + .or(Err(ProofError::InvalidJson()))?; anoncreds::libindy_prover_get_credentials_for_proof_req(&indy_proof_req) .map_err(|err| ProofError::CommonError(err)) } - fn _find_schemas(&self, credentials_identifiers: &Vec<(String, String, String, String)>) -> Result { - if credentials_identifiers.len() == 0 { return Ok("{}".to_string()); } + fn build_schemas_json(&self, credentials_identifiers: &Vec) -> Result { + let mut rtn: Value = json!({}); - let mut rtn: HashMap = HashMap::new(); + for ref cred_info in credentials_identifiers { + if rtn.get(&cred_info.schema_id).is_none() { + let (_, schema_json) = anoncreds::get_schema_json(&cred_info.schema_id) + .or( Err(ProofError::InvalidSchema()))?; - for &(ref attr_id, ref cred_uuid, ref schema_id, ref cred_def_id) in credentials_identifiers { - if !rtn.contains_key(schema_id) { - let schema = LedgerSchema::new_from_ledger(schema_id).or( Err(ProofError::InvalidSchema()))?; - let schema_json = serde_json::from_str(&schema.schema_json).or(Err(ProofError::InvalidSchema()))?; - rtn.insert(schema_id.to_owned(), schema_json); - } - } + let schema_json = serde_json::from_str(&schema_json) + .or(Err(ProofError::InvalidSchema()))?; - match rtn.is_empty() { - false => Ok(serde_json::to_string(&rtn) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?), - true => Err(ProofError::CommonError(error::INVALID_JSON.code_num)) + rtn[cred_info.schema_id.to_owned()] = schema_json; + } } + Ok(rtn.to_string()) } - fn _find_credential_def(&self, credentials_identifiers: &Vec<(String, String, String, String)>) -> Result { - if credentials_identifiers.len() == 0 { return Ok("{}".to_string()); } - - let mut rtn: HashMap = HashMap::new(); + fn build_cred_def_json(&self, credentials_identifiers: &Vec) -> Result { + let mut rtn: Value = json!({}); - for &(ref attr_id, ref cred_uuid, ref schema_id, ref cred_def_id) in credentials_identifiers { - if !rtn.contains_key(cred_def_id) { - let (_, credential_def) = retrieve_credential_def(cred_def_id) + for ref cred_info in credentials_identifiers { + if rtn.get(&cred_info.cred_def_id).is_none() { + let (_, credential_def) = anoncreds::get_cred_def_json(&cred_info.cred_def_id) .or(Err(ProofError::InvalidCredData()))?; + let credential_def = serde_json::from_str(&credential_def) .or(Err(ProofError::InvalidCredData()))?; - rtn.insert(cred_def_id.to_owned(), credential_def); - } - } - match rtn.is_empty() { - false => Ok(serde_json::to_string(&rtn) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?), - true => Err(ProofError::CommonError(error::INVALID_JSON.code_num)) + rtn[cred_info.cred_def_id.to_owned()] = credential_def; + } } - + Ok(rtn.to_string()) } - fn _build_requested_credentials(&self, - credentials_identifiers: &Vec<(String, String, String, String)>, - self_attested_attrs: &str) -> Result { + fn build_requested_credentials_json(&self, + credentials_identifiers: &Vec, + self_attested_attrs: &str) -> Result { let mut rtn: Value = json!({ "self_attested_attributes":{}, "requested_attributes":{}, @@ -176,10 +334,9 @@ impl DisclosedProof { //Todo: need to do same for predicates and self_attested //Todo: need to handle if the attribute is not revealed if let Value::Object(ref mut map) = rtn["requested_attributes"] { - for &(ref attr_id, ref cred_uuid, ref schema_id, ref cred_def_id) in credentials_identifiers { - - let insert_val = json!({"cred_id": cred_uuid, "revealed": true}); - map.insert(attr_id.to_owned(), insert_val); + for ref cred_info in credentials_identifiers { + let insert_val = json!({"cred_id": cred_info.referent, "revealed": true, "timestamp": cred_info.timestamp}); + map.insert(cred_info.requested_attr.to_owned(), insert_val); } } @@ -187,13 +344,12 @@ impl DisclosedProof { .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; rtn["self_attested_attributes"] = self_attested_attrs; - let rtn = serde_json::to_string(&rtn) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; - - Ok(rtn) + Ok(rtn.to_string()) } fn generate_proof(&mut self, credentials: &str, self_attested_attrs: &str) -> Result { + trace!("DisclosedProof::generate_proof >>> credentials: {}, self_attested_attrs: {}", credentials, self_attested_attrs); + debug!("generating proof {}", self.source_id); if settings::test_indy_mode_enabled() {return Ok(error::SUCCESS.code_num)} @@ -203,18 +359,22 @@ impl DisclosedProof { .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; - let credentials_identifiers = credential_def_identifiers(credentials)?; - let requested_credentials = self._build_requested_credentials(&credentials_identifiers, - self_attested_attrs)?; - let schemas = self._find_schemas(&credentials_identifiers)?; - let credential_defs_json = self._find_credential_def(&credentials_identifiers)?; - let revoc_regs_json = Some("{}"); + let mut credentials_identifiers = credential_def_identifiers(credentials, + &proof_req.proof_request_data)?; + + let revoc_states_json = build_rev_states_json(&mut credentials_identifiers)?; + let requested_credentials = self.build_requested_credentials_json(&credentials_identifiers, + self_attested_attrs)?; + + let schemas_json = self.build_schemas_json(&credentials_identifiers)?; + let credential_defs_json = self.build_cred_def_json(&credentials_identifiers)?; + let proof = anoncreds::libindy_prover_create_proof(&proof_req_data_json, &requested_credentials, &self.link_secret_alias, - &schemas, + &schemas_json, &credential_defs_json, - revoc_regs_json).map_err(|ec| ProofError::CommonError(ec))?; + Some(&revoc_states_json)).map_err(|ec| ProofError::CommonError(ec))?; let mut proof_msg = ProofMessage::new(); proof_msg.libindy_proof = proof; self.proof = Some(proof_msg); @@ -223,6 +383,8 @@ impl DisclosedProof { } fn send_proof(&mut self, connection_handle: u32) -> Result { + trace!("DisclosedProof::send_proof >>> connection_handle: {}", connection_handle); + debug!("sending proof {} via connection: {}", self.source_id, connection::get_source_id(connection_handle).unwrap_or_default()); // There feels like there's a much more rusty way to do the below. self.my_did = Some(connection::get_pw_did(connection_handle).or(Err(ProofError::ProofConnectionError()))?); @@ -285,12 +447,14 @@ impl DisclosedProof { fn set_source_id(&mut self, id: &str) { self.source_id = id.to_string(); } fn get_source_id(&self) -> &String { &self.source_id } fn to_string(&self) -> String { + trace!("DisclosedProof::to_string >>>"); json!({ "version": DEFAULT_SERIALIZE_VERSION, "data": json!(self), }).to_string() } fn from_str(s: &str) -> Result { + trace!("DisclosedProof::from_str >>> data: {}", s); let s:Value = serde_json::from_str(&s) .or(Err(ProofError::InvalidJson()))?; let proof: DisclosedProof= serde_json::from_value(s["data"].clone()) @@ -312,6 +476,8 @@ fn handle_err(code_num: u32) -> u32 { } pub fn create_proof(source_id: &str, proof_req: &str) -> Result { + trace!("create_proof >>> source_id: {}, proof_req: {}", source_id, proof_req); + debug!("creating disclosed proof with id: {}", source_id); let mut new_proof: DisclosedProof = Default::default(); @@ -392,6 +558,8 @@ pub fn is_valid_handle(handle: u32) -> bool { //TODO one function with credential pub fn get_proof_request(connection_handle: u32, msg_id: &str) -> Result { + trace!("get_proof_request >>> connection_handle: {}, msg_id: {}", connection_handle, msg_id); + let my_did = connection::get_pw_did(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; let my_vk = connection::get_pw_verkey(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; let agent_did = connection::get_agent_did(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; @@ -427,6 +595,8 @@ pub fn get_proof_request(connection_handle: u32, msg_id: &str) -> Result) -> Result { + trace!("get_proof_request_messages >>> connection_handle: {}, match_name: {:?}", connection_handle, match_name); + let my_did = connection::get_pw_did(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; let my_vk = connection::get_pw_verkey(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; let agent_did = connection::get_agent_did(connection_handle).map_err(|e| ProofError::CommonError(e.to_error_code()))?; @@ -479,8 +649,31 @@ mod tests { extern crate serde_json; use super::*; - use utils::constants::{ ADDRESS_CRED_ID, LICENCE_CRED_ID, ADDRESS_SCHEMA_ID, ADDRESS_CRED_DEF_ID, CRED_DEF_ID, SCHEMA_ID }; use serde_json::Value; + use utils::{ + constants::{ ADDRESS_CRED_ID, LICENCE_CRED_ID, ADDRESS_SCHEMA_ID, + ADDRESS_CRED_DEF_ID, CRED_DEF_ID, SCHEMA_ID, ADDRESS_CRED_REV_ID, + ADDRESS_REV_REG_ID, REV_REG_ID, CRED_REV_ID, TEST_TAILS_FILE, REV_STATE_JSON }, + get_temp_dir_path + }; + #[cfg(feature = "pool_tests")] + use time; + + fn proof_req_no_interval() -> ProofRequestData { + let proof_req = json!({ + "nonce": "123432421212", + "name": "proof_req_1", + "version": "0.1", + "requested_attributes": { + "address1_1": { "name": "address1" }, + "zip_2": { "name": "zip" }, + "height_1": { "name": "height" } + }, + "requested_predicates": {}, + }).to_string(); + + serde_json::from_str(&proof_req).unwrap() + } #[test] fn test_create_proof() { @@ -499,7 +692,7 @@ mod tests { fn test_proof_cycle() { init!("true"); - let connection_h = connection::build_connection("test_send_credential_offer").unwrap(); + let connection_h = connection::tests::build_test_connection(); let requests = get_proof_request_messages(connection_h, None).unwrap(); let requests:Value = serde_json::from_str(&requests).unwrap(); @@ -539,12 +732,35 @@ mod tests { #[test] fn test_find_schemas() { init!("true"); - let cred1 = ("height_1".to_string(), LICENCE_CRED_ID.to_string(), SCHEMA_ID.to_string(), CRED_DEF_ID.to_string() ); - let cred2 = ("zip_2".to_string(), ADDRESS_CRED_ID.to_string(), ADDRESS_SCHEMA_ID.to_string(), ADDRESS_CRED_DEF_ID.to_string() ); - let creds = vec![cred1, cred2]; let proof: DisclosedProof = Default::default(); - let schemas = proof._find_schemas(&creds).unwrap(); + assert_eq!(proof.build_schemas_json(&Vec::new()), Ok("{}".to_string())); + + let cred1 = CredInfo { + requested_attr: "height_1".to_string(), + referent: LICENCE_CRED_ID.to_string(), + schema_id: SCHEMA_ID.to_string(), + cred_def_id: CRED_DEF_ID.to_string(), + rev_reg_id: Some(REV_REG_ID.to_string()), + cred_rev_id: Some(CRED_REV_ID.to_string()), + revocation_interval: None, + tails_file: None, + timestamp: None, + }; + let cred2 = CredInfo { + requested_attr: "zip_2".to_string(), + referent: ADDRESS_CRED_ID.to_string(), + schema_id: ADDRESS_SCHEMA_ID.to_string(), + cred_def_id: ADDRESS_CRED_DEF_ID.to_string(), + rev_reg_id: Some(ADDRESS_REV_REG_ID.to_string()), + cred_rev_id: Some(ADDRESS_CRED_REV_ID.to_string()), + revocation_interval: None, + tails_file: None, + timestamp: None, + }; + let creds = vec![cred1, cred2]; + + let schemas = proof.build_schemas_json(&creds).unwrap(); assert!(schemas.len() > 0); assert!(schemas.contains(r#""id":"2hoqvcwupRTUNkXn6ArYzs:2:test-licence:4.4.4","name":"test-licence""#)); } @@ -553,22 +769,51 @@ mod tests { fn test_find_schemas_fails() { init!("false"); - let mut credential_ids = Vec::new(); - credential_ids.push(("1".to_string(), "2".to_string(), "3".to_string(), "4".to_string())); + let credential_ids = vec![CredInfo { + requested_attr: "1".to_string(), + referent: "2".to_string(), + schema_id: "3".to_string(), + cred_def_id: "3".to_string(), + rev_reg_id: Some("4".to_string()), + cred_rev_id: Some("5".to_string()), + revocation_interval: None, + tails_file: None, + timestamp: None, + }]; let proof: DisclosedProof = Default::default(); - assert_eq!(proof._find_schemas(&credential_ids).err(), + assert_eq!(proof.build_schemas_json(&credential_ids).err(), Some(ProofError::InvalidSchema())); } #[test] fn test_find_credential_def() { init!("true"); - let cred1 = ("height_1".to_string(), LICENCE_CRED_ID.to_string(), SCHEMA_ID.to_string(), CRED_DEF_ID.to_string() ); - let cred2 = ("zip_2".to_string(), ADDRESS_CRED_ID.to_string(), ADDRESS_SCHEMA_ID.to_string(), ADDRESS_CRED_DEF_ID.to_string() ); + let cred1 = CredInfo { + requested_attr: "height_1".to_string(), + referent: LICENCE_CRED_ID.to_string(), + schema_id: SCHEMA_ID.to_string(), + cred_def_id: CRED_DEF_ID.to_string(), + rev_reg_id: Some(REV_REG_ID.to_string()), + cred_rev_id: Some(CRED_REV_ID.to_string()), + revocation_interval: None, + tails_file: None, + timestamp: None, + }; + let cred2 = CredInfo { + requested_attr: "zip_2".to_string(), + referent: ADDRESS_CRED_ID.to_string(), + schema_id: ADDRESS_SCHEMA_ID.to_string(), + cred_def_id: ADDRESS_CRED_DEF_ID.to_string(), + rev_reg_id: Some(ADDRESS_REV_REG_ID.to_string()), + cred_rev_id: Some(ADDRESS_CRED_REV_ID.to_string()), + revocation_interval: None, + tails_file: None, + timestamp: None, + }; let creds = vec![cred1, cred2]; let proof: DisclosedProof = Default::default(); - let credential_def = proof._find_credential_def(&creds).unwrap(); + let credential_def = proof.build_cred_def_json(&creds).unwrap(); assert!(credential_def.len() > 0); assert!(credential_def.contains(r#""id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:2471","schemaId":"2471""#)); } @@ -577,18 +822,47 @@ mod tests { fn test_find_credential_def_fails() { init!("false"); - let mut credential_ids = Vec::new(); - credential_ids.push(("1".to_string(), "2".to_string(), "3".to_string(), "4".to_string())); + let credential_ids = vec![CredInfo { + requested_attr: "1".to_string(), + referent: "2".to_string(), + schema_id: "3".to_string(), + cred_def_id: "3".to_string(), + rev_reg_id: Some("4".to_string()), + cred_rev_id: Some("5".to_string()), + revocation_interval: None, + tails_file: None, + timestamp: None, + }]; let proof: DisclosedProof = Default::default(); - assert_eq!(proof._find_credential_def(&credential_ids).err(), + assert_eq!(proof.build_cred_def_json(&credential_ids).err(), Some(ProofError::InvalidCredData())); } #[test] fn test_build_requested_credentials() { init!("true"); - let cred1 = ("height_1".to_string(), LICENCE_CRED_ID.to_string(), SCHEMA_ID.to_string(), CRED_DEF_ID.to_string() ); - let cred2 = ("zip_2".to_string(), ADDRESS_CRED_ID.to_string(), ADDRESS_SCHEMA_ID.to_string(), ADDRESS_CRED_DEF_ID.to_string() ); + let cred1 = CredInfo { + requested_attr: "height_1".to_string(), + referent: LICENCE_CRED_ID.to_string(), + schema_id: SCHEMA_ID.to_string(), + cred_def_id: CRED_DEF_ID.to_string(), + rev_reg_id: Some(REV_REG_ID.to_string()), + cred_rev_id: Some(CRED_REV_ID.to_string()), + revocation_interval: None, + tails_file: None, + timestamp: Some(800), + }; + let cred2 = CredInfo { + requested_attr: "zip_2".to_string(), + referent: ADDRESS_CRED_ID.to_string(), + schema_id: ADDRESS_SCHEMA_ID.to_string(), + cred_def_id: ADDRESS_CRED_DEF_ID.to_string(), + rev_reg_id: Some(ADDRESS_REV_REG_ID.to_string()), + cred_rev_id: Some(ADDRESS_CRED_REV_ID.to_string()), + revocation_interval: None, + tails_file: None, + timestamp: Some(800), + }; let creds = vec![cred1, cred2]; let self_attested_attrs = json!({ "self_attested_attr_3": "my self attested 1", @@ -601,14 +875,14 @@ mod tests { "self_attested_attr_4": "my self attested 2", }, "requested_attributes":{ - "height_1": {"cred_id": LICENCE_CRED_ID, "revealed": true }, - "zip_2": {"cred_id": ADDRESS_CRED_ID, "revealed": true }, + "height_1": {"cred_id": LICENCE_CRED_ID, "revealed": true, "timestamp": 800}, + "zip_2": {"cred_id": ADDRESS_CRED_ID, "revealed": true, "timestamp": 800}, }, "requested_predicates":{} }); let proof: DisclosedProof = Default::default(); - let requested_credential = proof._build_requested_credentials(&creds, &self_attested_attrs).unwrap(); + let requested_credential = proof.build_requested_credentials_json(&creds, &self_attested_attrs).unwrap(); assert_eq!(test.to_string(), requested_credential); } @@ -616,7 +890,7 @@ mod tests { fn test_get_proof_request() { init!("true"); - let connection_h = connection::build_connection("test_get_proof_request").unwrap(); + let connection_h = connection::tests::build_test_connection(); let request = get_proof_request(connection_h, "123").unwrap(); assert!(request.len() > 50); @@ -626,7 +900,7 @@ mod tests { #[test] fn test_retrieve_credentials() { init!("ledger"); - ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS); + ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, false); let (_, _, req, _) = ::utils::libindy::anoncreds::tests::create_proof(); let mut proof_req = ProofRequestMessage::create(); @@ -635,14 +909,42 @@ mod tests { proof.proof_request = Some(proof_req); let retrieved_creds = proof.retrieve_credentials().unwrap(); + println!("retrieved_creds: {}", retrieved_creds); assert!(retrieved_creds.len() > 500); } + #[cfg(feature = "pool_tests")] + #[test] + fn test_retrieve_credentials_emtpy() { + init!("ledger"); + + let mut req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({}), + }); + let mut proof_req = ProofRequestMessage::create(); + let mut proof: DisclosedProof = Default::default(); + proof_req.proof_request_data = serde_json::from_str(&req.to_string()).unwrap(); + proof.proof_request = Some(proof_req.clone()); + + let retrieved_creds = proof.retrieve_credentials().unwrap(); + assert_eq!(retrieved_creds, "{}".to_string()); + + req["requested_attributes"]["address1_1"] = json!({"name": "address1"}); + proof_req.proof_request_data = serde_json::from_str(&req.to_string()).unwrap(); + proof.proof_request = Some(proof_req); + let retrieved_creds = proof.retrieve_credentials().unwrap(); + assert_eq!(retrieved_creds, json!({"attrs":{"address1_1":[]}}).to_string()); + } + #[cfg(feature = "pool_tests")] #[test] fn test_case_for_proof_req_doesnt_matter_for_retrieve_creds() { init!("ledger"); - ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS); + ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, false); let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let mut req = json!({ "nonce":"123432421212", @@ -692,50 +994,178 @@ mod tests { #[test] fn test_credential_def_identifiers() { - let cred1 = ("height_1".to_string(), LICENCE_CRED_ID.to_string(), SCHEMA_ID.to_string(), CRED_DEF_ID.to_string() ); - let cred2 = ("zip_2".to_string(), ADDRESS_CRED_ID.to_string(), ADDRESS_SCHEMA_ID.to_string(), ADDRESS_CRED_DEF_ID.to_string() ); + let cred1 = CredInfo { + requested_attr: "height_1".to_string(), + referent: LICENCE_CRED_ID.to_string(), + schema_id: SCHEMA_ID.to_string(), + cred_def_id: CRED_DEF_ID.to_string(), + rev_reg_id: Some(REV_REG_ID.to_string()), + cred_rev_id: Some(CRED_REV_ID.to_string()), + revocation_interval: Some(NonRevokedInterval { from: Some(123), to: Some(456) }), + tails_file: Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()), + timestamp: None, + }; + let cred2 = CredInfo { + requested_attr: "zip_2".to_string(), + referent: ADDRESS_CRED_ID.to_string(), + schema_id: ADDRESS_SCHEMA_ID.to_string(), + cred_def_id: ADDRESS_CRED_DEF_ID.to_string(), + rev_reg_id: Some(ADDRESS_REV_REG_ID.to_string()), + cred_rev_id: Some(ADDRESS_CRED_REV_ID.to_string()), + revocation_interval: Some(NonRevokedInterval { from: None, to: Some(987) }), + tails_file: None, + timestamp: None, + }; let selected_credentials : Value = json!({ "attrs":{ "height_1":{ - "cred_info":{ - "referent":LICENCE_CRED_ID, - "attrs":{ - "sex":"male", - "age":"111", - "name":"Bob", - "height":"4'11" - }, - "schema_id": SCHEMA_ID, - "cred_def_id": CRED_DEF_ID, - "rev_reg_id":null, - "cred_rev_id":null + "credential": { + "cred_info":{ + "referent":LICENCE_CRED_ID, + "attrs":{ + "sex":"male", + "age":"111", + "name":"Bob", + "height":"4'11" + }, + "schema_id": SCHEMA_ID, + "cred_def_id": CRED_DEF_ID, + "rev_reg_id":REV_REG_ID, + "cred_rev_id":CRED_REV_ID + }, + "interval":null }, - "interval":null + "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string(), }, "zip_2":{ - "cred_info":{ - "referent":ADDRESS_CRED_ID, - "attrs":{ - "address1":"101 Tela Lane", - "address2":"101 Wilson Lane", - "zip":"87121", - "state":"UT", - "city":"SLC" - }, - "schema_id":ADDRESS_SCHEMA_ID, - "cred_def_id":ADDRESS_CRED_DEF_ID, - "rev_reg_id":null, - "cred_rev_id":null + "credential": { + "cred_info":{ + "referent":ADDRESS_CRED_ID, + "attrs":{ + "address1":"101 Tela Lane", + "address2":"101 Wilson Lane", + "zip":"87121", + "state":"UT", + "city":"SLC" + }, + "schema_id":ADDRESS_SCHEMA_ID, + "cred_def_id":ADDRESS_CRED_DEF_ID, + "rev_reg_id":ADDRESS_REV_REG_ID, + "cred_rev_id":ADDRESS_CRED_REV_ID + }, + "interval":null }, - "interval":null } }, + "predicates":{ } + }); + let proof_req = json!({ + "nonce": "123432421212", + "name": "proof_req_1", + "version": "0.1", + "requested_attributes": { + "zip_2": { "name": "zip" }, + "height_1": { "name": "height", "non_revoked": {"from": 123, "to": 456} } + }, + "requested_predicates": {}, + "non_revoked": {"to": 987} + }).to_string(); + + let creds = credential_def_identifiers(&selected_credentials.to_string(), &serde_json::from_str(&proof_req).unwrap()).unwrap(); + assert_eq!(creds, vec![cred1, cred2]); + } + + #[test] + fn test_credential_def_identifiers_failure() { + // selected credentials has incorrect json + assert_eq!(credential_def_identifiers("", &proof_req_no_interval()), Err(ProofError::InvalidJson())); + + + // No Creds + assert_eq!(credential_def_identifiers("{}", &proof_req_no_interval()), Ok(Vec::new())); + assert_eq!(credential_def_identifiers(r#"{"attrs":{}}"#, &proof_req_no_interval()), Ok(Vec::new())); + + // missing cred info + let selected_credentials : Value = json!({ + "attrs":{ + "height_1":{ "interval":null } + }, "predicates":{ } }); - let creds = credential_def_identifiers(&selected_credentials.to_string()).unwrap(); - assert_eq!(creds, vec![cred1, cred2]); + assert_eq!(credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()), Err(ProofError::InvalidCredData())); + + // Optional Revocation + let mut selected_credentials : Value = json!({ + "attrs":{ + "height_1":{ + "credential": { + "cred_info":{ + "referent":LICENCE_CRED_ID, + "attrs":{ + "sex":"male", + "age":"111", + "name":"Bob", + "height":"4'11" + }, + "schema_id": SCHEMA_ID, + "cred_def_id": CRED_DEF_ID, + "cred_rev_id":CRED_REV_ID + }, + "interval":null + }, + "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string(), + }, + }, + "predicates":{ } + }); + let creds = vec![CredInfo { + requested_attr: "height_1".to_string(), + referent: LICENCE_CRED_ID.to_string(), + schema_id: SCHEMA_ID.to_string(), + cred_def_id: CRED_DEF_ID.to_string(), + rev_reg_id: None, + cred_rev_id: Some(CRED_REV_ID.to_string()), + revocation_interval: None, + tails_file: Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()), + timestamp: None, + }]; + assert_eq!(&credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()).unwrap(), &creds); + + // rev_reg_id is null + selected_credentials["attrs"]["height_1"]["cred_info"]["rev_reg_id"] = serde_json::Value::Null; + assert_eq!(&credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()).unwrap(), &creds); + + // Missing schema ID + let mut selected_credentials : Value = json!({ + "attrs":{ + "height_1":{ + "credential": { + "cred_info":{ + "referent":LICENCE_CRED_ID, + "attrs":{ + "sex":"male", + "age":"111", + "name":"Bob", + "height":"4'11" + }, + "cred_def_id": CRED_DEF_ID, + "rev_reg_id":REV_REG_ID, + "cred_rev_id":CRED_REV_ID + }, + "interval":null + }, + "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string() + }, + }, + "predicates":{ } + }); + assert_eq!(credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()), Err(ProofError::InvalidCredData())); + + // Schema Id is null + selected_credentials["attrs"]["height_1"]["cred_info"]["schema_id"] = serde_json::Value::Null; + assert_eq!(credential_def_identifiers(&selected_credentials.to_string(), &proof_req_no_interval()), Err(ProofError::InvalidCredData())); } #[cfg(feature = "pool_tests")] @@ -743,65 +1173,44 @@ mod tests { fn test_generate_proof() { init!("ledger"); let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); - let (schema_id, _, cred_def_id, _, _, _, _, cred_id) = ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS); - + let (schema_id, _, cred_def_id, _, _, _, _, cred_id, _, _) = ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, true); let mut proof_req = ProofRequestMessage::create(); + let to = time::get_time().sec; let indy_proof_req = json!({ - "nonce":"123432421212", - "name":"proof_req_1", - "version":"0.1", - "requested_attributes": json!({ - "address1_1": json!({ - "name":"address1", - "restrictions": [json!({ "issuer_did": did })] - }), - "zip_2": json!({ - "name":"zip", - "restrictions": [json!({ "issuer_did": did })] - }), - "self_attested_attr_3": json!({ + "nonce": "123432421212", + "name": "proof_req_1", + "version": "0.1", + "requested_attributes": { + "address1_1": { + "name": "address1", + "restrictions": [{"issuer_did": did}], + "non_revoked": {"from": 123, "to": to} + }, + "zip_2": { "name": "zip" } + }, + "self_attested_attr_3": json!({ "name":"self_attested_attr", - }), - }), - "requested_predicates": json!({}), + }), + "requested_predicates": {}, + "non_revoked": {"from": 098, "to": to} }).to_string(); proof_req.proof_request_data = serde_json::from_str(&indy_proof_req).unwrap(); + let mut proof: DisclosedProof = Default::default(); + proof.proof_request = Some(proof_req); + proof.link_secret_alias = "main".to_string(); + + let all_creds: Value = serde_json::from_str(&proof.retrieve_credentials().unwrap()).unwrap(); let selected_credentials : Value = json!({ "attrs":{ - "address1_1":{ - "cred_info":{ - "referent":cred_id, - "attrs":{ - "sex":"male", - "age":"111", - "name":"Bob", - "height":"4'11" - }, - "schema_id": schema_id, - "cred_def_id": cred_def_id, - "rev_reg_id":null, - "cred_rev_id":null - }, - "interval":null + "address1_1": { + "credential": all_creds["attrs"]["address1_1"][0], + "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string() + }, + "zip_2": { + "credential": all_creds["attrs"]["zip_2"][0], + "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string() }, - "zip_2":{ - "cred_info":{ - "referent":cred_id, - "attrs":{ - "address1":"101 Tela Lane", - "address2":"101 Wilson Lane", - "zip":"87121", - "state":"UT", - "city":"SLC" - }, - "schema_id":schema_id, - "cred_def_id":cred_def_id, - "rev_reg_id":null, - "cred_rev_id":null - }, - "interval":null - } }, "predicates":{ } }); @@ -810,11 +1219,7 @@ mod tests { "self_attested_attr_3":"attested_val" }); - let mut proof: DisclosedProof = Default::default(); - proof.proof_request = Some(proof_req); - proof.link_secret_alias = "main".to_string(); let generated_proof = proof.generate_proof(&selected_credentials.to_string(), &self_attested.to_string()); - assert!(generated_proof.is_ok()); } @@ -855,4 +1260,288 @@ mod tests { assert!(generated_proof.is_ok()); } + + #[test] + fn test_build_rev_states_json() { + init!("true"); + + let cred1 = CredInfo { + requested_attr: "height".to_string(), + referent: "abc".to_string(), + schema_id: SCHEMA_ID.to_string(), + cred_def_id: CRED_DEF_ID.to_string(), + rev_reg_id: Some(REV_REG_ID.to_string()), + cred_rev_id: Some(CRED_REV_ID.to_string()), + tails_file: Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()), + revocation_interval: None, + timestamp: None, + }; + let mut cred_info = vec![cred1]; + let states = build_rev_states_json(cred_info.as_mut()).unwrap(); + let rev_state_json: Value = serde_json::from_str(REV_STATE_JSON).unwrap(); + let expected = json!({REV_REG_ID: {"1": rev_state_json}}).to_string(); + assert_eq!(states, expected); + assert!(cred_info[0].timestamp.is_some()); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_build_rev_states_json_empty() { + init!("ledger"); + + // empty vector + assert_eq!(build_rev_states_json(Vec::new().as_mut()), Ok("{}".to_string())); + + // no rev_reg_id + let cred1 = CredInfo { + requested_attr: "height_1".to_string(), + referent: LICENCE_CRED_ID.to_string(), + schema_id: SCHEMA_ID.to_string(), + cred_def_id: CRED_DEF_ID.to_string(), + rev_reg_id: None, + cred_rev_id: Some(CRED_REV_ID.to_string()), + tails_file: Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()), + revocation_interval: None, + timestamp: None, + }; + assert_eq!(build_rev_states_json(vec![cred1].as_mut()), Ok("{}".to_string())); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_build_rev_states_json_real_no_cache() { + init!("ledger"); + + let attrs = r#"["address1","address2","city","state","zip"]"#; + let (schema_id, _, cred_def_id, _, _, _, _, cred_id, rev_reg_id, cred_rev_id) = + ::utils::libindy::anoncreds::tests::create_and_store_credential(attrs, true); + let cred2 = CredInfo { + requested_attr: "height".to_string(), + referent: cred_id, + schema_id, + cred_def_id, + rev_reg_id: rev_reg_id.clone(), + cred_rev_id: cred_rev_id, + tails_file: Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()), + revocation_interval: None, + timestamp: None, + }; + let rev_reg_id = rev_reg_id.unwrap(); + + // assert cache is empty + let cache = get_rev_reg_cache(&rev_reg_id); + assert_eq!(cache.rev_state, None); + + let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id).unwrap(); + let states = build_rev_states_json(vec![cred2].as_mut()).unwrap(); + assert!(states.contains(&rev_reg_id)); + + // check if this value is in cache now. + let states: Value = serde_json::from_str(&states).unwrap(); + let state: HashMap = serde_json::from_value(states[&rev_reg_id].clone()).unwrap(); + + let cache = get_rev_reg_cache(&rev_reg_id); + let cache_rev_state = cache.rev_state.unwrap(); + let cache_rev_state_value: Value = serde_json::from_str(&cache_rev_state.value).unwrap(); + assert_eq!(cache_rev_state.timestamp, state.keys().next().unwrap().parse::().unwrap()); + assert_eq!(cache_rev_state_value.to_string(), state.values().next().unwrap().to_string()); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_build_rev_states_json_real_cached() { + init!("ledger"); + + let current_timestamp = time::get_time().sec as u64; + let cached_rev_state = "{\"some\": \"json\"}".to_string(); + + let attrs = r#"["address1","address2","city","state","zip"]"#; + let (schema_id, _, cred_def_id, _, _, _, _, cred_id, rev_reg_id, cred_rev_id) = + ::utils::libindy::anoncreds::tests::create_and_store_credential(attrs, true); + let cred2 = CredInfo { + requested_attr: "height".to_string(), + referent: cred_id, + schema_id, + cred_def_id, + rev_reg_id: rev_reg_id.clone(), + cred_rev_id: cred_rev_id, + tails_file: Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()), + revocation_interval: None, + timestamp: None, + }; + let rev_reg_id = rev_reg_id.unwrap(); + + let cached_data = RevRegCache { + rev_state: Some(RevState { + timestamp: current_timestamp, + value: cached_rev_state.clone() + }) + }; + set_rev_reg_cache(&rev_reg_id, &cached_data); + + // assert data is successfully cached. + let cache = get_rev_reg_cache(&rev_reg_id); + assert_eq!(cache, cached_data); + + let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id).unwrap(); + let states = build_rev_states_json(vec![cred2].as_mut()).unwrap(); + assert!(states.contains(&rev_reg_id)); + + // assert cached data is unchanged. + let cache = get_rev_reg_cache(&rev_reg_id); + assert_eq!(cache, cached_data); + + // check if this value is in cache now. + let states: Value = serde_json::from_str(&states).unwrap(); + let state: HashMap = serde_json::from_value(states[&rev_reg_id].clone()).unwrap(); + + let cache_rev_state = cache.rev_state.unwrap(); + let cache_rev_state_value: Value = serde_json::from_str(&cache_rev_state.value).unwrap(); + assert_eq!(cache_rev_state.timestamp, state.keys().next().unwrap().parse::().unwrap()); + assert_eq!(cache_rev_state_value.to_string(), state.values().next().unwrap().to_string()); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_build_rev_states_json_real_with_older_cache() { + init!("ledger"); + + let current_timestamp = time::get_time().sec as u64; + let cached_timestamp = current_timestamp - 100; + let cached_rev_state = "{\"witness\":{\"omega\":\"2 0BB3DE371F14384496D1F4FEB47B86A935C858BC21033B16251442FCBC5370A1 2 026F2848F2972B74079BEE16CDA9D48AD2FF7C7E39087515CB9B6E9B38D73BCB 2 10C48056D8C226141A8D7030E9FA17B7F02A39B414B9B64B6AECDDA5AFD1E538 2 11DCECD73A8FA6CFCD0468C659C2F845A9215842B69BA10355C1F4BF2D9A9557 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000\"},\"rev_reg\":{\"accum\":\"2 033C0E6FAC660DF3582EF46021FAFDD93E111D1DC9DA59C4EA9B92BB21F8E0A4 2 02E0F749312228A93CF67BB5F86CA263FAE535A0F1CA449237D736939518EFF0 2 19BB82474D0BD0A1DDE72D377C8A965D6393071118B79D4220D4C9B93D090314 2 1895AAFD8050A8FAE4A93770C6C82881AB13134EE082C64CF6A7A379B3F6B217 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000\"},\"timestamp\":100}".to_string(); + + let attrs = r#"["address1","address2","city","state","zip"]"#; + let (schema_id, _, cred_def_id, _, _, _, _, cred_id, rev_reg_id, cred_rev_id) = + ::utils::libindy::anoncreds::tests::create_and_store_credential(attrs, true); + let cred2 = CredInfo { + requested_attr: "height".to_string(), + referent: cred_id, + schema_id, + cred_def_id, + rev_reg_id: rev_reg_id.clone(), + cred_rev_id: cred_rev_id, + tails_file: Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()), + revocation_interval: Some(NonRevokedInterval{from: Some(cached_timestamp + 1), to: None}), + timestamp: None, + }; + let rev_reg_id = rev_reg_id.unwrap(); + + let cached_data = RevRegCache { + rev_state: Some(RevState { + timestamp: cached_timestamp, + value: cached_rev_state.clone() + }) + }; + set_rev_reg_cache(&rev_reg_id, &cached_data); + + // assert data is successfully cached. + let cache = get_rev_reg_cache(&rev_reg_id); + assert_eq!(cache, cached_data); + + let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id).unwrap(); + let states = build_rev_states_json(vec![cred2].as_mut()).unwrap(); + assert!(states.contains(&rev_reg_id)); + + // assert cached data is updated. + let cache = get_rev_reg_cache(&rev_reg_id); + assert_ne!(cache, cached_data); + + // check if this value is in cache now. + let states: Value = serde_json::from_str(&states).unwrap(); + let state: HashMap = serde_json::from_value(states[&rev_reg_id].clone()).unwrap(); + + let cache_rev_state = cache.rev_state.unwrap(); + let cache_rev_state_value: Value = serde_json::from_str(&cache_rev_state.value).unwrap(); + assert_eq!(cache_rev_state.timestamp, state.keys().next().unwrap().parse::().unwrap()); + assert_eq!(cache_rev_state_value.to_string(), state.values().next().unwrap().to_string()); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_build_rev_states_json_real_with_newer_cache() { + init!("ledger"); + + let current_timestamp = time::get_time().sec as u64; + let cached_timestamp = current_timestamp + 100; + let cached_rev_state = "{\"witness\":{\"omega\":\"2 0BB3DE371F14384496D1F4FEB47B86A935C858BC21033B16251442FCBC5370A1 2 026F2848F2972B74079BEE16CDA9D48AD2FF7C7E39087515CB9B6E9B38D73BCB 2 10C48056D8C226141A8D7030E9FA17B7F02A39B414B9B64B6AECDDA5AFD1E538 2 11DCECD73A8FA6CFCD0468C659C2F845A9215842B69BA10355C1F4BF2D9A9557 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000\"},\"rev_reg\":{\"accum\":\"2 033C0E6FAC660DF3582EF46021FAFDD93E111D1DC9DA59C4EA9B92BB21F8E0A4 2 02E0F749312228A93CF67BB5F86CA263FAE535A0F1CA449237D736939518EFF0 2 19BB82474D0BD0A1DDE72D377C8A965D6393071118B79D4220D4C9B93D090314 2 1895AAFD8050A8FAE4A93770C6C82881AB13134EE082C64CF6A7A379B3F6B217 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000\"},\"timestamp\":100}".to_string(); + + let attrs = r#"["address1","address2","city","state","zip"]"#; + let (schema_id, _, cred_def_id, _, _, _, _, cred_id, rev_reg_id, cred_rev_id) = + ::utils::libindy::anoncreds::tests::create_and_store_credential(attrs, true); + let cred2 = CredInfo { + requested_attr: "height".to_string(), + referent: cred_id, + schema_id, + cred_def_id, + rev_reg_id: rev_reg_id.clone(), + cred_rev_id: cred_rev_id, + tails_file: Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()), + revocation_interval: Some(NonRevokedInterval{from: None, to: Some(cached_timestamp - 1)}), + timestamp: None, + }; + let rev_reg_id = rev_reg_id.unwrap(); + + let cached_data = RevRegCache { + rev_state: Some(RevState { + timestamp: cached_timestamp, + value: cached_rev_state.clone() + }) + }; + set_rev_reg_cache(&rev_reg_id, &cached_data); + + // assert data is successfully cached. + let cache = get_rev_reg_cache(&rev_reg_id); + assert_eq!(cache, cached_data); + + let (_, rev_reg_def_json) = get_rev_reg_def_json(&rev_reg_id).unwrap(); + let states = build_rev_states_json(vec![cred2].as_mut()).unwrap(); + assert!(states.contains(&rev_reg_id)); + + // assert cached data is unchanged. + let cache = get_rev_reg_cache(&rev_reg_id); + assert_eq!(cache, cached_data); + + // check if this value is not in cache. + let states: Value = serde_json::from_str(&states).unwrap(); + let state: HashMap = serde_json::from_value(states[&rev_reg_id].clone()).unwrap(); + + let cache_rev_state = cache.rev_state.unwrap(); + let cache_rev_state_value: Value = serde_json::from_str(&cache_rev_state.value).unwrap(); + assert_ne!(cache_rev_state.timestamp, state.keys().next().unwrap().parse::().unwrap()); + assert_ne!(cache_rev_state_value.to_string(), state.values().next().unwrap().to_string()); + } + + #[test] + fn test_get_credential_intervals_from_proof_req() { + + let proof_req = json!({ + "nonce": "123432421212", + "name": "proof_req_1", + "version": "0.1", + "requested_attributes": { + "address1_1": { + "name": "address1", + "non_revoked": {"from": 123, "to": 456} + }, + "zip_2": { "name": "zip" } + }, + "requested_predicates": {}, + "non_revoked": {"from": 098, "to": 123} + }); + let proof_req: ProofRequestData = serde_json::from_value(proof_req).unwrap(); + + // Attribute not found in proof req + assert_eq!(_get_revocation_interval("not here", &proof_req), Err(ProofError::InvalidCredData())); + + // attribute interval overrides proof request interval + let interval = Some(NonRevokedInterval {from: Some(123), to: Some(456)}); + assert_eq!(_get_revocation_interval("address1_1", &proof_req), Ok(interval)); + + // when attribute interval is None, defaults to proof req interval + let interval = Some(NonRevokedInterval {from: Some(098), to: Some(123)}); + assert_eq!(_get_revocation_interval("zip_2", &proof_req), Ok(interval)); + + // No interval provided for attribute or proof req + assert_eq!(_get_revocation_interval("address1_1", &proof_req_no_interval()), Ok(None)); + } } diff --git a/vcx/libvcx/src/error/cred_def.rs b/vcx/libvcx/src/error/cred_def.rs index fcd17ede..ca459d07 100644 --- a/vcx/libvcx/src/error/cred_def.rs +++ b/vcx/libvcx/src/error/cred_def.rs @@ -1,6 +1,8 @@ use std::fmt; use error::ToErrorCode; -use utils::error::{NO_PAYMENT_INFORMATION, INVALID_CREDENTIAL_DEF_HANDLE, BUILD_CREDENTIAL_DEF_REQ_ERR, CREDENTIAL_DEF_ALREADY_CREATED, CREATE_CREDENTIAL_DEF_ERR }; +use utils::error::{NO_PAYMENT_INFORMATION, INVALID_CREDENTIAL_DEF_HANDLE, BUILD_CREDENTIAL_DEF_REQ_ERR, + CREDENTIAL_DEF_ALREADY_CREATED, CREATE_CREDENTIAL_DEF_ERR, INVALID_REVOCATION_DETAILS, + INVALID_REV_REG_DEF_CREATION, INVALID_REV_ENTRY}; #[derive(Debug)] pub enum CredDefError { @@ -12,6 +14,9 @@ pub enum CredDefError { SchemaError(String), NoPaymentInformation(), CommonError(u32), + InvalidRevocationDetails(), + InvalidRevocationEntry(), + CreateRevRegDefError(), } impl fmt::Display for CredDefError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -24,6 +29,9 @@ impl fmt::Display for CredDefError { CredDefError::CreateCredDefError() => write!(f, "{}", CREATE_CREDENTIAL_DEF_ERR.message ), CredDefError::NoPaymentInformation() => write!(f, "{}", NO_PAYMENT_INFORMATION.message ), CredDefError::CredDefAlreadyCreatedError() => write!(f, "{}", CREDENTIAL_DEF_ALREADY_CREATED.message ), + CredDefError::InvalidRevocationDetails() => write!(f, "{}", INVALID_REVOCATION_DETAILS.message ), + CredDefError::CreateRevRegDefError() => write!(f, "{}", INVALID_REV_REG_DEF_CREATION.message ), + CredDefError::InvalidRevocationEntry() => write!(f, "{}", INVALID_REV_ENTRY.message ), } } } @@ -37,6 +45,9 @@ impl ToErrorCode for CredDefError { CredDefError::CreateCredDefError() => CREATE_CREDENTIAL_DEF_ERR.code_num, CredDefError::NoPaymentInformation() => NO_PAYMENT_INFORMATION.code_num, CredDefError::CredDefAlreadyCreatedError() => CREDENTIAL_DEF_ALREADY_CREATED.code_num, + CredDefError::InvalidRevocationDetails() => INVALID_REVOCATION_DETAILS.code_num, + CredDefError::CreateRevRegDefError() => INVALID_REV_REG_DEF_CREATION.code_num, + CredDefError::InvalidRevocationEntry() => INVALID_REV_ENTRY.code_num, CredDefError::CommonError(x) => x, } } diff --git a/vcx/libvcx/src/error/issuer_cred.rs b/vcx/libvcx/src/error/issuer_cred.rs index aea76b15..1496b229 100644 --- a/vcx/libvcx/src/error/issuer_cred.rs +++ b/vcx/libvcx/src/error/issuer_cred.rs @@ -1,5 +1,5 @@ use std::fmt; -use utils::error::{NO_PAYMENT_INFORMATION, OBJECT_CACHE_ERROR, INVALID_CREDENTIAL_JSON, NOT_READY, INVALID_ISSUER_CREDENTIAL_HANDLE, INVALID_CREDENTIAL_REQUEST, INVALID_JSON}; +use utils::error::{INVALID_REVOCATION_DETAILS, NO_PAYMENT_INFORMATION, OBJECT_CACHE_ERROR, INVALID_CREDENTIAL_JSON, NOT_READY, INVALID_ISSUER_CREDENTIAL_HANDLE, INVALID_CREDENTIAL_REQUEST, INVALID_JSON}; use error::ToErrorCode; use serde_json; @@ -13,6 +13,7 @@ pub enum IssuerCredError { InvalidCred(), NoPaymentInformation(), InvalidJson(), + InvalidRevocationInfo(), } impl fmt::Display for IssuerCredError { @@ -26,6 +27,7 @@ impl fmt::Display for IssuerCredError { IssuerCredError::InvalidJson() => write!(f, "{}", INVALID_JSON.message), IssuerCredError::NoPaymentInformation() => write!(f, "{}", NO_PAYMENT_INFORMATION.message), IssuerCredError::CreateError() => write!(f, "Could not create issuer credential"), + IssuerCredError::InvalidRevocationInfo() => write!(f, "{}",INVALID_REVOCATION_DETAILS.message), } } } @@ -39,6 +41,7 @@ impl ToErrorCode for IssuerCredError { IssuerCredError::InvalidCred() => INVALID_CREDENTIAL_JSON.code_num, IssuerCredError::CreateError() => OBJECT_CACHE_ERROR.code_num, IssuerCredError::NoPaymentInformation() => NO_PAYMENT_INFORMATION.code_num, + IssuerCredError::InvalidRevocationInfo() => INVALID_REVOCATION_DETAILS.code_num, IssuerCredError::CommonError(x) => x, } } diff --git a/vcx/libvcx/src/error/proof.rs b/vcx/libvcx/src/error/proof.rs index 6d63b7cf..2708530a 100644 --- a/vcx/libvcx/src/error/proof.rs +++ b/vcx/libvcx/src/error/proof.rs @@ -1,7 +1,7 @@ use std::fmt; use error::ToErrorCode; use utils::error::{INVALID_JSON, INVALID_PROOF_HANDLE, INVALID_PROOF, INVALID_PROOF_CREDENTIAL_DATA, INVALID_SCHEMA, -NOT_READY, INVALID_CONNECTION_HANDLE, CONNECTION_ERROR, FAILED_PROOF_COMPLIANCE, CREATE_PROOF_ERROR }; +NOT_READY, INVALID_CONNECTION_HANDLE, CONNECTION_ERROR, FAILED_PROOF_COMPLIANCE, CREATE_PROOF_ERROR, INVALID_REVOCATION_TIMESTAMP, INVALID_REVOCATION_DETAILS}; #[derive(Debug)] @@ -10,14 +10,15 @@ pub enum ProofError{ InvalidProof(), InvalidCredData(), InvalidSchema(), + InvalidRevocationInfo(), ProofNotReadyError(), ProofMessageError(u32), ProofConnectionError(), - // TODO: this could take a parameter CreateProofError(), InvalidConnection(), FailedProofCompliance(), InvalidJson(), + InvalidTimestamp(), CommonError(u32), } @@ -35,6 +36,8 @@ impl fmt::Display for ProofError { ProofError::CreateProofError() => write!(f, "{}", CREATE_PROOF_ERROR.message), ProofError::ProofMessageError(x) => write!(f, "Proof Error: Message Error value: , {}", x), ProofError::InvalidJson() => write!(f, "{}", INVALID_JSON.message), + ProofError::InvalidTimestamp() => write!(f, "{}", INVALID_REVOCATION_TIMESTAMP.message), + ProofError::InvalidRevocationInfo() => write!(f, "{}",INVALID_REVOCATION_DETAILS.message), ProofError::CommonError(x) => write!(f, "This Proof Error Common Error had value: {}", x), } } @@ -53,12 +56,14 @@ impl ToErrorCode for ProofError { ProofError::InvalidProof() => INVALID_PROOF.code_num, ProofError::InvalidSchema() => INVALID_SCHEMA.code_num, ProofError::InvalidCredData() => INVALID_PROOF_CREDENTIAL_DATA.code_num, + ProofError::InvalidRevocationInfo() => INVALID_REVOCATION_DETAILS.code_num, ProofError::InvalidConnection() => CONNECTION_ERROR.code_num, ProofError::CreateProofError() => CREATE_PROOF_ERROR.code_num, ProofError::ProofNotReadyError() => NOT_READY.code_num, ProofError::ProofConnectionError() => INVALID_CONNECTION_HANDLE.code_num, ProofError::FailedProofCompliance() => FAILED_PROOF_COMPLIANCE.code_num, ProofError::InvalidJson() => INVALID_JSON.code_num, + ProofError::InvalidTimestamp() => INVALID_REVOCATION_TIMESTAMP.code_num, ProofError::ProofMessageError(x) => x, ProofError::CommonError(x) => x, } diff --git a/vcx/libvcx/src/error/schema.rs b/vcx/libvcx/src/error/schema.rs index 6daad330..b9ff8b07 100644 --- a/vcx/libvcx/src/error/schema.rs +++ b/vcx/libvcx/src/error/schema.rs @@ -1,12 +1,12 @@ use std::fmt; use error::ToErrorCode; -use utils::error::{NO_PAYMENT_INFORMATION, INVALID_SCHEMA_CREATION, INVALID_SCHEMA_HANDLE, INVALID_SCHEMA_SEQ_NO}; +use utils::error::{NO_PAYMENT_INFORMATION, INVALID_SCHEMA_CREATION, INVALID_SCHEMA_HANDLE, INVALID_SCHEMA_SEQ_NO, DUPLICATE_SCHEMA, UNKNOWN_SCHEMA_REJECTION}; #[derive(Debug)] pub enum SchemaError { InvalidSchemaCreation(), InvalidHandle(), InvalidSchemaSeqNo(), - DuplicateSchema(String), + DuplicateSchema(), UnknownRejection(), NoPaymentInformation(), CommonError(u32), @@ -19,8 +19,8 @@ impl ToErrorCode for SchemaError { SchemaError::InvalidHandle() => INVALID_SCHEMA_HANDLE.code_num, SchemaError::InvalidSchemaSeqNo() => INVALID_SCHEMA_SEQ_NO.code_num, SchemaError::NoPaymentInformation() => NO_PAYMENT_INFORMATION.code_num, - SchemaError::UnknownRejection() => 8887, - SchemaError::DuplicateSchema(ref s) => 8888, + SchemaError::UnknownRejection() => UNKNOWN_SCHEMA_REJECTION.code_num, + SchemaError::DuplicateSchema() => DUPLICATE_SCHEMA.code_num, SchemaError::CommonError(x) => x, } } @@ -33,8 +33,8 @@ impl fmt::Display for SchemaError { SchemaError::InvalidHandle() => write!(f, "{}", INVALID_SCHEMA_HANDLE.message), SchemaError::InvalidSchemaSeqNo() => write!(f, "{}", INVALID_SCHEMA_SEQ_NO.message), SchemaError::NoPaymentInformation() => write!(f, "{}", NO_PAYMENT_INFORMATION.message), - SchemaError::UnknownRejection() => write!(f, "Unknown Rejection of Schema Creation, refer to libindy documentation."), - SchemaError::DuplicateSchema(ref s) => write!(f, "{}", s), + SchemaError::UnknownRejection() => write!(f, "{}", UNKNOWN_SCHEMA_REJECTION.code_num), + SchemaError::DuplicateSchema() => write!(f, "{}", DUPLICATE_SCHEMA.message), SchemaError::CommonError(x) => write!(f, "This Schema Common Error had a value of {}", x), } } diff --git a/vcx/libvcx/src/issuer_credential.rs b/vcx/libvcx/src/issuer_credential.rs index 2a6fd3fe..56cdf1ec 100644 --- a/vcx/libvcx/src/issuer_credential.rs +++ b/vcx/libvcx/src/issuer_credential.rs @@ -2,18 +2,20 @@ extern crate rand; extern crate serde_json; extern crate libc; +use std::collections::HashMap; use api::VcxStateType; use messages; use settings; use messages::{ GeneralMessage, MessageResponseCode::MessageAccepted, send_message::parse_msg_uid }; use connection; use credential_request::{ CredentialRequest }; -use utils::{error, - error::INVALID_JSON, - libindy::{ anoncreds::{ libindy_issuer_create_credential, libindy_issuer_create_credential_offer}, payments }, - constants::CRED_MSG, - openssl::encode -}; +use utils::error; +use utils::error::{INVALID_JSON}; +use utils::libindy::payments; +use utils::libindy::anoncreds; +use utils::constants::CRED_MSG; +use utils::openssl::encode; +use utils::libindy::payments::{PaymentTxn}; use error::{ issuer_cred::IssuerCredError, ToErrorCode, payment::PaymentError}; use utils::constants::DEFAULT_SERIALIZE_VERSION; use serde_json::Value; @@ -38,7 +40,18 @@ pub struct IssuerCredential { credential_name: String, pub credential_id: String, pub cred_def_id: String, + pub cred_def_handle: u32, ref_msg_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + rev_reg_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + tails_file: Option, + #[serde(skip_serializing_if = "Option::is_none")] + rev_reg_def_json: Option, + #[serde(skip_serializing_if = "Option::is_none")] + cred_rev_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + rev_cred_payment_txn: Option, price: u64, payment_address: Option, // the following 6 are pulled from the connection object @@ -72,6 +85,10 @@ pub struct CredentialMessage { pub cred_def_id: String, pub msg_type: String, pub claim_offer_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub cred_revoc_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub revoc_reg_delta_json: Option, pub version: String, pub from_did: String, } @@ -103,6 +120,8 @@ impl IssuerCredential { } fn send_credential_offer(&mut self, connection_handle: u32) -> Result { + trace!("IssuerCredential::send_credential_offer >>> connection_handle: {}", connection_handle); + debug!("sending credential offer for issuer_credential {} to connection {}", self.source_id, connection::get_source_id(connection_handle).unwrap_or_default()); if self.state != VcxStateType::VcxStateInitialized { warn!("credential {} has invalid state {} for sending credentialOffer", self.source_id, self.state as u32); @@ -125,7 +144,14 @@ impl IssuerCredential { let cred_json = json!(credential_offer); let mut payload = Vec::new(); - if let Some(x) = payment { payload.push(json!(x)); } + let connection_name = settings::get_config_value(settings::CONFIG_INSTITUTION_NAME).map_err(|e| IssuerCredError::CommonError(e))?; + let title = if let Some(x) = payment { + payload.push(json!(x)); + format!("{} is offering you a credential: {}", connection_name, self.credential_name) + } else { + format!("{} wants you to pay tokens for: {}", connection_name, self.credential_name) + }; + payload.push(cred_json); let payload = match serde_json::to_string(&payload) { Ok(p) => p, @@ -143,6 +169,8 @@ impl IssuerCredential { .edge_agent_payload(&data) .agent_did(&self.agent_did) .agent_vk(&self.agent_vk) + .set_title(&title) + .set_detail(&title) .status_code(&MessageAccepted.as_string()) .send_secure() { Err(x) => { @@ -160,6 +188,8 @@ impl IssuerCredential { } fn send_credential(&mut self, connection_handle: u32) -> Result { + trace!("IssuerCredential::send_credential >>> connection_handle: {}", connection_handle); + debug!("sending credential for issuer_credential {} to connection {}", self.source_id, connection::get_source_id(connection_handle).unwrap_or_default()); if self.state != VcxStateType::VcxStateRequestReceived { warn!("credential {} has invalid state {} for sending credential", self.source_id, self.state as u32); @@ -238,11 +268,16 @@ impl IssuerCredential { } fn update_state(&mut self) -> Result { + trace!("IssuerCredential::update_state >>>"); self.get_credential_offer_status() //There will probably be more things here once we do other things with the credential } - fn get_state(&self) -> u32 { let state = self.state as u32; state } + fn get_state(&self) -> u32 { + trace!("IssuerCredential::get_state >>>"); + let state = self.state as u32; + state + } fn get_offer_uid(&self) -> &String { &self.msg_uid } fn set_offer_uid(&mut self, uid: &str) {self.msg_uid = uid.to_owned();} fn set_credential_request(&mut self, credential_request:CredentialRequest) -> Result { @@ -253,38 +288,43 @@ impl IssuerCredential { fn get_credential_attributes(&self) -> &String { &self.credential_attributes} fn get_source_id(&self) -> &String { &self.source_id } - fn generate_credential(&self, credential_data: &str, did: &str) -> Result { + fn generate_credential(&mut self, credential_data: &str, did: &str) -> Result { let indy_cred_offer = &self.credential_offer.as_ref() .ok_or(IssuerCredError::InvalidCred())?.libindy_offer; let indy_cred_req = &self.credential_request.as_ref() .ok_or(IssuerCredError::InvalidCredRequest())?.libindy_cred_req; - //Todo: rev_reg_id and blob_storage need to be provided when we do revocation - let (cred, cred_revoc_id, revoc_reg_delta_json) = libindy_issuer_create_credential( + let (cred, cred_revoc_id, revoc_reg_delta_json) = anoncreds::libindy_issuer_create_credential( &indy_cred_offer, &indy_cred_req, credential_data, - None, - None) + self.rev_reg_id.clone(), + self.tails_file.clone()) .map_err(|x| IssuerCredError::CommonError(x))?; + self.cred_rev_id = cred_revoc_id.clone(); + Ok(CredentialMessage { claim_offer_id: self.msg_uid.clone(), from_did: String::from(did), version: String::from("0.1"), msg_type: String::from("CRED"), libindy_cred: cred, - //Todo: need to add indy api calls to populate this field - rev_reg_def_json: String::new(), + rev_reg_def_json: match self.rev_reg_def_json { + Some(_) => self.rev_reg_def_json.clone().unwrap(), + None => String::new(), + }, cred_def_id: self.cred_def_id.clone(), + cred_revoc_id, + revoc_reg_delta_json, }) } fn generate_credential_offer(&self, to_did: &str) -> Result { let attr_map = convert_to_map(&self.credential_attributes)?; //Todo: make a cred_def_offer error - let libindy_offer = libindy_issuer_create_credential_offer(&self.cred_def_id) + let libindy_offer = anoncreds:: libindy_issuer_create_credential_offer(&self.cred_def_id) .map_err(|err| IssuerCredError::CommonError(err))?; Ok(CredentialOffer { msg_type: String::from("CRED_OFFER"), @@ -301,6 +341,26 @@ impl IssuerCredential { }) } + fn revoke_cred(&mut self) -> Result<(), IssuerCredError> { + let tails_file = self.tails_file + .as_ref() + .ok_or(IssuerCredError::InvalidRevocationInfo())?; + + let rev_reg_id = self.rev_reg_id + .as_ref() + .ok_or(IssuerCredError::InvalidRevocationInfo())?; + + let cred_rev_id = self.cred_rev_id + .as_ref() + .ok_or(IssuerCredError::InvalidRevocationInfo())?; + + let (payment, _) = anoncreds::revoke_credential(tails_file, rev_reg_id, cred_rev_id) + .map_err(|e| IssuerCredError::CommonError(e))?; + + self.rev_cred_payment_txn = payment; + Ok(()) + } + fn generate_payment_info(&mut self) -> Result, IssuerCredError> { if self.price > 0 { let address: String = ::utils::libindy::payments::create_address(None).map_err(|x| IssuerCredError::CommonError(x))?; @@ -328,6 +388,8 @@ impl IssuerCredential { } fn get_payment_txn(&self) -> Result { + trace!("IssuerCredential::get_payment_txn >>>"); + match self.payment_address { Some(ref payment_address) if self.price > 0 => { Ok(payments::PaymentTxn { @@ -355,8 +417,27 @@ impl IssuerCredential { } } +/** + Input: supporting two formats: + eg: + perferred format: json, property/values + {"address2":"101 Wilson Lane"} + or + deprecated format: json, key/array (of one item) + {"address2":["101 Wilson Lane"]} + + + Output: json: dictionary with key, object of raw and encoded values + eg: + { + "address2": { + "encoded": "68086943237164982734333428280784300550565381723532936263016368251445461241953", + "raw": "101 Wilson Lane" + } + } +*/ pub fn encode_attributes(attributes: &str) -> Result { - let mut attributes: serde_json::Value = match serde_json::from_str(attributes) { +let mut attributes: serde_json::Value = match serde_json::from_str(attributes) { Ok(x) => x, Err(e) => { warn!("Invalid Json for Attribute data"); @@ -372,28 +453,45 @@ pub fn encode_attributes(attributes: &str) -> Result { } }; - for (attr, vec) in map.iter_mut(){ - let list = match vec.as_array_mut() { - Some(x) => x, - None => { + let mut dictionary = HashMap::new(); + + for (attr, attr_data) in map.iter_mut(){ + let first_attr : &str = match attr_data { + // old style input such as {"address2":["101 Wilson Lane"]} + serde_json::Value::Array(array_type) => { + + let attrib_value : &str = match array_type.get(0).and_then(serde_json::Value::as_str) { + Some(x) => x, + None => { + warn!("Cannot encode attribute: {}", error::INVALID_ATTRIBUTES_STRUCTURE.message); + return Err(IssuerCredError::CommonError(error::INVALID_ATTRIBUTES_STRUCTURE.code_num)) + } + }; + + warn!("Old attribute format detected. See vcx_issuer_create_credential api for additional information."); + attrib_value + }, + + // new style input such as {"address2":"101 Wilson Lane"} + serde_json::Value::String(str_type) => str_type, + + // anything else is an error + _ => { warn!("Invalid Json for Attribute data"); return Err(IssuerCredError::CommonError(INVALID_JSON.code_num)) } }; - let i = list[0].clone(); - let value = match i.as_str(){ - Some(v) => v, - None => { - warn!("Cannot encode attribute: {}", error::INVALID_ATTRIBUTES_STRUCTURE.message); - return Err(IssuerCredError::CommonError(error::INVALID_ATTRIBUTES_STRUCTURE.code_num)) - }, - }; - let encoded = encode(value).map_err(|x| IssuerCredError::CommonError(x))?; - let encoded_as_value: serde_json::Value = serde_json::Value::from(encoded); - list.push(encoded_as_value); + + let encoded = encode(&first_attr).map_err(|x| IssuerCredError::CommonError(x))?; + let attrib_values = json!({ + "raw" : first_attr, + "encoded": encoded + }); + + dictionary.insert(attr, attrib_values); } - match serde_json::to_string_pretty(&map) { + match serde_json::to_string_pretty(&dictionary) { Ok(x) => Ok(x), Err(x) => { warn!("Invalid Json for Attribute data"); @@ -435,13 +533,19 @@ fn parse_credential_req_payload(offer_uid: String, payload: &Vec) -> Result< Ok(my_credential_req) } -// TODO: The error arm of this Result is never thrown. aka this method is never Err. -pub fn issuer_credential_create(cred_def_id: String, - source_id: String, - issuer_did: String, - credential_name: String, - credential_data: String, - price: u64) -> Result { +pub fn issuer_credential_create(cred_def_handle: u32, + source_id: String, + issuer_did: String, + credential_name: String, + credential_data: String, + price: u64) -> Result { + trace!("issuer_credential_create >>> cred_def_handle: {}, source_id: {}, issuer_did: {}, credential_name: {}, credential_data: {}, price: {}", + cred_def_handle, source_id, issuer_did, credential_name, credential_data, price); + + let cred_def_id = ::credential_def::get_cred_def_id(cred_def_handle).map_err(|ec|IssuerCredError::CommonError(ec.to_error_code()))?; + let rev_reg_id = ::credential_def::get_rev_reg_id(cred_def_handle).map_err(|ec|IssuerCredError::CommonError(ec.to_error_code()))?; + let tails_file = ::credential_def::get_tails_file(cred_def_handle).map_err(|ec|IssuerCredError::CommonError(ec.to_error_code()))?; + let rev_reg_def_json = ::credential_def::get_rev_reg_def(cred_def_handle).map_err(|ec|IssuerCredError::CommonError(ec.to_error_code()))?; let mut new_issuer_credential = IssuerCredential { credential_id: source_id.to_string(), @@ -456,6 +560,11 @@ pub fn issuer_credential_create(cred_def_id: String, credential_offer: None, credential_name, ref_msg_id: None, + rev_reg_id, + rev_reg_def_json, + cred_rev_id: None, + rev_cred_payment_txn: None, + tails_file, price, payment_address: None, issued_did: String::new(), @@ -464,7 +573,8 @@ pub fn issuer_credential_create(cred_def_id: String, remote_vk: String::new(), agent_did: String::new(), agent_vk: String::new(), - cred_def_id + cred_def_id, + cred_def_handle }; new_issuer_credential.validate_credential_offer()?; @@ -535,6 +645,12 @@ pub fn send_credential(handle: u32, connection_handle: u32) -> Result Result<(), u32> { + ISSUER_CREDENTIAL_MAP.get_mut(handle,|i|{ + i.revoke_cred().map_err(|ec|ec.to_error_code()) + }) +} + fn get_offer_details(response: &str) -> Result { match serde_json::from_str(response) { Ok(json) => { @@ -587,7 +703,7 @@ pub fn get_source_id(handle: u32) -> Result { pub mod tests { use super::*; use settings; - use connection::{ build_connection }; + use connection::tests::build_test_connection; use credential_request::CredentialRequest; #[allow(unused_imports)] use utils::{ constants::*, @@ -596,6 +712,7 @@ pub mod tests { libindy_issuer_create_credential_offer, libindy_prover_create_credential_req }, wallet::get_wallet_handle, wallet}, + get_temp_dir_path, }; use error::{ issuer_cred::IssuerCredError }; @@ -648,13 +765,19 @@ pub mod tests { credential_offer: Some(credential_offer.to_owned()), credential_id: String::from(DEFAULT_CREDENTIAL_ID), price: 1, - payment_address: Some("pay:null:9UFgyjuJxi1i1HD".to_string()), + payment_address: Some(payments::build_test_address("9UFgyjuJxi1i1HD")), ref_msg_id: None, + rev_reg_id: None, + tails_file: None, + cred_rev_id: None, + rev_cred_payment_txn: None, + rev_reg_def_json: None, remote_did: DID.to_string(), remote_vk: VERKEY.to_string(), agent_did: DID.to_string(), agent_vk: VERKEY.to_string(), cred_def_id: CRED_DEF_ID.to_string(), + cred_def_handle: 0, }; issuer_credential } @@ -675,7 +798,11 @@ pub mod tests { pub fn create_full_issuer_credential() -> (IssuerCredential, ::credential::Credential) { let issuer_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); - let (_, _, cred_def_id, _) = ::utils::libindy::anoncreds::tests::create_and_store_credential_def(::utils::constants::DEFAULT_SCHEMA_ATTRS); + let (_, cred_def_handle) = ::credential_def::tests::create_cred_def_real(true); + let cred_def_id = ::credential_def::get_cred_def_id(cred_def_handle).unwrap(); + let rev_reg_id = ::credential_def::get_rev_reg_id(cred_def_handle).unwrap(); + let tails_file = ::credential_def::get_tails_file(cred_def_handle).unwrap(); + let rev_reg_def_json = ::credential_def::get_rev_reg_def(cred_def_handle).unwrap(); let credential_data = r#"{"address1": ["123 Main St"], "address2": ["Suite 3"], "city": ["Draper"], "state": ["UT"], "zip": ["84000"]}"#; let mut issuer_credential = IssuerCredential { @@ -691,6 +818,11 @@ pub mod tests { credential_name: "cred_name".to_string(), credential_id: String::new(), ref_msg_id: None, + rev_reg_id, + rev_reg_def_json, + cred_rev_id: None, + rev_cred_payment_txn: None, + tails_file, price: 1, payment_address: None, issued_did: String::new(), @@ -699,7 +831,8 @@ pub mod tests { remote_vk: String::new(), agent_did: String::new(), agent_vk: String::new(), - cred_def_id + cred_def_id, + cred_def_handle }; let payment = issuer_credential.generate_payment_info().unwrap(); @@ -720,7 +853,7 @@ pub mod tests { #[test] fn test_issuer_credential_create_succeeds() { init!("true"); - match issuer_credential_create(CRED_DEF_ID.to_string(), + match issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "1".to_string(), "8XFh8yBzrpJQmNyZzgoTqB".to_owned(), "credential_name".to_string(), @@ -734,7 +867,7 @@ pub mod tests { #[test] fn test_to_string_succeeds() { init!("true"); - let handle = issuer_credential_create(CRED_DEF_ID.to_string(), + let handle = issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "1".to_string(), "8XFh8yBzrpJQmNyZzgoTqB".to_owned(), "credential_name".to_string(), @@ -747,11 +880,11 @@ pub mod tests { #[test] fn test_send_credential_offer() { init!("true"); - let connection_handle = build_connection("test_send_credential_offer").unwrap(); + let connection_handle = build_test_connection(); let credential_id = DEFAULT_CREDENTIAL_ID; - let handle = issuer_credential_create(CRED_DEF_ID.to_string(), + let handle = issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "1".to_string(), "8XFh8yBzrpJQmNyZzgoTqB".to_owned(), "credential_name".to_string(), @@ -774,11 +907,11 @@ pub mod tests { #[test] fn test_retry_send_credential_offer() { init!("true"); - let connection_handle = build_connection("test_send_credential_offer").unwrap(); + let connection_handle = build_test_connection(); let credential_id = DEFAULT_CREDENTIAL_ID; - let handle = issuer_credential_create(CRED_DEF_ID.to_string(), + let handle = issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "1".to_string(), "8XFh8yBzrpJQmNyZzgoTqB".to_owned(), "credential_name".to_string(), @@ -804,7 +937,7 @@ pub mod tests { let mut credential = create_standard_issuer_credential(); credential.state = VcxStateType::VcxStateRequestReceived; - let connection_handle = build_connection("test_send_credential_offer").unwrap(); + let connection_handle = build_test_connection(); set_libindy_rc(error::TIMEOUT_LIBINDY_ERROR.code_num); assert_eq!(credential.send_credential(connection_handle), @@ -820,7 +953,7 @@ pub mod tests { #[test] fn test_from_string_succeeds() { init!("true"); - let handle = issuer_credential_create(CRED_DEF_ID.to_string(), + let handle = issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "1".to_string(), "8XFh8yBzrpJQmNyZzgoTqB".to_owned(), "credential_name".to_string(), @@ -839,7 +972,7 @@ pub mod tests { #[test] fn test_update_state_with_pending_credential_request() { init!("true"); - let connection_handle = build_connection("test_update_state_with_pending_credential_request").unwrap(); + let connection_handle = build_test_connection(); let credential_req:CredentialRequest = CredentialRequest::from_str(CREDENTIAL_REQ_STRING).unwrap(); let (credential_offer, _) = ::credential::parse_json_offer(CREDENTIAL_OFFER_JSON).unwrap(); let mut credential = IssuerCredential { @@ -856,7 +989,13 @@ pub mod tests { credential_name: DEFAULT_CREDENTIAL_NAME.to_owned(), credential_id: String::from(DEFAULT_CREDENTIAL_ID), cred_def_id: CRED_DEF_ID.to_string(), + cred_def_handle: 1, ref_msg_id: None, + rev_reg_id: None, + cred_rev_id: None, + rev_cred_payment_txn: None, + rev_reg_def_json: None, + tails_file: None, price: 0, payment_address: None, remote_did: DID.to_string(), @@ -875,7 +1014,7 @@ pub mod tests { #[test] fn test_issuer_credential_changes_state_after_being_validated() { init!("true"); - let handle = issuer_credential_create(CRED_DEF_ID.to_string(), + let handle = issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "1".to_string(), "8XFh8yBzrpJQmNyZzgoTqB".to_owned(), "credential_name".to_string(), @@ -918,7 +1057,7 @@ pub mod tests { let mut credential = create_standard_issuer_credential(); credential.state = VcxStateType::VcxStateRequestReceived; - let connection_handle = build_connection("test_send_credential_offer").unwrap(); + let connection_handle = build_test_connection(); credential.send_credential(connection_handle).unwrap(); assert_eq!(credential.state, VcxStateType::VcxStateAccepted); @@ -928,11 +1067,11 @@ pub mod tests { #[test] fn test_release_all() { init!("true"); - let h1 = issuer_credential_create(CRED_DEF_ID.to_string(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); - let h2 = issuer_credential_create(CRED_DEF_ID.to_string(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); - let h3 = issuer_credential_create(CRED_DEF_ID.to_string(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); - let h4 = issuer_credential_create(CRED_DEF_ID.to_string(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); - let h5 = issuer_credential_create(CRED_DEF_ID.to_string(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); + let h1 = issuer_credential_create(::credential_def::tests::create_cred_def_fake(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); + let h2 = issuer_credential_create(::credential_def::tests::create_cred_def_fake(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); + let h3 = issuer_credential_create(::credential_def::tests::create_cred_def_fake(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); + let h4 = issuer_credential_create(::credential_def::tests::create_cred_def_fake(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); + let h5 = issuer_credential_create(::credential_def::tests::create_cred_def_fake(),"1".to_string(),"8XFh8yBzrpJQmNyZzgoTqB".to_owned(),"credential_name".to_string(),"{\"attr\":\"value\"}".to_owned(),1).unwrap(); release_all(); assert_eq!(release(h1),Err(IssuerCredError::InvalidHandle())); assert_eq!(release(h2),Err(IssuerCredError::InvalidHandle())); @@ -951,14 +1090,14 @@ pub mod tests { #[test] fn test_encoding(){ - let issuer_credential_handle = self::issuer_credential_create(CRED_DEF_ID.to_string(), + let issuer_credential_handle = issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "IssuerCredentialName".to_string(), "000000000000000000000000Issuer02".to_string(), "CredentialNameHere".to_string(), r#"["name","gpa"]"#.to_string(), 1).unwrap(); assert!(self::get_encoded_attributes(issuer_credential_handle).is_err()); - let issuer_credential_handle = self::issuer_credential_create(CRED_DEF_ID.to_string(), + let issuer_credential_handle = issuer_credential_create(::credential_def::tests::create_cred_def_fake(), "IssuerCredentialName".to_string(), "000000000000000000000000Issuer02".to_string(), "CredentialNameHere".to_string(), @@ -975,7 +1114,7 @@ pub mod tests { payment_required: "one-time".to_string(), price: 1000, }; - println!("{}", serde_json::to_string(&payment_info).unwrap()) + let _ = serde_json::to_string(&payment_info).unwrap(); } #[test] @@ -985,7 +1124,7 @@ pub mod tests { // Success credential.price = 3; - credential.payment_address = Some("pay:null:9UFgyjuJxi1i1HD".to_string()); + credential.payment_address = Some(payments::build_test_address("9UFgyjuJxi1i1HD")); assert!(credential.verify_payment().is_ok()); // Err - Wrong payment amount @@ -1003,9 +1142,9 @@ pub mod tests { let mut credential = create_standard_issuer_credential(); credential.state = VcxStateType::VcxStateRequestReceived; credential.price = 3; - credential.payment_address = Some("pay:null:9UFgyjuJxi1i1HD".to_string()); + credential.payment_address = Some(payments::build_test_address("9UFgyjuJxi1i1HD")); - let connection_handle = build_connection("test_send_credential_offer").unwrap(); + let connection_handle = build_test_connection(); // Success credential.send_credential(connection_handle).unwrap(); @@ -1019,4 +1158,259 @@ pub mod tests { let payment = serde_json::to_string(&credential.get_payment_txn().unwrap()).unwrap(); assert!(payment.len() > 20); } + + #[test] + fn test_revoke_credential() { + init!("true"); + let mut credential = create_standard_issuer_credential(); + + credential.tails_file = Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()); + credential.cred_rev_id = None; + credential.rev_reg_id = None; + assert_eq!(credential.revoke_cred(), Err(IssuerCredError::InvalidRevocationInfo())); + credential.tails_file = None; + credential.cred_rev_id = Some(CRED_REV_ID.to_string()); + credential.rev_reg_id = None; + assert_eq!(credential.revoke_cred(), Err(IssuerCredError::InvalidRevocationInfo())); + credential.tails_file = None; + credential.cred_rev_id = None; + credential.rev_reg_id = Some(REV_REG_ID.to_string()); + assert_eq!(credential.revoke_cred(), Err(IssuerCredError::InvalidRevocationInfo())); + + credential.tails_file = Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()); + credential.cred_rev_id = Some(CRED_REV_ID.to_string()); + credential.rev_reg_id = Some(REV_REG_ID.to_string()); + credential.rev_cred_payment_txn = None; + + credential.revoke_cred().unwrap(); + assert!(credential.rev_cred_payment_txn.is_some()); + } + + + #[test] + fn test_encode_with_several_attributes_success() { + + /* + for reference....expectation is encode_attributes returns this: + + let expected = json!({ + "address2": { + "encoded": "68086943237164982734333428280784300550565381723532936263016368251445461241953", + "raw": "101 Wilson Lane" + }, + "zip": { + "encoded": "87121", + "raw": "87121" + }, + "city": { + "encoded": "101327353979588246869873249766058188995681113722618593621043638294296500696424", + "raw": "SLC" + }, + "address1": { + "encoded": "63690509275174663089934667471948380740244018358024875547775652380902762701972", + "raw": "101 Tela Lane" + }, + "state": { + "encoded": "93856629670657830351991220989031130499313559332549427637940645777813964461231", + "raw": "UT" + } + }); + */ + + static TEST_CREDENTIAL_DATA: &str = + r#"{"address2":["101 Wilson Lane"], + "zip":["87121"], + "state":["UT"], + "city":["SLC"], + "address1":["101 Tela Lane"] + }"#; + + let results_json = encode_attributes(TEST_CREDENTIAL_DATA).unwrap(); + + let results : Value = serde_json::from_str(&results_json).unwrap(); + + let address2 : &Value = &results["address2"]; + assert_eq!(encode("101 Wilson Lane").unwrap(), address2["encoded"]); + assert_eq!("101 Wilson Lane", address2["raw"]); + + let state : &Value = &results["state"]; + assert_eq!(encode("UT").unwrap(), state["encoded"]); + assert_eq!("UT", state["raw"]); + + let zip : &Value = &results["zip"]; + assert_eq!("87121", zip["encoded"]); + assert_eq!("87121", zip["raw"]); + + + } + + #[test] + fn test_encode_with_one_attribute_success() { + + let expected = json!({ + "address2": { + "encoded": "68086943237164982734333428280784300550565381723532936263016368251445461241953", + "raw": "101 Wilson Lane" + } + }); + + static TEST_CREDENTIAL_DATA: &str = + r#"{"address2":["101 Wilson Lane"]}"#; + + let expected_json = serde_json::to_string_pretty(&expected).unwrap(); + + let results_json = encode_attributes(TEST_CREDENTIAL_DATA).unwrap(); + + assert_eq!(expected_json, results_json, "encode_attributes failed to return expected results"); + } + + #[test] + fn test_encode_with_new_format_several_attributes_success() { + + /* + for reference....expectation is encode_attributes returns this: + + let expected = json!({ + "address2": { + "encoded": "68086943237164982734333428280784300550565381723532936263016368251445461241953", + "raw": "101 Wilson Lane" + }, + "zip": { + "encoded": "87121", + "raw": "87121" + }, + "city": { + "encoded": "101327353979588246869873249766058188995681113722618593621043638294296500696424", + "raw": "SLC" + }, + "address1": { + "encoded": "63690509275174663089934667471948380740244018358024875547775652380902762701972", + "raw": "101 Tela Lane" + }, + "state": { + "encoded": "93856629670657830351991220989031130499313559332549427637940645777813964461231", + "raw": "UT" + } + }); + */ + + static TEST_CREDENTIAL_DATA: &str = + r#"{"address2":"101 Wilson Lane", + "zip":"87121", + "state":"UT", + "city":"SLC", + "address1":"101 Tela Lane" + }"#; + + let results_json = encode_attributes(TEST_CREDENTIAL_DATA).unwrap(); + + let results : Value = serde_json::from_str(&results_json).unwrap(); + + let address2 : &Value = &results["address2"]; + assert_eq!(encode("101 Wilson Lane").unwrap(), address2["encoded"]); + assert_eq!("101 Wilson Lane", address2["raw"]); + + let state : &Value = &results["state"]; + assert_eq!(encode("UT").unwrap(), state["encoded"]); + assert_eq!("UT", state["raw"]); + + let zip : &Value = &results["zip"]; + assert_eq!("87121", zip["encoded"]); + assert_eq!("87121", zip["raw"]); + + } + + #[test] + fn test_encode_with_new_format_one_attribute_success() { + + let expected = json!({ + "address2": { + "encoded": "68086943237164982734333428280784300550565381723532936263016368251445461241953", + "raw": "101 Wilson Lane" + } + }); + + static TEST_CREDENTIAL_DATA: &str = + r#"{"address2": "101 Wilson Lane"}"#; + + let expected_json = serde_json::to_string_pretty(&expected).unwrap(); + + let results_json = encode_attributes(TEST_CREDENTIAL_DATA).unwrap(); + + assert_eq!(expected_json, results_json, "encode_attributes failed to return expected results"); + } + + #[test] + fn test_encode_with_mixed_format_several_attributes_success() { + + /* + for reference....expectation is encode_attributes returns this: + + let expected = json!({ + "address2": { + "encoded": "68086943237164982734333428280784300550565381723532936263016368251445461241953", + "raw": "101 Wilson Lane" + }, + "zip": { + "encoded": "87121", + "raw": "87121" + }, + "city": { + "encoded": "101327353979588246869873249766058188995681113722618593621043638294296500696424", + "raw": "SLC" + }, + "address1": { + "encoded": "63690509275174663089934667471948380740244018358024875547775652380902762701972", + "raw": "101 Tela Lane" + }, + "state": { + "encoded": "93856629670657830351991220989031130499313559332549427637940645777813964461231", + "raw": "UT" + } + }); + */ + + static TEST_CREDENTIAL_DATA: &str = + r#"{"address2":["101 Wilson Lane"], + "zip":"87121", + "state":"UT", + "city":["SLC"], + "address1":"101 Tela Lane" + }"#; + + let results_json = encode_attributes(TEST_CREDENTIAL_DATA).unwrap(); + + let results : Value = serde_json::from_str(&results_json).unwrap(); + let address2 : &Value = &results["address2"]; + + assert_eq!("68086943237164982734333428280784300550565381723532936263016368251445461241953", address2["encoded"]); + assert_eq!("101 Wilson Lane", address2["raw"]); + + let state : &Value = &results["state"]; + assert_eq!("93856629670657830351991220989031130499313559332549427637940645777813964461231", state["encoded"]); + assert_eq!("UT", state["raw"]); + + let zip : &Value = &results["zip"]; + assert_eq!("87121", zip["encoded"]); + assert_eq!("87121", zip["raw"]); + + } + + #[test] + fn test_encode_bad_format_returns_error() + { + static BAD_TEST_CREDENTIAL_DATA: &str = + r#"{"format doesnt make sense"}"#; + + assert!(encode_attributes(BAD_TEST_CREDENTIAL_DATA).is_err()) + } + + #[test] + fn test_encode_old_format_empty_array_error() + { + static BAD_TEST_CREDENTIAL_DATA: &str = + r#"{"address2":[]}"#; + + assert!(encode_attributes(BAD_TEST_CREDENTIAL_DATA).is_err()) + } } diff --git a/vcx/libvcx/src/lib.rs b/vcx/libvcx/src/lib.rs index 465de544..98523f6b 100644 --- a/vcx/libvcx/src/lib.rs +++ b/vcx/libvcx/src/lib.rs @@ -1,12 +1,16 @@ +#![cfg_attr(feature = "fatal_warnings", deny(warnings))] #![allow(unused_variables)] #![allow(dead_code)] #![crate_name = "vcx"] +//this is needed for some large json macro invocations +#![recursion_limit="128"] extern crate serde; extern crate rand; extern crate reqwest; extern crate url; extern crate openssl; -extern crate indy; +extern crate indyrs as indy; +extern crate futures; #[macro_use] extern crate log; @@ -21,6 +25,8 @@ extern crate serde_json; #[macro_use] extern crate lazy_static; +extern crate time; + #[macro_use] pub mod utils; pub mod settings; @@ -56,30 +62,200 @@ mod tests { use rand::Rng; use std::thread; use std::time::Duration; - use ::utils::devsetup::tests::{set_institution, set_consumer}; - use utils::constants::DEFAULT_SCHEMA_ATTRS; + use utils::{ + devsetup::tests::{set_institution, set_consumer}, + constants::{DEFAULT_SCHEMA_ATTRS, TEST_TAILS_FILE}, + get_temp_dir_path + }; #[cfg(feature = "agency")] #[cfg(feature = "pool_tests")] #[test] fn test_delete_connection() { init!("agency"); - let alice = connection::build_connection("alice").unwrap(); + let alice = connection::create_connection("alice").unwrap(); + connection::connect(alice,None).unwrap(); connection::delete_connection(alice).unwrap(); assert!(connection::release(alice).is_err()); teardown!("agency"); } + + fn attr_names() -> (String, String, String, String, String) { + let address1 = "Address1".to_string(); + let address2 = "address2".to_string(); + let city = "CITY".to_string(); + let state = "State".to_string(); + let zip = "zip".to_string(); + (address1, address2, city, state, zip) + } + fn requested_attrs(did: &str, schema_id: &str, cred_def_id: &str, from: Option, to: Option) -> Value { + let (address1, address2, city, state, zip) = attr_names(); + json!([ + { + "name":address1, + "non_revoked": {"from": from, "to": to}, + "restrictions": [{ + "issuer_did": did, + "schema_id": schema_id, + "cred_def_id": cred_def_id, + }] + }, + { + "name":address2, + "non_revoked": {"from": from, "to": to}, + "restrictions": [{ + "issuer_did": did, + "schema_id": schema_id, + "cred_def_id": cred_def_id, + }], + }, + { + "name":city, + "non_revoked": {"from": from, "to": to}, + "restrictions": [{ + "issuer_did": did, + "schema_id": schema_id, + "cred_def_id": cred_def_id, + }] + }, + { + "name":state, + "non_revoked": {"from": from, "to": to}, + "restrictions": [{ + "issuer_did": did, + "schema_id": schema_id, + "cred_def_id": cred_def_id, + }] + }, + { + "name":zip, + "non_revoked": {"from": from, "to": to}, + "restrictions": [{ + "issuer_did": did, + "schema_id": schema_id, + "cred_def_id": cred_def_id, + }] + } + ]) + + } + + fn send_cred_offer(did: &str, cred_def_handle: u32, connection: u32, credential_data: &str) -> u32 { + + let credential_offer = issuer_credential::issuer_credential_create(cred_def_handle, + "1".to_string(), + did.to_string(), + "credential_name".to_string(), + credential_data.to_string(), + 1).unwrap(); + println!("sending credential offer"); + issuer_credential::send_credential_offer(credential_offer, connection).unwrap(); + thread::sleep(Duration::from_millis(2000)); + credential_offer + } + + fn send_cred_req(connection: u32) -> u32 { + set_consumer(); + let credential_offers = credential::get_credential_offer_messages(connection).unwrap(); + let offers: Value = serde_json::from_str(&credential_offers).unwrap(); + let offers = serde_json::to_string(&offers[0]).unwrap(); + let credential = credential::credential_create_with_offer("TEST_CREDENTIAL", &offers).unwrap(); + assert_eq!(VcxStateType::VcxStateRequestReceived as u32, credential::get_state(credential).unwrap()); + println!("sending credential request"); + credential::send_credential_request(credential, connection).unwrap(); + thread::sleep(Duration::from_millis(2000)); + credential + } + + fn send_credential(issuer_handle: u32, connection: u32, credential_handle: u32) { + set_institution(); + issuer_credential::update_state(issuer_handle).unwrap(); + assert_eq!(VcxStateType::VcxStateRequestReceived as u32, issuer_credential::get_state(issuer_handle).unwrap()); + println!("sending credential"); + issuer_credential::send_credential(issuer_handle, connection).unwrap(); + thread::sleep(Duration::from_millis(2000)); + // AS CONSUMER STORE CREDENTIAL + tests::set_consumer(); + credential::update_state(credential_handle).unwrap(); + thread::sleep(Duration::from_millis(2000)); + println!("storing credential"); + credential::get_credential_id(credential_handle).unwrap(); + assert_eq!(VcxStateType::VcxStateAccepted as u32, credential::get_state(credential_handle).unwrap()); + } + + fn send_proof_request(connection_handle: u32, requested_attrs: &str, requested_preds: &str, revocation_interval: &str, log_msg: &str) -> (u32, String) { + let proof_req_handle = proof::create_proof("1".to_string(), + requested_attrs.to_string(), + requested_preds.to_string(), + revocation_interval.to_string(), + "name".to_string()).unwrap(); + println!("sending proof request {}", log_msg); + proof::send_proof_request(proof_req_handle, connection_handle).unwrap(); + let req_uuid = proof::get_proof_uuid(proof_req_handle).unwrap(); + thread::sleep(Duration::from_millis(2000)); + (proof_req_handle, req_uuid) + } + + fn create_proof(connection_handle: u32, msg_uid: &str) -> u32 { + set_consumer(); + let requests = disclosed_proof::get_proof_request_messages(connection_handle, None).unwrap(); + let requests: Value = serde_json::from_str(&requests).unwrap(); + let mut req = None; + for _req in requests.as_array().unwrap() { + if _req["msg_ref_id"] == json!(msg_uid) { req = Some(_req); } + } + let requests = serde_json::to_string(req.unwrap()).unwrap(); + disclosed_proof::create_proof(::utils::constants::DEFAULT_PROOF_NAME, &requests).unwrap() + } + + fn generate_and_send_proof(proof_handle: u32, connection_handle: u32, selected_credentials: Value){ + set_consumer(); + disclosed_proof::generate_proof(proof_handle, selected_credentials.to_string(), "{}".to_string()).unwrap(); + println!("sending proof"); + disclosed_proof::send_proof(proof_handle, connection_handle).unwrap(); + assert_eq!(VcxStateType::VcxStateAccepted as u32, disclosed_proof::get_state(proof_handle).unwrap()); + thread::sleep(Duration::from_millis(5000)); + } + + fn default_selected_credentials(proof_handle: u32) -> Value { + println!("retrieving matching credentials"); + let retrieved_credentials = disclosed_proof::retrieve_credentials(proof_handle).unwrap(); + let matching_credentials: Value = serde_json::from_str(&retrieved_credentials).unwrap(); + let (address1, address2, city, state, zip) = attr_names(); + json!({ + "attrs":{ + address1.to_string():{"credential": matching_credentials["attrs"][address1][0], "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()}, + address2.to_string():{"credential": matching_credentials["attrs"][address2][0], "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()}, + city.to_string():{"credential": matching_credentials["attrs"][city][0], "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()}, + state.to_string():{"credential": matching_credentials["attrs"][state][0], "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()}, + zip.to_string():{"credential": matching_credentials["attrs"][zip][0], "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()}, + }, + "predicates":{ + } + }) + + } + + fn revoke_credential(issuer_handle: u32, rev_reg_id: Option) { + // GET REV REG DELTA BEFORE REVOCATION + let (_, delta, timestamp) = ::utils::libindy::anoncreds::get_rev_reg_delta_json(&rev_reg_id.clone().unwrap(), None, None).unwrap(); + println!("revoking credential"); + ::issuer_credential::revoke_credential(issuer_handle).unwrap(); + let (_, delta_after_revoke, _) = ::utils::libindy::anoncreds::get_rev_reg_delta_json(&rev_reg_id.unwrap(), Some(timestamp+1), None).unwrap(); + assert_ne!(delta, delta_after_revoke); + } + #[cfg(feature = "agency")] #[cfg(feature = "pool_tests")] - #[cfg(feature = "sovtoken")] #[test] fn test_real_proof() { let number_of_attributes = 10; init!("agency"); let institution_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let (faber, alice) = ::connection::tests::create_connected_connections(); + // AS INSTITUTION SEND CREDENTIAL OFFER println!("creating schema/credential_def and paying fees"); let mut attrs_list:Value = serde_json::Value::Array(vec![]); @@ -87,88 +263,134 @@ mod tests { attrs_list.as_array_mut().unwrap().push(json!(format!("key{}",i))); } let attrs_list = attrs_list.to_string(); - let (schema_id, _, cred_def_id, _) = ::utils::libindy::anoncreds::tests::create_and_store_credential_def(&attrs_list); + let (schema_id, schema_json, cred_def_id, cred_def_json, cred_def_handle, _) = ::utils::libindy::anoncreds::tests::create_and_store_credential_def(&attrs_list, false); let mut credential_data = json!({}); for i in 1..number_of_attributes { credential_data[format!("key{}",i)] = json!([format!("value{}",i)]); } let credential_data = credential_data.to_string(); - let credential_offer = issuer_credential::issuer_credential_create(cred_def_id.clone(), - "1".to_string(), - institution_did.clone(), - "credential_name".to_string(), - credential_data.to_owned(), - 1).unwrap(); - println!("sending credential offer"); - issuer_credential::send_credential_offer(credential_offer, alice).unwrap(); - thread::sleep(Duration::from_millis(2000)); + let credential_offer = send_cred_offer(&institution_did, cred_def_handle, alice, &credential_data); + // AS CONSUMER SEND CREDENTIAL REQUEST - set_consumer(); - let credential_offers = credential::get_credential_offer_messages(faber).unwrap(); - let offers: Value = serde_json::from_str(&credential_offers).unwrap(); - let offers = serde_json::to_string(&offers[0]).unwrap(); - let credential = credential::credential_create_with_offer("TEST_CREDENTIAL", &offers).unwrap(); - assert_eq!(VcxStateType::VcxStateRequestReceived as u32, credential::get_state(credential).unwrap()); - println!("sending credential request"); - credential::send_credential_request(credential, faber).unwrap(); - thread::sleep(Duration::from_millis(2000)); + let credential = send_cred_req(faber); + // AS INSTITUTION SEND CREDENTIAL - set_institution(); - issuer_credential::update_state(credential_offer).unwrap(); - assert_eq!(VcxStateType::VcxStateRequestReceived as u32, issuer_credential::get_state(credential_offer).unwrap()); - println!("sending credential"); - issuer_credential::send_credential(credential_offer, alice).unwrap(); - thread::sleep(Duration::from_millis(2000)); - // AS CONSUMER STORE CREDENTIAL - tests::set_consumer(); - credential::update_state(credential).unwrap(); - thread::sleep(Duration::from_millis(2000)); - println!("storing credential"); - let cred_id = credential::get_credential_id(credential).unwrap(); - assert_eq!(VcxStateType::VcxStateAccepted as u32, credential::get_state(credential).unwrap()); + send_credential(credential_offer, alice, credential); + // AS INSTITUTION SEND PROOF REQUEST tests::set_institution(); - let address1 = "Address1"; - let address2 = "address2"; - let city = "CITY"; - let state = "State"; - let zip = "zip"; let restrictions = json!({ "issuer_did": institution_did, "schema_id": schema_id, "cred_def_id": cred_def_id, }); let mut attrs:Value = serde_json::Value::Array(vec![]); for i in 1..number_of_attributes { attrs.as_array_mut().unwrap().push(json!({ "name":format!("key{}", i), "restrictions": [restrictions]})); } - let requested_attrs = attrs.to_string(); - let proof_req_handle = proof::create_proof("1".to_string(), requested_attrs, "[]".to_string(), "name".to_string()).unwrap(); - println!("sending proof request"); - proof::send_proof_request(proof_req_handle, alice).unwrap(); - thread::sleep(Duration::from_millis(2000)); - set_consumer(); - let requests = disclosed_proof::get_proof_request_messages(faber, None).unwrap(); - let requests: Value = serde_json::from_str(&requests).unwrap(); - let requests = serde_json::to_string(&requests[0]).unwrap(); - let proof_handle = disclosed_proof::create_proof(::utils::constants::DEFAULT_PROOF_NAME, &requests).unwrap(); + let (proof_req_handle, req_uuid) = send_proof_request(alice, &attrs.to_string(), "[]", "{}", ""); + + let proof_handle = create_proof(faber, &req_uuid); println!("retrieving matching credentials"); let retrieved_credentials = disclosed_proof::retrieve_credentials(proof_handle).unwrap(); let matching_credentials: Value = serde_json::from_str(&retrieved_credentials).unwrap(); let mut credentials: Value = json!({"attrs":{}, "predicates":{}}); + for i in 1..number_of_attributes { - credentials["attrs"][format!("key{}",i)] = matching_credentials["attrs"][format!("key{}",i)][0].clone(); - } - let selected_credentials = credentials.to_string(); - disclosed_proof::generate_proof(proof_handle, selected_credentials.to_string(), "{}".to_string()).unwrap(); - println!("sending proof"); - disclosed_proof::send_proof(proof_handle, faber).unwrap(); + credentials["attrs"][format!("key{}",i)] = json!({ + "credential": matching_credentials["attrs"][format!("key{}",i)][0].clone(), + "tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string(), + }); + }; + generate_and_send_proof(proof_handle, faber, credentials); + + // AS INSTITUTION VALIDATE PROOF + set_institution(); + proof::update_state(proof_req_handle).unwrap(); + assert_eq!(proof::get_proof_state(proof_req_handle).unwrap(), ProofStateType::ProofValidated as u32); + println!("proof validated!"); + + teardown!("agency"); + } + + #[cfg(feature = "agency")] + #[cfg(feature = "pool_tests")] + #[test] + fn test_real_proof_with_revocation() { + let number_of_attributes = 10; + init!("agency"); + let institution_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + let (faber, alice) = ::connection::tests::create_connected_connections(); + + // CREATE SCHEMA AND CRED DEF + println!("creating schema/credential_def and paying fees"); + let attrs_list = json!(["address1", "address2", "city", "state", "zip"]).to_string(); + let (schema_id, schema_json, cred_def_id, cred_def_json, cred_def_handle, rev_reg_id) = + ::utils::libindy::anoncreds::tests::create_and_store_credential_def(&attrs_list, true); + + // AS INSTITUTION SEND CREDENTIAL OFFER + let (address1, address2, city, state, zip) = attr_names(); + let credential_data = json!({address1: ["123 Main St"], address2: ["Suite 3"], city: ["Draper"], state: ["UT"], zip: ["84000"]}).to_string(); + let credential_offer = send_cred_offer(&institution_did, cred_def_handle, alice, &credential_data); + + // AS CONSUMER SEND CREDENTIAL REQUEST + let credential = send_cred_req(faber); + + // AS INSTITUTION SEND CREDENTIAL + send_credential(credential_offer, alice, credential); + + // AS INSTITUTION SEND PROOF REQUEST + tests::set_institution(); + + let time_before_revocation = time::get_time().sec as u64; + let mut _requested_attrs = requested_attrs(&institution_did, &schema_id, &cred_def_id, None, Some(time_before_revocation)); + let(proof_req_handle, req_uuid) = send_proof_request(alice, &_requested_attrs.to_string(), "[]", "{}", ""); + + //AS Consumer - (Prover) GET PROOF REQ AND ASSOCIATED CREDENTIALS, GENERATE AND SEND PROOF + let proof_handle = create_proof(faber, &req_uuid); + let _selected_credentials = default_selected_credentials(proof_handle); + generate_and_send_proof(proof_handle, faber, _selected_credentials); - assert_eq!(VcxStateType::VcxStateAccepted as u32, disclosed_proof::get_state(proof_handle).unwrap()); - thread::sleep(Duration::from_millis(5000)); // AS INSTITUTION VALIDATE PROOF set_institution(); proof::update_state(proof_req_handle).unwrap(); assert_eq!(proof::get_proof_state(proof_req_handle).unwrap(), ProofStateType::ProofValidated as u32); println!("proof validated!"); let wallet = ::utils::libindy::payments::get_wallet_token_info().unwrap(); + + // AS INSTITUTION REVOKE CRED + revoke_credential(credential_offer, rev_reg_id); + + // VERIFIER SEND NEW PROOF REQ, Expected revoked proof + let requested_time = time::get_time().sec as u64; + let mut _requested_attrs = requested_attrs(&institution_did, &schema_id, &cred_def_id, None, Some(requested_time)); + _requested_attrs[0]["non_revoked"] = json!({"from": requested_time+1}); + let interval = json!({"from": time::get_time().sec+1}).to_string(); + let(proof_req_handle2, req_uuid2) = send_proof_request(alice, &_requested_attrs.to_string(), "[]", &interval, "- revoked creds"); + + //AS Consumer - (Prover) Generate Proof with revoked credentials + let revoked_proof = create_proof(faber, &req_uuid2); + let _selected_credentials = default_selected_credentials(revoked_proof); + generate_and_send_proof(revoked_proof, faber, _selected_credentials); + + // AS INSTITUTION VALIDATE REVOKED PROOF + set_institution(); + proof::update_state(proof_req_handle2).unwrap(); + assert_eq!(proof::get_proof_state(proof_req_handle2).unwrap(), ProofStateType::ProofInvalid as u32); + println!("proof invalid - revoked!"); + + // VERIFIER SENDS PROOF_REQ WITH INTERVAL BEFORE REVOCATION + let _requested_attrs = requested_attrs(&institution_did, &schema_id, &cred_def_id, None, Some(time_before_revocation)); + let(proof_req_handle3, req_uuid3) = send_proof_request(alice, &_requested_attrs.to_string(), "[]", "{}", ""); + + //AS Consumer - (Prover) Generate Proof with revoked credentials but valid interval + let valid_interval_proof = create_proof(faber, &req_uuid3); + let _selected_credentials = default_selected_credentials(valid_interval_proof); + generate_and_send_proof(valid_interval_proof, faber, _selected_credentials); + + // AS INSTITUTION VALIDATE REVOKED PROOF - VALID + set_institution(); + proof::update_state(proof_req_handle3).unwrap(); + assert_eq!(proof::get_proof_state(proof_req_handle3).unwrap(), ProofStateType::ProofValidated as u32); + println!("proof valid for specified interval!"); + teardown!("agency"); } } diff --git a/vcx/libvcx/src/messages/agent_utils.rs b/vcx/libvcx/src/messages/agent_utils.rs index 529ec1b3..2590b35f 100644 --- a/vcx/libvcx/src/messages/agent_utils.rs +++ b/vcx/libvcx/src/messages/agent_utils.rs @@ -70,6 +70,7 @@ pub struct Config { agency_verkey: String, wallet_name: Option, wallet_key: String, + wallet_type: Option, agent_seed: Option, enterprise_seed: Option, wallet_key_derivation: Option, @@ -79,10 +80,10 @@ pub struct Config { } pub fn connect_register_provision(config: &str) -> Result { + trace!("connect_register_provision >>> config: {:?}", config); trace!("***Registering with agency"); let my_config: Config = serde_json::from_str(&config).or(Err(error::INVALID_CONFIGURATION.code_num))?; - let (wallet_name_string, wallet_name) = match my_config.wallet_name { Some(x) => (format!("\"wallet_name\":\"{}\",", x), x), None => ("".to_string(), settings::DEFAULT_WALLET_NAME.to_string()), @@ -97,8 +98,11 @@ pub fn connect_register_provision(config: &str) -> Result { if let Some(_key_derivation) = &my_config.wallet_key_derivation { settings::set_config_value(settings::CONFIG_WALLET_KEY_DERIVATION, _key_derivation); } + if let Some(_wallet_type) = &my_config.wallet_type { + settings::set_config_value(settings::CONFIG_WALLET_TYPE, _wallet_type); + } - wallet::init_wallet(&wallet_name)?; + wallet::init_wallet(&wallet_name, my_config.wallet_type.as_ref().map(String::as_str))?; trace!("initialized wallet"); match ::utils::libindy::anoncreds::libindy_prover_create_master_secret(::settings::DEFAULT_LINK_SECRET_ALIAS) { @@ -114,9 +118,18 @@ pub fn connect_register_provision(config: &str) -> Result { let seed_opt = if seed.len() > 0 {Some(seed.as_ref())} else {None}; let (my_did, my_vk) = create_and_store_my_did(seed_opt)?; + let issuer_did; + let issuer_vk; let issuer_seed = my_config.enterprise_seed.as_ref().unwrap_or(&String::new()).to_string(); - let issuer_seed_opt = if issuer_seed.len() > 0 {Some(issuer_seed.as_ref())} else {None}; - let (issuer_did, issuer_vk) = create_and_store_my_did(issuer_seed_opt)?; + if issuer_seed != seed { + let issuer_seed_opt = if issuer_seed.len() > 0 { Some(issuer_seed.as_ref()) } else { None }; + let (did1, vk1) = create_and_store_my_did(issuer_seed_opt)?; + issuer_did = did1; + issuer_vk = vk1; + } else { + issuer_did = my_did.clone(); + issuer_vk = my_vk.clone(); + } settings::set_config_value(settings::CONFIG_INSTITUTION_DID,&my_did); settings::set_config_value(settings::CONFIG_SDK_TO_REMOTE_VERKEY,&my_vk); @@ -220,6 +233,8 @@ pub fn connect_register_provision(config: &str) -> Result { } pub fn update_agent_info(id: &str, value: &str) -> Result<(), u32> { + trace!("update_agent_info >>> id: {}, value: {}", id, value); + let new_config = UpdateAgentMsg { msg_type: MsgType { name: "UPDATE_COM_METHOD".to_string(), ver: "1.0".to_string(), }, com_method: ComMethod { id: id.to_string(), e_type: 1, value: value.to_string(), }, @@ -276,9 +291,9 @@ mod tests { fn test_real_connect_register_provision() { settings::set_defaults(); - let agency_did = "YRuVCckY6vfZfX9kcQZe3u"; - let agency_vk = "J8Yct6FwmarXjrE2khZesUXRVVSVczSoa9sFaGe6AD2v"; - let host = "https://enym-eagency.pdev.evernym.com"; + let agency_did = "VsKV7grR1BUE29mG2Fm2kX"; + let agency_vk = "Hezce2UWMZ3wUhVkh2LfKSs8nDzWwzs2Win7EzNN3YaR"; + let host = "http://localhost:8080"; let wallet_key = "test_key"; let config = json!({ "agency_url": host.to_string(), diff --git a/vcx/libvcx/src/messages/create_key.rs b/vcx/libvcx/src/messages/create_key.rs index 4cafa04b..11f4cdce 100644 --- a/vcx/libvcx/src/messages/create_key.rs +++ b/vcx/libvcx/src/messages/create_key.rs @@ -50,6 +50,8 @@ pub struct CreateKeyResponse { impl CreateKeyMsg{ pub fn create() -> CreateKeyMsg { + trace!("CreateKeyMsg::create_message >>>"); + CreateKeyMsg { to_did: String::new(), payload: CreateKeyPayload{ @@ -91,6 +93,8 @@ impl CreateKeyMsg{ } pub fn send_secure(&mut self) -> Result, u32> { + trace!("CreateKeyMsg::send >>>"); + let data = match self.msgpack() { Ok(x) => x, Err(x) => return Err(x), @@ -144,6 +148,8 @@ impl GeneralMessage for CreateKeyMsg { } pub fn parse_create_keys_response(response: Vec) -> Result<(String, String), u32> { + trace!("parse_create_keys_response >>>"); + let data = unbundle_from_agency(response)?; debug!("create keys response inner bundle: {:?}", data[0]); diff --git a/vcx/libvcx/src/messages/get_message.rs b/vcx/libvcx/src/messages/get_message.rs index 8a82bad1..c2cf18d9 100644 --- a/vcx/libvcx/src/messages/get_message.rs +++ b/vcx/libvcx/src/messages/get_message.rs @@ -48,6 +48,8 @@ pub struct GetMessages { impl GetMessages{ pub fn create() -> GetMessages { + trace!("GetMessages::create_message >>>"); + GetMessages { to_did: String::new(), to_vk: String::new(), @@ -90,6 +92,8 @@ impl GetMessages{ } pub fn send_secure(&mut self) -> Result, u32> { + trace!("GetMessages::send >>>"); + let data = match self.msgpack() { Ok(x) => x, Err(x) => return Err(x), @@ -106,6 +110,8 @@ impl GetMessages{ } pub fn download_messages(&mut self) -> Result, u32> { + trace!("GetMessages::download >>>"); + if self.validate_rc != error::SUCCESS.code_num { return Err(self.validate_rc) } @@ -238,6 +244,7 @@ pub struct GetMessagesResponse { } fn parse_get_messages_response(response: Vec) -> Result, u32> { + trace!("parse_get_messages_response >>>"); let data = unbundle_from_agency(response)?; trace!("get_message response: {:?}", data[0]); @@ -270,6 +277,8 @@ pub struct ConnectionMessages { } fn parse_get_connection_messages_response(response: Vec) -> Result, u32> { + trace!("parse_get_connection_messages_response >>>"); + let data = unbundle_from_agency(response)?; trace!("parse_get_connection_message response: {:?}", data[0]); @@ -299,6 +308,8 @@ fn parse_get_connection_messages_response(response: Vec) -> Result>) -> Result, u32> { + trace!("get_connection_messages >>> pw_did: {}, pw_vk: {}, agent_vk: {}, msg_uid: {:?}", + pw_did, pw_vk, agent_vk, msg_uid); match get_messages() .to(&pw_did) @@ -323,6 +334,9 @@ pub fn get_connection_messages(pw_did: &str, pw_vk: &str, agent_did: &str, agent } pub fn get_ref_msg(msg_id: &str, pw_did: &str, pw_vk: &str, agent_did: &str, agent_vk: &str) -> Result<(String, Vec), u32> { + trace!("get_ref_msg >>> msg_id: {}, pw_did: {}, pw_vk: {}, agent_did: {}, agent_vk: {}", + msg_id, pw_did, pw_vk, agent_did, agent_vk); + let message = get_connection_messages(pw_did, pw_vk, agent_did, agent_vk, Some(vec![msg_id.to_string()]))?; trace!("checking for ref_msg: {:?}", message); @@ -347,6 +361,8 @@ pub fn get_ref_msg(msg_id: &str, pw_did: &str, pw_vk: &str, agent_did: &str, age } pub fn download_messages(pairwise_dids: Option>, status_codes: Option>, uids: Option>) -> Result, u32> { + trace!("download_messages >>> pairwise_dids: {:?}, status_codes: {:?}, uids: {:?}", + pairwise_dids, status_codes, uids); if settings::test_agency_mode_enabled() { ::utils::httpclient::set_next_u8_response(::utils::constants::GET_ALL_MESSAGES_RESPONSE.to_vec()); @@ -431,12 +447,8 @@ mod tests { }; let data = encode::to_vec_named(&response).unwrap(); - - println!("generated response: {:?}", data); let bundle = Bundled::create(data).encode().unwrap(); - println!("bundle: {:?}", bundle); let result = parse_get_messages_response(bundle).unwrap(); - println!("response: {:?}", result); } #[cfg(feature = "agency")] @@ -450,9 +462,9 @@ mod tests { let institution_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let (faber, alice) = ::connection::tests::create_connected_connections(); - let (schema_id, _, cred_def_id, _) = ::utils::libindy::anoncreds::tests::create_and_store_credential_def(::utils::constants::DEFAULT_SCHEMA_ATTRS); + let (_, cred_def_handle) = ::credential_def::tests::create_cred_def_real(false); let credential_data = r#"{"address1": ["123 Main St"], "address2": ["Suite 3"], "city": ["Draper"], "state": ["UT"], "zip": ["84000"]}"#; - let credential_offer = ::issuer_credential::issuer_credential_create(cred_def_id.clone(), + let credential_offer = ::issuer_credential::issuer_credential_create(cred_def_handle, "1".to_string(), institution_did.clone(), "credential_name".to_string(), diff --git a/vcx/libvcx/src/messages/invite.rs b/vcx/libvcx/src/messages/invite.rs index c800b93b..7349f2e6 100644 --- a/vcx/libvcx/src/messages/invite.rs +++ b/vcx/libvcx/src/messages/invite.rs @@ -37,6 +37,8 @@ struct SendMsgDetailPayload { #[serde(rename = "phoneNo")] #[serde(skip_serializing_if = "Option::is_none")] phone: Option, + #[serde(rename = "includePublicDID")] + include_public_did: bool, } #[derive(Clone, Serialize, Debug, PartialEq, PartialOrd)] @@ -77,6 +79,9 @@ pub struct SendInvite { validate_rc: u32, agent_did: String, agent_vk: String, + #[serde(rename = "publicDID")] + #[serde(skip_serializing_if = "Option::is_none")] + public_did: Option, } #[derive(Clone, Serialize, Debug, PartialEq, PartialOrd)] @@ -103,6 +108,9 @@ pub struct SenderDetail { pub logo_url: Option, #[serde(rename = "verKey")] pub verkey: String, + #[serde(rename = "publicDID")] + #[serde(skip_serializing_if = "Option::is_none")] + pub public_did: Option, } #[derive(Clone, Deserialize, Serialize, Debug, PartialEq, PartialOrd)] @@ -158,6 +166,7 @@ impl InviteDetail { did: String::new(), logo_url: Some(String::new()), verkey: String::new(), + public_did: None, }, sender_agency_detail: SenderAgencyDetail { did: String::new(), @@ -173,6 +182,8 @@ impl InviteDetail { impl SendInvite{ pub fn create() -> SendInvite { + trace!("SendInvite::create_message >>>"); + SendInvite { to_did: String::new(), to_vk: String::new(), @@ -181,11 +192,14 @@ impl SendInvite{ msg_detail_payload: SendMsgDetailPayload { msg_type: MsgType { name: "MSG_DETAIL".to_string(), ver: "1.0".to_string(), } , key_proof: KeyDlgProofPayload { agent_did: String::new(), agent_delegated_key: String::new(), signature: String::new() , } , - phone: None, } , + phone: None, + include_public_did: false, + } , }, validate_rc: error::SUCCESS.code_num, agent_did: String::new(), agent_vk: String::new(), + public_did: None, } } @@ -202,6 +216,14 @@ impl SendInvite{ } } + pub fn public_did(&mut self, did: Option) -> &mut Self{ + if did.is_some() { + self.payload.msg_detail_payload.include_public_did = true; + } + self.public_did = did.clone(); + self + } + pub fn phone_number(&mut self, phone_number: &Option)-> &mut Self{ if let &Some(ref p_num) = phone_number { match validation::validate_phone_number(p_num.as_str()) { @@ -218,13 +240,15 @@ impl SendInvite{ pub fn generate_signature(&mut self) -> Result { let signature = format!("{}{}", self.payload.msg_detail_payload.key_proof.agent_did, self.payload.msg_detail_payload.key_proof.agent_delegated_key); - let signature = crypto::sign(wallet::get_wallet_handle(), &self.to_vk, signature.as_bytes())?; + let signature = crypto::sign(&self.to_vk, signature.as_bytes())?; let signature = base64::encode(&signature); self.payload.msg_detail_payload.key_proof.signature = signature.to_string(); Ok(error::SUCCESS.code_num) } pub fn send_secure(&mut self) -> Result, u32> { + trace!("SendInvite::send >>>"); + let data = match self.msgpack() { Ok(x) => x, Err(x) => return Err(x), @@ -268,6 +292,8 @@ impl AcceptInvite{ debug!("connection invitation details: {}", serde_json::to_string(&self.payload.msg_detail_payload).unwrap_or("failure".to_string())); } pub fn create() -> AcceptInvite { + trace!("AcceptInvite::create_message >>>"); + AcceptInvite { to_did: String::new(), to_vk: String::new(), @@ -323,13 +349,15 @@ impl AcceptInvite{ pub fn generate_signature(&mut self) -> Result { let signature = format!("{}{}", self.payload.msg_detail_payload.key_proof.agent_did, self.payload.msg_detail_payload.key_proof.agent_delegated_key); - let signature = crypto::sign(wallet::get_wallet_handle(), &self.to_vk, signature.as_bytes())?; + let signature = crypto::sign(&self.to_vk, signature.as_bytes())?; let signature = base64::encode(&signature); self.payload.msg_detail_payload.key_proof.signature = signature.to_string(); Ok(error::SUCCESS.code_num) } pub fn send_secure(&mut self) -> Result { + trace!("AcceptInvite::send >>>"); + let data = match self.msgpack() { Ok(x) => x, Err(x) => return Err(x), diff --git a/vcx/libvcx/src/messages/mod.rs b/vcx/libvcx/src/messages/mod.rs index 6151a6b1..c3e3e8e6 100644 --- a/vcx/libvcx/src/messages/mod.rs +++ b/vcx/libvcx/src/messages/mod.rs @@ -16,7 +16,6 @@ pub mod update_message; use std::u8; use settings; use utils::libindy::crypto; -use utils::libindy::wallet; use utils::error; use self::rmp_serde::encode; use self::create_key::CreateKeyMsg; @@ -193,7 +192,7 @@ pub fn bundle_for_agency(message: Vec, did: &str) -> Result, u32> { let my_vk = settings::get_config_value(settings::CONFIG_SDK_TO_REMOTE_VERKEY)?; trace!("pre encryption msg: {:?}", message); - let msg = crypto::prep_msg(wallet::get_wallet_handle(), &my_vk, &agent_vk, &message[..])?; + let msg = crypto::prep_msg(&my_vk, &agent_vk, &message[..])?; debug!("forwarding agency bundle to {}", did); let outer = Forward { @@ -211,7 +210,7 @@ pub fn bundle_for_agency(message: Vec, did: &str) -> Result, u32> { pub fn bundle_for_agent(message: Vec, pw_vk: &str, agent_did: &str, agent_vk: &str) -> Result, u32> { debug!("pre encryption msg: {:?}", message); - let msg = crypto::prep_msg(wallet::get_wallet_handle(), &pw_vk, agent_vk, &message[..])?; + let msg = crypto::prep_msg(&pw_vk, agent_vk, &message[..])?; /* forward to did */ debug!("forwarding agent bundle to {}", agent_did); diff --git a/vcx/libvcx/src/messages/proofs/proof_message.rs b/vcx/libvcx/src/messages/proofs/proof_message.rs index a14e4fb8..58ffd1ab 100644 --- a/vcx/libvcx/src/messages/proofs/proof_message.rs +++ b/vcx/libvcx/src/messages/proofs/proof_message.rs @@ -1,6 +1,6 @@ extern crate serde_json; -use utils::{ error, serde_utils }; +use utils::{ error }; use serde_json::Value; use error::proof::ProofError; @@ -19,6 +19,14 @@ pub struct ProofMessage{ pub libindy_proof: String, } +#[derive(Debug, Deserialize, Serialize, PartialEq)] +pub struct CredInfo { + pub schema_id: String, + pub cred_def_id: String, + pub rev_reg_id: Option, + pub timestamp: Option, +} + impl ProofMessage { pub fn new() -> ProofMessage { ProofMessage { @@ -45,22 +53,30 @@ impl ProofMessage { }) } - pub fn get_credential_info(&self) -> Result, ProofError> { + pub fn get_credential_info(&self) -> Result, ProofError> { let mut rtn = Vec::new(); let credentials: Value = serde_json::from_str(&self.libindy_proof) - .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; + .or(Err(ProofError::InvalidJson()))?; if let Value::Array(ref identifiers) = credentials["identifiers"] { for identifier in identifiers { - let reg_rev_id = String::new(); - rtn.push(( - serde_utils::get_value_to_string("schema_id", identifier) - .map_err(|e| ProofError::CommonError(e))?, - serde_utils::get_value_to_string("cred_def_id", identifier) - .map_err(|e| ProofError::CommonError(e))?, - reg_rev_id - )); + if let (Some(schema_id), Some(cred_def_id)) = (identifier["schema_id"].as_str(), + identifier["cred_def_id"].as_str()) { + let rev_reg_id = identifier["rev_reg_id"] + .as_str() + .map(|x| x.to_string()); + + let timestamp = identifier["timestamp"].as_u64(); + rtn.push( + CredInfo { + schema_id: schema_id.to_string(), + cred_def_id: cred_def_id.to_string(), + rev_reg_id, + timestamp, + } + ); + } else { return Err(ProofError::InvalidCredData()) } } } @@ -72,6 +88,7 @@ impl ProofMessage { #[cfg(test)] pub mod tests { use super::*; + use ::utils::constants::{SCHEMA_ID, CRED_DEF_ID, REV_REG_ID}; static TEMP_REQUESTER_DID: &'static str = "GxtnGN6ypZYgEqcftSQFnC"; static MSG_FROM_API: &str = r#"{"proofs":{"claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4":{"proof":{"primary_proof":{"eq_proof":{"revealed_attrs":{"sex":"5944657099558967239210949258394887428692050081607692519917050011144233115103","name":"1139481716457488690172217916278103335"},"a_prime":"55115757663642844902979276276581544287881791112969892277372135316353511833640150801244335663890109536491278379177551666081054765286807563008348637104046950934828407012194403360724040287698135607556244297972578864339500981366412262454282194811242239615009347165118318516694216754501345324782597475927199400880006212632553233049354866295429520527445980181939247828351677971991914388778860092824318440481574181300185829423762990910739241691289976584754979812272223819007422499654272590946235912914032826994670588466080422906806402660885408376207875827950805200378568062518210110828954480363081643567615791016011737856977","e":"34976147138641338975844073241645969211530343885520088294714132974884138611036204288689212378023649179372520412699253155486970203797562324","v":"961473607552945346906354315658276499450491951690969023699851664262072769313929148332129868528140265952852653009499943891795293148107502144091334703992581737220352761140064276811372868396353572957613845323343723271098601244774874235526135299483412285009916812621185291842845156342501611029106982811773616231232684804116984093651972537804480090649736612551759833591251845595059217608938213987633789344584340351801507541774726753840600143685051258161251666953243698589585559347435011414292427590918153421953579895479604685390401357681887618798200391305919594609949167659780330698000168295871428737686822637913218269005987492318466661186509308179489615192663542904993253626728197630057096161118638090776180812895097232529119979970798938360220605280817954648588493778338816318524451785027916181454650102696493927306340658666852294316562458212054696739343800993703515542777264448535624584845146378512183572107830260813929222999","m":{},"m1":"75548120024969192086664289521241751069844239013520403238642886571169851979005373784309432586593371476370934469326730539754613694936161784687213609047455188306625204249706249661640538349287762196100659095340756990269587317065862046598569445591945049204366911309949910119711238973099702616527117177036784698661","m2":"287944186286321709724396773443214682376883853676549188669693055373059354657799325692443906346632814001611911026063358134413175852024773765930829079850890920811398176944587192618"},"ge_proofs":[{"u":{"1":"1","0":"0","3":"3","2":"4"},"r":{"1":"1","0":"2","DELTA":"3","3":"4","2":"5"},"mj":"6","alpha":"7","t":{"1":"8","3":"3","0":"2","DELTA":"1","2":"2"},"predicate":{"attr_name":"age","p_type":"GE","value":18,"schema_seq_no":14,"issuer_did":"33UDR9R7fjwELRvH9JT6HH"}}]},"non_revoc_proof":null},"schema_seq_no":103,"issuer_did":"V4SGRU86Z58d6TV7PBUe6f"}},"aggregated_proof":{"c_hash":"63330487197040957750863022608534150304998351350639315143102570772502292901825","c_list":[[1,180,153,212,162,132,5,189,14,181,140,112,236,109,182,76,91,6,161,215,62,207,205,135,86,211,49,197,215,198,104,201,14,22,48,6,112,170,31,191,110,118,121,15,62,114,126,249,221,107,114,161,163,234,19,233,150,236,182,217,195,6,218,217,193,6,94,160,33,23,103,147,109,221,81,38,138,20,225,141,68,37,142,10,225,79,164,119,168,250,188,186,47,229,165,8,237,230,14,35,53,176,97,28,82,105,87,210,117,16,154,222,66,11,96,172,90,13,239,190,29,71,11,88,53,36,219,139,67,21,136,58,161,164,97,106,56,230,55,157,59,35,187,235,154,194,111,93,168,135,67,15,97,136,38,169,87,142,32,255,50,247,111,83,44,88,251,99,6,226,182,170,146,229,118,164,118,228,235,51,137,168,135,50,1,14,1,201,72,175,102,241,149,117,88,83,84,37,205,130,26,155,124,158,211,89,112,33,46,24,94,93,202,8,127,172,214,178,6,156,79,188,132,223,239,127,200,158,95,247,139,101,51,162,168,175,74,1,67,201,94,108,192,14,130,109,217,248,193,10,142,37,95,231,227,251,209]]},"requested_proof":{"revealed_attrs":{"attr2_uuid":["claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4","male","5944657099558967239210949258394887428692050081607692519917050011144233115103"],"attr1_uuid":["claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4","Alex","1139481716457488690172217916278103335"]},"unrevealed_attrs":{},"self_attested_attrs":{"self_attr":"self_value"},"predicates":{"predicate_id":"claim::71b6070f-14ba-45fa-876d-1fe8491fe5d4"}},"remoteDid":"KP8AaEBc368CMK1PqZaEzX","userPairwiseDid":"PofTCeegEXT7S2aAePhM6a"}"#; static TEST_ATTRS: &str = r#"[{"schema_seq_no":14,"issuer_did":"33UDR9R7fjwELRvH9JT6HH","credential_uuid":"claim::f33cc7c8-924f-4541-aeff-29a9aed9c46b","proof_attrs":[{"name":"state","value":"UT","revealed":true}]},{"schema_seq_no":15,"issuer_did":"4fUDR9R7fjwELRvH9JT6HH","credential_uuid":"claim::f22cc7c8-924f-4541-aeff-29a9aed9c46b","proof_attrs":[{"name":"state","value":"UT","revealed":true}]}]"#; @@ -100,10 +117,45 @@ pub mod tests { #[test] fn test_get_credential_data() { init!("true"); - let proof = create_default_proof(); - let credential_data = proof.get_credential_info().unwrap(); - assert_eq!(&credential_data[0].0, "NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"); - assert_eq!(&credential_data[0].1, "NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0"); - assert_eq!(&credential_data[0].2, ""); + let mut proof = ProofMessage::new(); + proof.libindy_proof = "".to_string(); + assert_eq!(proof.get_credential_info(), Err(ProofError::InvalidJson())); + + proof.libindy_proof = "{}".to_string(); + assert_eq!(proof.get_credential_info(), Ok(Vec::new())); + + proof.libindy_proof = json!({"identifiers": []}).to_string(); + assert_eq!(proof.get_credential_info(), Ok(Vec::new())); + + proof.libindy_proof = json!({"identifiers": [{}]}).to_string(); + assert_eq!(proof.get_credential_info(), Err(ProofError::InvalidCredData())); + + proof.libindy_proof = json!({"identifiers": [{ + "schema_id": null, + "cred_def_id": null, + }]}).to_string(); + assert_eq!(proof.get_credential_info(), Err(ProofError::InvalidCredData())); + + proof.libindy_proof = json!({"identifiers": [{ + "schema_id": SCHEMA_ID, + "cred_def_id": CRED_DEF_ID, + }]}).to_string(); + let mut cred_info = CredInfo { + schema_id: SCHEMA_ID.to_string(), + cred_def_id: CRED_DEF_ID.to_string(), + rev_reg_id: None, + timestamp: None + }; + assert_eq!(&proof.get_credential_info().unwrap()[0], &cred_info); + + proof.libindy_proof = json!({"identifiers": [{ + "schema_id": SCHEMA_ID, + "cred_def_id": CRED_DEF_ID, + "rev_reg_id": REV_REG_ID, + "timestamp": 123 + }]}).to_string(); + cred_info.rev_reg_id = Some(REV_REG_ID.to_string()); + cred_info.timestamp = Some(123); + assert_eq!(&proof.get_credential_info().unwrap()[0], &cred_info); } } diff --git a/vcx/libvcx/src/messages/proofs/proof_request.rs b/vcx/libvcx/src/messages/proofs/proof_request.rs index 7637a832..7c61467b 100644 --- a/vcx/libvcx/src/messages/proofs/proof_request.rs +++ b/vcx/libvcx/src/messages/proofs/proof_request.rs @@ -29,6 +29,8 @@ pub struct AttrInfo { pub name: String, #[serde(skip_serializing_if = "Option::is_none")] pub restrictions: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub non_revoked: Option } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] @@ -44,10 +46,13 @@ pub struct Filter { #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct PredicateInfo { pub name: String, + //Todo: Update p_type to use Enum pub p_type: String, pub p_value: i32, #[serde(skip_serializing_if = "Option::is_none")] pub restrictions: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub non_revoked: Option } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] @@ -55,6 +60,12 @@ pub struct ProofPredicates { predicates: Vec } +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)] +pub struct NonRevokedInterval { + pub from: Option, + pub to: Option +} + #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct ProofRequestData{ nonce: String, @@ -63,6 +74,7 @@ pub struct ProofRequestData{ data_version: String, pub requested_attributes: HashMap, pub requested_predicates: HashMap, + pub non_revoked: Option } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] @@ -75,6 +87,8 @@ pub struct ProofRequestMessage{ #[serde(skip_serializing, default)] validate_rc: u32, pub msg_ref_id: Option, + from_timestamp: Option, + to_timestamp: Option } impl ProofPredicates { @@ -102,9 +116,12 @@ impl ProofRequestMessage { data_version: String::new(), requested_attributes:HashMap::new(), requested_predicates: HashMap::new(), + non_revoked: None }, validate_rc: 0, msg_ref_id: None, + from_timestamp: None, + to_timestamp: None, } } @@ -196,6 +213,16 @@ impl ProofRequestMessage { self } + pub fn from_timestamp(&mut self, from: Option) -> &mut Self { + self.from_timestamp = from; + self + } + + pub fn to_timestamp(&mut self, to: Option) -> &mut Self { + self.to_timestamp = to; + self + } + pub fn serialize_message(&mut self) -> Result { if self.validate_rc != error::SUCCESS.code_num { return Err(self.validate_rc) @@ -235,6 +262,7 @@ mod tests { data_version: String::new(), requested_attributes: HashMap::new(), requested_predicates: HashMap::new(), + non_revoked: None }; assert_eq!(request.proof_request_data, proof_data); } @@ -259,6 +287,8 @@ mod tests { .proof_data_version(data_version) .requested_attrs(REQUESTED_ATTRS) .requested_predicates(REQUESTED_PREDICATES) + .to_timestamp(Some(100)) + .from_timestamp(Some(1)) .clone(); let serialized_msg = request.serialize_message().unwrap(); @@ -267,6 +297,8 @@ mod tests { assert!(serialized_msg.contains(r#"proof_request_data":{"nonce":"123432421212","name":"Test","version":"3.75","requested_attributes""#)); assert!(serialized_msg.contains(r#""age":{"name":"age","restrictions":[{"schema_id":"6XFh8yBzrpJQmNyZzgoTqB:2:schema_name:0.0.11","schema_issuer_did":"6XFh8yBzrpJQmNyZzgoTqB","schema_name":"Faber Student Info","schema_version":"1.0","issuer_did":"8XFh8yBzrpJQmNyZzgoTqB","cred_def_id":"8XFh8yBzrpJQmNyZzgoTqB:3:CL:1766"},{"schema_id":"5XFh8yBzrpJQmNyZzgoTqB:2:schema_name:0.0.11","schema_issuer_did":"5XFh8yBzrpJQmNyZzgoTqB","schema_name":"BYU Student Info","schema_version":"1.0","issuer_did":"66Fh8yBzrpJQmNyZzgoTqB","cred_def_id":"66Fh8yBzrpJQmNyZzgoTqB:3:CL:1766"}]}"#)); + assert!(serialized_msg.contains(r#""to_timestamp":100"#)); + assert!(serialized_msg.contains(r#""from_timestamp":1"#)); } #[test] diff --git a/vcx/libvcx/src/messages/send_message.rs b/vcx/libvcx/src/messages/send_message.rs index 2e483d45..c9e9becd 100644 --- a/vcx/libvcx/src/messages/send_message.rs +++ b/vcx/libvcx/src/messages/send_message.rs @@ -54,6 +54,8 @@ pub struct MessageDetailPayload { impl SendMessage{ pub fn create() -> SendMessage { + trace!("SendMessage::create_message >>>"); + SendMessage { message: String::new(), to_did: String::new(), @@ -102,6 +104,8 @@ impl SendMessage{ } pub fn send_secure(&mut self) -> Result, u32> { + trace!("SendMessage::send >>>"); + let data = match self.msgpack() { Ok(x) => x, Err(x) => return Err(x), diff --git a/vcx/libvcx/src/messages/update_connection.rs b/vcx/libvcx/src/messages/update_connection.rs index c9ee2709..145fb962 100644 --- a/vcx/libvcx/src/messages/update_connection.rs +++ b/vcx/libvcx/src/messages/update_connection.rs @@ -62,6 +62,8 @@ impl DeleteConnectionPayload { } impl DeleteConnection { pub fn create() -> DeleteConnection { + trace!("DeleteConnection::create_message >>>"); + DeleteConnection { to_did: String::new(), to_vk: String::new(), @@ -72,6 +74,8 @@ impl DeleteConnection { } } pub fn send_secure(&mut self) -> Result, u32> { + trace!("DeleteConnection::send >>>"); + let data = match self.msgpack() { Ok(x) => x, Err(x) => return Err(x), diff --git a/vcx/libvcx/src/messages/update_message.rs b/vcx/libvcx/src/messages/update_message.rs index e385c74b..23fe2f70 100644 --- a/vcx/libvcx/src/messages/update_message.rs +++ b/vcx/libvcx/src/messages/update_message.rs @@ -37,6 +37,8 @@ struct UpdateMessagesResponse { impl UpdateMessages{ pub fn send_secure(&mut self) -> Result<(), u32> { + trace!("UpdateMessages::send >>>"); + let data = encode::to_vec_named(&self).or(Err(error::UNKNOWN_ERROR.code_num))?; trace!("update_message content: {:?}", data); @@ -78,6 +80,7 @@ fn parse_update_messages_response(response: Vec) -> Result<(), u32> { } pub fn update_agency_messages(status_code: &str, msg_json: &str) -> Result<(), u32> { + trace!("update_agency_messages >>> status_code: {:?}, msg_json: {:?}", status_code, msg_json); debug!("updating agency messages {} to status code: {}", msg_json, status_code); let uids_by_conns: Vec = serde_json::from_str(msg_json) @@ -118,9 +121,10 @@ mod tests { let institution_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let (faber, alice) = ::connection::tests::create_connected_connections(); - let (schema_id, _, cred_def_id, _) = ::utils::libindy::anoncreds::tests::create_and_store_credential_def(::utils::constants::DEFAULT_SCHEMA_ATTRS); + let (_, cred_def_handle) = ::credential_def::tests::create_cred_def_real(false); + let credential_data = r#"{"address1": ["123 Main St"], "address2": ["Suite 3"], "city": ["Draper"], "state": ["UT"], "zip": ["84000"]}"#; - let credential_offer = ::issuer_credential::issuer_credential_create(cred_def_id.clone(), + let credential_offer = ::issuer_credential::issuer_credential_create(cred_def_handle, "1".to_string(), institution_did.clone(), "credential_name".to_string(), diff --git a/vcx/libvcx/src/messages/update_profile.rs b/vcx/libvcx/src/messages/update_profile.rs index e8545036..3e7e89d9 100644 --- a/vcx/libvcx/src/messages/update_profile.rs +++ b/vcx/libvcx/src/messages/update_profile.rs @@ -49,6 +49,8 @@ pub struct UpdateProfileResponse { impl UpdateProfileData{ pub fn create() -> UpdateProfileData { + trace!("UpdateProfileData::create_message >>>"); + UpdateProfileData { to_did: String::new(), payload: UpdateProfileDataPayload{ @@ -80,7 +82,19 @@ impl UpdateProfileData{ } } + pub fn use_public_did(&mut self, did: &Option) -> &mut Self { + if let Some(x) = did { + self.payload.configs.push(AttrValue { + name: "publicDid".to_string(), + value: x.to_string(), + }); + }; + self + } + pub fn send_secure(&mut self) -> Result, u32> { + trace!("UpdateProfileData::send_secure >>>"); + let data = match self.msgpack() { Ok(x) => x, Err(x) => return Err(x), diff --git a/vcx/libvcx/src/object_cache/mod.rs b/vcx/libvcx/src/object_cache/mod.rs index e9e60645..c52723c7 100644 --- a/vcx/libvcx/src/object_cache/mod.rs +++ b/vcx/libvcx/src/object_cache/mod.rs @@ -9,7 +9,7 @@ use std::ops::DerefMut; use utils::error; pub struct ObjectCache{ - store: Mutex>>, + pub store: Mutex>>, } impl Default for ObjectCache { diff --git a/vcx/libvcx/src/proof.rs b/vcx/libvcx/src/proof.rs index 36732dd6..93b33146 100644 --- a/vcx/libvcx/src/proof.rs +++ b/vcx/libvcx/src/proof.rs @@ -7,16 +7,14 @@ use self::openssl::bn::{ BigNum, BigNumRef }; use settings; use connection; use api::{ VcxStateType, ProofStateType }; -use std::collections::HashMap; -use messages::proofs::proof_message::{ProofMessage}; +use messages::proofs::proof_message::{ProofMessage, CredInfo}; use messages; use messages::proofs::proof_request::{ ProofRequestMessage }; use messages::GeneralMessage; use utils::error; use utils::constants::*; use utils::libindy::anoncreds::libindy_verifier_verify_proof; -use credential_def::{ retrieve_credential_def }; -use schema::{ LedgerSchema }; +use utils::libindy::anoncreds; use error::proof::ProofError; use error::ToErrorCode; use serde_json::Value; @@ -27,6 +25,12 @@ lazy_static! { static ref PROOF_MAP: ObjectCache = Default::default(); } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +struct RevocationInterval { + from: Option, + to: Option, +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Proof { source_id: String, @@ -47,6 +51,7 @@ pub struct Proof { remote_vk: String, agent_did: String, agent_vk: String, + revocation_interval: RevocationInterval } impl Proof { @@ -83,107 +88,159 @@ impl Proof { self.proof_state = ProofStateType::ProofInvalid; return Ok(error::SUCCESS.code_num) } + debug!("Indy validated proof: {}", self.source_id); self.proof_state = ProofStateType::ProofValidated; Ok(error::SUCCESS.code_num) } - fn build_credential_defs_json(&self, credential_data: &Vec<(String, String, String)>) -> Result { - debug!("{} building credentialdef json for proof validation", self.source_id); - let mut credential_json: HashMap = HashMap::new(); + fn build_credential_defs_json(&self, credential_data: &Vec) -> Result { + debug!("{} building credential_def_json for proof validation", self.source_id); + let mut credential_json = json!({}); - for &(_, ref cred_def_id, _) in credential_data.iter() { - if !credential_json.contains_key(cred_def_id) { - let (_, credential_def) = retrieve_credential_def(cred_def_id) - .map_err(|ec| ProofError::CommonError(ec.to_error_code()))?; + for ref cred_info in credential_data.iter() { + if credential_json.get(&cred_info.cred_def_id).is_none() { + let (id, credential_def) = anoncreds::get_cred_def_json(&cred_info.cred_def_id) + .map_err(|ec| ProofError::CommonError(ec))?; let credential_def = serde_json::from_str(&credential_def) .or(Err(ProofError::InvalidCredData()))?; - credential_json.insert(cred_def_id.to_string(), credential_def); + credential_json[id] = credential_def; } } - serde_json::to_string(&credential_json).map_err(|err| { - ProofError::CommonError(error::INVALID_CREDENTIAL_DEF_JSON.code_num) - }) + Ok(credential_json.to_string()) } - fn build_proof_json(&self) -> Result { - debug!("{} building proof json for proof validation", self.source_id); - match self.proof { - Some(ref x) => Ok(x.libindy_proof.clone()), - None => Err(ProofError::InvalidProof()), + fn build_schemas_json(&self, credential_data: &Vec) -> Result { + debug!("{} building schemas json for proof validation", self.source_id); + + let mut schemas_json = json!({}); + + for ref cred_info in credential_data.iter() { + if schemas_json.get(&cred_info.schema_id).is_none() { + let (id, schema_json) = anoncreds::get_schema_json(&cred_info.schema_id) + .or(Err(ProofError::InvalidSchema()))?; + + let schema_val = serde_json::from_str(&schema_json) + .or(Err(ProofError::InvalidSchema()))?; + + schemas_json[id] = schema_val; + } } + + Ok(schemas_json.to_string()) } - fn build_schemas_json(&self, credential_data: &Vec<(String, String, String)>) -> Result { - debug!("{} building schemas json for proof validation", self.source_id); + fn build_rev_reg_defs_json(&self, credential_data: &Vec) -> Result { + debug!("{} building rev_reg_def_json for proof validation", self.source_id); - let mut schema_json: HashMap = HashMap::new(); + let mut rev_reg_defs_json = json!({}); - for &(ref schema_id, _, _) in credential_data.iter() { - if !schema_json.contains_key(schema_id) { - let schema = LedgerSchema::new_from_ledger(schema_id) - .or(Err(ProofError::InvalidSchema()))?; + for ref cred_info in credential_data.iter() { + let rev_reg_id = cred_info + .rev_reg_id + .as_ref() + .ok_or(ProofError::InvalidRevocationInfo())?; - let schema_val = serde_json::from_str(&schema.schema_json) + if rev_reg_defs_json.get(rev_reg_id).is_none() { + let (id, json) = anoncreds::get_rev_reg_def_json(rev_reg_id) + .or(Err(ProofError::InvalidRevocationInfo()))?; + + let rev_reg_def_json = serde_json::from_str(&json) .or(Err(ProofError::InvalidSchema()))?; - schema_json.insert(schema_id.to_string(), schema_val); + rev_reg_defs_json[id] = rev_reg_def_json; + } + } + + Ok(rev_reg_defs_json.to_string()) + } + + fn build_rev_reg_json(&self, credential_data: &Vec) -> Result { + debug!("{} building rev_reg_json for proof validation", self.source_id); + + let mut rev_regs_json = json!({}); + + for ref cred_info in credential_data.iter() { + let rev_reg_id = cred_info + .rev_reg_id + .as_ref() + .ok_or(ProofError::InvalidRevocationInfo())?; + + let timestamp = cred_info + .timestamp + .as_ref() + .ok_or(ProofError::InvalidTimestamp())?; + + if rev_regs_json.get(rev_reg_id).is_none() { + let (id, json, timestamp) = anoncreds::get_rev_reg(rev_reg_id, timestamp.to_owned()) + .or(Err(ProofError::InvalidRevocationInfo()))?; + + let rev_reg_json: Value = serde_json::from_str(&json) + .or(Err(ProofError::InvalidJson()))?; + + let rev_reg_json = json!({timestamp.to_string(): rev_reg_json}); + rev_regs_json[id] = rev_reg_json; } } - serde_json::to_string(&schema_json).or(Err(ProofError::InvalidSchema())) + Ok(rev_regs_json.to_string()) + } + + fn build_proof_json(&self) -> Result { + debug!("{} building proof json for proof validation", self.source_id); + match self.proof { + Some(ref x) => Ok(x.libindy_proof.clone()), + None => Err(ProofError::InvalidProof()), + } } fn build_proof_req_json(&self) -> Result { debug!("{} building proof request json for proof validation", self.source_id); - match self.proof_request { - Some(ref x) => { - Ok(x.get_proof_request_data()) - }, - None => Err(ProofError::InvalidProof()), + if let Some(ref x) = self.proof_request { + return Ok(x.get_proof_request_data()) } + + Err(ProofError::InvalidProof()) } fn proof_validation(&mut self) -> Result { - let proof_req_msg = match self.proof_request.clone() { - Some(x) => x, - None => return Err(ProofError::InvalidProof()), - }; - - let proof_msg = match self.proof.clone() { - Some(x) => x, - None => return Err(ProofError::InvalidProof()), - }; + let proof_msg = self.proof + .clone() + .ok_or(ProofError::InvalidProof())?; let credential_data = proof_msg.get_credential_info()?; - //if credential_data.len() == 0 { - // return Err(ProofError::InvalidCredData()) - //} - - let credential_def_msg = match self.build_credential_defs_json(&credential_data) { - Ok(x) => x, - Err(_) => format!("{{}}"), - }; - - let schemas_json = match self.build_schemas_json(&credential_data) { - Ok(x) => x, - Err(_) => format!("{{}}"), - }; + let credential_defs_json = self.build_credential_defs_json(&credential_data) + .unwrap_or(json!({}).to_string()); + let schemas_json = self.build_schemas_json(&credential_data) + .unwrap_or(json!({}).to_string()); + let rev_reg_defs_json = self.build_rev_reg_defs_json(&credential_data) + .unwrap_or(json!({}).to_string()); + let rev_regs_json = self.build_rev_reg_json(&credential_data) + .unwrap_or(json!({}).to_string()); let proof_json = self.build_proof_json()?; let proof_req_json = self.build_proof_req_json()?; - debug!("*******\n{}\n********", credential_def_msg); + + debug!("*******\n{}\n********", credential_defs_json); debug!("*******\n{}\n********", schemas_json); debug!("*******\n{}\n********", proof_json); debug!("*******\n{}\n********", proof_req_json); -// proof_compliance(&proof_req_msg.proof_request_data, &proof_msg)?; - self.validate_proof_indy(&proof_req_json, &proof_json, &schemas_json, &credential_def_msg, "{}", "{}") + debug!("*******\n{}\n********", rev_reg_defs_json); + debug!("*******\n{}\n********", rev_regs_json); + self.validate_proof_indy(&proof_req_json, + &proof_json, + &schemas_json, + &credential_defs_json, + &rev_reg_defs_json, + &rev_regs_json) } fn send_proof_request(&mut self, connection_handle: u32) -> Result { + trace!("Proof::send_proof_request >>> connection_handle: {}", connection_handle); + if self.state != VcxStateType::VcxStateInitialized { warn!("proof {} has invalid state {} for sending proofRequest", self.source_id, self.state as u32); return Err(ProofError::ProofNotReadyError()) @@ -206,19 +263,19 @@ impl Proof { let mut proof_obj = messages::proof_request(); let proof_request = proof_obj .type_version(&self.version) - .tid(1) - .mid(9) .nonce(&self.nonce) .proof_name(&self.name) .proof_data_version(data_version) .requested_attrs(&self.requested_attrs) .requested_predicates(&self.requested_predicates) + .from_timestamp(self.revocation_interval.from) + .to_timestamp(self.revocation_interval.to) .serialize_message() .map_err(|ec| ProofError::ProofMessageError(ec))?; self.proof_request = Some(proof_obj); let data = connection::generate_encrypted_payload(&self.prover_vk, &self.remote_vk, &proof_request, "PROOF_REQUEST").map_err(|_| ProofError::ProofConnectionError())?; - let title = format!("{} wants you to share {}", settings::get_config_value(settings::CONFIG_INSTITUTION_NAME).map_err(|e| ProofError::CommonError(e))?, self.name); + let title = format!("{} wants you to share: {}", settings::get_config_value(settings::CONFIG_INSTITUTION_NAME).map_err(|e| ProofError::CommonError(e))?, self.name); match messages::send_message().to(&self.prover_did) .to_vk(&self.prover_vk) @@ -289,10 +346,15 @@ impl Proof { } fn update_state(&mut self) -> Result { + trace!("Proof::update_state >>>"); self.get_proof_request_status() } - fn get_state(&self) -> u32 {let state = self.state as u32; state} + fn get_state(&self) -> u32 { + trace!("Proof::get_state >>>"); + let state = self.state as u32; + state + } fn get_proof_state(&self) -> u32 {let state = self.proof_state as u32; state} @@ -320,13 +382,15 @@ impl Proof { pub fn create_proof(source_id: String, requested_attrs: String, requested_predicates: String, + revocation_details: String, name: String) -> Result { + trace!("create_proof >>> source_id: {}, requested_attrs: {}, requested_predicates: {}, name: {}", source_id, requested_attrs, requested_predicates, name); // TODO: Get this to actually validate as json, not just check length. - let length = requested_attrs.len(); - if length <= 0 { - return Err(ProofError::CommonError(error::INVALID_JSON.code_num)) - } + if requested_attrs.len() <= 0 { return Err(ProofError::CommonError(error::INVALID_JSON.code_num)) } + + let revocation_details: RevocationInterval = serde_json::from_str(&revocation_details) + .or(Err(ProofError::CommonError(error::INVALID_JSON.code_num)))?; debug!("creating proof with source_id: {}, name: {}, requested_attrs: {}, requested_predicates: {}", source_id, name, requested_attrs, requested_predicates); @@ -349,6 +413,7 @@ pub fn create_proof(source_id: String, remote_vk: String::new(), agent_did: String::new(), agent_vk: String::new(), + revocation_interval: revocation_details }; new_proof.validate_proof_request().map_err(|ec| ProofError::CommonError(ec))?; @@ -458,7 +523,6 @@ pub fn get_proof_uuid(handle: u32) -> Result { } fn parse_proof_payload(payload: &Vec) -> Result { - debug!("parsing proof payload: {:?}", payload); let data = messages::extract_json_payload(payload)?; let my_credential_req = ProofMessage::from_str(&data).map_err(|err| { @@ -487,7 +551,7 @@ pub fn generate_nonce() -> Result { mod tests { use super::*; use utils::httpclient; - use connection::build_connection; + use connection::tests::build_test_connection; use utils::libindy::{pool, set_libindy_rc}; static PROOF_MSG: &str = r#"{"msg_type":"proof","version":"0.1","to_did":"BnRXf8yDMUwGyZVDkSENeq","from_did":"GxtnGN6ypZYgEqcftSQFnC","proof_request_id":"cCanHnpFAD","proofs":{"claim::e5fec91f-d03d-4513-813c-ab6db5715d55":{"proof":{"primary_proof":{"eq_proof":{"revealed_attrs":{"state":"96473275571522321025213415717206189191162"},"a_prime":"22605045280481376895214546474258256134055560453004805058368015338423404000586901936329279496160366852115900235316791489357953785379851822281248296428005020302405076144264617943389810572564188437603815231794326272302243703078443007359698858400857606408856314183672828086906560155576666631125808137726233827430076624897399072853872527464581329767287002222137559918765406079546649258389065217669558333867707240780369514832185660287640444094973804045885379406641474693993903268791773620198293469768106363470543892730424494655747935463337367735239405840517696064464669905860189004121807576749786474060694597244797343224031","e":"70192089123105616042684481760592174224585053817450673797400202710878562748001698340846985261463026529360990669802293480312441048965520897","v":"1148619141217957986496757711054111791862691178309410923416837802801708689012670430650138736456223586898110113348220116209094530854607083005898964558239710027534227973983322542548800291320747321452329327824406430787211689678096549398458892087551551587767498991043777397791000822007896620414888602588897806008609113730393639807814070738699614969916095861363383223421727858670289337712185089527052065958362840287749622133424503902085247641830693297082507827948006947829401008622239294382186995101394791468192083810475776455445579931271665980788474331866572497866962452476638881287668931141052552771328556458489781734943404258692308937784221642452132005267809852656378394530342203469943982066011466088478895643800295937901139711103301249691253510784029114718919483272055970725860849610885050165709968510696738864528287788491998027072378656038991754015693216663830793243584350961586874315757599094357535856429087122365865868729","m":{"address2":"11774234640096848605908744857306447015748098256395922562149769943967941106193320512788344020652220849708117081570187385467979956319507248530701654682748372348387275979419669108338","city":"4853213962270369118453000522408430296589146124488849630769837449684434138367659379663124155088827069418193027370932024893343033367076071757003149452226758383807126385017161888440","address1":"12970590675851114145396120869959510754345567924518524026685086869487243290925032320159287997675756075512889990901552679591155319959039145119122576164798225386578339739435869622811","zip":"8333721522340131864419931745588776943042067606218561135102011966361165456174036379901390244538991611895455576519950813910672825465382312504250936740379785802177629077591444977329"},"m1":"92853615502250003546205004470333326341901175168428906399291824325990659330595200000112546157141090642053863739870044907457400076448073272490169488870502566172795456430489790324815765612798273406119873266684053517977802902202155082987833343670942161987285661291655743810590661447300059024966135828466539810035","m2":"14442362430453309930284822850357071315613831915865367971974791350454381198894252834180803515368579729220423713315556807632571621646127926114010380486713602821529657583905131582938"},"ge_proofs":[]},"non_revoc_proof":null},"schema_seq_no":15,"issuer_did":"4fUDR9R7fjwELRvH9JT6HH"}},"aggregated_proof":{"c_hash":"68430476900085482958838239880418115228681348197588159723604944078288347793331","c_list":[[179,17,2,242,194,227,92,203,28,32,255,113,112,20,5,243,9,111,220,111,21,210,116,12,167,119,253,181,37,40,143,215,140,42,179,97,75,229,96,94,54,248,206,3,48,14,61,219,160,122,139,227,166,183,37,43,197,200,28,220,217,10,65,42,6,195,124,44,164,65,114,206,51,231,254,156,170,141,21,153,50,251,237,65,147,97,243,17,157,116,213,201,80,119,106,70,88,60,55,36,33,160,135,106,60,212,191,235,116,57,78,177,61,86,44,226,205,100,134,118,93,6,26,58,220,66,232,166,202,62,90,174,231,207,19,239,233,223,70,191,199,100,157,62,139,176,28,184,9,70,116,199,142,237,198,183,12,32,53,84,207,202,77,56,97,177,154,169,223,201,212,163,212,101,184,255,215,167,16,163,136,44,25,123,49,15,229,41,149,133,159,86,106,208,234,73,207,154,194,162,141,63,159,145,94,47,174,51,225,91,243,2,221,202,59,11,212,243,197,208,116,42,242,131,221,137,16,169,203,215,239,78,254,150,42,169,202,132,172,106,179,130,178,130,147,24,173,213,151,251,242,44,54,47,208,223]]},"requested_proof":{"revealed_attrs":{"sdf":["claim::e5fec91f-d03d-4513-813c-ab6db5715d55","UT","96473275571522321025213415717206189191162"]},"unrevealed_attrs":{},"self_attested_attrs":{},"predicates":{}}}"#; extern "C" fn create_cb(command_handle: u32, err: u32, connection_handle: u32) { @@ -516,6 +580,7 @@ mod tests { remote_vk: VERKEY.to_string(), agent_did: DID.to_string(), agent_vk: VERKEY.to_string(), + revocation_interval: RevocationInterval { from: None, to: None} }) } @@ -526,6 +591,29 @@ mod tests { create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), + r#"{"support_revocation":false}"#.to_string(), + "Optional".to_owned()).unwrap(); + } + + #[test] + fn test_revocation_details() { + init!("true"); + + // No Revocation + create_proof("1".to_string(), + REQUESTED_ATTRS.to_owned(), + REQUESTED_PREDICATES.to_owned(), + r#"{"support_revocation":false}"#.to_string(), + "Optional".to_owned()).unwrap(); + + // Support Revocation Success + let revocation_details = json!({ + "to": 1234, + }); + create_proof("1".to_string(), + REQUESTED_ATTRS.to_owned(), + REQUESTED_PREDICATES.to_owned(), + revocation_details.to_string(), "Optional".to_owned()).unwrap(); } @@ -541,6 +629,7 @@ mod tests { let handle = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), + r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); let proof_string = to_string(handle).unwrap(); let s:Value = serde_json::from_str(&proof_string).unwrap(); @@ -554,6 +643,7 @@ mod tests { let handle = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), + r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); let proof_data = to_string(handle).unwrap(); let proof1: Proof = Proof::from_str(&proof_data).unwrap(); @@ -570,6 +660,7 @@ mod tests { let handle = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), + r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); assert!(release(handle).is_ok()); assert!(!is_valid_handle(handle)); @@ -579,7 +670,7 @@ mod tests { fn test_send_proof_request() { init!("true"); - let connection_handle = build_connection("test_send_proof_request").unwrap(); + let connection_handle = build_test_connection(); connection::set_agent_verkey(connection_handle, VERKEY).unwrap(); connection::set_agent_did(connection_handle, DID).unwrap(); connection::set_their_pw_verkey(connection_handle, VERKEY).unwrap(); @@ -587,6 +678,7 @@ mod tests { let handle = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), + r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); assert_eq!(send_proof_request(handle, connection_handle).unwrap(), error::SUCCESS.code_num); assert_eq!(get_state(handle).unwrap(), VcxStateType::VcxStateOfferSent as u32); @@ -601,12 +693,13 @@ mod tests { //2. Test that when no PW connection exists, send message fails on invalid did init!("true"); - let connection_handle = build_connection("test_send_proof_request").unwrap(); + let connection_handle = build_test_connection(); connection::set_pw_did(connection_handle, "").unwrap(); let handle = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), + r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); assert!(send_proof_request(handle, connection_handle).is_err()); @@ -618,6 +711,7 @@ mod tests { let handle = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), + r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); assert!(is_valid_handle(handle)); assert!(get_proof(handle).is_err()) @@ -627,7 +721,7 @@ mod tests { fn test_update_state_with_pending_proof() { init!("true"); - let connection_handle = build_connection("test_send_proof_request").unwrap(); + let connection_handle = build_test_connection(); let mut proof = Box::new(Proof { source_id: "12".to_string(), @@ -648,6 +742,7 @@ mod tests { remote_vk: VERKEY.to_string(), agent_did: DID.to_string(), agent_vk: VERKEY.to_string(), + revocation_interval: RevocationInterval { from: None, to: None} }); httpclient::set_next_u8_response(PROOF_RESPONSE.to_vec()); @@ -661,7 +756,7 @@ mod tests { fn test_get_proof_returns_proof_when_proof_state_invalid() { init!("true"); - let connection_handle = build_connection("test_send_proof_request").unwrap(); + let connection_handle = build_test_connection(); let mut proof = Box::new(Proof { source_id: "12".to_string(), @@ -682,6 +777,7 @@ mod tests { remote_vk: VERKEY.to_string(), agent_did: DID.to_string(), agent_vk: VERKEY.to_string(), + revocation_interval: RevocationInterval { from: None, to: None} }); httpclient::set_next_u8_response(PROOF_RESPONSE.to_vec()); @@ -703,30 +799,96 @@ mod tests { init!("true"); let proof = create_boxed_proof(); - let cred1 = ("schema_key1".to_string(), "cred_def_key1".to_string(), "".to_string()); - let cred2 = ("schema_key2".to_string(), "cred_def_key2".to_string(), "".to_string()); - let cred3 = ("schema_key3".to_string(), "cred_def_key3".to_string(), "".to_string()); - let credentials = vec![cred1.clone(), cred2.clone(), cred3.clone()]; + let cred1 = CredInfo { + schema_id: "schema_key1".to_string(), + cred_def_id: "cred_def_key1".to_string(), + rev_reg_id: None, + timestamp: None + }; + let cred2 = CredInfo { + schema_id: "schema_key2".to_string(), + cred_def_id: "cred_def_key2".to_string(), + rev_reg_id: None, + timestamp: None + }; + let credentials = vec![cred1, cred2]; let credential_json = proof.build_credential_defs_json(&credentials).unwrap(); - assert!(credential_json.contains(r#""cred_def_key1":{"id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:2471""#)); - assert!(credential_json.contains(r#""cred_def_key2":{"id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:2471""#)); - assert!(credential_json.contains(r#""cred_def_key3":{"id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:2471""#)); + let json: Value = serde_json::from_str(CRED_DEF_JSON).unwrap(); + let expected = json!({CRED_DEF_ID:json}).to_string(); + assert_eq!(credential_json, expected); } #[test] fn test_build_schemas_json_with_multiple_schemas() { init!("true"); let proof = create_boxed_proof(); - let cred1 = ("schema_key1".to_string(), "cred_def_key1".to_string(), "".to_string()); - let cred2 = ("schema_key2".to_string(), "cred_def_key2".to_string(), "".to_string()); - let cred3 = ("schema_key3".to_string(), "cred_def_key3".to_string(), "".to_string()); - let credentials = vec![cred1.clone(), cred2.clone(), cred3.clone()]; - let credential_json = proof.build_schemas_json(&credentials).unwrap(); + let cred1 = CredInfo { + schema_id: "schema_key1".to_string(), + cred_def_id: "cred_def_key1".to_string(), + rev_reg_id: None, + timestamp: None + }; + let cred2 = CredInfo { + schema_id: "schema_key2".to_string(), + cred_def_id: "cred_def_key2".to_string(), + rev_reg_id: None, + timestamp: None + }; + let credentials = vec![cred1, cred2]; + let schema_json = proof.build_schemas_json(&credentials).unwrap(); + + let json: Value = serde_json::from_str(SCHEMA_JSON).unwrap(); + let expected = json!({SCHEMA_ID:json}).to_string(); + assert_eq!(schema_json, expected); + } + + #[test] + fn test_build_rev_reg_defs_json() { + init!("true"); + let proof = create_boxed_proof(); + let cred1 = CredInfo { + schema_id: "schema_key1".to_string(), + cred_def_id: "cred_def_key1".to_string(), + rev_reg_id: Some("id1".to_string()), + timestamp: None + }; + let cred2 = CredInfo { + schema_id: "schema_key2".to_string(), + cred_def_id: "cred_def_key2".to_string(), + rev_reg_id: Some("id2".to_string()), + timestamp: None + }; + let credentials = vec![cred1, cred2]; + let rev_reg_defs_json = proof.build_rev_reg_defs_json(&credentials).unwrap(); + + let json: Value = serde_json::from_str(&rev_def_json()).unwrap(); + let expected = json!({REV_REG_ID:json}).to_string(); + assert_eq!(rev_reg_defs_json, expected); + } + + #[test] + fn test_build_rev_reg_json() { + init!("true"); + let proof = create_boxed_proof(); + let cred1 = CredInfo { + schema_id: "schema_key1".to_string(), + cred_def_id: "cred_def_key1".to_string(), + rev_reg_id: Some("id1".to_string()), + timestamp: Some(1), + }; + let cred2 = CredInfo { + schema_id: "schema_key2".to_string(), + cred_def_id: "cred_def_key2".to_string(), + rev_reg_id: Some("id2".to_string()), + timestamp: Some(2), + }; + let credentials = vec![cred1, cred2]; + let rev_reg_json = proof.build_rev_reg_json(&credentials).unwrap(); - assert!(credential_json.contains(r#""schema_key1":{"attrNames":["height","name","sex","age"],"id":"2hoqvcwupRTUNkXn6ArYzs:2:test-licence:4.4.4""#)); - assert!(credential_json.contains(r#""schema_key2":{"attrNames":["height","name","sex","age"],"id":"2hoqvcwupRTUNkXn6ArYzs:2:test-licence:4.4.4""#)); - assert!(credential_json.contains(r#""schema_key3":{"attrNames":["height","name","sex","age"],"id":"2hoqvcwupRTUNkXn6ArYzs:2:test-licence:4.4.4""#)); + let json: Value = serde_json::from_str(REV_REG_JSON).unwrap(); + let expected = json!({REV_REG_ID:{"1":json}}).to_string(); + assert_eq!(rev_reg_json, expected); } #[test] @@ -746,11 +908,11 @@ mod tests { #[test] fn test_release_all() { init!("true"); - let h1 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), "Optional".to_owned()).unwrap(); - let h2 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), "Optional".to_owned()).unwrap(); - let h3 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), "Optional".to_owned()).unwrap(); - let h4 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), "Optional".to_owned()).unwrap(); - let h5 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), "Optional".to_owned()).unwrap(); + let h1 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(),r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); + let h2 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(),r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); + let h3 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(),r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); + let h4 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(),r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); + let h5 = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(),r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); release_all(); assert_eq!(release(h1).err(), Some(ProofError::InvalidHandle())); assert_eq!(release(h2).err(), Some(ProofError::InvalidHandle())); @@ -789,6 +951,7 @@ mod tests { remote_vk: VERKEY.to_string(), agent_did: DID.to_string(), agent_vk: VERKEY.to_string(), + revocation_interval: RevocationInterval { from: None, to: None} }; let rc = proof.proof_validation(); assert!(rc.is_ok()); @@ -803,7 +966,7 @@ mod tests { fn test_send_proof_request_can_be_retried() { init!("true"); - let connection_handle = build_connection("test_send_proof_request").unwrap(); + let connection_handle = build_test_connection(); connection::set_agent_verkey(connection_handle, VERKEY).unwrap(); connection::set_agent_did(connection_handle, DID).unwrap(); connection::set_their_pw_verkey(connection_handle, VERKEY).unwrap(); @@ -811,6 +974,7 @@ mod tests { let handle = create_proof("1".to_string(), REQUESTED_ATTRS.to_owned(), REQUESTED_PREDICATES.to_owned(), + r#"{"support_revocation":false}"#.to_string(), "Optional".to_owned()).unwrap(); set_libindy_rc(error::TIMEOUT_LIBINDY_ERROR.code_num); assert_eq!(send_proof_request(handle, connection_handle).err(), Some(ProofError::CommonError(error::TIMEOUT_LIBINDY_ERROR.code_num))); @@ -827,7 +991,7 @@ mod tests { fn test_get_proof_request_status_can_be_retried() { init!("true"); - let connection_handle = build_connection("test_send_proof_request").unwrap(); + let connection_handle = build_test_connection(); let new_handle = 1; @@ -876,6 +1040,7 @@ mod tests { assert_eq!(create_proof("my source id".to_string(), empty.to_string(), "{}".to_string(), + r#"{"support_revocation":false}"#.to_string(), "my name".to_string()).err(), Some(ProofError::CommonError(INVALID_JSON.code_num))); diff --git a/vcx/libvcx/src/schema.rs b/vcx/libvcx/src/schema.rs index e1646345..87f68691 100644 --- a/vcx/libvcx/src/schema.rs +++ b/vcx/libvcx/src/schema.rs @@ -6,17 +6,8 @@ use settings; use std::fmt; use std::string::ToString; use utils::error; -use utils::constants::{ SCHEMA_ID, SCHEMA_JSON, SCHEMA_TXN_TYPE }; -use utils::libindy::{ - ledger::{ - libindy_build_get_schema_request, - libindy_submit_request, - libindy_build_schema_request, - libindy_parse_get_schema_response, - }, - anoncreds::libindy_issuer_create_schema, - payments::{pay_for_txn, PaymentTxn}, -}; +use utils::libindy::anoncreds; +use utils::libindy::payments::PaymentTxn; use error::schema::SchemaError; use utils::constants::DEFAULT_SERIALIZE_VERSION; use object_cache::ObjectCache; @@ -33,12 +24,6 @@ pub struct SchemaData { attr_names: Vec, } -#[derive(Debug, Serialize, Deserialize)] -pub struct LedgerSchema { - pub schema_id: String, - pub schema_json: String, -} - #[derive(Debug, Serialize, Deserialize, PartialEq)] pub struct CreateSchema { data: Vec, @@ -64,91 +49,6 @@ impl Default for CreateSchema { } } -pub trait Schema: ToString { - type SchemaType; - - fn retrieve_schema(submitter_did: &str, schema_id: &str) -> Result<(String, String), SchemaError> { - if settings::test_indy_mode_enabled() { return Ok((SCHEMA_ID.to_string(), SCHEMA_JSON.to_string()))} - - //Todo: Change SchemaError to InvalidSchemaId - let get_schema_req = libindy_build_get_schema_request(submitter_did, schema_id) - .or(Err(SchemaError::InvalidSchemaSeqNo()))?; - - let get_schema_response = libindy_submit_request(&get_schema_req) - .map_err(|err| SchemaError::CommonError(err))?; - - libindy_parse_get_schema_response(&get_schema_response) - .map_err(|err| SchemaError::CommonError(err)) - } - - fn create_schema(submitter_did: &str, - name: &str, - version: &str, - data: &str) -> Result<(String, Option), SchemaError> { - if settings::test_indy_mode_enabled() { - return Ok((SCHEMA_ID.to_string(), Some(PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap()))); - } - - let (id, create_schema) = libindy_issuer_create_schema(submitter_did, name, version, data) - .or(Err(SchemaError::InvalidSchemaCreation()))?; - - let request = libindy_build_schema_request(submitter_did, &create_schema) - .or(Err(SchemaError::InvalidSchemaCreation()))?; - - let (payment, response) = pay_for_txn(&request, SCHEMA_TXN_TYPE) - .map_err(|err| SchemaError::CommonError(err))?; - - Self::check_submit_schema_response(&response)?; - - Ok((id, payment)) - } - - fn check_submit_schema_response(txn: &str) -> Result<(), SchemaError> { - let txn_val: Value = serde_json::from_str(txn) - .or(Err(SchemaError::CommonError(error::INVALID_JSON.code_num)))?; - - match txn_val.get("result") { - Some(_) => return Ok(()), - None => warn!("No result found in ledger txn. Must be Rejectd"), - }; - - match txn_val.get("op") { - Some(m) => { - if m == "REJECT" { - match txn_val.get("reason") { - Some(r) => Err(SchemaError::DuplicateSchema(r.to_string())), - None => Err(SchemaError::UnknownRejection()), - } - } else { - return Err(SchemaError::CommonError(error::INVALID_JSON.code_num)) - }}, - None => return Err(SchemaError::CommonError(error::INVALID_JSON.code_num)) - } - } -} - -impl Schema for LedgerSchema { - type SchemaType = LedgerSchema; -} - -impl Schema for CreateSchema { - type SchemaType = CreateSchema; -} - -impl fmt::Display for LedgerSchema { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match serde_json::to_string(&self.schema_json ){ - Ok(s) => { - write!(f, "{}", s) - }, - Err(e) => { - error!("{}: {:?}",error::INVALID_SCHEMA.message, e); - write!(f, "null") - } - } - } -} - impl fmt::Display for CreateSchema { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match serde_json::to_string(&self){ @@ -163,22 +63,6 @@ impl fmt::Display for CreateSchema { } } -impl LedgerSchema { - - pub fn new_from_ledger(id: &str) -> Result - { - let submitter_did = &settings::get_config_value(settings::CONFIG_INSTITUTION_DID) - .map_err(|e| SchemaError::CommonError(e))?; - - let (schema_id, schema_json) = LedgerSchema::retrieve_schema(submitter_did, id)?; - - Ok(LedgerSchema{ - schema_id, - schema_json, - }) - } -} - impl CreateSchema { pub fn set_sequence_num(&mut self, sequence_num: u32) {self.sequence_num = sequence_num;} @@ -190,6 +74,7 @@ impl CreateSchema { pub fn get_schema_id(&self) -> &String { &self.schema_id } fn get_payment_txn(&self) -> Result { + trace!("CreateSchema::get_payment_txn >>>"); Ok(self.payment_txn.clone().ok_or(error::NOT_READY.code_num)?) } @@ -214,11 +99,17 @@ pub fn create_new_schema(source_id: &str, name: String, version: String, data: String) -> Result { + trace!("create_new_schema >>> source_id: {}, issuer_did: {}, name: {}, version: {}, data: {}", + source_id, issuer_did, name, version, data); + debug!("creating schema with source_id: {}, name: {}, issuer_did: {}", source_id, name, issuer_did); - let (schema_id, payment_txn) = LedgerSchema::create_schema(&issuer_did, - &name, - &version, - &data)?; + + let (schema_id, payment_txn) = anoncreds::create_schema(&name, &version, &data) + .map_err(|e| { + if e == error::UNKNOWN_SCHEMA_REJECTION.code_num {SchemaError::UnknownRejection()} + else if e == error::DUPLICATE_SCHEMA.code_num {SchemaError::DuplicateSchema()} + else {SchemaError::CommonError(e)} + })?; debug!("created schema on ledger with id: {}", schema_id); @@ -240,10 +131,13 @@ pub fn create_new_schema(source_id: &str, pub fn get_schema_attrs(source_id: String, schema_id: String) -> Result<(u32, String), SchemaError> { + trace!("get_schema_attrs >>> source_id: {}, schema_id: {}", source_id, schema_id); + let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID) .map_err(|e| SchemaError::CommonError(e))?; - let (schema_id, schema_json) = LedgerSchema::retrieve_schema(&submitter_did, &schema_id)?; + let (schema_id, schema_json) = anoncreds::get_schema_json(&schema_id) + .or(Err(SchemaError::InvalidSchemaSeqNo()))?; let schema_data: SchemaData = serde_json::from_str(&schema_json) .or(Err(SchemaError::CommonError(error::INVALID_JSON.code_num)))?; @@ -331,12 +225,16 @@ pub mod tests { use super::*; #[allow(unused_imports)] use rand::Rng; - use utils::error::INVALID_JSON; + use utils::constants::{ SCHEMA_ID, SCHEMA_JSON }; - #[test] - fn test_ledger_schema_to_string(){ - let schema = LedgerSchema {schema_json: "".to_string(), schema_id: "".to_string()}; - println!("{}", schema.to_string()); + pub fn create_schema_real() -> u32 { + let data = r#"["address1","address2","zip","city","state"]"#.to_string(); + let schema_name: String = rand::thread_rng().gen_ascii_chars().take(25).collect::(); + let schema_version: String = format!("{}.{}",rand::thread_rng().gen::().to_string(), + rand::thread_rng().gen::().to_string()); + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + + create_new_schema("id", did, schema_name, schema_version, data).unwrap() } #[test] @@ -393,8 +291,7 @@ pub mod tests { "name".to_string(), "1.0".to_string(), "".to_string()); - - assert_eq!(schema.err(),Some(SchemaError::InvalidSchemaCreation())); + assert_eq!(schema, Err(SchemaError::CommonError(error::INVALID_LIBINDY_PARAM.code_num))) } #[cfg(feature = "pool_tests")] @@ -410,15 +307,8 @@ pub mod tests { #[cfg(feature = "pool_tests")] #[test] fn test_create_schema_with_pool(){ - use settings; init!("ledger"); - let data = r#"["address1","address2","zip","city","state"]"#.to_string(); - let schema_name: String = rand::thread_rng().gen_ascii_chars().take(25).collect::(); - let schema_version: String = format!("{}.{}",rand::thread_rng().gen::().to_string(), - rand::thread_rng().gen::().to_string()); - let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); - - let handle = create_new_schema("id", did, schema_name, schema_version, data).unwrap(); + let handle = create_schema_real(); let payment = serde_json::to_string(&get_payment_txn(handle).unwrap()).unwrap(); assert!(payment.len() > 50); @@ -429,27 +319,21 @@ pub mod tests { #[cfg(feature = "pool_tests")] #[test] fn test_create_schema_no_fees_with_pool(){ - use settings; init!("ledger"); ::utils::libindy::payments::mint_tokens_and_set_fees(Some(0),Some(0),Some(r#"{"101":0, "102":0}"#.to_string()), None).unwrap(); - let data = r#"["address1","address2","zip","city","state"]"#.to_string(); - let schema_name: String = rand::thread_rng().gen_ascii_chars().take(25).collect::(); - let schema_version: String = format!("{}.{}",rand::thread_rng().gen::().to_string(), - rand::thread_rng().gen::().to_string()); - let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); - - let handle = create_new_schema("id", did, schema_name, schema_version, data).unwrap(); - + let handle = create_schema_real(); assert!(handle > 0); let schema_id = get_schema_id(handle).unwrap(); } #[cfg(feature = "pool_tests")] #[test] - fn test_create_duplicate_fails(){ + fn test_create_duplicate_fails_no_fees(){ use settings; init!("ledger"); + ::utils::libindy::payments::mint_tokens_and_set_fees(Some(0),Some(0),Some(r#"{"101":0, "102":0}"#.to_string()), None).unwrap(); + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let data = r#"["address1","address2","zip","city","state"]"#.to_string(); @@ -460,30 +344,7 @@ pub mod tests { assert!(rc.is_ok()); let rc = create_new_schema("id", did.clone(), schema_name.clone(), schema_version.clone(), data.clone()); - assert!(rc.is_err()); - } - - #[cfg(feature = "pool_tests")] - #[test] - fn from_pool_ledger_with_id(){ - use settings; - init!("ledger"); - let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); - let (schema_id, schema_json) = ::utils::libindy::anoncreds::tests::create_and_write_test_schema(::utils::constants::DEFAULT_SCHEMA_ATTRS); - - let rc = LedgerSchema::retrieve_schema(&did, &schema_id); - - let (id, retrieved_schema) = rc.unwrap(); - assert!(retrieved_schema.contains(&schema_id)); - - } - - #[test] - fn from_ledger_schema_id(){ - init!("true"); - let (id, retrieved_schema) = LedgerSchema::retrieve_schema(SCHEMA_ID, "2hoqvcwupRTUNkXn6ArYzs").unwrap(); - assert_eq!(&retrieved_schema, SCHEMA_JSON); - assert_eq!(&id, SCHEMA_ID); + assert_eq!(rc, Err(SchemaError::DuplicateSchema())); } #[test] @@ -510,8 +371,6 @@ pub mod tests { init!("false"); assert_eq!(get_sequence_num(145661).err(), Some(SchemaError::CommonError(error::INVALID_OBJ_HANDLE.code_num))); assert_eq!(to_string(13435178).err(), Some(SchemaError::CommonError(error::INVALID_OBJ_HANDLE.code_num))); - let test: Result = LedgerSchema::new_from_ledger(SCHEMA_ID); - assert_eq!(from_string("{}").err(), Some(SchemaError::CommonError(INVALID_JSON.code_num))); } #[test] diff --git a/vcx/libvcx/src/settings.rs b/vcx/libvcx/src/settings.rs index e40ea723..a25f8355 100644 --- a/vcx/libvcx/src/settings.rs +++ b/vcx/libvcx/src/settings.rs @@ -3,7 +3,7 @@ extern crate serde_json; use std::collections::HashMap; use std::sync::RwLock; -use utils::error; +use utils::{get_temp_dir_path, error}; use std::path::Path; use url::Url; use messages::validation; @@ -35,10 +35,14 @@ pub static CONFIG_WALLET_TYPE: &'static str = "wallet_type"; pub static CONFIG_WALLET_HANDLE: &'static str = "wallet_handle"; pub static CONFIG_THREADPOOL_SIZE: &'static str = "threadpool_size"; pub static CONFIG_WALLET_KEY_DERIVATION: &'static str = "wallet_key_derivation"; +pub static CONFIG_PROTOCOL_VERSION: &'static str = "protocol_version"; +pub static CONFIG_PAYMENT_METHOD: &'static str = "payment_method"; +pub static DEFAULT_PROTOCOL_VERSION: usize = 2; +pub static MAX_SUPPORTED_PROTOCOL_VERSION: usize = 2; pub static UNINITIALIZED_WALLET_KEY: &str = ""; -pub static DEFAULT_GENESIS_PATH: &str = "/tmp/genesis.txn"; -pub static DEFAULT_EXPORTED_WALLET_PATH: &str = "/tmp/wallet.txn"; +pub static DEFAULT_GENESIS_PATH: &str = "genesis.txn"; +pub static DEFAULT_EXPORTED_WALLET_PATH: &str = "wallet.txn"; pub static DEFAULT_WALLET_NAME: &str = "LIBVCX_SDK_WALLET"; pub static DEFAULT_POOL_NAME: &str = "pool1"; pub static DEFAULT_LINK_SECRET_ALIAS: &str = "main"; @@ -48,11 +52,13 @@ pub static DEFAULT_DID: &str = "2hoqvcwupRTUNkXn6ArYzs"; pub static DEFAULT_VERKEY: &str = "FuN98eH2eZybECWkofW6A9BKJxxnTatBCopfUiNxo6ZB"; pub static DEFAULT_ENABLE_TEST_MODE: &str = "false"; pub static DEFAULT_WALLET_BACKUP_KEY: &str = "backup_wallet_key"; -pub static DEFAULT_WALLET_KEY: &str = "foobar1234"; +pub static DEFAULT_WALLET_KEY: &str = "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY"; pub static DEFAULT_THREADPOOL_SIZE: usize = 8; pub static MASK_VALUE: &str = "********"; -pub static DEFAULT_WALLET_KEY_DERIVATION: &str = "ARGON2I_INT"; - +pub static DEFAULT_WALLET_KEY_DERIVATION: &str = "RAW"; +pub static DEFAULT_PAYMENT_PLUGIN: &str = "libnullpay.so"; +pub static DEFAULT_PAYMENT_INIT_FUNCTION: &str = "nullpay_init"; +pub static DEFAULT_PAYMENT_METHOD: &str = "null"; pub static MAX_THREADPOOL_SIZE: usize = 128; lazy_static! { @@ -71,6 +77,7 @@ impl ToString for HashMap { } } pub fn set_defaults() -> u32 { + trace!("set_defaults >>>"); // if this fails the program should exit let mut settings = SETTINGS.write().unwrap(); @@ -89,15 +96,20 @@ pub fn set_defaults() -> u32 { settings.insert(CONFIG_SDK_TO_REMOTE_DID.to_string(),DEFAULT_DID.to_string()); settings.insert(CONFIG_SDK_TO_REMOTE_VERKEY.to_string(),DEFAULT_VERKEY.to_string()); settings.insert(CONFIG_WALLET_KEY.to_string(),DEFAULT_WALLET_KEY.to_string()); + settings.insert(CONFIG_WALLET_KEY_DERIVATION.to_string(),DEFAULT_WALLET_KEY_DERIVATION.to_string()); settings.insert(CONFIG_LINK_SECRET_ALIAS.to_string(), DEFAULT_LINK_SECRET_ALIAS.to_string()); - settings.insert(CONFIG_EXPORTED_WALLET_PATH.to_string(), DEFAULT_EXPORTED_WALLET_PATH.to_string()); + settings.insert(CONFIG_PROTOCOL_VERSION.to_string(), DEFAULT_PROTOCOL_VERSION.to_string()); + settings.insert(CONFIG_EXPORTED_WALLET_PATH.to_string(), + get_temp_dir_path(Some(DEFAULT_EXPORTED_WALLET_PATH)).to_str().unwrap_or("").to_string()); settings.insert(CONFIG_WALLET_BACKUP_KEY.to_string(), DEFAULT_WALLET_BACKUP_KEY.to_string()); settings.insert(CONFIG_THREADPOOL_SIZE.to_string(), DEFAULT_THREADPOOL_SIZE.to_string()); + settings.insert(CONFIG_PAYMENT_METHOD.to_string(), DEFAULT_PAYMENT_METHOD.to_string()); error::SUCCESS.code_num } pub fn validate_config(config: &HashMap) -> Result { + trace!("validate_config >>> config: {:?}", config); //Mandatory parameters if config.get(CONFIG_WALLET_KEY).is_none() { @@ -120,7 +132,6 @@ pub fn validate_config(config: &HashMap) -> Result { validate_optional_config_val(config.get(CONFIG_AGENCY_ENDPOINT), error::INVALID_URL.code_num, Url::parse)?; validate_optional_config_val(config.get(CONFIG_INSTITUTION_LOGO_URL), error::INVALID_URL.code_num, Url::parse)?; - Ok(error::SUCCESS.code_num) } @@ -178,6 +189,8 @@ pub fn test_agency_mode_enabled() -> bool { } pub fn process_config_string(config: &str) -> Result { + trace!("process_config_string >>> config {}", config); + let configuration: Value = serde_json::from_str(config).or(Err(error::INVALID_JSON.code_num))?; if let Value::Object(ref map) = configuration { for (key, value) in map { @@ -191,6 +204,8 @@ pub fn process_config_string(config: &str) -> Result { } pub fn process_config_file(path: &str) -> Result { + trace!("process_config_file >>> path: {}", path); + if !Path::new(path).is_file() { error!("Configuration path was invalid"); Err(error::INVALID_CONFIGURATION.code_num) @@ -199,7 +214,29 @@ pub fn process_config_file(path: &str) -> Result { } } +pub fn get_protocol_version() -> usize { + let protocol_version = match get_config_value(CONFIG_PROTOCOL_VERSION) { + Ok(ver) => ver.parse::().unwrap_or_else(|err| { + warn!("Can't parse value of protocol version from config ({}), use default one ({})", err, DEFAULT_PROTOCOL_VERSION); + DEFAULT_PROTOCOL_VERSION + }), + Err(err) => { + info!("Can't fetch protocol version from config ({}), use default one ({})", err, DEFAULT_PROTOCOL_VERSION); + DEFAULT_PROTOCOL_VERSION + }, + }; + if protocol_version > MAX_SUPPORTED_PROTOCOL_VERSION { + error!("Protocol version from config {}, greater then maximal supported {}, use maximum one", + protocol_version, MAX_SUPPORTED_PROTOCOL_VERSION); + MAX_SUPPORTED_PROTOCOL_VERSION + } else { + protocol_version + } +} + pub fn get_config_value(key: &str) -> Result { + trace!("get_config_value >>> key: {}", key); + SETTINGS .read() .or(Err(error::INVALID_CONFIGURATION.code_num))? @@ -208,6 +245,7 @@ pub fn get_config_value(key: &str) -> Result { } pub fn set_config_value(key: &str, value: &str) { + trace!("set_config_value >>> key: {}, value: {}", key, value); SETTINGS.write().unwrap().insert(key.to_string(), value.to_string()); } @@ -221,7 +259,26 @@ pub fn get_wallet_credentials() -> String { credentials.to_string() } +pub fn validate_payment_method() -> Result<(), u32> { + let config = SETTINGS.read().unwrap(); + if let Some(method) = config.get(CONFIG_PAYMENT_METHOD) { + if !method.to_string().is_empty() { + return Ok(()); + } + } + return Err(error::MISSING_PAYMENT_METHOD.code_num); +} + +pub fn get_payment_method() -> String { + + let payment_method = get_config_value(CONFIG_PAYMENT_METHOD).unwrap_or(DEFAULT_PAYMENT_METHOD.to_string()); + + payment_method +} + pub fn write_config_to_file(config: &str, path_string: &str) -> Result<(), u32> { + trace!("write_config_to_file >>> config: {}, path_string: {}", config, path_string); + let mut file = fs::File::create(Path::new(path_string)) .or(Err(error::UNKNOWN_ERROR.code_num))?; @@ -231,6 +288,7 @@ pub fn write_config_to_file(config: &str, path_string: &str) -> Result<(), u32> } pub fn read_config_file(path: &str) -> Result { + trace!("read_config_file >>> path: {}", path); let mut file = fs::File::open(path).or(Err(error::UNKNOWN_ERROR.code_num))?; let mut config = String::new(); file.read_to_string(&mut config).or(Err(error::UNKNOWN_ERROR.code_num))?; @@ -238,8 +296,8 @@ pub fn read_config_file(path: &str) -> Result { } pub fn remove_file_if_exists(filename: &str){ + trace!("remove_file_if_exists >>> filename: {}", filename); if Path::new(filename).exists() { - println!("{}", format!("Removing file for testing: {}.", &filename)); match fs::remove_file(filename) { Ok(t) => (), Err(e) => println!("Unable to remove file: {:?}", e) @@ -248,6 +306,7 @@ pub fn remove_file_if_exists(filename: &str){ } pub fn clear_config() { + trace!("clear_config >>>"); let mut config = SETTINGS.write().unwrap(); config.clear(); } @@ -255,6 +314,7 @@ pub fn clear_config() { #[cfg(test)] pub mod tests { use super::*; + use utils::get_temp_dir_path; #[test] fn test_bad_path() { @@ -264,7 +324,8 @@ pub mod tests { #[test] fn test_read_config_file() { - let config_path = "/tmp/test_init.json"; + let config_path_buf = get_temp_dir_path(Some("test_init.json")); + let config_path = config_path_buf.to_str().unwrap(); let content = json!({ "pool_name" : "pool1", @@ -287,7 +348,8 @@ pub mod tests { #[test] fn test_process_file() { - let config_path = "/tmp/test_init.json"; + let config_path_buf = get_temp_dir_path(Some("test_init.json")); + let config_path = config_path_buf.to_str().unwrap(); let content = json!({ "pool_name" : "pool1", @@ -306,6 +368,7 @@ pub mod tests { write_config_to_file(&content, config_path).unwrap(); assert_eq!(process_config_file(config_path), Ok(error::SUCCESS.code_num)); + assert_eq!(get_config_value("institution_name").unwrap(), "evernym enterprise".to_string()); } @@ -327,7 +390,6 @@ pub mod tests { }).to_string(); assert_eq!(process_config_string(&content), Ok(error::SUCCESS.code_num)); - assert_eq!(get_config_value("institution_name").unwrap(), "evernym enterprise".to_string()); } #[test] @@ -349,7 +411,7 @@ pub mod tests { "institution_verkey": "444MFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE", }).to_string(); let config: HashMap = serde_json::from_str(&content).unwrap(); - assert_eq!(validate_config(&config), Ok(error::SUCCESS.code_num)) + assert_eq!(validate_config(&config), Ok(error::SUCCESS.code_num)); } #[test] @@ -437,7 +499,27 @@ pub mod tests { assert_eq!(get_config_value(&key), Err(error::INVALID_CONFIGURATION.code_num)); set_config_value(&key, &value1); - assert_eq!(get_config_value(&key).unwrap(), value1) + assert_eq!(get_config_value(&key).unwrap(), value1); + } + + #[test] + fn test_payment_plugin_validation() { + clear_config(); + set_config_value(CONFIG_PAYMENT_METHOD, "null"); + assert_eq!(validate_payment_method(), Ok(())); + } + + #[test] + fn test_payment_plugin_validation_empty_string() { + clear_config(); + set_config_value(CONFIG_PAYMENT_METHOD, ""); + assert_eq!(validate_payment_method(), Err(error::MISSING_PAYMENT_METHOD.code_num)); + } + + #[test] + fn test_payment_plugin_validation_missing_option() { + clear_config(); + assert_eq!(validate_payment_method(), Err(error::MISSING_PAYMENT_METHOD.code_num)); } #[test] @@ -448,7 +530,7 @@ pub mod tests { "wallet_name":"test_clear_config", "institution_name" : "evernym enterprise", "genesis_path":"/tmp/pool1.txn", - "wallet_key":"key" + "wallet_key":"key", }).to_string(); assert_eq!(process_config_string(&content), Ok(error::SUCCESS.code_num)); @@ -470,24 +552,4 @@ pub mod tests { assert_eq!(get_config_value("genesis_path"), Err(error::INVALID_CONFIGURATION.code_num)); assert_eq!(get_config_value("wallet_key"), Err(error::INVALID_CONFIGURATION.code_num)); } - - #[test] - fn test_log_settings() { - // log settings should mask the wallet_key field - ::utils::logger::LoggerUtils::init_test_logging("trace"); - set_defaults(); - let key = "secretkeyabc123foobar"; - { - let mut settings = SETTINGS.write().unwrap(); - settings.insert(CONFIG_WALLET_KEY.to_string(), key.to_string()).unwrap(); - let masked_settings = settings.to_string(); - match masked_settings.get(CONFIG_WALLET_KEY) { - None => panic!("Test Failure"), - Some(value) => { - assert_ne!(value, key); - }, - } - } - log_settings(); - } } diff --git a/vcx/libvcx/src/utils/constants.rs b/vcx/libvcx/src/utils/constants.rs index e88f8337..211d6e84 100644 --- a/vcx/libvcx/src/utils/constants.rs +++ b/vcx/libvcx/src/utils/constants.rs @@ -1,7 +1,7 @@ pub static TRUSTEE_SEED: &str = "000000000000000000000000Trustee1"; pub static DEFAULT_CONNECTION: &str = r#"{ "data": {"source_id":"test_vcx_connection_deserialialize_succeeds","pw_did":"8XFh8yBzrpJQmNyZzgoTqB","pw_verkey":"EkVTa7SCJ5SntpYyX7CSb2pcBhiVGT9kWSagA8a9T69A","did_endpoint":"","state":1,"uuid":"","endpoint":"","invite_detail":{"statusCode":"","connReqId":"","senderDetail":{"name":"","agentKeyDlgProof":{"agentDID":"","agentDelegatedKey":"","signature":""},"DID":"","logoUrl":"","verKey":""},"senderAgencyDetail":{"DID":"","verKey":"","endpoint":""},"targetName":"","statusMsg":""},"agent_did":"U5LXs4U7P9msh647kToezy","agent_vk":"FktSZg8idAVzyQZrdUppK6FTrfAzW3wWVzAjJAfdUvJq","their_pw_did":"","their_pw_verkey":""}, "version": "1.0"}"#; -pub static PROOF_WITH_INVALID_STATE: &str = r#"{"version": "1.0", "data": {"source_id":"12","requested_attrs":"[]","requested_predicates":"[]","msg_uid":"1234","ref_msg_id":"","prover_did":"GxtnGN6ypZYgEqcftSQFnC","prover_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE","state":2,"proof_state":2,"name":"","version":"1.0","nonce":"961863172979029799927308","proof":{"version":null,"to_did":null,"from_did":"2hoqvcwupRTUNkXn6ArYzs","proof_request_id":null,"libindy_proof":"{\"proof\":{\"proofs\":[{\"primary_proof\":{\"eq_proof\":{\"revealed_attrs\":{\"height\":\"25730877424947290072821310314181366395232879096832067784637233452620527354832\"},\"a_prime\":\"38468418127731713846178166829900143659393677229712995051558764704141198507982648296401969636617588869861413307083753301762347483561957199290251336021254439417128789026797145955984477221928182716204666352890028385023937842540450361420097431103250392570474089279140901696959752391635073270330468558954154194880702790759376380828440599338338035102331855027981011522557698834567753067206379930537016802075588341699458415972853098876747173416240143668330291197735072667092484763377784337539369362424727574865068876688736052128096968676805203613672531258006236254876884539045951639996619312445298338421294090709530014047972\",\"e\":\"154078967579028599771552225886166146397929690979656551248794150917378672515744224327631618260919015840285570941655123195202127789024078135\",\"v\":\"206650133702888797106822089576260511315673996444862232713919667631626480886927207636881658994691173459660978470403788734073760986620439580327132172963903472672583889688091094464120932708544221005169282402276486398643728400258904453278589049261526042465920275552343146712126256206336127806445434742377573251943058722259168851068891655316911187921990994131523755157817493625393978273746841320890182523140193423913928559137162375489508181000985374480875452950168078202002947841784773449595843073868172932201241350786838279665427992380489948833966021265302305724133918107232723382414241129228666424999973733399390438351369295116174512952324655959161674143294515337045202195459469964668483620985630335061682143952781081831116452202093796615884290232292781138886212342340265668009181731599782785279647873100827946769634016500720049437476277189417112183735003803866677542572168327201194005588295394938009893292601407316947642057\",\"m\":{\"name\":\"14317716492247065262512085019242237626449349441784394518514556593022994618325172736939996637063811425293094487652328383060228760217994402651170775306896722104418394329136611665343\",\"sex\":\"8273745146209996536038161334350089227113461716010701639169426048225428692159803922820821608832094611045622626669925382646938907151072414621800860596480606194039134705353081803165\",\"age\":\"4231054238529313674658593809238740704947764327405783946044127139188368334326617067522789723682113480091638434843954405217871598117884495148611034594431191670951925727063609682142\"},\"m1\":\"16077226648328465055653412522911855274309958773843607345305448528622673753821631144391688614271906713516184930726137071718220068885208665576942267877314141485128646733383927169667\",\"m2\":\"307531169989829093446786072508374599980728424269742153927811014293368496751029791103279482568696302054852869211813229594821072258566732852546275657912143510656140808146570824720\"},\"ge_proofs\":[]},\"non_revoc_proof\":null},{\"primary_proof\":{\"eq_proof\":{\"revealed_attrs\":{\"zip\":\"87121\"},\"a_prime\":\"22980705139335906693053137711136685933424776233380522453236439180929171299011892824616949981164043529861955976054341945627864882207456050318677121965935325809960446974596053408189551134515661563862881524571666187501122727801571323962966939474493588390360235667182579376145777468800550303664425178193631930564561723049183538282927599646527763284632796539606623768493060689100637116557667392220137410257431636511734992150836591814150936385237171600961922867616324375992788124580682105182900641444243976480856417385889949104486232380947645106164632331171061660796550392089851795426395070995493017794224520143054337746226\",\"e\":\"76282690374532772355879731548661978686850655961351295143503770941243495894338646017819430303027631933773624894143890625703962889768334045\",\"v\":\"163871248639398190945096440069662043127433951676852686546662953990786336996280725854469331726507733342023726300968336464180819246217513732235319949041996672970221003956107560478434062889302155642951932803028117639377419264243738845986591937119464296481011393554214365156921584039126625544193907434264722552626541996733765842362796948507495611245373172036135730178153875129763269752283501582374835061149405781305302348777575898058826139676172730891145943354354439852572793023260967354663689451699372085619446239471849305899996510995214404287577854904161278837483206040916543645383485994543595801626414351505157344120135188489094726450444310061126540914936137480569107724783635454491729295985282727332506496566440072535547642673629304980130245867106221256256513324156573289395988175082198939634551744626563343338338645642842406849216774021364088580494818675743281114570002722646356579330947996683078403354861328714045713581\",\"m\":{\"address1\":\"2165248344508520353766357402265701632395315972098389246389194385640539802337506425769768511519194552740720360820738302295920953335678232689667564165385439841496989825062838947259\",\"city\":\"14062441033587386074492953540858319607901106300870471376856462969255832720301575817298818494188653003203361668892633055754558023030908562519641589325943130928722511367589407296271\",\"state\":\"11954929001972442840069739994692033321109974653475671754863492167150247470566249523034076167519681518942499808749455624562697764021989162427160744700038173075463513230932710770940\",\"address2\":\"2198595304337627823960842218004760109114526286118976571409953402213833883269372274404781681446225341390202046798836378163125679905151333013089084872570388631925688246279177041270\"},\"m1\":\"16077226648328465055653412522911855274309958773843607345305448528622673753821631144391688614271906713516184930726137071718220068885208665576942267877314141485128646733383927169667\",\"m2\":\"7254196164614359653064600331737708502722271621243294598936016708686019460661844338759513800739179938931900307018966658914402446151530199048125880029627236169040751994424664466186\"},\"ge_proofs\":[]},\"non_revoc_proof\":null}],\"aggregated_proof\":{\"c_hash\":\"53950352519396118727110126559791411098081490918154654750464505328600997082590\",\"c_list\":[[1,48,186,131,141,25,34,1,69,221,204,87,153,98,112,57,80,249,204,167,228,160,102,249,42,73,87,42,83,247,68,76,140,62,243,157,1,67,210,213,245,34,93,156,193,240,22,134,110,195,171,11,248,100,90,14,108,42,146,160,37,91,237,36,30,57,0,172,118,172,207,33,92,200,45,238,106,252,153,58,215,235,157,121,77,41,193,216,116,13,160,165,177,98,69,99,130,143,105,84,194,117,25,167,232,41,190,252,91,231,65,99,131,73,216,51,114,109,233,68,87,174,112,159,188,34,13,169,83,136,51,228,244,232,219,169,221,151,163,120,224,13,215,143,179,213,168,229,220,73,152,33,102,196,44,26,182,32,80,1,91,20,161,55,14,46,224,70,38,169,6,219,209,25,58,152,14,112,111,19,65,99,232,176,88,251,145,33,229,114,86,11,54,17,217,142,139,159,55,64,246,217,192,1,85,223,140,35,11,151,176,210,178,65,134,197,123,0,179,72,89,144,101,15,119,34,174,255,43,215,253,212,234,79,246,91,189,0,230,32,200,19,93,232,133,78,144,215,203,110,42,219,69,126,50,222,228],[182,10,208,238,76,37,81,249,58,137,231,34,175,186,222,26,202,1,232,233,178,215,26,96,239,149,81,239,221,218,232,30,207,112,70,179,59,218,119,6,136,201,242,60,160,129,213,64,160,136,197,82,4,219,218,190,77,123,58,226,181,7,53,200,121,117,148,189,65,226,196,60,168,22,173,0,42,112,149,63,153,25,58,94,132,124,99,198,201,220,40,245,155,16,209,167,91,144,27,203,65,167,119,193,231,194,190,224,118,210,97,94,175,53,166,214,219,243,91,11,114,181,169,167,32,21,188,175,110,61,208,240,118,27,223,230,28,3,68,48,57,214,247,228,205,40,142,118,30,58,81,103,103,252,161,173,205,123,124,65,143,27,2,13,55,174,45,95,146,46,214,64,128,239,151,161,51,118,0,208,244,100,255,245,195,225,91,251,116,147,238,130,243,151,236,88,49,153,186,103,87,229,169,54,26,183,176,164,68,243,206,233,8,245,104,255,198,51,252,90,168,223,23,81,48,216,217,153,203,119,127,249,211,53,17,66,144,113,201,77,199,224,53,226,175,209,181,55,14,97,54,54,78,240,37,50]]}},\"requested_proof\":{\"revealed_attrs\":{\"height_1\":{\"sub_proof_index\":0,\"raw\":\"4'11\",\"encoded\":\"25730877424947290072821310314181366395232879096832067784637233452620527354832\"},\"zip_2\":{\"sub_proof_index\":1,\"raw\":\"87121\",\"encoded\":\"87121\"}},\"self_attested_attrs\":{},\"unrevealed_attrs\":{},\"predicates\":{}},\"identifiers\":[{\"schema_id\":\"2hoqvcwupRTUNkXn6ArYzs:2:schema_name:0.0.11\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"rev_reg_id\":null,\"timestamp\":null},{\"schema_id\":\"2hoqvcwupRTUNkXn6ArYzs:2:Home Address - Test:0.0.1\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:2200\",\"rev_reg_id\":null,\"timestamp\":null}]}"},"proof_request":{"@type":{"name":"PROOF_REQUEST","version":""},"@topic":{"mid":0,"tid":0},"proof_request_data":{"nonce":"123432421212","name":"proof_req_1","version":"0.1","requested_attributes":{"height_1":{"name":"height","restrictions":[{"schema_id":null,"schema_issuer_did":null,"schema_name":null,"schema_version":null,"issuer_did":"2hoqvcwupRTUNkXn6ArYzs","cred_def_id":null}]},"zip_2":{"name":"zip","restrictions":[{"schema_id":null,"schema_issuer_did":null,"schema_name":null,"schema_version":null,"issuer_did":"2hoqvcwupRTUNkXn6ArYzs","cred_def_id":null}]}},"requested_predicates":{}},"msg_ref_id":null},"remote_did":"FhrSrYtQcw3p9xwf7NYemf","remote_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE","agent_did":"FhrSrYtQcw3p9xwf7NYemf","agent_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE"}}"#; -pub static PROOF_OFFER_SENT: &str = r#"{"version": "1.0", "data": {"nonce":"123456","version":"1.0","handle":1,"msg_uid":"","ref_msg_id":"","name":"Name Data","prover_vk":"","agent_did":"","agent_vk":"","remote_did":"","remote_vk":"","prover_did":"8XFh8yBzrpJQmNyZzgoTqB","requested_attrs":"{\"attrs\":[{\"name\":\"person name\"},{\"schema_seq_no\":1,\"name\":\"address_1\"},{\"schema_seq_no\":2,\"issuer_did\":\"ISSUER_DID2\",\"name\":\"address_2\"},{\"schema_seq_no\":1,\"name\":\"city\"},{\"schema_seq_no\":1,\"name\":\"state\"},{\"schema_seq_no\":1,\"name\":\"zip\"}]}","requested_predicates":"{\"attr_name\":\"age\",\"p_type\":\"GE\",\"value\":18,\"schema_seq_no\":1,\"issuer_did\":\"DID1\"}","source_id":"source id","state":2,"proof_state":0,"proof":null,"proof_request":null}}"#; +pub static PROOF_WITH_INVALID_STATE: &str = r#"{"version": "1.0", "data": {"source_id":"12","requested_attrs":"[]","requested_predicates":"[]","msg_uid":"1234","ref_msg_id":"","prover_did":"GxtnGN6ypZYgEqcftSQFnC","prover_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE","state":2,"proof_state":2,"name":"","version":"1.0","nonce":"961863172979029799927308","proof":{"version":null,"to_did":null,"from_did":"2hoqvcwupRTUNkXn6ArYzs","proof_request_id":null,"libindy_proof":"{\"proof\":{\"proofs\":[{\"primary_proof\":{\"eq_proof\":{\"revealed_attrs\":{\"height\":\"25730877424947290072821310314181366395232879096832067784637233452620527354832\"},\"a_prime\":\"38468418127731713846178166829900143659393677229712995051558764704141198507982648296401969636617588869861413307083753301762347483561957199290251336021254439417128789026797145955984477221928182716204666352890028385023937842540450361420097431103250392570474089279140901696959752391635073270330468558954154194880702790759376380828440599338338035102331855027981011522557698834567753067206379930537016802075588341699458415972853098876747173416240143668330291197735072667092484763377784337539369362424727574865068876688736052128096968676805203613672531258006236254876884539045951639996619312445298338421294090709530014047972\",\"e\":\"154078967579028599771552225886166146397929690979656551248794150917378672515744224327631618260919015840285570941655123195202127789024078135\",\"v\":\"206650133702888797106822089576260511315673996444862232713919667631626480886927207636881658994691173459660978470403788734073760986620439580327132172963903472672583889688091094464120932708544221005169282402276486398643728400258904453278589049261526042465920275552343146712126256206336127806445434742377573251943058722259168851068891655316911187921990994131523755157817493625393978273746841320890182523140193423913928559137162375489508181000985374480875452950168078202002947841784773449595843073868172932201241350786838279665427992380489948833966021265302305724133918107232723382414241129228666424999973733399390438351369295116174512952324655959161674143294515337045202195459469964668483620985630335061682143952781081831116452202093796615884290232292781138886212342340265668009181731599782785279647873100827946769634016500720049437476277189417112183735003803866677542572168327201194005588295394938009893292601407316947642057\",\"m\":{\"name\":\"14317716492247065262512085019242237626449349441784394518514556593022994618325172736939996637063811425293094487652328383060228760217994402651170775306896722104418394329136611665343\",\"sex\":\"8273745146209996536038161334350089227113461716010701639169426048225428692159803922820821608832094611045622626669925382646938907151072414621800860596480606194039134705353081803165\",\"age\":\"4231054238529313674658593809238740704947764327405783946044127139188368334326617067522789723682113480091638434843954405217871598117884495148611034594431191670951925727063609682142\"},\"m1\":\"16077226648328465055653412522911855274309958773843607345305448528622673753821631144391688614271906713516184930726137071718220068885208665576942267877314141485128646733383927169667\",\"m2\":\"307531169989829093446786072508374599980728424269742153927811014293368496751029791103279482568696302054852869211813229594821072258566732852546275657912143510656140808146570824720\"},\"ge_proofs\":[]},\"non_revoc_proof\":null},{\"primary_proof\":{\"eq_proof\":{\"revealed_attrs\":{\"zip\":\"87121\"},\"a_prime\":\"22980705139335906693053137711136685933424776233380522453236439180929171299011892824616949981164043529861955976054341945627864882207456050318677121965935325809960446974596053408189551134515661563862881524571666187501122727801571323962966939474493588390360235667182579376145777468800550303664425178193631930564561723049183538282927599646527763284632796539606623768493060689100637116557667392220137410257431636511734992150836591814150936385237171600961922867616324375992788124580682105182900641444243976480856417385889949104486232380947645106164632331171061660796550392089851795426395070995493017794224520143054337746226\",\"e\":\"76282690374532772355879731548661978686850655961351295143503770941243495894338646017819430303027631933773624894143890625703962889768334045\",\"v\":\"163871248639398190945096440069662043127433951676852686546662953990786336996280725854469331726507733342023726300968336464180819246217513732235319949041996672970221003956107560478434062889302155642951932803028117639377419264243738845986591937119464296481011393554214365156921584039126625544193907434264722552626541996733765842362796948507495611245373172036135730178153875129763269752283501582374835061149405781305302348777575898058826139676172730891145943354354439852572793023260967354663689451699372085619446239471849305899996510995214404287577854904161278837483206040916543645383485994543595801626414351505157344120135188489094726450444310061126540914936137480569107724783635454491729295985282727332506496566440072535547642673629304980130245867106221256256513324156573289395988175082198939634551744626563343338338645642842406849216774021364088580494818675743281114570002722646356579330947996683078403354861328714045713581\",\"m\":{\"address1\":\"2165248344508520353766357402265701632395315972098389246389194385640539802337506425769768511519194552740720360820738302295920953335678232689667564165385439841496989825062838947259\",\"city\":\"14062441033587386074492953540858319607901106300870471376856462969255832720301575817298818494188653003203361668892633055754558023030908562519641589325943130928722511367589407296271\",\"state\":\"11954929001972442840069739994692033321109974653475671754863492167150247470566249523034076167519681518942499808749455624562697764021989162427160744700038173075463513230932710770940\",\"address2\":\"2198595304337627823960842218004760109114526286118976571409953402213833883269372274404781681446225341390202046798836378163125679905151333013089084872570388631925688246279177041270\"},\"m1\":\"16077226648328465055653412522911855274309958773843607345305448528622673753821631144391688614271906713516184930726137071718220068885208665576942267877314141485128646733383927169667\",\"m2\":\"7254196164614359653064600331737708502722271621243294598936016708686019460661844338759513800739179938931900307018966658914402446151530199048125880029627236169040751994424664466186\"},\"ge_proofs\":[]},\"non_revoc_proof\":null}],\"aggregated_proof\":{\"c_hash\":\"53950352519396118727110126559791411098081490918154654750464505328600997082590\",\"c_list\":[[1,48,186,131,141,25,34,1,69,221,204,87,153,98,112,57,80,249,204,167,228,160,102,249,42,73,87,42,83,247,68,76,140,62,243,157,1,67,210,213,245,34,93,156,193,240,22,134,110,195,171,11,248,100,90,14,108,42,146,160,37,91,237,36,30,57,0,172,118,172,207,33,92,200,45,238,106,252,153,58,215,235,157,121,77,41,193,216,116,13,160,165,177,98,69,99,130,143,105,84,194,117,25,167,232,41,190,252,91,231,65,99,131,73,216,51,114,109,233,68,87,174,112,159,188,34,13,169,83,136,51,228,244,232,219,169,221,151,163,120,224,13,215,143,179,213,168,229,220,73,152,33,102,196,44,26,182,32,80,1,91,20,161,55,14,46,224,70,38,169,6,219,209,25,58,152,14,112,111,19,65,99,232,176,88,251,145,33,229,114,86,11,54,17,217,142,139,159,55,64,246,217,192,1,85,223,140,35,11,151,176,210,178,65,134,197,123,0,179,72,89,144,101,15,119,34,174,255,43,215,253,212,234,79,246,91,189,0,230,32,200,19,93,232,133,78,144,215,203,110,42,219,69,126,50,222,228],[182,10,208,238,76,37,81,249,58,137,231,34,175,186,222,26,202,1,232,233,178,215,26,96,239,149,81,239,221,218,232,30,207,112,70,179,59,218,119,6,136,201,242,60,160,129,213,64,160,136,197,82,4,219,218,190,77,123,58,226,181,7,53,200,121,117,148,189,65,226,196,60,168,22,173,0,42,112,149,63,153,25,58,94,132,124,99,198,201,220,40,245,155,16,209,167,91,144,27,203,65,167,119,193,231,194,190,224,118,210,97,94,175,53,166,214,219,243,91,11,114,181,169,167,32,21,188,175,110,61,208,240,118,27,223,230,28,3,68,48,57,214,247,228,205,40,142,118,30,58,81,103,103,252,161,173,205,123,124,65,143,27,2,13,55,174,45,95,146,46,214,64,128,239,151,161,51,118,0,208,244,100,255,245,195,225,91,251,116,147,238,130,243,151,236,88,49,153,186,103,87,229,169,54,26,183,176,164,68,243,206,233,8,245,104,255,198,51,252,90,168,223,23,81,48,216,217,153,203,119,127,249,211,53,17,66,144,113,201,77,199,224,53,226,175,209,181,55,14,97,54,54,78,240,37,50]]}},\"requested_proof\":{\"revealed_attrs\":{\"height_1\":{\"sub_proof_index\":0,\"raw\":\"4'11\",\"encoded\":\"25730877424947290072821310314181366395232879096832067784637233452620527354832\"},\"zip_2\":{\"sub_proof_index\":1,\"raw\":\"87121\",\"encoded\":\"87121\"}},\"self_attested_attrs\":{},\"unrevealed_attrs\":{},\"predicates\":{}},\"identifiers\":[{\"schema_id\":\"2hoqvcwupRTUNkXn6ArYzs:2:schema_name:0.0.11\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"rev_reg_id\":null,\"timestamp\":null},{\"schema_id\":\"2hoqvcwupRTUNkXn6ArYzs:2:Home Address - Test:0.0.1\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:2200\",\"rev_reg_id\":null,\"timestamp\":null}]}"},"proof_request":{"@type":{"name":"PROOF_REQUEST","version":""},"@topic":{"mid":0,"tid":0},"proof_request_data":{"nonce":"123432421212","name":"proof_req_1","version":"0.1","requested_attributes":{"height_1":{"name":"height","restrictions":[{"schema_id":null,"schema_issuer_did":null,"schema_name":null,"schema_version":null,"issuer_did":"2hoqvcwupRTUNkXn6ArYzs","cred_def_id":null}]},"zip_2":{"name":"zip","restrictions":[{"schema_id":null,"schema_issuer_did":null,"schema_name":null,"schema_version":null,"issuer_did":"2hoqvcwupRTUNkXn6ArYzs","cred_def_id":null}]}},"requested_predicates":{}},"msg_ref_id":null},"remote_did":"FhrSrYtQcw3p9xwf7NYemf","remote_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE","agent_did":"FhrSrYtQcw3p9xwf7NYemf","agent_vk":"91qMFrZjXDoi2Vc8Mm14Ys112tEZdDegBZZoembFEATE","revocation_interval":{}}}"#; +pub static PROOF_OFFER_SENT: &str = r#"{"version": "1.0", "data": {"nonce":"123456","version":"1.0","handle":1,"msg_uid":"","ref_msg_id":"","name":"Name Data","prover_vk":"","agent_did":"","agent_vk":"","remote_did":"","remote_vk":"","prover_did":"8XFh8yBzrpJQmNyZzgoTqB","requested_attrs":"{\"attrs\":[{\"name\":\"person name\"},{\"schema_seq_no\":1,\"name\":\"address_1\"},{\"schema_seq_no\":2,\"issuer_did\":\"ISSUER_DID2\",\"name\":\"address_2\"},{\"schema_seq_no\":1,\"name\":\"city\"},{\"schema_seq_no\":1,\"name\":\"state\"},{\"schema_seq_no\":1,\"name\":\"zip\"}]}","requested_predicates":"{\"attr_name\":\"age\",\"p_type\":\"GE\",\"value\":18,\"schema_seq_no\":1,\"issuer_did\":\"DID1\"}","source_id":"source id","state":2,"proof_state":0,"proof":null,"proof_request":null,"revocation_interval":{}}}"#; pub const LARGE_NONCE: usize = 80; pub static SCHEMA_CREATOR_DID: &str = "2hoqvcwupRTUNkXn6ArYzs"; pub static SCHEMA_TYPE: &str = "101"; @@ -50,7 +50,7 @@ pub const UPDATE_PROOF_RESPONSE: &'static [u8; 293] = &[129, 167, 98, 117, 110, pub const PROOF_RESPONSE: &'static [u8; 18153] = &[129, 167, 98, 117, 110, 100, 108, 101, 100, 145, 220, 70, 166, 204, 130, 204, 165, 64, 116, 121, 112, 101, 204, 130, 204, 164, 110, 97, 109, 101, 204, 164, 77, 83, 71, 83, 204, 163, 118, 101, 114, 204, 163, 49, 46, 48, 204, 164, 109, 115, 103, 115, 204, 145, 204, 135, 204, 170, 115, 116, 97, 116, 117, 115, 67, 111, 100, 101, 204, 166, 77, 83, 45, 49, 48, 51, 204, 167, 112, 97, 121, 108, 111, 97, 100, 204, 220, 69, 204, 170, 204, 208, 204, 130, 204, 208, 204, 165, 64, 116, 121, 112, 101, 204, 208, 204, 131, 204, 208, 204, 164, 110, 97, 109, 101, 204, 208, 204, 165, 80, 82, 79, 79, 70, 204, 208, 204, 163, 118, 101, 114, 204, 208, 204, 163, 49, 46, 48, 204, 208, 204, 163, 102, 109, 116, 204, 208, 204, 164, 106, 115, 111, 110, 204, 208, 204, 164, 64, 109, 115, 103, 204, 208, 204, 218, 69, 126, 123, 34, 118, 101, 114, 115, 105, 111, 110, 34, 58, 110, 117, 108, 108, 44, 34, 116, 111, 95, 100, 105, 100, 34, 58, 110, 117, 108, 108, 44, 34, 102, 114, 111, 109, 95, 100, 105, 100, 34, 58, 34, 50, 104, 111, 113, 118, 99, 119, 117, 112, 82, 84, 85, 78, 107, 88, 110, 54, 65, 114, 89, 122, 115, 34, 44, 34, 112, 114, 111, 111, 102, 95, 114, 101, 113, 117, 101, 115, 116, 95, 105, 100, 34, 58, 110, 117, 108, 108, 44, 34, 108, 105, 98, 105, 110, 100, 121, 95, 112, 114, 111, 111, 102, 34, 58, 34, 123, 92, 34, 112, 114, 111, 111, 102, 92, 34, 58, 123, 92, 34, 112, 114, 111, 111, 102, 115, 92, 34, 58, 91, 123, 92, 34, 112, 114, 105, 109, 97, 114, 121, 95, 112, 114, 111, 111, 102, 92, 34, 58, 123, 92, 34, 101, 113, 95, 112, 114, 111, 111, 102, 92, 34, 58, 123, 92, 34, 114, 101, 118, 101, 97, 108, 101, 100, 95, 97, 116, 116, 114, 115, 92, 34, 58, 123, 92, 34, 110, 97, 109, 101, 92, 34, 58, 92, 34, 49, 49, 51, 57, 52, 56, 49, 55, 49, 54, 52, 53, 55, 52, 56, 56, 54, 57, 48, 49, 55, 50, 50, 49, 55, 57, 49, 54, 50, 55, 56, 49, 48, 51, 51, 51, 53, 92, 34, 125, 44, 92, 34, 97, 95, 112, 114, 105, 109, 101, 92, 34, 58, 92, 34, 53, 51, 51, 49, 50, 56, 50, 57, 57, 52, 50, 54, 51, 53, 48, 51, 51, 50, 49, 51, 53, 52, 55, 55, 56, 53, 54, 54, 51, 48, 51, 50, 53, 50, 55, 55, 48, 48, 54, 54, 55, 53, 54, 57, 57, 55, 55, 55, 53, 56, 49, 53, 50, 55, 48, 50, 48, 54, 53, 57, 49, 49, 55, 50, 54, 48, 52, 48, 55, 56, 48, 53, 57, 48, 50, 51, 55, 56, 55, 48, 52, 56, 50, 54, 49, 52, 54, 52, 50, 53, 50, 48, 55, 52, 51, 57, 55, 51, 48, 52, 54, 56, 51, 49, 55, 53, 49, 51, 57, 55, 50, 50, 54, 51, 51, 48, 54, 50, 57, 52, 48, 50, 50, 56, 51, 57, 49, 53, 50, 57, 56, 48, 49, 48, 55, 53, 53, 50, 56, 54, 51, 53, 57, 48, 52, 50, 50, 49, 52, 50, 53, 52, 49, 56, 54, 48, 55, 51, 49, 51, 49, 50, 57, 51, 50, 53, 54, 54, 49, 55, 53, 50, 50, 50, 52, 51, 55, 56, 56, 56, 54, 57, 48, 54, 55, 48, 54, 50, 52, 53, 57, 48, 52, 56, 56, 49, 57, 48, 52, 57, 48, 57, 51, 48, 48, 48, 56, 54, 49, 55, 48, 54, 57, 55, 54, 53, 53, 57, 52, 53, 52, 51, 53, 51, 48, 53, 52, 52, 49, 53, 50, 50, 52, 50, 49, 55, 53, 52, 49, 53, 48, 56, 50, 53, 49, 56, 50, 56, 57, 48, 49, 50, 51, 48, 51, 49, 53, 55, 50, 55, 52, 53, 50, 49, 57, 52, 57, 48, 54, 55, 48, 55, 49, 52, 54, 49, 56, 50, 48, 51, 56, 50, 57, 50, 55, 55, 52, 56, 51, 55, 56, 55, 52, 49, 53, 56, 49, 50, 51, 57, 48, 53, 49, 51, 50, 50, 48, 52, 55, 53, 52, 52, 57, 52, 48, 57, 57, 57, 53, 55, 57, 51, 53, 56, 57, 51, 55, 49, 48, 51, 49, 49, 51, 48, 55, 54, 49, 49, 49, 56, 53, 53, 53, 54, 50, 53, 51, 53, 54, 50, 55, 51, 49, 51, 48, 50, 48, 56, 53, 54, 52, 51, 49, 57, 48, 51, 56, 48, 48, 57, 51, 55, 57, 54, 55, 49, 50, 49, 53, 48, 48, 55, 51, 56, 54, 51, 50, 51, 54, 51, 55, 52, 54, 55, 49, 55, 54, 54, 54, 56, 51, 56, 51, 48, 49, 49, 54, 54, 52, 51, 54, 52, 50, 56, 49, 52, 53, 49, 49, 49, 52, 49, 51, 56, 55, 50, 48, 50, 50, 55, 54, 54, 55, 55, 49, 55, 57, 57, 55, 56, 55, 55, 56, 48, 50, 51, 56, 54, 56, 49, 57, 49, 54, 50, 48, 56, 48, 51, 48, 51, 49, 53, 53, 53, 53, 55, 50, 48, 57, 54, 53, 48, 53, 52, 57, 51, 54, 57, 53, 52, 53, 56, 56, 52, 56, 51, 51, 54, 55, 53, 48, 48, 55, 50, 56, 55, 50, 56, 50, 52, 48, 56, 50, 57, 52, 54, 49, 54, 54, 54, 50, 52, 48, 50, 53, 56, 50, 54, 52, 48, 50, 49, 56, 53, 48, 55, 57, 48, 55, 56, 57, 53, 53, 53, 55, 49, 54, 52, 48, 54, 52, 51, 55, 56, 49, 54, 52, 52, 54, 48, 56, 53, 54, 57, 50, 56, 57, 55, 51, 55, 50, 52, 55, 50, 51, 57, 57, 52, 52, 50, 57, 51, 51, 55, 52, 52, 57, 53, 52, 54, 49, 50, 50, 53, 53, 48, 57, 48, 50, 57, 51, 57, 55, 56, 54, 55, 57, 50, 57, 50, 48, 57, 50, 57, 52, 48, 50, 52, 50, 49, 51, 55, 48, 57, 55, 56, 56, 92, 34, 44, 92, 34, 101, 92, 34, 58, 92, 34, 50, 48, 54, 56, 50, 51, 53, 57, 54, 52, 51, 52, 49, 50, 54, 56, 50, 50, 57, 53, 56, 51, 49, 48, 50, 55, 51, 54, 49, 56, 57, 48, 53, 55, 53, 52, 55, 53, 56, 51, 56, 53, 50, 51, 54, 52, 56, 55, 52, 49, 52, 50, 49, 53, 53, 49, 57, 48, 51, 48, 56, 48, 53, 57, 53, 49, 56, 56, 49, 56, 49, 56, 51, 51, 51, 51, 51, 53, 55, 54, 49, 56, 50, 57, 48, 55, 49, 48, 56, 50, 55, 48, 52, 51, 49, 49, 52, 50, 50, 55, 53, 56, 56, 51, 52, 50, 52, 53, 54, 52, 56, 51, 51, 50, 56, 51, 55, 51, 48, 55, 55, 52, 52, 48, 48, 54, 56, 55, 55, 54, 54, 55, 56, 51, 57, 51, 55, 92, 34, 44, 92, 34, 118, 92, 34, 58, 92, 34, 57, 55, 55, 57, 48, 52, 54, 51, 51, 54, 49, 54, 56, 51, 49, 50, 53, 56, 50, 53, 56, 50, 48, 56, 55, 57, 50, 48, 52, 52, 53, 53, 50, 53, 53, 56, 51, 49, 51, 48, 51, 49, 50, 50, 53, 50, 55, 52, 48, 56, 48, 55, 56, 54, 51, 54, 57, 50, 54, 48, 53, 57, 49, 51, 55, 57, 49, 55, 54, 51, 53, 54, 54, 57, 51, 54, 57, 57, 53, 52, 55, 53, 52, 54, 51, 53, 55, 53, 54, 52, 51, 50, 48, 56, 57, 52, 55, 56, 50, 53, 51, 56, 56, 57, 57, 57, 49, 54, 56, 49, 57, 49, 48, 54, 54, 49, 53, 56, 54, 49, 56, 55, 48, 49, 56, 52, 52, 48, 54, 49, 56, 48, 57, 48, 50, 53, 52, 57, 51, 52, 54, 49, 50, 56, 48, 48, 51, 53, 50, 49, 49, 55, 50, 55, 49, 53, 48, 56, 57, 49, 48, 54, 52, 48, 50, 50, 49, 48, 54, 50, 53, 51, 56, 48, 55, 48, 50, 57, 56, 55, 56, 54, 50, 50, 52, 49, 53, 56, 55, 53, 56, 53, 49, 53, 57, 56, 48, 57, 56, 54, 48, 48, 54, 55, 52, 49, 54, 50, 55, 48, 56, 56, 49, 50, 50, 54, 56, 52, 52, 53, 50, 50, 57, 48, 53, 51, 48, 49, 49, 50, 56, 50, 51, 55, 49, 51, 57, 49, 53, 52, 51, 53, 49, 55, 56, 56, 55, 53, 54, 48, 48, 54, 55, 52, 52, 51, 54, 49, 55, 56, 48, 48, 56, 55, 51, 49, 50, 50, 56, 49, 49, 52, 53, 49, 52, 57, 52, 55, 50, 57, 49, 50, 53, 50, 50, 55, 48, 50, 55, 56, 56, 57, 51, 50, 48, 56, 53, 52, 51, 54, 51, 54, 52, 50, 53, 54, 52, 55, 51, 55, 57, 57, 56, 51, 48, 52, 50, 48, 56, 53, 53, 49, 53, 55, 57, 51, 52, 54, 54, 56, 50, 54, 54, 57, 50, 52, 56, 55, 53, 56, 48, 49, 50, 49, 54, 49, 49, 57, 49, 50, 48, 48, 48, 52, 51, 51, 53, 54, 57, 53, 57, 57, 49, 54, 50, 49, 50, 56, 54, 50, 52, 48, 52, 56, 55, 48, 51, 51, 55, 56, 55, 56, 53, 51, 50, 54, 56, 48, 49, 48, 51, 54, 51, 50, 54, 57, 49, 53, 49, 56, 51, 49, 54, 50, 48, 52, 48, 50, 50, 54, 50, 50, 54, 54, 54, 48, 50, 52, 56, 51, 49, 54, 57, 56, 48, 52, 53, 49, 52, 52, 55, 55, 55, 48, 56, 55, 50, 52, 50, 50, 55, 53, 52, 53, 52, 56, 49, 53, 56, 50, 52, 55, 49, 49, 54, 48, 48, 50, 51, 54, 49, 49, 54, 52, 57, 48, 56, 53, 51, 56, 51, 50, 50, 49, 48, 53, 51, 54, 51, 57, 54, 53, 50, 51, 53, 53, 48, 50, 55, 57, 50, 56, 49, 56, 57, 55, 55, 57, 54, 55, 56, 48, 57, 54, 53, 54, 56, 48, 54, 54, 52, 56, 50, 53, 54, 55, 55, 54, 51, 53, 55, 49, 54, 50, 52, 57, 57, 52, 57, 55, 49, 53, 54, 52, 48, 55, 48, 57, 57, 56, 52, 52, 51, 49, 50, 56, 51, 50, 50, 54, 55, 52, 51, 49, 49, 54, 48, 51, 48, 52, 52, 50, 48, 55, 54, 55, 54, 57, 49, 53, 48, 48, 57, 54, 51, 49, 48, 49, 52, 55, 55, 56, 50, 55, 50, 49, 51, 51, 56, 48, 52, 48, 56, 54, 54, 48, 52, 52, 57, 57, 53, 54, 50, 57, 56, 50, 55, 52, 51, 54, 56, 53, 50, 55, 54, 55, 49, 48, 54, 48, 51, 57, 56, 50, 51, 52, 55, 50, 48, 52, 50, 48, 48, 57, 51, 53, 48, 56, 54, 51, 50, 52, 52, 50, 55, 51, 57, 50, 49, 57, 51, 49, 49, 50, 48, 53, 49, 57, 51, 52, 53, 56, 53, 48, 50, 53, 52, 48, 57, 51, 57, 54, 54, 54, 57, 55, 57, 48, 48, 48, 55, 53, 54, 52, 52, 53, 48, 57, 56, 53, 49, 52, 50, 50, 48, 55, 50, 49, 57, 51, 49, 49, 54, 51, 50, 52, 54, 57, 57, 55, 54, 48, 48, 56, 56, 48, 52, 50, 54, 50, 53, 54, 49, 49, 48, 50, 51, 57, 52, 52, 54, 50, 54, 55, 55, 51, 56, 49, 53, 55, 53, 49, 49, 51, 55, 52, 49, 51, 50, 49, 53, 48, 53, 54, 51, 51, 49, 57, 55, 54, 52, 49, 55, 53, 52, 52, 48, 53, 48, 57, 48, 57, 50, 50, 57, 54, 50, 48, 52, 48, 49, 48, 48, 51, 54, 57, 56, 54, 57, 55, 54, 51, 51, 54, 51, 51, 57, 53, 51, 48, 57, 55, 50, 50, 48, 57, 52, 50, 49, 52, 48, 57, 56, 54, 53, 55, 48, 48, 55, 50, 57, 50, 53, 50, 49, 56, 57, 50, 57, 52, 49, 56, 49, 51, 53, 50, 53, 57, 54, 53, 53, 53, 55, 51, 56, 55, 49, 56, 52, 51, 48, 54, 48, 50, 57, 50, 52, 53, 56, 49, 48, 53, 55, 56, 54, 56, 53, 49, 51, 54, 49, 56, 52, 54, 56, 50, 52, 54, 50, 50, 53, 48, 48, 56, 55, 55, 56, 48, 51, 49, 50, 51, 50, 50, 57, 54, 57, 52, 55, 56, 54, 55, 57, 48, 56, 48, 53, 56, 53, 54, 50, 53, 48, 50, 49, 53, 50, 48, 50, 49, 48, 92, 34, 44, 92, 34, 109, 92, 34, 58, 123, 92, 34, 104, 101, 105, 103, 104, 116, 92, 34, 58, 92, 34, 49, 50, 50, 54, 51, 50, 56, 57, 52, 49, 53, 56, 51, 50, 54, 56, 49, 50, 50, 50, 49, 57, 49, 50, 51, 49, 51, 48, 55, 55, 52, 50, 48, 48, 53, 55, 53, 55, 54, 50, 48, 49, 48, 54, 52, 52, 57, 51, 48, 53, 55, 49, 55, 48, 52, 55, 55, 56, 52, 54, 55, 48, 55, 57, 50, 55, 56, 56, 56, 55, 53, 54, 57, 53, 53, 51, 57, 55, 53, 51, 51, 54, 52, 55, 56, 49, 51, 55, 53, 52, 57, 50, 54, 55, 49, 52, 53, 52, 50, 56, 55, 55, 57, 51, 55, 54, 54, 49, 56, 52, 52, 52, 51, 51, 48, 50, 51, 52, 54, 57, 50, 50, 48, 52, 50, 53, 50, 49, 49, 56, 56, 57, 56, 48, 50, 54, 55, 48, 50, 49, 51, 48, 54, 57, 49, 50, 52, 51, 57, 56, 51, 55, 49, 56, 52, 57, 52, 50, 52, 54, 51, 56, 51, 49, 51, 52, 52, 50, 54, 55, 53, 49, 51, 49, 49, 52, 53, 51, 57, 92, 34, 44, 92, 34, 115, 101, 120, 92, 34, 58, 92, 34, 49, 53, 48, 51, 55, 49, 53, 53, 52, 53, 52, 48, 57, 52, 52, 53, 57, 53, 50, 55, 55, 51, 49, 52, 51, 52, 50, 48, 54, 52, 56, 49, 49, 49, 52, 51, 49, 57, 50, 52, 48, 53, 50, 49, 53, 48, 51, 55, 57, 52, 56, 50, 55, 56, 53, 50, 48, 55, 48, 55, 48, 49, 56, 48, 50, 51, 48, 55, 49, 54, 56, 50, 52, 49, 57, 52, 57, 57, 52, 54, 57, 50, 51, 48, 56, 51, 54, 54, 52, 55, 56, 52, 51, 53, 53, 50, 55, 52, 55, 53, 51, 50, 48, 53, 50, 57, 55, 49, 50, 50, 51, 56, 54, 55, 57, 49, 54, 54, 55, 53, 50, 54, 55, 53, 55, 56, 51, 57, 48, 48, 49, 48, 56, 52, 49, 49, 52, 52, 52, 54, 50, 57, 49, 56, 53, 53, 51, 50, 53, 51, 56, 52, 56, 56, 49, 55, 53, 53, 52, 55, 54, 49, 48, 56, 57, 48, 51, 48, 55, 54, 54, 52, 52, 49, 48, 50, 53, 50, 52, 92, 34, 44, 92, 34, 97, 103, 101, 92, 34, 58, 92, 34, 49, 52, 53, 48, 49, 56, 55, 50, 52, 48, 57, 57, 52, 48, 51, 50, 55, 57, 57, 56, 52, 49, 50, 56, 57, 51, 49, 53, 55, 48, 56, 49, 53, 49, 50, 51, 54, 51, 48, 56, 57, 55, 57, 48, 55, 53, 52, 48, 55, 57, 57, 52, 49, 54, 57, 57, 52, 51, 55, 53, 57, 52, 56, 53, 49, 52, 54, 55, 54, 54, 53, 48, 53, 57, 56, 48, 51, 54, 57, 51, 53, 50, 52, 49, 48, 48, 48, 55, 52, 52, 50, 56, 53, 52, 52, 57, 52, 52, 48, 56, 52, 53, 55, 48, 50, 49, 52, 49, 51, 56, 56, 57, 55, 49, 56, 52, 55, 50, 57, 55, 53, 56, 55, 50, 54, 54, 49, 51, 48, 55, 49, 54, 53, 48, 51, 49, 52, 52, 56, 48, 53, 55, 57, 48, 55, 52, 53, 53, 54, 55, 48, 48, 50, 48, 48, 51, 54, 54, 54, 56, 56, 56, 57, 53, 53, 54, 53, 49, 52, 53, 51, 56, 50, 51, 54, 48, 54, 57, 56, 92, 34, 125, 44, 92, 34, 109, 49, 92, 34, 58, 92, 34, 53, 49, 49, 49, 54, 49, 52, 52, 57, 50, 55, 51, 49, 50, 50, 50, 57, 51, 51, 54, 56, 50, 50, 51, 56, 54, 48, 54, 57, 56, 54, 55, 52, 50, 48, 49, 50, 54, 52, 57, 49, 56, 54, 56, 51, 50, 56, 48, 50, 54, 57, 53, 52, 51, 54, 50, 57, 51, 53, 56, 51, 56, 55, 56, 51, 49, 57, 57, 57, 50, 56, 56, 55, 57, 55, 49, 53, 56, 49, 49, 56, 56, 56, 55, 54, 56, 48, 54, 55, 53, 57, 52, 52, 55, 53, 57, 52, 51, 50, 54, 49, 55, 51, 57, 53, 55, 51, 54, 53, 56, 55, 57, 49, 49, 51, 56, 52, 56, 49, 52, 53, 57, 51, 49, 51, 51, 54, 56, 56, 57, 56, 57, 50, 51, 50, 53, 54, 50, 50, 53, 57, 48, 50, 56, 57, 49, 51, 51, 53, 56, 49, 54, 57, 52, 54, 57, 57, 51, 51, 53, 50, 49, 53, 56, 53, 56, 56, 48, 53, 49, 48, 53, 48, 54, 52, 51, 51, 49, 92, 34, 44, 92, 34, 109, 50, 92, 34, 58, 92, 34, 49, 53, 52, 53, 53, 54, 54, 50, 50, 53, 52, 51, 54, 54, 52, 53, 55, 53, 48, 51, 56, 49, 57, 55, 48, 49, 51, 52, 54, 53, 56, 48, 48, 56, 51, 55, 55, 52, 48, 51, 57, 52, 55, 53, 56, 53, 53, 55, 53, 56, 48, 52, 57, 54, 49, 53, 57, 52, 50, 55, 54, 48, 54, 54, 56, 49, 54, 57, 48, 49, 49, 56, 57, 52, 54, 54, 50, 55, 56, 48, 50, 48, 50, 56, 51, 54, 51, 49, 57, 52, 51, 51, 56, 54, 51, 50, 48, 53, 57, 53, 50, 49, 53, 50, 56, 55, 57, 57, 53, 57, 57, 57, 56, 52, 51, 52, 55, 50, 51, 49, 48, 54, 53, 51, 50, 55, 55, 57, 50, 49, 53, 52, 55, 55, 52, 52, 57, 55, 56, 49, 53, 51, 52, 51, 49, 56, 57, 57, 54, 57, 55, 52, 48, 48, 49, 53, 57, 57, 55, 49, 52, 57, 54, 54, 51, 57, 54, 56, 53, 54, 51, 55, 52, 53, 56, 49, 52, 56, 54, 92, 34, 125, 44, 92, 34, 103, 101, 95, 112, 114, 111, 111, 102, 115, 92, 34, 58, 91, 123, 92, 34, 117, 92, 34, 58, 123, 92, 34, 51, 92, 34, 58, 92, 34, 49, 51, 51, 51, 56, 55, 57, 55, 52, 49, 57, 48, 49, 48, 56, 49, 57, 52, 51, 48, 51, 49, 51, 49, 53, 56, 52, 49, 52, 50, 51, 57, 53, 56, 56, 57, 49, 49, 53, 51, 51, 55, 48, 50, 57, 57, 56, 55, 49, 49, 49, 49, 51, 54, 51, 54, 48, 54, 53, 55, 56, 54, 57, 55, 52, 52, 55, 53, 53, 49, 54, 56, 56, 48, 50, 56, 53, 57, 48, 53, 54, 57, 51, 56, 49, 50, 50, 53, 53, 49, 50, 57, 56, 54, 57, 53, 57, 50, 57, 55, 50, 51, 49, 48, 49, 49, 56, 50, 51, 52, 53, 52, 50, 52, 54, 53, 49, 57, 48, 50, 48, 50, 48, 51, 49, 52, 53, 56, 52, 55, 51, 52, 49, 54, 57, 53, 53, 54, 56, 48, 48, 56, 51, 55, 54, 50, 49, 54, 49, 55, 53, 53, 48, 57, 55, 51, 48, 56, 48, 49, 55, 54, 49, 51, 55, 51, 56, 52, 48, 57, 48, 49, 52, 52, 53, 48, 52, 49, 50, 92, 34, 44, 92, 34, 49, 92, 34, 58, 92, 34, 55, 57, 57, 52, 57, 50, 53, 52, 50, 48, 55, 53, 48, 52, 50, 52, 54, 48, 52, 54, 56, 55, 52, 51, 52, 50, 51, 50, 50, 52, 52, 52, 57, 53, 50, 54, 52, 48, 52, 50, 57, 57, 57, 51, 48, 53, 55, 48, 57, 48, 54, 53, 48, 48, 54, 48, 55, 57, 49, 51, 57, 52, 53, 55, 49, 54, 57, 52, 52, 53, 48, 50, 56, 48, 50, 48, 52, 53, 51, 54, 53, 56, 57, 53, 57, 55, 53, 49, 49, 56, 50, 48, 54, 53, 56, 53, 52, 51, 49, 55, 54, 57, 55, 54, 48, 55, 49, 56, 48, 55, 55, 50, 57, 56, 50, 52, 55, 49, 50, 57, 54, 53, 51, 52, 54, 50, 49, 52, 54, 55, 48, 53, 48, 56, 51, 49, 57, 57, 52, 56, 54, 54, 52, 48, 51, 50, 51, 51, 56, 56, 50, 56, 57, 51, 53, 48, 51, 55, 51, 53, 48, 50, 56, 51, 50, 51, 51, 54, 50, 50, 48, 55, 52, 55, 56, 49, 56, 92, 34, 44, 92, 34, 50, 92, 34, 58, 92, 34, 49, 52, 49, 48, 54, 54, 57, 55, 55, 53, 54, 54, 51, 49, 57, 52, 53, 48, 54, 48, 50, 57, 52, 50, 49, 54, 56, 57, 55, 50, 53, 49, 54, 48, 53, 50, 52, 51, 49, 51, 53, 51, 49, 48, 49, 56, 52, 53, 49, 50, 48, 52, 57, 53, 54, 52, 51, 50, 49, 52, 57, 55, 57, 57, 53, 53, 57, 52, 56, 49, 57, 55, 48, 56, 49, 49, 57, 57, 50, 53, 57, 56, 54, 51, 52, 54, 52, 57, 51, 54, 49, 56, 52, 57, 49, 57, 50, 49, 52, 54, 53, 55, 56, 53, 52, 56, 54, 55, 53, 56, 57, 49, 49, 54, 50, 57, 56, 55, 51, 55, 49, 55, 51, 54, 52, 50, 51, 51, 52, 56, 48, 48, 50, 55, 49, 52, 56, 53, 50, 57, 57, 55, 53, 54, 51, 56, 54, 51, 54, 55, 54, 53, 54, 52, 50, 50, 56, 57, 51, 57, 57, 54, 51, 48, 50, 55, 48, 54, 55, 55, 57, 52, 56, 55, 52, 56, 55, 49, 92, 34, 44, 92, 34, 48, 92, 34, 58, 92, 34, 50, 50, 56, 52, 57, 48, 56, 53, 52, 50, 52, 52, 55, 50, 56, 53, 53, 51, 49, 54, 52, 50, 50, 57, 51, 50, 51, 53, 50, 48, 53, 55, 54, 52, 55, 49, 57, 53, 57, 54, 49, 56, 57, 48, 57, 54, 52, 48, 49, 55, 53, 55, 55, 55, 50, 57, 57, 48, 54, 52, 56, 50, 52, 54, 56, 49, 49, 55, 52, 49, 56, 57, 57, 55, 52, 50, 48, 50, 55, 48, 50, 49, 55, 54, 48, 56, 55, 51, 57, 54, 50, 55, 53, 57, 56, 48, 56, 56, 50, 54, 55, 54, 55, 48, 57, 53, 51, 49, 56, 49, 53, 51, 57, 56, 51, 49, 49, 55, 52, 55, 56, 54, 48, 54, 55, 51, 51, 53, 53, 49, 56, 56, 50, 50, 56, 55, 52, 52, 51, 52, 49, 54, 57, 48, 53, 51, 54, 57, 50, 49, 50, 56, 51, 48, 52, 48, 50, 54, 50, 53, 48, 49, 57, 53, 50, 48, 51, 49, 54, 48, 48, 48, 54, 49, 57, 49, 50, 50, 92, 34, 125, 44, 92, 34, 114, 92, 34, 58, 123, 92, 34, 68, 69, 76, 84, 65, 92, 34, 58, 92, 34, 52, 52, 54, 52, 49, 55, 51, 55, 56, 54, 56, 54, 54, 56, 52, 53, 49, 49, 50, 51, 52, 48, 50, 54, 55, 55, 51, 51, 53, 53, 55, 48, 56, 49, 50, 53, 50, 51, 57, 56, 50, 52, 54, 51, 50, 54, 51, 52, 52, 51, 55, 54, 57, 50, 55, 55, 55, 49, 57, 57, 50, 48, 55, 53, 49, 48, 53, 57, 51, 55, 55, 53, 55, 54, 57, 54, 54, 49, 51, 50, 48, 53, 49, 55, 53, 48, 53, 52, 57, 53, 55, 56, 50, 56, 48, 56, 49, 50, 51, 57, 48, 49, 57, 51, 49, 53, 48, 57, 57, 54, 54, 48, 50, 52, 54, 51, 57, 48, 51, 57, 48, 51, 56, 49, 48, 56, 57, 57, 55, 56, 52, 57, 50, 51, 57, 52, 53, 55, 48, 48, 54, 54, 53, 48, 57, 49, 48, 49, 54, 54, 53, 55, 57, 53, 50, 49, 49, 56, 56, 49, 52, 53, 56, 48, 52, 53, 57, 50, 56, 57, 49, 49, 49, 52, 52, 50, 57, 53, 53, 49, 56, 56, 52, 49, 56, 56, 49, 54, 51, 49, 54, 56, 50, 48, 50, 50, 52, 48, 55, 49, 54, 57, 51, 49, 55, 49, 48, 52, 54, 55, 49, 52, 51, 57, 53, 50, 49, 56, 52, 57, 55, 56, 56, 57, 49, 54, 57, 52, 57, 57, 56, 51, 53, 57, 53, 48, 51, 49, 54, 49, 50, 49, 52, 54, 50, 52, 53, 54, 49, 56, 50, 53, 56, 51, 51, 57, 48, 56, 48, 55, 51, 55, 49, 49, 51, 57, 49, 54, 51, 55, 49, 51, 57, 50, 51, 57, 57, 48, 48, 52, 51, 51, 55, 55, 51, 55, 51, 54, 56, 56, 54, 51, 57, 56, 50, 52, 54, 53, 49, 54, 55, 54, 53, 56, 52, 52, 55, 57, 56, 53, 55, 52, 50, 54, 48, 48, 51, 56, 55, 50, 48, 54, 52, 53, 50, 56, 50, 56, 55, 52, 56, 52, 55, 57, 56, 56, 48, 50, 52, 55, 53, 55, 50, 54, 57, 48, 50, 53, 48, 54, 54, 56, 52, 57, 52, 56, 55, 49, 50, 48, 55, 54, 57, 48, 51, 51, 56, 51, 53, 50, 56, 52, 56, 57, 50, 54, 56, 52, 56, 50, 55, 57, 55, 52, 53, 57, 48, 56, 52, 55, 50, 48, 50, 57, 56, 48, 57, 50, 56, 51, 49, 56, 50, 56, 52, 56, 48, 50, 50, 57, 54, 49, 56, 52, 56, 55, 57, 52, 51, 48, 50, 54, 50, 51, 53, 50, 56, 51, 56, 53, 51, 55, 57, 57, 53, 51, 50, 57, 53, 54, 56, 51, 52, 55, 55, 48, 52, 52, 52, 51, 48, 51, 50, 51, 53, 56, 52, 51, 54, 52, 48, 49, 57, 50, 53, 57, 48, 55, 48, 48, 54, 50, 48, 51, 56, 48, 48, 55, 56, 49, 56, 48, 53, 51, 48, 50, 52, 49, 49, 50, 57, 48, 52, 49, 51, 55, 57, 55, 53, 52, 55, 55, 48, 51, 54, 52, 51, 54, 56, 48, 53, 50, 51, 56, 49, 54, 52, 53, 48, 57, 54, 52, 57, 48, 55, 50, 54, 57, 51, 54, 53, 55, 52, 48, 51, 51, 51, 57, 53, 52, 55, 54, 55, 50, 53, 48, 56, 55, 50, 48, 48, 53, 48, 56, 48, 51, 56, 51, 55, 56, 54, 57, 54, 50, 56, 51, 54, 51, 52, 57, 52, 51, 55, 57, 55, 50, 50, 51, 51, 49, 48, 50, 54, 56, 54, 48, 48, 55, 48, 55, 48, 49, 53, 49, 57, 49, 51, 50, 51, 49, 52, 48, 53, 54, 55, 51, 48, 53, 51, 49, 49, 49, 51, 53, 55, 50, 53, 55, 53, 52, 49, 48, 55, 48, 55, 57, 52, 49, 57, 48, 51, 52, 54, 56, 53, 52, 57, 52, 54, 49, 53, 53, 51, 52, 56, 48, 48, 48, 57, 51, 56, 55, 57, 52, 49, 54, 56, 51, 49, 51, 53, 53, 53, 48, 53, 52, 57, 51, 53, 48, 57, 55, 53, 49, 49, 50, 56, 48, 48, 53, 53, 56, 53, 55, 51, 53, 55, 55, 49, 52, 48, 52, 52, 53, 55, 53, 48, 57, 57, 55, 49, 51, 54, 48, 52, 53, 49, 52, 56, 54, 56, 48, 50, 54, 50, 49, 51, 92, 34, 44, 92, 34, 48, 92, 34, 58, 92, 34, 55, 54, 51, 50, 51, 52, 55, 49, 50, 56, 55, 53, 51, 55, 55, 50, 53, 55, 52, 53, 48, 53, 56, 57, 54, 56, 50, 52, 51, 57, 52, 54, 53, 51, 54, 57, 50, 51, 49, 51, 50, 48, 53, 57, 53, 50, 51, 56, 51, 50, 50, 55, 48, 49, 52, 51, 48, 56, 56, 52, 55, 54, 55, 52, 49, 53, 51, 48, 57, 51, 49, 55, 57, 52, 50, 57, 50, 51, 54, 50, 53, 57, 55, 56, 49, 56, 53, 57, 53, 50, 52, 54, 48, 50, 51, 50, 49, 53, 54, 52, 54, 54, 56, 53, 57, 54, 48, 56, 54, 48, 53, 52, 51, 57, 56, 53, 54, 54, 57, 48, 48, 51, 54, 51, 55, 51, 53, 54, 54, 53, 51, 57, 54, 56, 53, 56, 48, 55, 50, 54, 48, 49, 50, 56, 51, 49, 50, 55, 50, 57, 53, 50, 55, 50, 54, 54, 52, 56, 48, 57, 55, 51, 55, 57, 55, 48, 55, 57, 55, 56, 48, 50, 53, 56, 50, 55, 51, 50, 52, 52, 54, 49, 51, 55, 48, 55, 52, 54, 48, 56, 48, 51, 48, 50, 51, 51, 52, 57, 52, 54, 54, 49, 53, 54, 51, 54, 50, 51, 48, 57, 56, 50, 53, 55, 51, 48, 53, 55, 57, 50, 57, 49, 55, 56, 53, 55, 48, 55, 57, 53, 53, 55, 54, 48, 50, 53, 51, 55, 55, 57, 55, 53, 54, 55, 53, 55, 55, 50, 57, 49, 57, 56, 56, 51, 52, 52, 49, 48, 55, 49, 51, 49, 57, 49, 48, 57, 56, 55, 55, 54, 55, 52, 50, 53, 53, 50, 48, 57, 52, 50, 53, 55, 53, 49, 56, 51, 49, 51, 53, 49, 56, 55, 49, 49, 50, 50, 50, 54, 56, 54, 55, 55, 57, 52, 57, 56, 54, 54, 48, 57, 51, 55, 51, 50, 51, 55, 52, 57, 49, 52, 50, 49, 50, 48, 51, 53, 57, 48, 51, 53, 56, 56, 48, 48, 53, 55, 49, 56, 57, 57, 57, 57, 55, 55, 56, 51, 54, 54, 48, 49, 54, 57, 52, 50, 55, 52, 57, 51, 54, 54, 53, 51, 50, 57, 55, 50, 52, 57, 53, 57, 55, 51, 55, 55, 52, 53, 56, 51, 48, 54, 48, 49, 56, 54, 57, 48, 56, 51, 56, 56, 57, 55, 48, 55, 52, 57, 52, 56, 57, 48, 48, 54, 48, 49, 53, 48, 48, 54, 48, 56, 51, 54, 49, 54, 49, 48, 54, 50, 57, 56, 50, 57, 57, 53, 54, 55, 55, 56, 57, 53, 50, 52, 54, 51, 56, 56, 56, 53, 52, 53, 48, 52, 51, 51, 50, 57, 50, 55, 52, 49, 50, 55, 52, 54, 56, 56, 54, 55, 53, 54, 50, 56, 56, 54, 52, 55, 49, 55, 54, 54, 55, 53, 57, 53, 56, 55, 55, 55, 54, 52, 55, 49, 52, 50, 57, 57, 56, 50, 50, 50, 50, 48, 54, 48, 52, 53, 53, 54, 50, 56, 56, 51, 54, 52, 56, 52, 56, 53, 49, 52, 51, 53, 51, 52, 57, 56, 53, 56, 54, 53, 49, 51, 56, 54, 57, 52, 55, 50, 56, 50, 48, 50, 52, 50, 54, 51, 55, 53, 51, 57, 51, 53, 57, 49, 57, 57, 57, 49, 49, 56, 52, 51, 55, 48, 55, 54, 57, 53, 51, 50, 52, 52, 51, 51, 53, 53, 55, 52, 56, 48, 52, 48, 51, 54, 48, 57, 50, 57, 56, 56, 54, 57, 48, 54, 51, 57, 54, 55, 56, 49, 48, 53, 57, 52, 51, 49, 56, 54, 57, 50, 56, 54, 56, 48, 56, 49, 54, 53, 56, 55, 51, 52, 56, 49, 50, 57, 49, 53, 57, 52, 52, 51, 50, 51, 55, 53, 52, 55, 52, 50, 54, 55, 57, 52, 51, 55, 50, 54, 55, 56, 57, 52, 55, 57, 52, 57, 57, 52, 53, 49, 49, 49, 51, 57, 49, 52, 49, 48, 54, 53, 55, 55, 50, 55, 52, 52, 57, 49, 52, 51, 51, 51, 57, 54, 56, 52, 57, 48, 50, 49, 56, 54, 53, 56, 55, 54, 53, 57, 53, 54, 50, 53, 54, 55, 54, 48, 56, 55, 51, 57, 48, 50, 52, 51, 48, 48, 48, 48, 50, 51, 54, 50, 52, 55, 54, 50, 92, 34, 44, 92, 34, 50, 92, 34, 58, 92, 34, 57, 50, 50, 48, 49, 53, 49, 50, 49, 49, 54, 52, 57, 51, 56, 51, 54, 56, 50, 56, 54, 51, 49, 53, 50, 57, 55, 51, 51, 49, 50, 57, 48, 48, 49, 48, 54, 48, 49, 56, 54, 48, 50, 55, 52, 50, 56, 57, 48, 48, 50, 50, 54, 48, 48, 57, 54, 54, 55, 50, 48, 55, 57, 52, 54, 55, 55, 53, 54, 54, 51, 52, 49, 50, 55, 54, 51, 48, 52, 57, 51, 50, 51, 48, 54, 51, 53, 54, 54, 51, 56, 50, 52, 49, 48, 50, 57, 56, 54, 53, 57, 54, 56, 48, 56, 48, 57, 54, 51, 48, 51, 48, 56, 57, 49, 56, 56, 50, 54, 55, 55, 52, 55, 49, 53, 57, 54, 53, 57, 50, 52, 51, 52, 53, 51, 52, 56, 56, 55, 51, 57, 54, 52, 49, 54, 51, 51, 52, 57, 57, 53, 55, 54, 54, 54, 50, 51, 51, 51, 48, 51, 57, 48, 56, 57, 56, 50, 53, 49, 50, 53, 51, 51, 48, 53, 56, 52, 55, 55, 49, 48, 55, 52, 52, 48, 48, 52, 49, 49, 54, 52, 57, 55, 52, 52, 55, 49, 57, 50, 51, 57, 51, 50, 53, 50, 53, 51, 57, 50, 49, 51, 49, 53, 48, 55, 50, 48, 56, 48, 53, 56, 57, 55, 50, 49, 49, 52, 48, 49, 51, 53, 53, 52, 50, 54, 49, 49, 56, 54, 56, 55, 54, 49, 53, 54, 51, 57, 49, 48, 49, 51, 48, 51, 48, 50, 52, 57, 57, 52, 48, 49, 54, 53, 54, 55, 52, 51, 53, 48, 51, 50, 57, 57, 54, 57, 52, 54, 57, 52, 57, 51, 54, 57, 48, 49, 55, 50, 50, 48, 52, 52, 54, 50, 53, 50, 49, 54, 52, 51, 51, 48, 54, 53, 53, 52, 50, 53, 53, 53, 49, 52, 57, 53, 52, 56, 50, 48, 48, 53, 54, 51, 48, 48, 50, 55, 57, 50, 57, 52, 48, 56, 50, 54, 54, 53, 57, 57, 51, 57, 56, 50, 48, 54, 56, 52, 56, 57, 54, 51, 50, 55, 49, 55, 57, 57, 48, 50, 56, 56, 48, 56, 51, 53, 48, 49, 51, 51, 50, 50, 56, 54, 53, 50, 48, 48, 52, 52, 48, 53, 56, 56, 51, 54, 57, 54, 54, 57, 56, 55, 50, 49, 56, 52, 52, 54, 56, 51, 53, 48, 52, 48, 52, 56, 51, 51, 49, 51, 54, 50, 49, 49, 54, 53, 48, 49, 55, 50, 51, 52, 53, 54, 55, 52, 53, 49, 48, 49, 56, 51, 49, 57, 56, 56, 57, 56, 49, 49, 49, 49, 57, 53, 51, 56, 56, 54, 54, 55, 49, 55, 57, 53, 52, 49, 55, 55, 48, 56, 48, 52, 54, 48, 48, 52, 50, 52, 56, 57, 53, 54, 54, 48, 51, 50, 48, 52, 54, 52, 52, 55, 50, 53, 49, 49, 51, 48, 49, 51, 48, 50, 52, 53, 53, 55, 52, 54, 53, 57, 54, 51, 56, 54, 54, 52, 50, 53, 53, 52, 56, 57, 57, 57, 56, 55, 55, 55, 52, 56, 57, 52, 56, 50, 50, 49, 49, 57, 57, 48, 53, 54, 56, 51, 51, 56, 50, 54, 49, 50, 57, 52, 53, 57, 49, 52, 52, 50, 48, 54, 53, 54, 56, 57, 55, 50, 56, 52, 48, 57, 50, 51, 51, 53, 55, 48, 55, 51, 56, 50, 53, 52, 56, 52, 57, 51, 50, 48, 57, 50, 54, 52, 54, 54, 56, 53, 54, 56, 49, 57, 53, 53, 48, 50, 50, 52, 55, 49, 48, 52, 51, 55, 49, 53, 55, 57, 51, 51, 48, 55, 50, 52, 53, 53, 57, 48, 49, 54, 57, 55, 54, 49, 50, 55, 48, 52, 50, 54, 54, 49, 53, 56, 51, 50, 53, 56, 56, 56, 55, 56, 57, 54, 57, 50, 48, 50, 57, 48, 55, 51, 56, 48, 55, 56, 52, 55, 57, 54, 51, 51, 56, 57, 48, 56, 55, 53, 57, 53, 48, 48, 57, 55, 48, 57, 57, 52, 55, 49, 55, 56, 57, 56, 50, 50, 52, 48, 55, 52, 48, 54, 49, 49, 54, 56, 53, 54, 56, 49, 50, 56, 52, 50, 56, 51, 55, 55, 57, 48, 56, 53, 54, 57, 56, 54, 55, 53, 57, 52, 56, 92, 34, 44, 92, 34, 49, 92, 34, 58, 92, 34, 53, 50, 51, 53, 49, 57, 49, 56, 49, 54, 55, 50, 48, 52, 55, 51, 48, 56, 50, 52, 55, 55, 53, 57, 50, 53, 53, 55, 49, 48, 56, 57, 54, 56, 53, 53, 50, 49, 48, 54, 50, 50, 49, 51, 51, 48, 52, 56, 48, 53, 49, 50, 56, 56, 54, 56, 57, 54, 50, 56, 48, 53, 48, 53, 51, 48, 53, 57, 51, 56, 49, 57, 56, 50, 53, 48, 57, 50, 55, 52, 50, 56, 54, 56, 50, 53, 57, 48, 57, 54, 57, 53, 56, 48, 57, 49, 54, 51, 54, 51, 56, 56, 53, 57, 57, 53, 54, 55, 54, 48, 50, 57, 52, 55, 53, 55, 51, 56, 48, 51, 48, 48, 54, 49, 49, 55, 53, 52, 52, 55, 50, 50, 55, 49, 49, 52, 49, 57, 55, 57, 49, 50, 49, 54, 52, 57, 48, 52, 54, 50, 56, 48, 54, 56, 48, 56, 56, 55, 57, 57, 48, 51, 52, 52, 53, 49, 50, 54, 52, 56, 51, 49, 52, 52, 56, 55, 49, 54, 56, 52, 50, 50, 48, 57, 50, 50, 53, 55, 56, 50, 55, 49, 54, 54, 53, 50, 52, 57, 54, 54, 57, 48, 51, 54, 57, 50, 53, 57, 54, 56, 49, 55, 54, 50, 48, 53, 54, 49, 52, 49, 48, 49, 48, 48, 54, 56, 51, 49, 53, 55, 48, 52, 57, 55, 51, 50, 52, 52, 54, 50, 57, 50, 48, 54, 53, 51, 55, 55, 50, 55, 52, 49, 51, 55, 49, 52, 54, 50, 51, 54, 56, 50, 53, 56, 48, 52, 48, 51, 51, 55, 48, 53, 49, 55, 52, 51, 48, 56, 51, 55, 48, 51, 51, 55, 51, 50, 54, 56, 56, 54, 53, 49, 52, 57, 50, 49, 56, 50, 49, 53, 50, 49, 55, 48, 50, 56, 48, 57, 50, 53, 50, 52, 53, 50, 53, 55, 55, 51, 51, 48, 53, 55, 57, 55, 53, 52, 50, 57, 56, 48, 51, 54, 55, 52, 53, 53, 53, 51, 52, 56, 53, 52, 53, 50, 54, 48, 49, 49, 50, 54, 53, 57, 56, 50, 49, 50, 57, 49, 50, 51, 52, 51, 50, 57, 53, 56, 53, 54, 54, 56, 49, 53, 49, 57, 49, 52, 53, 52, 54, 48, 54, 53, 51, 57, 50, 50, 55, 49, 56, 51, 49, 51, 49, 49, 57, 52, 54, 51, 55, 56, 53, 57, 49, 53, 53, 48, 56, 57, 56, 54, 56, 49, 52, 53, 50, 52, 49, 49, 55, 51, 53, 57, 48, 57, 48, 49, 54, 53, 55, 49, 51, 53, 55, 51, 51, 56, 57, 49, 51, 50, 53, 51, 56, 56, 57, 50, 56, 57, 54, 48, 56, 50, 57, 54, 56, 54, 55, 57, 57, 50, 53, 50, 53, 55, 53, 51, 52, 52, 51, 56, 53, 50, 56, 48, 54, 51, 49, 49, 56, 53, 49, 52, 53, 52, 48, 48, 57, 55, 50, 56, 50, 50, 50, 49, 54, 53, 48, 57, 55, 48, 57, 51, 48, 52, 49, 48, 54, 51, 56, 56, 51, 50, 54, 50, 50, 54, 56, 56, 54, 50, 56, 51, 54, 52, 54, 54, 55, 56, 51, 55, 57, 48, 51, 56, 54, 56, 57, 49, 57, 53, 51, 57, 57, 56, 53, 53, 55, 56, 56, 53, 50, 49, 49, 51, 56, 49, 55, 53, 51, 49, 54, 51, 54, 49, 54, 56, 50, 53, 48, 56, 49, 52, 49, 57, 57, 53, 50, 48, 54, 48, 54, 48, 56, 49, 51, 56, 57, 53, 51, 51, 57, 53, 53, 48, 53, 50, 50, 53, 57, 51, 56, 49, 56, 48, 56, 54, 50, 48, 51, 48, 57, 48, 50, 52, 53, 49, 50, 48, 50, 52, 51, 52, 55, 53, 51, 54, 48, 54, 57, 57, 55, 52, 50, 57, 54, 51, 52, 53, 54, 57, 52, 55, 56, 51, 51, 57, 50, 55, 57, 52, 57, 53, 55, 57, 48, 48, 50, 56, 51, 53, 53, 57, 48, 50, 50, 54, 50, 52, 50, 51, 55, 53, 51, 57, 48, 56, 53, 50, 48, 48, 55, 51, 53, 49, 50, 56, 56, 49, 48, 53, 51, 54, 50, 51, 48, 54, 53, 55, 48, 49, 49, 53, 55, 53, 53, 55, 48, 56, 53, 52, 53, 57, 56, 53, 50, 49, 55, 92, 34, 44, 92, 34, 51, 92, 34, 58, 92, 34, 50, 49, 57, 55, 48, 56, 48, 53, 51, 53, 56, 49, 53, 55, 53, 48, 54, 50, 53, 56, 50, 53, 51, 51, 48, 48, 53, 55, 53, 50, 54, 51, 49, 55, 48, 55, 50, 48, 53, 50, 48, 56, 57, 57, 49, 49, 49, 56, 52, 56, 55, 54, 53, 54, 55, 54, 53, 54, 49, 54, 56, 51, 48, 55, 53, 49, 48, 50, 50, 50, 54, 57, 50, 57, 51, 56, 50, 55, 53, 55, 53, 52, 57, 55, 57, 50, 57, 52, 57, 54, 57, 54, 49, 52, 48, 53, 51, 49, 53, 54, 56, 54, 50, 52, 53, 52, 49, 49, 53, 54, 48, 57, 52, 51, 54, 57, 57, 56, 52, 57, 52, 50, 48, 52, 52, 57, 49, 56, 55, 48, 48, 55, 51, 56, 49, 52, 57, 50, 50, 52, 49, 51, 57, 50, 51, 56, 48, 51, 57, 50, 48, 56, 50, 49, 49, 48, 49, 56, 57, 57, 57, 51, 54, 57, 49, 53, 54, 49, 56, 48, 50, 52, 55, 51, 54, 57, 56, 50, 49, 56, 57, 51, 52, 51, 49, 56, 51, 56, 55, 48, 54, 50, 54, 53, 51, 56, 52, 49, 48, 57, 56, 52, 57, 56, 53, 52, 56, 50, 55, 57, 57, 50, 56, 51, 51, 50, 48, 55, 53, 57, 48, 57, 55, 54, 53, 53, 54, 54, 57, 53, 57, 48, 54, 53, 53, 49, 50, 50, 51, 53, 50, 53, 54, 53, 48, 57, 49, 52, 54, 52, 49, 51, 48, 55, 55, 48, 56, 52, 54, 51, 55, 49, 57, 50, 49, 50, 55, 56, 52, 49, 50, 55, 53, 50, 54, 53, 55, 50, 50, 54, 54, 49, 56, 54, 56, 52, 53, 49, 48, 53, 57, 52, 49, 57, 56, 50, 56, 49, 49, 48, 56, 55, 49, 50, 49, 57, 49, 53, 56, 53, 55, 53, 56, 54, 57, 55, 52, 52, 49, 57, 53, 48, 57, 57, 49, 56, 56, 57, 48, 51, 54, 57, 53, 49, 55, 55, 48, 57, 54, 53, 51, 48, 52, 53, 54, 54, 52, 52, 50, 56, 55, 50, 49, 52, 50, 50, 50, 48, 50, 48, 50, 51, 56, 50, 51, 57, 53, 49, 57, 49, 53, 51, 57, 49, 50, 52, 57, 55, 51, 50, 55, 48, 52, 55, 50, 50, 53, 54, 57, 53, 57, 52, 54, 51, 56, 50, 48, 53, 52, 57, 56, 48, 57, 52, 50, 57, 53, 51, 55, 53, 49, 48, 51, 48, 56, 53, 55, 50, 48, 51, 48, 49, 49, 49, 50, 50, 48, 54, 56, 53, 53, 57, 54, 53, 54, 49, 56, 55, 48, 51, 56, 54, 50, 54, 55, 57, 49, 52, 52, 54, 53, 49, 54, 54, 53, 52, 49, 56, 50, 49, 53, 53, 49, 53, 56, 53, 51, 57, 48, 53, 55, 55, 49, 50, 54, 57, 55, 55, 51, 55, 55, 54, 52, 55, 48, 48, 53, 53, 56, 51, 53, 50, 55, 55, 57, 50, 57, 54, 53, 48, 48, 52, 54, 54, 51, 50, 55, 56, 51, 48, 51, 57, 53, 51, 53, 55, 54, 56, 48, 51, 53, 48, 56, 52, 49, 52, 53, 56, 54, 49, 53, 51, 52, 52, 49, 50, 56, 55, 56, 57, 54, 55, 57, 56, 54, 55, 48, 51, 54, 54, 53, 54, 54, 57, 55, 54, 48, 53, 55, 50, 48, 51, 55, 54, 52, 51, 54, 51, 54, 54, 52, 51, 53, 49, 57, 57, 50, 54, 49, 54, 55, 48, 49, 49, 52, 48, 51, 50, 49, 55, 56, 52, 54, 54, 53, 50, 56, 50, 53, 54, 52, 51, 53, 49, 53, 54, 56, 51, 52, 48, 55, 56, 56, 56, 57, 50, 48, 49, 53, 54, 55, 53, 57, 52, 52, 57, 49, 50, 54, 54, 52, 54, 52, 51, 52, 53, 52, 49, 53, 49, 51, 53, 53, 55, 49, 57, 50, 52, 56, 48, 56, 55, 51, 48, 57, 53, 53, 54, 54, 51, 57, 54, 51, 49, 48, 55, 56, 48, 53, 56, 57, 56, 52, 53, 50, 49, 54, 52, 54, 48, 51, 56, 56, 51, 56, 49, 53, 55, 54, 48, 50, 50, 50, 56, 56, 48, 56, 48, 51, 49, 56, 51, 48, 57, 48, 49, 50, 50, 57, 50, 55, 48, 50, 49, 57, 48, 54, 92, 34, 125, 44, 92, 34, 109, 106, 92, 34, 58, 92, 34, 49, 52, 53, 48, 49, 56, 55, 50, 52, 48, 57, 57, 52, 48, 51, 50, 55, 57, 57, 56, 52, 49, 50, 56, 57, 51, 49, 53, 55, 48, 56, 49, 53, 49, 50, 51, 54, 51, 48, 56, 57, 55, 57, 48, 55, 53, 52, 48, 55, 57, 57, 52, 49, 54, 57, 57, 52, 51, 55, 53, 57, 52, 56, 53, 49, 52, 54, 55, 54, 54, 53, 48, 53, 57, 56, 48, 51, 54, 57, 51, 53, 50, 52, 49, 48, 48, 48, 55, 52, 52, 50, 56, 53, 52, 52, 57, 52, 52, 48, 56, 52, 53, 55, 48, 50, 49, 52, 49, 51, 56, 56, 57, 55, 49, 56, 52, 55, 50, 57, 55, 53, 56, 55, 50, 54, 54, 49, 51, 48, 55, 49, 54, 53, 48, 51, 49, 52, 52, 56, 48, 53, 55, 57, 48, 55, 52, 53, 53, 54, 55, 48, 48, 50, 48, 48, 51, 54, 54, 54, 56, 56, 56, 57, 53, 53, 54, 53, 49, 52, 53, 51, 56, 50, 51, 54, 48, 54, 57, 56, 92, 34, 44, 92, 34, 97, 108, 112, 104, 97, 92, 34, 58, 92, 34, 51, 49, 57, 49, 56, 55, 48, 51, 57, 49, 56, 52, 50, 52, 54, 48, 53, 52, 50, 49, 56, 54, 55, 51, 48, 54, 54, 51, 55, 53, 50, 57, 51, 56, 48, 56, 50, 55, 57, 56, 55, 55, 56, 53, 55, 56, 56, 52, 48, 53, 48, 53, 48, 54, 55, 50, 55, 55, 52, 49, 51, 56, 55, 51, 54, 49, 54, 54, 51, 57, 52, 49, 57, 51, 57, 48, 52, 54, 50, 49, 48, 56, 57, 53, 50, 52, 53, 51, 51, 57, 52, 52, 55, 53, 48, 49, 57, 53, 49, 49, 52, 49, 50, 57, 48, 57, 54, 49, 49, 57, 55, 53, 53, 48, 53, 49, 53, 50, 54, 56, 52, 54, 55, 50, 53, 50, 53, 52, 55, 54, 51, 56, 50, 52, 50, 48, 48, 48, 54, 54, 49, 51, 56, 49, 54, 49, 49, 51, 56, 55, 49, 50, 55, 50, 56, 49, 57, 49, 56, 49, 49, 54, 54, 51, 57, 56, 57, 55, 57, 48, 53, 57, 53, 51, 57, 57, 53, 55, 55, 57, 51, 49, 55, 55, 55, 48, 53, 55, 48, 54, 57, 54, 52, 52, 56, 50, 54, 55, 54, 48, 55, 49, 54, 49, 55, 52, 50, 49, 53, 53, 48, 50, 55, 54, 48, 51, 51, 50, 56, 50, 51, 48, 56, 55, 51, 53, 51, 50, 48, 56, 50, 48, 57, 48, 54, 50, 55, 53, 48, 51, 49, 54, 51, 52, 56, 48, 57, 54, 56, 48, 48, 55, 53, 49, 52, 48, 48, 55, 55, 53, 54, 49, 54, 51, 54, 55, 54, 49, 51, 56, 52, 54, 53, 57, 49, 48, 49, 57, 51, 52, 49, 57, 57, 56, 53, 49, 56, 55, 51, 57, 49, 55, 54, 56, 50, 55, 53, 57, 49, 56, 56, 52, 56, 50, 56, 56, 48, 51, 52, 53, 55, 55, 54, 57, 56, 51, 54, 48, 50, 50, 54, 53, 56, 55, 51, 54, 56, 57, 52, 51, 48, 55, 52, 55, 48, 50, 50, 56, 48, 50, 49, 49, 48, 55, 51, 57, 48, 57, 56, 53, 51, 53, 53, 51, 52, 49, 48, 48, 54, 51, 53, 56, 48, 54, 51, 55, 56, 51, 51, 56, 48, 51, 53, 50, 53, 53, 51, 50, 48, 51, 54, 56, 54, 56, 52, 52, 49, 49, 55, 53, 53, 52, 52, 53, 54, 56, 52, 49, 56, 54, 50, 54, 54, 52, 54, 57, 56, 48, 51, 48, 52, 49, 57, 51, 49, 57, 48, 54, 48, 48, 49, 54, 56, 53, 53, 49, 54, 48, 52, 50, 52, 55, 48, 53, 52, 54, 48, 50, 54, 55, 52, 56, 56, 50, 48, 52, 50, 53, 52, 55, 57, 57, 52, 56, 55, 55, 51, 49, 53, 55, 56, 57, 54, 54, 52, 56, 54, 51, 53, 48, 56, 54, 52, 50, 57, 55, 54, 57, 50, 49, 54, 57, 56, 54, 52, 50, 54, 57, 54, 51, 50, 49, 55, 52, 54, 51, 51, 56, 52, 57, 52, 56, 57, 56, 52, 49, 57, 55, 52, 50, 54, 55, 50, 55, 54, 49, 54, 57, 56, 54, 53, 50, 51, 52, 54, 56, 49, 53, 50, 52, 51, 49, 55, 51, 53, 51, 54, 54, 55, 51, 57, 57, 50, 53, 48, 54, 53, 53, 56, 48, 50, 48, 55, 54, 52, 55, 56, 49, 57, 51, 55, 57, 48, 49, 57, 56, 57, 51, 49, 55, 48, 51, 57, 57, 55, 48, 52, 51, 50, 55, 57, 51, 49, 49, 54, 54, 48, 54, 49, 57, 56, 53, 51, 51, 50, 49, 54, 57, 50, 51, 50, 54, 51, 55, 48, 54, 55, 55, 56, 56, 48, 55, 56, 57, 51, 48, 49, 48, 56, 49, 57, 55, 51, 56, 48, 51, 51, 53, 53, 50, 48, 54, 48, 53, 48, 56, 53, 52, 48, 48, 54, 49, 54, 51, 53, 56, 53, 50, 52, 54, 56, 50, 50, 55, 57, 53, 56, 57, 56, 54, 54, 56, 54, 55, 51, 49, 52, 51, 55, 48, 55, 50, 50, 55, 52, 50, 54, 48, 50, 52, 48, 56, 55, 50, 51, 48, 51, 57, 52, 50, 55, 50, 49, 56, 51, 50, 56, 57, 49, 50, 57, 49, 49, 54, 56, 54, 49, 48, 48, 49, 52, 56, 56, 51, 56, 48, 48, 50, 49, 56, 52, 53, 52, 54, 48, 51, 52, 55, 51, 53, 52, 51, 51, 57, 49, 50, 51, 51, 49, 54, 50, 55, 48, 54, 55, 54, 49, 53, 57, 51, 56, 52, 52, 48, 51, 54, 56, 55, 52, 49, 51, 51, 57, 54, 57, 56, 49, 52, 57, 55, 57, 53, 55, 54, 50, 51, 54, 53, 50, 55, 49, 52, 56, 50, 53, 56, 57, 51, 56, 52, 52, 50, 50, 52, 52, 54, 48, 57, 56, 49, 52, 54, 57, 51, 51, 52, 50, 54, 53, 55, 56, 54, 53, 54, 57, 51, 52, 48, 56, 54, 54, 57, 52, 56, 50, 52, 53, 51, 56, 54, 49, 55, 55, 55, 56, 54, 57, 52, 51, 92, 34, 44, 92, 34, 116, 92, 34, 58, 123, 92, 34, 51, 92, 34, 58, 92, 34, 51, 55, 57, 55, 50, 57, 50, 56, 48, 52, 48, 50, 56, 55, 48, 49, 57, 57, 54, 54, 50, 55, 57, 55, 48, 53, 50, 57, 48, 48, 55, 55, 49, 55, 55, 49, 50, 48, 52, 51, 56, 57, 49, 54, 56, 56, 49, 49, 54, 54, 53, 57, 53, 55, 50, 57, 52, 51, 51, 54, 53, 54, 56, 52, 53, 50, 51, 54, 56, 57, 52, 55, 54, 52, 50, 48, 51, 52, 53, 48, 56, 50, 53, 51, 53, 50, 51, 53, 56, 55, 52, 53, 56, 55, 50, 53, 51, 48, 54, 55, 56, 55, 50, 51, 49, 57, 51, 54, 55, 51, 49, 54, 56, 54, 57, 57, 50, 54, 49, 53, 53, 57, 50, 53, 50, 51, 52, 55, 50, 48, 54, 49, 51, 52, 57, 51, 49, 56, 53, 49, 57, 48, 48, 55, 57, 50, 51, 53, 52, 57, 50, 57, 56, 49, 49, 55, 48, 49, 52, 48, 57, 53, 57, 52, 50, 54, 52, 52, 54, 52, 50, 50, 52, 57, 53, 51, 52, 49, 57, 48, 55, 57, 52, 51, 56, 55, 49, 50, 52, 54, 56, 55, 50, 48, 53, 56, 53, 52, 50, 48, 56, 56, 52, 57, 55, 55, 52, 56, 50, 57, 52, 51, 48, 54, 48, 51, 55, 57, 48, 54, 52, 49, 54, 57, 52, 51, 54, 57, 55, 52, 51, 57, 48, 49, 49, 49, 55, 56, 50, 55, 48, 48, 50, 55, 56, 53, 50, 50, 56, 49, 49, 50, 56, 53, 51, 55, 50, 57, 49, 52, 48, 49, 52, 54, 57, 57, 52, 48, 50, 48, 51, 55, 57, 50, 48, 52, 53, 48, 49, 52, 53, 48, 51, 54, 50, 51, 50, 54, 48, 55, 54, 52, 51, 49, 57, 48, 55, 48, 50, 56, 55, 55, 50, 55, 54, 48, 52, 55, 53, 50, 57, 54, 57, 51, 57, 48, 51, 51, 49, 51, 50, 55, 52, 52, 56, 49, 53, 54, 51, 56, 57, 56, 49, 52, 53, 56, 56, 49, 50, 56, 57, 57, 52, 55, 50, 57, 56, 49, 57, 49, 51, 50, 50, 49, 54, 53, 50, 54, 52, 53, 48, 49, 52, 50, 52, 51, 54, 48, 53, 57, 54, 50, 49, 49, 54, 54, 48, 49, 48, 52, 54, 57, 50, 50, 51, 55, 52, 55, 51, 51, 48, 55, 50, 57, 52, 55, 57, 51, 57, 57, 55, 53, 52, 57, 49, 54, 56, 57, 53, 56, 52, 49, 50, 49, 56, 54, 55, 51, 52, 51, 48, 56, 57, 57, 52, 56, 52, 57, 52, 56, 48, 51, 50, 53, 49, 51, 54, 48, 57, 56, 54, 48, 51, 49, 54, 52, 54, 48, 48, 50, 52, 52, 49, 56, 57, 48, 51, 51, 51, 54, 56, 57, 51, 55, 50, 49, 54, 48, 52, 49, 50, 51, 50, 55, 48, 48, 54, 56, 52, 55, 49, 55, 49, 57, 53, 49, 52, 51, 52, 52, 56, 56, 57, 55, 51, 48, 57, 57, 50, 49, 54, 57, 54, 48, 51, 55, 57, 57, 54, 56, 50, 49, 54, 56, 50, 49, 54, 49, 50, 52, 53, 54, 51, 51, 48, 57, 57, 53, 49, 52, 48, 51, 50, 54, 55, 50, 49, 48, 56, 51, 54, 50, 52, 55, 49, 56, 52, 55, 50, 56, 55, 55, 56, 48, 55, 54, 55, 53, 51, 54, 53, 50, 55, 57, 50, 50, 49, 50, 53, 50, 57, 48, 51, 53, 52, 48, 48, 55, 50, 48, 56, 52, 54, 49, 53, 51, 52, 53, 48, 54, 54, 56, 48, 52, 50, 57, 48, 55, 57, 51, 50, 53, 54, 55, 51, 51, 48, 51, 56, 52, 55, 49, 50, 50, 54, 48, 50, 92, 34, 44, 92, 34, 49, 92, 34, 58, 92, 34, 56, 51, 55, 57, 55, 57, 50, 51, 49, 49, 49, 49, 50, 52, 54, 57, 56, 51, 51, 55, 49, 57, 48, 51, 53, 48, 55, 52, 48, 54, 50, 53, 52, 49, 57, 52, 54, 49, 51, 51, 49, 54, 55, 52, 53, 57, 55, 51, 49, 55, 52, 57, 57, 50, 56, 53, 55, 49, 49, 49, 57, 54, 48, 53, 57, 50, 48, 49, 49, 49, 54, 50, 51, 51, 54, 57, 54, 51, 53, 49, 52, 54, 50, 50, 49, 57, 54, 53, 53, 52, 55, 51, 57, 55, 52, 50, 56, 53, 55, 50, 56, 52, 49, 55, 48, 52, 50, 54, 51, 54, 51, 50, 49, 48, 48, 50, 54, 54, 50, 53, 52, 48, 48, 56, 52, 56, 54, 53, 48, 53, 57, 56, 55, 55, 52, 49, 53, 57, 56, 56, 52, 57, 50, 54, 53, 56, 48, 48, 50, 52, 53, 53, 54, 56, 49, 56, 57, 50, 51, 53, 55, 57, 54, 53, 55, 51, 52, 52, 49, 50, 55, 55, 56, 52, 52, 49, 51, 53, 57, 54, 57, 52, 51, 54, 51, 57, 53, 54, 49, 53, 48, 53, 48, 52, 50, 48, 55, 48, 51, 52, 51, 54, 52, 55, 55, 52, 54, 51, 50, 50, 54, 57, 54, 50, 54, 53, 56, 56, 54, 49, 54, 56, 50, 48, 56, 54, 55, 55, 56, 54, 56, 52, 53, 54, 56, 49, 54, 50, 57, 51, 48, 56, 53, 55, 51, 56, 55, 55, 54, 54, 52, 50, 50, 53, 53, 52, 53, 55, 54, 56, 53, 54, 57, 48, 48, 52, 55, 50, 56, 54, 53, 51, 54, 48, 56, 50, 53, 54, 51, 48, 57, 54, 52, 57, 55, 53, 55, 55, 57, 55, 55, 57, 57, 55, 48, 49, 54, 57, 52, 55, 51, 52, 57, 53, 51, 53, 49, 49, 52, 48, 55, 57, 57, 49, 57, 52, 53, 54, 48, 54, 50, 51, 51, 48, 49, 53, 55, 48, 52, 52, 57, 56, 51, 53, 49, 51, 52, 57, 54, 55, 57, 48, 50, 56, 48, 57, 54, 55, 50, 55, 49, 50, 55, 53, 57, 50, 56, 50, 52, 49, 54, 55, 52, 55, 48, 50, 51, 57, 49, 50, 49, 54, 49, 55, 53, 50, 49, 50, 51, 54, 50, 56, 52, 57, 52, 52, 53, 53, 50, 48, 50, 50, 48, 52, 50, 57, 56, 57, 49, 57, 53, 48, 52, 53, 55, 57, 54, 53, 53, 48, 50, 48, 54, 57, 51, 48, 53, 51, 53, 48, 49, 52, 56, 57, 48, 57, 52, 54, 57, 54, 51, 55, 49, 52, 53, 51, 50, 56, 54, 53, 52, 49, 51, 55, 55, 51, 51, 48, 50, 53, 53, 54, 57, 50, 49, 48, 51, 51, 56, 48, 55, 52, 48, 56, 57, 52, 49, 48, 53, 50, 49, 52, 51, 52, 54, 50, 56, 54, 49, 50, 53, 51, 48, 51, 54, 56, 53, 55, 50, 51, 53, 51, 55, 52, 49, 52, 50, 56, 51, 49, 54, 56, 49, 54, 48, 57, 54, 51, 56, 55, 50, 51, 50, 54, 54, 49, 49, 51, 50, 57, 50, 53, 51, 57, 54, 57, 54, 48, 51, 49, 54, 48, 52, 49, 51, 56, 54, 57, 55, 54, 53, 49, 54, 54, 51, 53, 56, 57, 50, 51, 55, 48, 56, 51, 50, 55, 53, 49, 56, 50, 53, 56, 57, 48, 55, 55, 53, 51, 55, 56, 54, 53, 56, 49, 50, 50, 48, 51, 54, 55, 53, 51, 54, 51, 57, 51, 49, 50, 55, 54, 48, 49, 52, 56, 53, 52, 55, 50, 48, 57, 56, 55, 55, 55, 56, 54, 53, 55, 54, 49, 52, 49, 48, 50, 55, 52, 52, 92, 34, 44, 92, 34, 48, 92, 34, 58, 92, 34, 50, 54, 53, 48, 53, 48, 51, 55, 53, 51, 50, 54, 56, 53, 53, 57, 50, 51, 52, 51, 50, 53, 48, 52, 53, 54, 48, 53, 48, 56, 56, 55, 55, 52, 50, 57, 49, 52, 50, 54, 55, 49, 52, 52, 52, 55, 53, 51, 48, 57, 50, 48, 48, 51, 50, 54, 56, 54, 54, 57, 57, 54, 54, 48, 51, 51, 49, 49, 51, 50, 56, 49, 56, 52, 49, 56, 50, 57, 52, 52, 48, 49, 51, 56, 54, 52, 53, 56, 49, 49, 51, 57, 50, 57, 48, 49, 53, 54, 54, 57, 57, 55, 48, 48, 53, 52, 57, 56, 55, 48, 52, 54, 56, 54, 57, 57, 53, 50, 53, 53, 57, 57, 51, 56, 50, 53, 48, 48, 55, 50, 51, 50, 51, 50, 48, 50, 52, 50, 56, 53, 57, 53, 48, 53, 48, 50, 54, 52, 49, 52, 56, 52, 53, 49, 53, 57, 55, 51, 52, 50, 48, 50, 52, 57, 57, 57, 49, 57, 53, 57, 56, 56, 57, 53, 54, 56, 50, 53, 57, 57, 53, 53, 56, 53, 53, 55, 54, 57, 49, 51, 48, 51, 53, 48, 53, 55, 55, 50, 55, 48, 54, 55, 53, 55, 52, 53, 56, 53, 55, 54, 53, 48, 48, 55, 53, 55, 51, 54, 51, 49, 54, 54, 49, 49, 57, 48, 49, 48, 54, 51, 50, 53, 57, 53, 49, 53, 54, 50, 54, 52, 55, 57, 55, 51, 57, 57, 57, 53, 53, 54, 51, 48, 55, 57, 48, 52, 49, 53, 54, 54, 48, 50, 57, 55, 50, 50, 53, 54, 55, 55, 50, 51, 54, 56, 54, 50, 54, 49, 50, 52, 57, 53, 54, 51, 53, 57, 49, 49, 51, 57, 52, 56, 52, 55, 57, 51, 51, 55, 57, 57, 56, 52, 55, 51, 55, 48, 48, 49, 54, 51, 55, 51, 54, 57, 49, 51, 57, 52, 57, 57, 49, 52, 54, 49, 56, 52, 54, 56, 55, 56, 54, 57, 56, 50, 48, 55, 56, 57, 54, 49, 56, 54, 52, 48, 53, 52, 49, 53, 53, 55, 49, 54, 48, 57, 56, 57, 54, 55, 50, 51, 51, 52, 57, 51, 50, 57, 56, 51, 51, 49, 52, 50, 57, 48, 57, 52, 57, 54, 49, 56, 53, 50, 48, 53, 48, 50, 53, 49, 52, 56, 48, 57, 51, 55, 50, 52, 52, 48, 57, 55, 48, 56, 52, 52, 56, 48, 48, 55, 57, 51, 51, 56, 54, 53, 48, 48, 54, 57, 52, 55, 52, 51, 52, 51, 56, 52, 57, 54, 53, 51, 52, 57, 56, 50, 48, 52, 56, 51, 54, 54, 52, 55, 50, 48, 56, 52, 50, 53, 54, 55, 51, 57, 48, 57, 57, 52, 57, 51, 51, 56, 51, 52, 52, 48, 51, 57, 56, 54, 52, 57, 54, 50, 57, 51, 48, 51, 54, 48, 48, 57, 57, 56, 56, 56, 51, 55, 57, 49, 49, 50, 50, 50, 55, 56, 55, 57, 49, 52, 55, 49, 50, 52, 52, 55, 57, 54, 55, 52, 52, 53, 52, 50, 49, 57, 51, 54, 48, 53, 54, 52, 48, 49, 54, 51, 51, 51, 54, 57, 50, 50, 56, 55, 54, 49, 50, 55, 57, 53, 50, 53, 53, 50, 52, 57, 56, 51, 57, 53, 49, 54, 53, 55, 57, 54, 56, 53, 54, 52, 52, 50, 49, 54, 54, 48, 49, 55, 49, 48, 55, 54, 51, 57, 53, 49, 55, 51, 48, 55, 48, 52, 52, 49, 52, 55, 56, 48, 56, 56, 57, 52, 55, 57, 55, 53, 55, 55, 54, 52, 55, 55, 49, 56, 50, 52, 54, 56, 54, 49, 50, 49, 49, 51, 53, 54, 54, 52, 92, 34, 44, 92, 34, 68, 69, 76, 84, 65, 92, 34, 58, 92, 34, 52, 51, 48, 54, 53, 56, 51, 53, 51, 55, 53, 54, 54, 53, 56, 49, 57, 52, 52, 48, 57, 57, 57, 53, 49, 53, 52, 50, 49, 56, 51, 53, 54, 54, 51, 51, 55, 48, 48, 48, 51, 54, 57, 56, 55, 54, 54, 57, 57, 57, 49, 51, 54, 48, 56, 49, 54, 52, 53, 56, 48, 52, 53, 50, 56, 54, 57, 51, 49, 49, 54, 50, 52, 50, 56, 51, 53, 50, 52, 50, 50, 54, 56, 57, 55, 54, 56, 56, 54, 53, 52, 49, 53, 48, 48, 56, 56, 53, 51, 55, 50, 57, 49, 57, 49, 57, 51, 53, 57, 53, 53, 50, 49, 54, 52, 57, 55, 52, 50, 53, 56, 51, 56, 52, 55, 52, 49, 50, 48, 55, 56, 57, 51, 55, 53, 53, 56, 53, 57, 52, 49, 51, 52, 54, 53, 50, 56, 57, 56, 51, 50, 57, 53, 51, 49, 51, 52, 53, 52, 55, 52, 57, 55, 51, 54, 57, 52, 52, 54, 57, 52, 55, 52, 48, 52, 56, 49, 52, 51, 48, 55, 55, 55, 48, 50, 50, 50, 54, 56, 55, 54, 51, 50, 51, 49, 52, 56, 51, 56, 52, 53, 48, 48, 49, 51, 52, 57, 48, 48, 49, 50, 54, 57, 56, 51, 55, 55, 54, 48, 48, 53, 48, 52, 56, 56, 49, 53, 57, 51, 56, 48, 49, 48, 57, 56, 52, 56, 53, 50, 54, 55, 49, 56, 54, 52, 57, 57, 52, 51, 52, 57, 55, 49, 53, 49, 56, 48, 53, 56, 50, 53, 55, 52, 54, 51, 53, 57, 56, 54, 55, 54, 55, 56, 52, 55, 49, 52, 51, 52, 53, 55, 49, 57, 49, 48, 57, 53, 53, 52, 48, 50, 57, 51, 57, 51, 51, 53, 54, 52, 52, 48, 52, 54, 50, 55, 50, 55, 53, 57, 53, 49, 49, 55, 54, 54, 54, 57, 53, 56, 57, 52, 52, 54, 56, 55, 52, 56, 48, 51, 52, 50, 50, 56, 48, 53, 52, 57, 50, 52, 53, 57, 56, 56, 54, 51, 53, 52, 53, 56, 57, 57, 50, 49, 53, 54, 54, 53, 48, 52, 57, 53, 53, 53, 48, 53, 48, 55, 50, 57, 48, 55, 50, 48, 49, 54, 48, 48, 56, 57, 55, 50, 57, 50, 52, 52, 54, 52, 52, 53, 50, 55, 51, 50, 50, 54, 55, 53, 57, 54, 52, 53, 49, 53, 50, 51, 52, 55, 55, 54, 48, 48, 52, 53, 48, 51, 48, 51, 50, 54, 57, 53, 52, 55, 52, 50, 48, 55, 53, 55, 49, 48, 49, 52, 56, 52, 56, 49, 48, 55, 50, 49, 55, 52, 57, 48, 56, 56, 49, 52, 52, 57, 48, 53, 51, 53, 54, 54, 52, 50, 49, 51, 49, 54, 49, 48, 54, 51, 50, 55, 57, 48, 52, 57, 55, 52, 53, 51, 54, 55, 49, 57, 51, 51, 48, 57, 51, 50, 57, 48, 51, 52, 48, 55, 54, 49, 54, 51, 48, 51, 53, 53, 56, 53, 55, 56, 54, 52, 54, 54, 50, 52, 56, 54, 54, 49, 56, 53, 55, 52, 48, 54, 55, 54, 49, 51, 52, 55, 57, 57, 52, 54, 48, 51, 52, 52, 50, 57, 48, 52, 51, 57, 49, 55, 53, 57, 54, 48, 51, 50, 54, 50, 54, 53, 51, 54, 48, 53, 54, 52, 51, 55, 51, 55, 49, 56, 55, 53, 49, 49, 54, 54, 51, 50, 55, 56, 57, 48, 52, 55, 50, 50, 49, 51, 51, 49, 48, 57, 53, 57, 55, 56, 55, 54, 49, 57, 56, 51, 52, 50, 50, 53, 55, 57, 53, 57, 56, 53, 49, 55, 50, 49, 56, 51, 52, 49, 57, 50, 92, 34, 44, 92, 34, 50, 92, 34, 58, 92, 34, 52, 54, 54, 50, 56, 57, 53, 50, 50, 57, 56, 57, 53, 57, 51, 51, 51, 48, 56, 48, 49, 50, 49, 55, 49, 48, 56, 56, 50, 51, 48, 56, 54, 48, 49, 54, 57, 52, 56, 52, 49, 49, 48, 55, 56, 56, 52, 48, 49, 54, 54, 55, 49, 50, 54, 50, 52, 56, 49, 49, 50, 48, 49, 51, 57, 56, 53, 50, 51, 50, 54, 48, 55, 56, 50, 55, 48, 57, 56, 53, 53, 53, 56, 52, 55, 52, 50, 49, 49, 52, 54, 56, 52, 49, 51, 53, 51, 53, 50, 53, 49, 51, 54, 53, 56, 57, 55, 51, 52, 51, 48, 51, 57, 52, 55, 51, 57, 56, 53, 52, 50, 51, 51, 57, 52, 54, 54, 51, 52, 51, 57, 57, 49, 53, 56, 56, 54, 53, 52, 51, 55, 48, 57, 53, 56, 53, 57, 52, 55, 57, 49, 57, 53, 49, 48, 56, 57, 55, 55, 56, 48, 57, 52, 53, 48, 50, 57, 50, 55, 57, 51, 50, 49, 57, 49, 50, 57, 49, 57, 54, 53, 52, 48, 57, 56, 50, 48, 50, 53, 57, 49, 48, 52, 49, 51, 51, 51, 53, 52, 54, 51, 48, 53, 51, 52, 53, 50, 50, 54, 56, 57, 49, 52, 57, 49, 57, 51, 52, 55, 53, 50, 53, 56, 53, 54, 52, 52, 53, 53, 55, 57, 49, 53, 52, 56, 57, 53, 51, 53, 49, 53, 52, 50, 53, 52, 54, 55, 51, 53, 52, 51, 57, 48, 49, 52, 57, 54, 48, 54, 50, 55, 57, 53, 50, 57, 55, 49, 50, 51, 56, 50, 51, 57, 53, 57, 53, 49, 55, 49, 57, 48, 50, 54, 57, 50, 50, 56, 53, 51, 48, 49, 49, 49, 55, 56, 50, 54, 48, 53, 48, 51, 52, 48, 57, 56, 53, 56, 54, 57, 50, 56, 57, 49, 55, 48, 57, 56, 55, 56, 50, 54, 56, 54, 48, 49, 56, 57, 51, 54, 55, 51, 48, 50, 54, 57, 55, 49, 50, 55, 51, 57, 53, 52, 53, 56, 57, 56, 48, 48, 56, 49, 48, 50, 48, 50, 50, 56, 55, 50, 56, 51, 50, 56, 49, 51, 57, 49, 56, 50, 57, 56, 51, 49, 53, 54, 53, 54, 48, 56, 53, 51, 54, 50, 50, 51, 55, 56, 53, 53, 57, 52, 52, 51, 54, 51, 57, 50, 55, 54, 55, 54, 48, 55, 53, 57, 48, 57, 49, 56, 50, 54, 56, 51, 48, 54, 57, 48, 48, 51, 55, 57, 49, 55, 50, 48, 48, 57, 53, 56, 57, 56, 48, 49, 49, 49, 52, 56, 50, 57, 52, 54, 57, 48, 53, 57, 57, 55, 56, 51, 52, 50, 50, 51, 54, 53, 51, 49, 49, 50, 49, 55, 55, 51, 55, 55, 56, 49, 50, 50, 56, 48, 56, 56, 53, 54, 51, 53, 56, 48, 56, 55, 52, 54, 49, 57, 51, 51, 48, 54, 55, 49, 51, 48, 55, 50, 53, 56, 57, 57, 53, 51, 56, 50, 51, 49, 48, 49, 54, 57, 55, 48, 56, 51, 56, 56, 56, 48, 52, 52, 55, 52, 49, 48, 49, 48, 52, 56, 51, 52, 56, 53, 53, 55, 51, 53, 51, 49, 53, 50, 51, 48, 49, 53, 55, 48, 52, 55, 50, 55, 57, 48, 49, 56, 54, 51, 48, 57, 50, 55, 51, 49, 54, 52, 49, 49, 53, 56, 48, 54, 56, 51, 53, 57, 53, 48, 49, 51, 49, 55, 48, 49, 51, 49, 52, 52, 53, 53, 48, 55, 52, 54, 54, 49, 55, 57, 55, 55, 54, 50, 57, 51, 50, 54, 49, 55, 52, 53, 48, 54, 57, 55, 55, 48, 49, 48, 53, 56, 92, 34, 125, 44, 92, 34, 112, 114, 101, 100, 105, 99, 97, 116, 101, 92, 34, 58, 123, 92, 34, 97, 116, 116, 114, 95, 110, 97, 109, 101, 92, 34, 58, 92, 34, 97, 103, 101, 92, 34, 44, 92, 34, 112, 95, 116, 121, 112, 101, 92, 34, 58, 92, 34, 71, 69, 92, 34, 44, 92, 34, 118, 97, 108, 117, 101, 92, 34, 58, 49, 56, 125, 125, 93, 125, 44, 92, 34, 110, 111, 110, 95, 114, 101, 118, 111, 99, 95, 112, 114, 111, 111, 102, 92, 34, 58, 110, 117, 108, 108, 125, 93, 44, 92, 34, 97, 103, 103, 114, 101, 103, 97, 116, 101, 100, 95, 112, 114, 111, 111, 102, 92, 34, 58, 123, 92, 34, 99, 95, 104, 97, 115, 104, 92, 34, 58, 92, 34, 49, 53, 49, 48, 55, 53, 57, 49, 49, 52, 56, 49, 50, 51, 57, 50, 49, 49, 51, 55, 49, 52, 54, 49, 57, 52, 51, 53, 55, 49, 56, 53, 51, 49, 54, 52, 49, 54, 54, 53, 56, 49, 48, 54, 52, 52, 54, 53, 51, 51, 54, 51, 51, 53, 49, 54, 55, 54, 56, 51, 54, 52, 51, 49, 54, 57, 52, 51, 48, 56, 57, 53, 56, 48, 48, 52, 50, 92, 34, 44, 92, 34, 99, 95, 108, 105, 115, 116, 92, 34, 58, 91, 91, 49, 44, 49, 54, 54, 44, 56, 49, 44, 49, 54, 55, 44, 49, 50, 57, 44, 49, 54, 56, 44, 57, 44, 49, 57, 53, 44, 50, 48, 54, 44, 50, 48, 57, 44, 49, 48, 54, 44, 49, 56, 49, 44, 49, 53, 48, 44, 49, 54, 44, 49, 57, 53, 44, 49, 49, 55, 44, 54, 51, 44, 49, 55, 55, 44, 52, 52, 44, 50, 49, 53, 44, 56, 44, 51, 54, 44, 57, 54, 44, 49, 54, 44, 49, 57, 49, 44, 50, 48, 49, 44, 49, 50, 51, 44, 49, 55, 51, 44, 50, 52, 50, 44, 57, 48, 44, 50, 53, 50, 44, 49, 52, 55, 44, 50, 57, 44, 49, 54, 52, 44, 50, 51, 48, 44, 50, 50, 44, 49, 52, 56, 44, 50, 48, 49, 44, 55, 48, 44, 50, 49, 57, 44, 49, 44, 49, 55, 52, 44, 54, 56, 44, 50, 49, 50, 44, 49, 55, 50, 44, 50, 48, 44, 50, 52, 55, 44, 49, 48, 54, 44, 50, 51, 57, 44, 57, 54, 44, 56, 52, 44, 54, 50, 44, 50, 49, 51, 44, 50, 48, 53, 44, 50, 50, 44, 50, 55, 44, 53, 54, 44, 51, 50, 44, 49, 51, 44, 56, 55, 44, 56, 54, 44, 49, 53, 52, 44, 52, 55, 44, 56, 55, 44, 50, 50, 51, 44, 49, 51, 51, 44, 52, 56, 44, 49, 48, 51, 44, 49, 56, 49, 44, 49, 55, 51, 44, 56, 44, 49, 48, 49, 44, 49, 44, 54, 51, 44, 57, 53, 44, 49, 55, 50, 44, 49, 48, 57, 44, 50, 53, 52, 44, 49, 54, 48, 44, 50, 51, 56, 44, 52, 52, 44, 49, 56, 52, 44, 49, 54, 44, 49, 52, 51, 44, 53, 57, 44, 51, 56, 44, 51, 48, 44, 49, 55, 48, 44, 52, 57, 44, 49, 50, 53, 44, 49, 57, 55, 44, 50, 50, 49, 44, 50, 50, 50, 44, 53, 52, 44, 53, 56, 44, 50, 49, 48, 44, 50, 53, 50, 44, 49, 51, 55, 44, 49, 52, 53, 44, 55, 48, 44, 57, 57, 44, 49, 52, 50, 44, 50, 51, 51, 44, 49, 53, 56, 44, 49, 54, 50, 44, 49, 55, 52, 44, 54, 44, 49, 48, 55, 44, 51, 49, 44, 49, 52, 44, 53, 48, 44, 49, 49, 49, 44, 50, 52, 52, 44, 49, 51, 55, 44, 49, 50, 50, 44, 50, 44, 49, 54, 44, 50, 49, 56, 44, 50, 44, 56, 56, 44, 50, 48, 48, 44, 55, 50, 44, 52, 48, 44, 49, 52, 49, 44, 49, 51, 57, 44, 49, 56, 56, 44, 52, 51, 44, 52, 56, 44, 50, 51, 55, 44, 50, 52, 53, 44, 49, 54, 57, 44, 49, 54, 50, 44, 56, 57, 44, 49, 49, 50, 44, 56, 49, 44, 48, 44, 50, 51, 44, 52, 54, 44, 49, 57, 49, 44, 49, 53, 50, 44, 50, 50, 49, 44, 57, 51, 44, 49, 50, 53, 44, 49, 48, 53, 44, 50, 51, 56, 44, 49, 44, 50, 50, 50, 44, 49, 53, 55, 44, 54, 56, 44, 54, 49, 44, 50, 51, 44, 49, 56, 57, 44, 55, 44, 49, 49, 51, 44, 49, 54, 50, 44, 54, 49, 44, 50, 51, 48, 44, 49, 55, 50, 44, 49, 52, 51, 44, 56, 44, 49, 53, 55, 44, 49, 51, 44, 50, 50, 57, 44, 50, 50, 49, 44, 50, 49, 52, 44, 55, 57, 44, 56, 52, 44, 50, 52, 54, 44, 55, 53, 44, 49, 53, 54, 44, 50, 52, 48, 44, 55, 54, 44, 49, 50, 52, 44, 57, 51, 44, 51, 57, 44, 51, 48, 44, 49, 54, 55, 44, 49, 50, 50, 44, 49, 55, 53, 44, 50, 52, 54, 44, 49, 49, 55, 44, 49, 48, 53, 44, 54, 44, 50, 48, 51, 44, 50, 48, 55, 44, 56, 55, 44, 50, 49, 55, 44, 52, 48, 44, 50, 49, 53, 44, 50, 48, 44, 50, 48, 57, 44, 49, 56, 56, 44, 49, 55, 53, 44, 54, 44, 50, 53, 48, 44, 51, 49, 44, 49, 51, 44, 54, 52, 44, 49, 44, 50, 53, 48, 44, 54, 52, 44, 49, 53, 52, 44, 50, 51, 50, 44, 54, 52, 44, 52, 54, 44, 56, 52, 44, 55, 44, 49, 56, 48, 44, 49, 50, 49, 44, 53, 50, 44, 49, 44, 50, 51, 48, 44, 49, 50, 50, 44, 51, 48, 44, 57, 56, 44, 49, 52, 54, 44, 50, 50, 48, 44, 54, 44, 49, 54, 56, 44, 49, 57, 44, 53, 55, 44, 55, 56, 44, 55, 55, 44, 49, 49, 52, 44, 56, 52, 44, 57, 54, 44, 52, 56, 44, 49, 54, 50, 44, 53, 52, 44, 51, 53, 44, 51, 48, 44, 49, 52, 49, 44, 49, 56, 54, 44, 49, 54, 51, 44, 57, 57, 44, 49, 56, 53, 44, 49, 50, 51, 44, 50, 52, 44, 50, 49, 55, 44, 49, 51, 57, 44, 50, 49, 56, 44, 50, 50, 55, 44, 49, 52, 49, 44, 50, 51, 54, 44, 49, 48, 53, 44, 49, 54, 48, 44, 50, 52, 49, 44, 56, 51, 44, 50, 48, 49, 44, 49, 53, 50, 44, 54, 54, 44, 57, 56, 44, 51, 55, 44, 50, 53, 51, 44, 49, 54, 50, 44, 49, 57, 53, 44, 50, 50, 48, 93, 44, 91, 50, 48, 44, 50, 53, 52, 44, 50, 53, 50, 44, 50, 50, 44, 50, 51, 49, 44, 55, 53, 44, 49, 56, 44, 49, 55, 48, 44, 49, 55, 57, 44, 49, 48, 57, 44, 50, 50, 48, 44, 50, 51, 48, 44, 50, 55, 44, 50, 49, 57, 44, 49, 52, 57, 44, 51, 50, 44, 50, 49, 52, 44, 50, 48, 57, 44, 49, 52, 57, 44, 49, 51, 51, 44, 53, 48, 44, 56, 56, 44, 50, 49, 55, 44, 55, 56, 44, 53, 44, 57, 54, 44, 49, 52, 53, 44, 49, 51, 49, 44, 50, 53, 48, 44, 49, 53, 57, 44, 54, 49, 44, 49, 48, 56, 44, 54, 53, 44, 50, 49, 57, 44, 57, 52, 44, 55, 53, 44, 53, 50, 44, 56, 52, 44, 50, 53, 49, 44, 49, 54, 57, 44, 49, 57, 50, 44, 56, 52, 44, 49, 51, 53, 44, 53, 56, 44, 49, 51, 49, 44, 50, 54, 44, 51, 54, 44, 49, 52, 57, 44, 50, 55, 44, 50, 50, 52, 44, 49, 48, 54, 44, 54, 49, 44, 53, 44, 49, 57, 52, 44, 49, 57, 54, 44, 50, 52, 55, 44, 53, 51, 44, 55, 49, 44, 50, 49, 55, 44, 49, 49, 53, 44, 49, 49, 53, 44, 49, 51, 50, 44, 50, 49, 53, 44, 50, 52, 48, 44, 50, 51, 49, 44, 49, 57, 44, 49, 51, 49, 44, 49, 48, 54, 44, 50, 53, 50, 44, 57, 44, 56, 56, 44, 54, 54, 44, 50, 51, 55, 44, 49, 57, 44, 49, 48, 53, 44, 50, 50, 49, 44, 49, 50, 55, 44, 49, 55, 55, 44, 50, 53, 48, 44, 52, 44, 49, 50, 55, 44, 50, 51, 44, 49, 54, 55, 44, 54, 56, 44, 50, 53, 53, 44, 49, 56, 50, 44, 50, 51, 52, 44, 53, 53, 44, 50, 48, 50, 44, 49, 57, 57, 44, 49, 53, 57, 44, 54, 54, 44, 49, 44, 49, 56, 49, 44, 50, 50, 44, 52, 48, 44, 49, 49, 50, 44, 49, 52, 52, 44, 50, 49, 57, 44, 55, 56, 44, 50, 53, 49, 44, 49, 55, 50, 44, 56, 44, 49, 57, 51, 44, 49, 51, 57, 44, 49, 55, 53, 44, 51, 44, 49, 54, 48, 44, 54, 44, 50, 53, 53, 44, 55, 54, 44, 50, 51, 50, 44, 50, 49, 53, 44, 54, 55, 44, 49, 53, 55, 44, 50, 51, 57, 44, 49, 51, 44, 49, 55, 57, 44, 49, 55, 51, 44, 49, 55, 52, 44, 49, 53, 56, 44, 49, 50, 48, 44, 55, 44, 50, 50, 54, 44, 52, 56, 44, 57, 57, 44, 51, 54, 44, 49, 50, 57, 44, 49, 52, 54, 44, 56, 53, 44, 49, 57, 52, 44, 54, 52, 44, 56, 54, 44, 50, 54, 44, 50, 52, 50, 44, 50, 52, 56, 44, 49, 57, 50, 44, 49, 56, 50, 44, 50, 50, 53, 44, 49, 57, 51, 44, 49, 48, 44, 49, 52, 54, 44, 49, 49, 51, 44, 50, 52, 57, 44, 49, 56, 51, 44, 54, 52, 44, 49, 56, 57, 44, 49, 48, 49, 44, 54, 57, 44, 49, 49, 56, 44, 50, 52, 57, 44, 52, 54, 44, 49, 53, 53, 44, 50, 48, 54, 44, 56, 53, 44, 49, 53, 48, 44, 50, 52, 53, 44, 54, 54, 44, 52, 44, 49, 54, 51, 44, 50, 49, 50, 44, 49, 54, 56, 44, 50, 50, 50, 44, 55, 54, 44, 49, 51, 54, 44, 53, 54, 44, 49, 51, 53, 44, 50, 50, 57, 44, 49, 56, 56, 44, 49, 50, 53, 44, 49, 55, 56, 44, 49, 56, 56, 44, 50, 49, 44, 54, 53, 44, 52, 52, 44, 50, 51, 52, 44, 53, 44, 49, 56, 48, 44, 49, 52, 48, 44, 54, 53, 44, 53, 51, 44, 49, 54, 54, 44, 49, 57, 49, 44, 50, 44, 49, 56, 57, 44, 50, 48, 55, 44, 55, 51, 44, 53, 48, 44, 49, 50, 57, 44, 49, 57, 49, 44, 56, 50, 44, 49, 54, 54, 44, 54, 48, 44, 49, 56, 55, 44, 55, 57, 44, 50, 49, 49, 44, 54, 51, 44, 53, 54, 44, 50, 50, 54, 44, 50, 53, 44, 49, 57, 50, 44, 48, 44, 49, 50, 56, 44, 49, 57, 50, 44, 55, 44, 50, 51, 56, 44, 49, 56, 57, 44, 57, 48, 44, 56, 54, 44, 49, 48, 52, 44, 50, 55, 44, 49, 48, 57, 44, 50, 55, 44, 50, 57, 44, 49, 55, 51, 44, 55, 57, 44, 49, 52, 55, 44, 56, 52, 44, 50, 51, 51, 44, 55, 53, 44, 50, 51, 57, 44, 50, 52, 53, 44, 50, 54, 44, 49, 55, 57, 44, 49, 52, 56, 44, 53, 48, 44, 49, 51, 52, 44, 49, 48, 57, 44, 50, 50, 51, 44, 53, 57, 44, 49, 56, 52, 44, 57, 56, 44, 49, 48, 55, 44, 49, 56, 54, 44, 49, 56, 55, 44, 51, 56, 44, 56, 54, 44, 49, 53, 54, 44, 49, 51, 51, 44, 49, 52, 52, 44, 50, 53, 49, 44, 49, 56, 56, 44, 49, 57, 57, 44, 55, 50, 44, 50, 51, 54, 44, 49, 56, 49, 44, 49, 50, 49, 44, 56, 51, 44, 52, 50, 44, 52, 48, 44, 49, 44, 49, 57, 52, 44, 53, 55, 44, 49, 55, 54, 44, 49, 55, 52, 44, 52, 56, 93, 44, 91, 50, 44, 49, 53, 49, 44, 50, 48, 54, 44, 49, 55, 56, 44, 50, 50, 48, 44, 49, 57, 57, 44, 49, 49, 51, 44, 49, 49, 56, 44, 49, 49, 50, 44, 49, 53, 52, 44, 49, 48, 51, 44, 55, 56, 44, 53, 54, 44, 49, 49, 51, 44, 49, 52, 49, 44, 55, 52, 44, 49, 48, 44, 53, 54, 44, 49, 53, 50, 44, 57, 51, 44, 49, 49, 54, 44, 49, 56, 53, 44, 49, 52, 54, 44, 50, 49, 49, 44, 52, 50, 44, 50, 44, 50, 53, 52, 44, 49, 50, 57, 44, 49, 50, 48, 44, 49, 54, 55, 44, 49, 57, 51, 44, 49, 49, 49, 44, 54, 50, 44, 56, 51, 44, 49, 51, 54, 44, 49, 48, 48, 44, 49, 51, 55, 44, 54, 48, 44, 49, 48, 44, 56, 57, 44, 56, 53, 44, 49, 50, 51, 44, 50, 50, 50, 44, 55, 57, 44, 50, 48, 56, 44, 53, 53, 44, 50, 48, 50, 44, 49, 49, 53, 44, 50, 51, 52, 44, 52, 51, 44, 49, 57, 52, 44, 50, 52, 56, 44, 50, 49, 48, 44, 49, 51, 56, 44, 49, 57, 51, 44, 49, 52, 52, 44, 49, 53, 55, 44, 55, 49, 44, 49, 48, 49, 44, 56, 49, 44, 52, 51, 44, 51, 51, 44, 49, 53, 49, 44, 49, 52, 49, 44, 53, 53, 44, 57, 50, 44, 52, 50, 44, 49, 49, 52, 44, 50, 57, 44, 49, 57, 50, 44, 49, 56, 57, 44, 49, 53, 49, 44, 50, 50, 48, 44, 49, 51, 49, 44, 50, 52, 54, 44, 49, 55, 51, 44, 49, 48, 57, 44, 49, 57, 53, 44, 50, 52, 57, 44, 49, 50, 53, 44, 49, 49, 49, 44, 49, 54, 57, 44, 51, 51, 44, 50, 50, 53, 44, 52, 56, 44, 50, 50, 50, 44, 50, 49, 50, 44, 49, 55, 51, 44, 52, 53, 44, 50, 49, 50, 44, 49, 50, 50, 44, 54, 53, 44, 50, 49, 49, 44, 49, 54, 53, 44, 49, 55, 49, 44, 51, 49, 44, 55, 49, 44, 57, 50, 44, 50, 52, 53, 44, 49, 50, 54, 44, 54, 44, 50, 52, 51, 44, 50, 52, 53, 44, 50, 48, 53, 44, 49, 50, 53, 44, 54, 54, 44, 50, 44, 50, 51, 57, 44, 50, 52, 56, 44, 49, 48, 44, 50, 48, 53, 44, 49, 50, 56, 44, 49, 53, 44, 56, 49, 44, 56, 44, 49, 57, 51, 44, 49, 51, 49, 44, 49, 52, 50, 44, 50, 49, 49, 44, 49, 53, 50, 44, 50, 51, 57, 44, 52, 55, 44, 49, 48, 55, 44, 49, 51, 50, 44, 49, 54, 53, 44, 49, 52, 56, 44, 49, 52, 51, 44, 49, 52, 54, 44, 49, 48, 57, 44, 50, 50, 51, 44, 49, 50, 48, 44, 50, 51, 56, 44, 51, 49, 44, 50, 56, 44, 57, 54, 44, 50, 53, 44, 49, 53, 50, 44, 50, 49, 53, 44, 56, 53, 44, 49, 51, 53, 44, 50, 53, 51, 44, 50, 51, 51, 44, 49, 57, 44, 49, 57, 57, 44, 50, 48, 49, 44, 57, 57, 44, 50, 50, 50, 44, 49, 54, 54, 44, 55, 57, 44, 49, 55, 54, 44, 55, 49, 44, 52, 49, 44, 49, 54, 49, 44, 49, 51, 52, 44, 49, 55, 53, 44, 49, 49, 57, 44, 49, 51, 57, 44, 57, 44, 49, 51, 49, 44, 49, 56, 54, 44, 49, 56, 49, 44, 49, 51, 54, 44, 49, 49, 51, 44, 49, 51, 56, 44, 51, 53, 44, 57, 56, 44, 49, 49, 48, 44, 49, 49, 55, 44, 50, 49, 48, 44, 50, 51, 56, 44, 50, 51, 48, 44, 54, 49, 44, 49, 57, 48, 44, 49, 52, 57, 44, 51, 57, 44, 50, 50, 53, 44, 54, 55, 44, 52, 50, 44, 49, 51, 56, 44, 55, 55, 44, 53, 53, 44, 50, 52, 54, 44, 55, 44, 49, 56, 48, 44, 52, 49, 44, 51, 44, 49, 52, 56, 44, 49, 52, 54, 44, 52, 53, 44, 52, 51, 44, 49, 51, 48, 44, 49, 51, 53, 44, 54, 51, 44, 53, 51, 44, 49, 54, 55, 44, 49, 56, 53, 44, 50, 52, 50, 44, 56, 48, 44, 51, 56, 44, 49, 53, 44, 57, 49, 44, 50, 51, 56, 44, 49, 51, 44, 49, 51, 44, 49, 51, 55, 44, 49, 50, 52, 44, 49, 52, 44, 49, 48, 49, 44, 49, 53, 48, 44, 50, 53, 51, 44, 53, 48, 44, 52, 55, 44, 49, 49, 49, 44, 50, 52, 48, 44, 49, 48, 52, 44, 50, 48, 55, 44, 55, 53, 44, 49, 50, 55, 44, 49, 53, 48, 44, 49, 48, 52, 44, 49, 48, 56, 44, 49, 56, 50, 44, 49, 57, 44, 54, 44, 49, 54, 57, 44, 49, 48, 48, 44, 49, 48, 48, 44, 49, 48, 53, 44, 49, 54, 54, 44, 49, 50, 50, 44, 51, 54, 44, 52, 54, 44, 49, 55, 57, 44, 49, 48, 50, 44, 50, 55, 44, 55, 53, 44, 52, 56, 44, 49, 49, 50, 44, 51, 54, 44, 49, 55, 55, 44, 50, 48, 44, 53, 48, 44, 55, 56, 44, 55, 49, 44, 54, 48, 44, 50, 51, 48, 44, 49, 53, 50, 44, 55, 52, 44, 49, 52, 48, 44, 50, 52, 44, 54, 54, 44, 49, 49, 48, 44, 54, 49, 44, 49, 57, 54, 44, 50, 48, 53, 44, 48, 44, 50, 49, 54, 93, 44, 91, 49, 44, 49, 49, 51, 44, 57, 53, 44, 56, 57, 44, 49, 49, 44, 54, 57, 44, 49, 53, 50, 44, 57, 48, 44, 49, 56, 44, 50, 49, 54, 44, 50, 52, 44, 49, 53, 54, 44, 54, 54, 44, 49, 57, 49, 44, 50, 48, 51, 44, 49, 49, 55, 44, 49, 48, 44, 50, 48, 56, 44, 57, 57, 44, 49, 51, 51, 44, 54, 52, 44, 52, 50, 44, 49, 50, 50, 44, 57, 54, 44, 49, 57, 52, 44, 49, 55, 55, 44, 55, 48, 44, 49, 51, 56, 44, 49, 55, 55, 44, 49, 53, 57, 44, 51, 51, 44, 49, 50, 52, 44, 49, 56, 52, 44, 49, 56, 51, 44, 49, 49, 50, 44, 49, 53, 52, 44, 53, 56, 44, 50, 50, 48, 44, 49, 56, 50, 44, 56, 49, 44, 56, 54, 44, 49, 51, 49, 44, 49, 56, 57, 44, 50, 48, 57, 44, 51, 53, 44, 49, 50, 52, 44, 49, 57, 51, 44, 50, 51, 53, 44, 49, 50, 56, 44, 49, 50, 54, 44, 49, 53, 48, 44, 49, 57, 56, 44, 49, 55, 56, 44, 49, 49, 53, 44, 49, 56, 52, 44, 49, 56, 52, 44, 56, 57, 44, 51, 51, 44, 50, 51, 48, 44, 49, 55, 48, 44, 49, 54, 54, 44, 53, 51, 44, 49, 55, 50, 44, 50, 50, 49, 44, 56, 49, 44, 49, 49, 54, 44, 49, 57, 54, 44, 49, 57, 57, 44, 49, 56, 57, 44, 49, 54, 48, 44, 50, 50, 53, 44, 49, 49, 55, 44, 50, 52, 56, 44, 49, 48, 50, 44, 49, 49, 57, 44, 49, 51, 54, 44, 51, 55, 44, 51, 50, 44, 52, 51, 44, 49, 52, 56, 44, 50, 53, 52, 44, 49, 55, 51, 44, 49, 52, 50, 44, 51, 55, 44, 50, 51, 49, 44, 49, 54, 48, 44, 49, 55, 56, 44, 49, 52, 55, 44, 56, 54, 44, 57, 55, 44, 49, 55, 57, 44, 50, 51, 44, 50, 50, 49, 44, 49, 57, 57, 44, 50, 48, 51, 44, 49, 49, 49, 44, 49, 52, 52, 44, 50, 48, 51, 44, 56, 56, 44, 53, 56, 44, 57, 55, 44, 49, 55, 55, 44, 50, 53, 49, 44, 49, 52, 50, 44, 50, 55, 44, 50, 53, 52, 44, 49, 56, 52, 44, 55, 57, 44, 49, 50, 55, 44, 49, 49, 53, 44, 50, 53, 53, 44, 50, 50, 48, 44, 49, 51, 53, 44, 50, 51, 48, 44, 50, 52, 52, 44, 50, 50, 54, 44, 54, 52, 44, 49, 53, 53, 44, 49, 55, 55, 44, 57, 57, 44, 51, 49, 44, 49, 48, 49, 44, 50, 57, 44, 49, 51, 55, 44, 56, 50, 44, 49, 51, 56, 44, 49, 51, 48, 44, 50, 48, 54, 44, 50, 55, 44, 50, 49, 52, 44, 52, 52, 44, 54, 48, 44, 49, 50, 51, 44, 49, 54, 53, 44, 50, 52, 48, 44, 57, 51, 44, 49, 50, 48, 44, 50, 50, 49, 44, 49, 55, 53, 44, 49, 57, 55, 44, 56, 54, 44, 50, 48, 57, 44, 49, 54, 53, 44, 49, 54, 57, 44, 49, 50, 54, 44, 49, 50, 48, 44, 50, 54, 44, 56, 55, 44, 50, 48, 56, 44, 55, 54, 44, 49, 52, 55, 44, 50, 52, 53, 44, 57, 55, 44, 49, 52, 54, 44, 49, 57, 44, 53, 48, 44, 49, 50, 50, 44, 49, 53, 48, 44, 55, 56, 44, 49, 50, 50, 44, 57, 49, 44, 50, 48, 52, 44, 52, 51, 44, 53, 44, 50, 51, 44, 49, 54, 53, 44, 56, 55, 44, 49, 57, 52, 44, 49, 53, 54, 44, 50, 51, 51, 44, 49, 56, 49, 44, 49, 57, 52, 44, 49, 49, 51, 44, 51, 48, 44, 52, 49, 44, 53, 52, 44, 57, 50, 44, 53, 54, 44, 50, 48, 50, 44, 56, 57, 44, 49, 57, 51, 44, 50, 50, 49, 44, 57, 50, 44, 49, 55, 48, 44, 49, 48, 54, 44, 49, 57, 56, 44, 56, 54, 44, 50, 49, 54, 44, 49, 56, 54, 44, 50, 57, 44, 50, 49, 57, 44, 52, 50, 44, 50, 53, 44, 49, 51, 55, 44, 49, 54, 44, 50, 53, 50, 44, 49, 54, 51, 44, 49, 50, 49, 44, 49, 48, 52, 44, 57, 49, 44, 50, 49, 50, 44, 56, 44, 49, 55, 48, 44, 57, 52, 44, 53, 55, 44, 49, 49, 50, 44, 50, 50, 57, 44, 50, 51, 53, 44, 49, 55, 53, 44, 56, 55, 44, 49, 52, 54, 44, 51, 56, 44, 50, 52, 48, 44, 49, 52, 51, 44, 56, 53, 44, 49, 56, 52, 44, 50, 50, 49, 44, 49, 49, 50, 44, 55, 53, 44, 50, 44, 53, 51, 44, 50, 49, 56, 44, 55, 49, 44, 50, 48, 49, 44, 49, 54, 57, 44, 49, 57, 44, 49, 53, 44, 52, 54, 44, 49, 53, 52, 44, 50, 50, 57, 44, 49, 56, 55, 44, 52, 49, 44, 50, 51, 54, 44, 50, 48, 50, 44, 50, 48, 44, 49, 51, 52, 44, 50, 48, 50, 44, 49, 53, 52, 44, 52, 50, 44, 49, 56, 48, 44, 49, 54, 55, 44, 55, 48, 44, 50, 49, 49, 44, 51, 49, 44, 49, 48, 52, 44, 49, 50, 51, 44, 50, 53, 53, 44, 56, 49, 44, 50, 53, 44, 53, 49, 44, 53, 57, 44, 49, 54, 57, 44, 49, 50, 55, 44, 52, 56, 44, 50, 52, 50, 44, 49, 56, 50, 44, 49, 57, 52, 93, 44, 91, 49, 44, 52, 52, 44, 50, 48, 53, 44, 49, 56, 48, 44, 55, 52, 44, 55, 51, 44, 56, 57, 44, 50, 50, 54, 44, 50, 50, 44, 51, 56, 44, 49, 54, 50, 44, 49, 54, 57, 44, 49, 54, 49, 44, 50, 48, 55, 44, 49, 56, 51, 44, 53, 56, 44, 53, 57, 44, 55, 51, 44, 51, 56, 44, 52, 57, 44, 50, 51, 53, 44, 49, 55, 49, 44, 49, 57, 48, 44, 49, 51, 48, 44, 49, 52, 49, 44, 50, 53, 53, 44, 49, 51, 57, 44, 50, 52, 55, 44, 55, 51, 44, 50, 51, 44, 49, 56, 49, 44, 49, 51, 48, 44, 49, 48, 48, 44, 55, 56, 44, 49, 55, 48, 44, 52, 50, 44, 49, 56, 48, 44, 49, 56, 48, 44, 52, 53, 44, 49, 52, 57, 44, 51, 52, 44, 52, 55, 44, 49, 57, 57, 44, 49, 50, 56, 44, 51, 50, 44, 54, 53, 44, 49, 49, 44, 52, 49, 44, 52, 57, 44, 54, 52, 44, 49, 53, 52, 44, 50, 50, 56, 44, 49, 52, 51, 44, 49, 56, 48, 44, 49, 54, 50, 44, 50, 52, 50, 44, 49, 49, 49, 44, 49, 53, 51, 44, 51, 57, 44, 50, 52, 48, 44, 55, 50, 44, 49, 51, 53, 44, 49, 53, 54, 44, 56, 48, 44, 50, 49, 51, 44, 49, 49, 57, 44, 53, 49, 44, 50, 50, 49, 44, 50, 48, 48, 44, 52, 54, 44, 49, 54, 48, 44, 50, 53, 49, 44, 48, 44, 49, 54, 51, 44, 49, 44, 57, 55, 44, 49, 57, 56, 44, 49, 57, 48, 44, 49, 55, 51, 44, 49, 52, 56, 44, 50, 51, 49, 44, 54, 44, 50, 48, 56, 44, 53, 44, 50, 52, 54, 44, 49, 55, 54, 44, 50, 51, 54, 44, 53, 48, 44, 49, 55, 44, 50, 53, 49, 44, 50, 53, 49, 44, 56, 49, 44, 50, 49, 49, 44, 57, 56, 44, 50, 50, 48, 44, 49, 53, 54, 44, 49, 51, 55, 44, 50, 52, 50, 44, 49, 49, 48, 44, 52, 44, 56, 44, 51, 51, 44, 49, 53, 48, 44, 50, 50, 56, 44, 54, 48, 44, 49, 54, 53, 44, 49, 53, 50, 44, 56, 54, 44, 49, 54, 54, 44, 50, 50, 50, 44, 49, 57, 56, 44, 49, 54, 54, 44, 49, 52, 54, 44, 56, 52, 44, 54, 49, 44, 49, 49, 51, 44, 49, 48, 48, 44, 54, 49, 44, 50, 44, 49, 55, 50, 44, 55, 52, 44, 51, 52, 44, 50, 50, 48, 44, 49, 50, 55, 44, 50, 51, 51, 44, 49, 49, 57, 44, 50, 48, 54, 44, 57, 50, 44, 49, 48, 55, 44, 53, 51, 44, 52, 48, 44, 49, 50, 52, 44, 50, 48, 54, 44, 53, 54, 44, 49, 56, 49, 44, 50, 51, 56, 44, 49, 53, 52, 44, 52, 53, 44, 57, 54, 44, 49, 55, 49, 44, 50, 49, 57, 44, 52, 54, 44, 49, 54, 48, 44, 55, 44, 54, 44, 50, 53, 53, 44, 53, 53, 44, 49, 54, 57, 44, 49, 49, 54, 44, 49, 55, 48, 44, 49, 52, 51, 44, 51, 53, 44, 49, 50, 56, 44, 50, 51, 56, 44, 56, 52, 44, 50, 48, 54, 44, 49, 51, 44, 50, 50, 52, 44, 49, 52, 57, 44, 57, 55, 44, 50, 51, 56, 44, 49, 57, 53, 44, 49, 48, 56, 44, 52, 55, 44, 54, 55, 44, 50, 53, 51, 44, 49, 57, 53, 44, 49, 48, 51, 44, 49, 57, 52, 44, 49, 53, 53, 44, 53, 50, 44, 50, 51, 49, 44, 57, 49, 44, 53, 55, 44, 54, 44, 50, 53, 44, 49, 50, 51, 44, 52, 53, 44, 49, 49, 44, 54, 56, 44, 50, 51, 44, 49, 55, 52, 44, 49, 48, 56, 44, 52, 48, 44, 49, 54, 53, 44, 51, 57, 44, 54, 51, 44, 50, 51, 57, 44, 52, 54, 44, 49, 50, 49, 44, 50, 51, 52, 44, 49, 44, 50, 52, 50, 44, 49, 56, 50, 44, 55, 53, 44, 56, 51, 44, 55, 57, 44, 50, 49, 56, 44, 50, 53, 49, 44, 49, 55, 51, 44, 50, 50, 55, 44, 49, 57, 51, 44, 49, 55, 49, 44, 51, 48, 44, 56, 55, 44, 57, 53, 44, 50, 56, 44, 49, 55, 53, 44, 49, 55, 53, 44, 49, 51, 52, 44, 50, 51, 54, 44, 54, 54, 44, 50, 57, 44, 49, 49, 57, 44, 55, 54, 44, 50, 50, 52, 44, 56, 52, 44, 55, 55, 44, 50, 49, 53, 44, 50, 57, 44, 49, 56, 56, 44, 49, 50, 44, 50, 48, 49, 44, 50, 50, 54, 44, 50, 50, 44, 50, 52, 52, 44, 49, 52, 57, 44, 51, 48, 44, 49, 55, 55, 44, 49, 53, 57, 44, 49, 56, 49, 44, 50, 51, 44, 51, 48, 44, 55, 55, 44, 49, 49, 50, 44, 52, 54, 44, 49, 56, 48, 44, 49, 54, 48, 44, 53, 54, 44, 57, 51, 44, 49, 50, 52, 44, 50, 48, 44, 51, 57, 44, 50, 51, 50, 44, 49, 49, 57, 44, 51, 56, 44, 49, 57, 56, 44, 55, 44, 50, 51, 53, 44, 50, 48, 55, 44, 51, 56, 44, 49, 57, 55, 44, 50, 50, 57, 44, 49, 48, 50, 44, 49, 53, 56, 44, 49, 56, 50, 44, 49, 55, 48, 93, 44, 91, 49, 44, 56, 53, 44, 51, 55, 44, 49, 55, 48, 44, 55, 49, 44, 50, 50, 51, 44, 49, 51, 54, 44, 50, 48, 57, 44, 49, 56, 57, 44, 54, 54, 44, 56, 53, 44, 50, 53, 48, 44, 49, 50, 57, 44, 51, 50, 44, 50, 52, 51, 44, 54, 50, 44, 49, 49, 56, 44, 50, 49, 49, 44, 49, 54, 56, 44, 53, 44, 57, 53, 44, 50, 56, 44, 52, 52, 44, 49, 50, 57, 44, 50, 53, 48, 44, 49, 56, 53, 44, 50, 48, 51, 44, 49, 50, 51, 44, 49, 52, 55, 44, 53, 51, 44, 51, 52, 44, 50, 52, 53, 44, 49, 54, 55, 44, 50, 56, 44, 49, 54, 57, 44, 49, 52, 55, 44, 49, 56, 48, 44, 52, 50, 44, 51, 57, 44, 49, 57, 57, 44, 50, 50, 48, 44, 49, 53, 53, 44, 49, 51, 56, 44, 55, 57, 44, 50, 49, 55, 44, 50, 53, 50, 44, 49, 52, 53, 44, 49, 53, 52, 44, 55, 56, 44, 54, 49, 44, 57, 55, 44, 49, 57, 48, 44, 49, 50, 49, 44, 53, 44, 53, 44, 56, 55, 44, 53, 54, 44, 49, 52, 51, 44, 49, 54, 54, 44, 49, 51, 53, 44, 49, 56, 44, 49, 51, 53, 44, 50, 57, 44, 49, 49, 49, 44, 55, 52, 44, 49, 57, 49, 44, 50, 50, 50, 44, 55, 52, 44, 49, 49, 54, 44, 54, 48, 44, 56, 56, 44, 50, 52, 55, 44, 49, 53, 44, 49, 53, 49, 44, 50, 50, 55, 44, 50, 48, 48, 44, 50, 51, 51, 44, 54, 51, 44, 52, 52, 44, 49, 54, 55, 44, 57, 44, 50, 52, 54, 44, 55, 50, 44, 50, 48, 48, 44, 50, 53, 50, 44, 56, 48, 44, 49, 49, 48, 44, 49, 54, 52, 44, 49, 53, 44, 53, 55, 44, 49, 57, 44, 52, 53, 44, 51, 57, 44, 54, 56, 44, 50, 48, 55, 44, 49, 50, 55, 44, 49, 52, 44, 49, 57, 50, 44, 51, 44, 49, 51, 54, 44, 50, 51, 51, 44, 56, 53, 44, 50, 51, 50, 44, 55, 57, 44, 49, 53, 51, 44, 57, 57, 44, 53, 55, 44, 50, 49, 54, 44, 49, 53, 50, 44, 49, 53, 56, 44, 57, 52, 44, 50, 51, 52, 44, 55, 54, 44, 49, 56, 49, 44, 52, 53, 44, 49, 57, 57, 44, 52, 50, 44, 52, 52, 44, 53, 52, 44, 54, 44, 55, 57, 44, 55, 56, 44, 49, 52, 54, 44, 50, 49, 53, 44, 49, 57, 52, 44, 49, 49, 50, 44, 49, 55, 48, 44, 57, 53, 44, 49, 55, 54, 44, 50, 48, 52, 44, 49, 54, 55, 44, 51, 44, 49, 55, 44, 53, 49, 44, 49, 54, 48, 44, 49, 57, 55, 44, 49, 55, 44, 50, 51, 55, 44, 49, 44, 49, 50, 53, 44, 50, 50, 49, 44, 53, 49, 44, 50, 50, 57, 44, 50, 48, 55, 44, 49, 48, 57, 44, 50, 49, 49, 44, 50, 50, 51, 44, 50, 50, 57, 44, 53, 44, 49, 53, 52, 44, 55, 56, 44, 49, 54, 51, 44, 50, 51, 51, 44, 51, 52, 44, 57, 51, 44, 49, 57, 55, 44, 50, 49, 57, 44, 49, 55, 56, 44, 57, 50, 44, 49, 57, 49, 44, 50, 50, 57, 44, 49, 51, 44, 49, 53, 56, 44, 50, 48, 51, 44, 51, 55, 44, 53, 51, 44, 49, 57, 55, 44, 57, 54, 44, 52, 48, 44, 49, 53, 57, 44, 54, 49, 44, 49, 48, 54, 44, 55, 52, 44, 53, 50, 44, 49, 57, 48, 44, 49, 52, 44, 55, 53, 44, 49, 56, 48, 44, 56, 44, 50, 48, 50, 44, 50, 52, 55, 44, 56, 52, 44, 49, 57, 56, 44, 49, 53, 48, 44, 49, 48, 52, 44, 49, 52, 49, 44, 56, 56, 44, 53, 53, 44, 49, 51, 54, 44, 49, 57, 49, 44, 49, 55, 44, 49, 57, 48, 44, 53, 55, 44, 50, 49, 48, 44, 57, 54, 44, 52, 49, 44, 52, 52, 44, 49, 55, 57, 44, 49, 54, 57, 44, 53, 55, 44, 50, 51, 54, 44, 49, 55, 54, 44, 51, 48, 44, 49, 57, 48, 44, 53, 50, 44, 57, 55, 44, 49, 54, 53, 44, 53, 51, 44, 53, 49, 44, 48, 44, 49, 51, 52, 44, 56, 50, 44, 56, 54, 44, 54, 52, 44, 49, 49, 53, 44, 49, 51, 56, 44, 56, 57, 44, 49, 49, 44, 49, 57, 50, 44, 50, 53, 48, 44, 49, 54, 49, 44, 49, 54, 48, 44, 52, 52, 44, 57, 52, 44, 51, 53, 44, 49, 53, 54, 44, 50, 52, 57, 44, 53, 49, 44, 49, 48, 48, 44, 50, 52, 54, 44, 55, 56, 44, 55, 48, 44, 52, 56, 44, 50, 52, 44, 50, 50, 54, 44, 54, 51, 44, 54, 55, 44, 50, 50, 49, 44, 50, 49, 54, 44, 50, 51, 48, 44, 54, 53, 44, 50, 56, 44, 49, 52, 57, 44, 53, 57, 44, 55, 55, 44, 49, 57, 55, 44, 49, 55, 50, 44, 49, 56, 57, 44, 50, 48, 56, 44, 54, 44, 49, 57, 53, 44, 50, 49, 57, 44, 49, 48, 49, 44, 56, 51, 44, 49, 51, 55, 44, 54, 50, 44, 50, 48, 56, 93, 93, 125, 125, 44, 92, 34, 114, 101, 113, 117, 101, 115, 116, 101, 100, 95, 112, 114, 111, 111, 102, 92, 34, 58, 123, 92, 34, 114, 101, 118, 101, 97, 108, 101, 100, 95, 97, 116, 116, 114, 115, 92, 34, 58, 123, 92, 34, 97, 116, 116, 114, 49, 95, 114, 101, 102, 101, 114, 101, 110, 116, 92, 34, 58, 123, 92, 34, 115, 117, 98, 95, 112, 114, 111, 111, 102, 95, 105, 110, 100, 101, 120, 92, 34, 58, 48, 44, 92, 34, 114, 97, 119, 92, 34, 58, 92, 34, 65, 108, 101, 120, 92, 34, 44, 92, 34, 101, 110, 99, 111, 100, 101, 100, 92, 34, 58, 92, 34, 49, 49, 51, 57, 52, 56, 49, 55, 49, 54, 52, 53, 55, 52, 56, 56, 54, 57, 48, 49, 55, 50, 50, 49, 55, 57, 49, 54, 50, 55, 56, 49, 48, 51, 51, 51, 53, 92, 34, 125, 125, 44, 92, 34, 115, 101, 108, 102, 95, 97, 116, 116, 101, 115, 116, 101, 100, 95, 97, 116, 116, 114, 115, 92, 34, 58, 123, 92, 34, 97, 116, 116, 114, 51, 95, 114, 101, 102, 101, 114, 101, 110, 116, 92, 34, 58, 92, 34, 56, 45, 56, 48, 48, 45, 51, 48, 48, 92, 34, 125, 44, 92, 34, 117, 110, 114, 101, 118, 101, 97, 108, 101, 100, 95, 97, 116, 116, 114, 115, 92, 34, 58, 123, 92, 34, 97, 116, 116, 114, 50, 95, 114, 101, 102, 101, 114, 101, 110, 116, 92, 34, 58, 123, 92, 34, 115, 117, 98, 95, 112, 114, 111, 111, 102, 95, 105, 110, 100, 101, 120, 92, 34, 58, 48, 125, 125, 44, 92, 34, 112, 114, 101, 100, 105, 99, 97, 116, 101, 115, 92, 34, 58, 123, 92, 34, 112, 114, 101, 100, 105, 99, 97, 116, 101, 49, 95, 114, 101, 102, 101, 114, 101, 110, 116, 92, 34, 58, 123, 92, 34, 115, 117, 98, 95, 112, 114, 111, 111, 102, 95, 105, 110, 100, 101, 120, 92, 34, 58, 48, 125, 125, 125, 44, 92, 34, 105, 100, 101, 110, 116, 105, 102, 105, 101, 114, 115, 92, 34, 58, 91, 123, 92, 34, 115, 99, 104, 101, 109, 97, 95, 105, 100, 92, 34, 58, 92, 34, 78, 99, 89, 120, 105, 68, 88, 107, 112, 89, 105, 54, 111, 118, 53, 70, 99, 89, 68, 105, 49, 101, 58, 50, 58, 103, 118, 116, 58, 49, 46, 48, 92, 34, 44, 92, 34, 99, 114, 101, 100, 95, 100, 101, 102, 95, 105, 100, 92, 34, 58, 92, 34, 78, 99, 89, 120, 105, 68, 88, 107, 112, 89, 105, 54, 111, 118, 53, 70, 99, 89, 68, 105, 49, 101, 58, 51, 58, 67, 76, 58, 78, 99, 89, 120, 105, 68, 88, 107, 112, 89, 105, 54, 111, 118, 53, 70, 99, 89, 68, 105, 49, 101, 58, 50, 58, 103, 118, 116, 58, 49, 46, 48, 92, 34, 44, 92, 34, 114, 101, 118, 95, 114, 101, 103, 95, 105, 100, 92, 34, 58, 110, 117, 108, 108, 44, 92, 34, 116, 105, 109, 101, 115, 116, 97, 109, 112, 92, 34, 58, 110, 117, 108, 108, 125, 93, 125, 34, 125, 204, 169, 115, 101, 110, 100, 101, 114, 68, 73, 68, 204, 182, 87, 86, 115, 87, 86, 104, 56, 110, 76, 57, 54, 66, 69, 51, 84, 51, 113, 119, 97, 67, 100, 53, 204, 163, 117, 105, 100, 204, 167, 109, 109, 105, 51, 121, 122, 101, 204, 164, 116, 121, 112, 101, 204, 165, 112, 114, 111, 111, 102, 204, 168, 114, 101, 102, 77, 115, 103, 73, 100, 204, 192, 204, 175, 100, 101, 108, 105, 118, 101, 114, 121, 68, 101, 116, 97, 105, 108, 115, 204, 145, 204, 131, 204, 162, 116, 111, 204, 182, 51, 88, 107, 57, 118, 120, 75, 57, 106, 101, 105, 113, 86, 97, 67, 80, 114, 69, 81, 56, 98, 103, 204, 170, 115, 116, 97, 116, 117, 115, 67, 111, 100, 101, 204, 167, 77, 68, 83, 45, 49, 48, 49, 204, 179, 108, 97, 115, 116, 85, 112, 100, 97, 116, 101, 100, 68, 97, 116, 101, 84, 105, 109, 101, 204, 189, 50, 48, 49, 55, 45, 49, 50, 45, 49, 52, 84, 48, 51, 58, 51, 53, 58, 50, 48, 46, 52, 52, 52, 90, 91, 85, 84, 67, 93]; pub const DELETE_CONNECTION_ENCRYPTED_RESPONSE: &'static [u8; 301] = &[168, 213, 210, 163, 182, 121, 79, 64, 89, 151, 13, 184, 100, 184, 23, 134, 143, 106, 240, 184, 43, 53, 79, 240, 69, 117, 97, 155, 204, 243, 194, 58, 103, 213, 47, 156, 211, 208, 136, 116, 145, 118, 20, 225, 67, 190, 217, 13, 5, 249, 84, 101, 215, 17, 150, 69, 152, 16, 64, 19, 190, 65, 43, 171, 187, 58, 8, 37, 243, 198, 55, 227, 174, 151, 172, 218, 241, 16, 43, 15, 180, 44, 119, 163, 56, 126, 200, 181, 178, 185, 133, 93, 35, 24, 87, 90, 83, 235, 1, 210, 48, 8, 141, 215, 56, 243, 67, 79, 183, 225, 238, 195, 120, 206, 42, 114, 210, 82, 205, 35, 167, 121, 200, 36, 0, 121, 153, 68, 29, 114, 96, 144, 65, 192, 115, 215, 120, 6, 187, 94, 165, 203, 207, 86, 248, 135, 148, 201, 220, 91, 130, 43, 190, 232, 127, 110, 186, 128, 29, 99, 66, 5, 41, 125, 236, 37, 234, 46, 35, 130, 253, 244, 221, 47, 32, 235, 12, 190, 147, 184, 81, 26, 148, 206, 182, 228, 175, 0, 205, 11, 120, 149, 170, 123, 169, 181, 32, 70, 127, 119, 19, 43, 200, 190, 170, 164, 230, 182, 223, 203, 192, 4, 175, 200, 28, 206, 241, 217, 243, 75, 120, 33, 233, 2, 140, 143, 178, 90, 214, 250, 191, 118, 130, 27, 6, 161, 50, 37, 237, 234, 144, 209, 242, 44, 80, 48, 200, 15, 111, 24, 8, 107, 84, 56, 44, 241, 203, 39, 133, 92, 123, 112, 144, 178, 182, 43, 230, 95, 197, 46, 186, 101, 174, 30, 58, 209, 191, 243, 224, 227, 206, 253, 199, 59, 242, 81, 77, 6, 48, 128, 42, 59, 89, 14, 14, 2, 96, 28, 217, 67, 7]; #[cfg(test)] -pub const DEFAULT_SERIALIZED_ISSUER_CREDENTIAL: &'static str = r#"{"data" :{"source_id":"1","credential_attributes":"{\"attr\":\"value\"}","msg_uid":"","schema_seq_no":0,"issuer_did":"8XFh8yBzrpJQmNyZzgoTqB","state":1,"credential_request":null,"credential_offer":null,"credential_name":"credential_name","credential_id":"2936720225","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766","price":0,"payment_address":null,"ref_msg_id":null,"agent_did":"","agent_vk":"","issued_did":"","issued_vk":"","remote_did":"","remote_vk":""}, "version": "1.0"}"#; +pub const DEFAULT_SERIALIZED_ISSUER_CREDENTIAL: &'static str = r#"{"data" :{"source_id":"1","credential_attributes":"{\"attr\":\"value\"}","msg_uid":"","schema_seq_no":0,"issuer_did":"8XFh8yBzrpJQmNyZzgoTqB","state":1,"credential_request":null,"credential_offer":null,"credential_name":"credential_name","credential_id":"2936720225","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766","price":0,"payment_address":null,"ref_msg_id":null,"agent_did":"","agent_vk":"","issued_did":"","issued_vk":"","remote_did":"","remote_vk":"","cred_def_handle":1}, "version": "1.0"}"#; pub const DEFAULT_SERIALIZED_CREDENTIAL: &str = r#"{"version": "1.0","data":{"source_id":"test_credential_serialize_deserialize","state":3,"credential_name":null,"credential_request":null,"credential_offer":{"msg_type":"CRED_OFFER","version":"0.1","to_did":"8XFh8yBzrpJQmNyZzgoTqB","from_did":"8XFh8yBzrpJQmNyZzgoTqB","libindy_offer":"{\"schema_id\":\"2hoqvcwupRTUNkXn6ArYzs:2:schema_name:0.0.11\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"key_correctness_proof\":{\"c\":\"81455034389059130581506970475392033040313255495112570189348030990050944959723\",\"xz_cap\":\"313645697267968767252234073635675430449902008059550004460259716107399731378591839990019486954341409015811398444145390509019258403747288031702507727573872041899321045924287139508392740014051146807378366748171039375722083582850094590251566094137198468729226768809401256609008814847622114541957109991869490323195581928533376835343922482073783968747913611549869005687592623346914265913612170394649557294382253996246104002213172081216651539025706643350612557508228429410997102814965307308636524874409734625285377555470610010065029649043789306111101285927931757335536116856245613021564584847709796772325323716389295248332887528840195072737364278387101996545501723112970168561425282691953586374723401\",\"xr_cap\":{\"age\":\"882754630824080045376337358848444600715931719237593270810742883245639461185815851876695993155364347227577960272007297643455666310248109151421699898719086697252758726897984721300131927517824869533193272729923436764134176057310403382007926964744387461941410106739551156849252510593074993038770740497381973934250838808938096281745915721201706218145129356389886319652075267352853728443472451999347485331725183791798330085570375973775830893185375873153450320600510970851511952771344003741169784422212142610068911032856394030732377780807267819554991221318614567131747542069695452212861957610989952712388162117309870024706736915145245688230386906705817571265829695877232812698581971245658766976413035\",\"height\":\"987637616420540109240639213457114631238834322455397854134075974962516028070241761486895351636137675737583463907200584608953198912009428606796987435233170230262246507002244616435810064614719873830573727071246389627645604379157359983051337498205555868770767724876429776832782322071025598605854225056296405802351270140259313942108556513054492873024197036931111152136704979025907027537437514085689067466225661223523070057146052814725207863140129032189711026590245299845102901392525049014890473357388530510591717159458757929233202259332009161834669583439224425159885860519286698297401104830776447810193871233628235105641793685350321428066559473844839135685992587694149460959649026855973744322255314\",\"name\":\"1546639434545851623074023662485597065284112939224695559955181790271051962463722945049040324831863838273446566781589598791986646525127962031342679728936610678403807319789934638790962870799709103831307094501191346766422178361730723105585107221227683700136793784629414737866344469139276697568820727798174438114746109084012381033673759358527018948810066386903378176283974585934466197449653414224049202874335628877153172622300824161652402616917051692229112366954543190460604470158025596786552965425465904108943932508335616457348969058666355825158659883154681844070175331759147881082936624886840666700175491257446990494466033687900546604556189308597860524376648979247121908124398665458633017197827236\",\"sex\":\"716474787042335984121980741678479956610893721743783933016481046646620232719875607171626872246169633453851120125820240948330986140162546620706675695953306343625792456607323180362022779776451183315417053730047607706403536921566872327898942782065882640264019040337889347226013768331343768976174940163847488834059250858062959921604207705933170308295671034308248661208253191415678118624962846251281290296191433330052514696549137940098226268222146864337521249047457556625050919427268119508782974114298993324181252788789806496387982332099887944556949042187369539832351477275159404450154234059063271817130338030393531532967222197942953924825232879558249711884940237537025210406407183892784259089230597\"}},\"nonce\":\"161126724054910446992163\"}","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766","credential_attrs":{"address1":["101 Tela Lane"],"address2":["101 Wilson Lane"],"city":["SLC"],"state":["UT"],"zip":["87121"]},"schema_seq_no":1487,"claim_name":"Credential","claim_id":"defaultCredentialId","msg_ref_id":"abcd"},"msg_uid":null,"agent_did":null,"agent_vk":null,"my_did":null,"my_vk":null,"their_did":null,"their_vk":null,"cred_id":null,"credential":null,"payment_info":null,"payment_txn":null}}"#; pub const FULL_CREDENTIAL_SERIALIZED: &'static str = r#"{"version": "1.0", "data": {"source_id":"TEST_CREDENTIAL","state":4,"credential_name":null,"credential_request":{"libindy_cred_req":"{\"libindy_cred_req\":\"{\\\"prover_did\\\":\\\"2hoqvcwupRTUNkXn6ArYzs\\\",\\\"cred_def_id\\\":\\\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\\\",\\\"blinded_ms\\\":{\\\"u\\\":\\\"8732071602357015307810566138808197234658312581785137109788113302982640059349967050965447489217593298616209988826723701562661343443517589847218013366407845073616266391756009264980040238952349445643778936575656535779015458023493903785780518101975701982901383514030208868847307622362696880263163343848494510595690307613204277848599695882210459126941797459019913953592724097855109613611647709745072773427626720401442235193011557232562555622244156336806151662441234847773393387649719209243455960347563274791229126202016215550120934775060992031280966045894859557271641817491943416048075445449722000591059568013176905304195\\\",\\\"ur\\\":null},\\\"blinded_ms_correctness_proof\\\":{\\\"c\\\":\\\"26530740026507431379491385424781000855170637402280225419270466226736067904512\\\",\\\"v_dash_cap\\\":\\\"143142764256221649591394190756594263575252787336888260277569702754606119430149731374696604981582865909586330696038557351486556018124278706293019764236792379930773289730781387402321307275066512629558473696520197393762713894449968058415758200647216768004242460019909604733610794104180629190082978779757591726666340720737832809779281945323437475154340615798778337960748836468199407007775031657682302038533398039806427675709453395148841959462470861915712789403465722659960342165041260269463103782446132475688821810775202828210979373826636650138063942962121467854349698464501455098258293105554402435773328031261630390919907379686173528652481917022556931483089035786146580024468924714494948737711000361399753716101561779590\\\",\\\"ms_cap\\\":\\\"6713785684292289748157544902063599004332363811033155861083956757033688921010462943169460951559595511857618896433311745591610892377735569122165958960965808330552472093346163460366\\\"},\\\"nonce\\\":\\\"1154549882365416803296713\\\"}\",\"libindy_cred_req_meta\":\"{\\\"master_secret_blinding_data\\\":{\\\"v_prime\\\":\\\"19573554835481719662327485122688893711456991477879921695470731620175963787279917341526369852398210114401207141951797741891847253211319668203346462590568438671120943726162783813341598838616013039004762423956877028539225355867586807673681018234178116101643797916210905197387018359780257940149589162122784199178788814187547780152684853122014747482921656188183260370150999742557975345375106137123621426061675848590309427394874048446416740808489978625893734432529086470382099078632291038405367083882596203500659091849643476443635802557200596085378755820180062431900445542883509174786917819553164472263849777903881905876531213020487201635195790520\\\",\\\"vr_prime\\\":null},\\\"nonce\\\":\\\"143213049816807095013964\\\",\\\"master_secret_name\\\":\\\"main\\\"}\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"tid\":\"cCanHnpFAD\",\"to_did\":\"BnRXf8yDMUwGyZVDkSENeq\",\"from_did\":\"GxtnGN6ypZYgEqcftSQFnC\",\"version\":\"0.1\",\"mid\":\"\"}","libindy_cred_req_meta":"","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:2471","tid":"","to_did":"","from_did":"8XFh8yBzrpJQmNyZzgoTqB","version":"0.1","mid":""},"credential_offer":{"msg_type":"CRED_OFFER","version":"0.1","to_did":"8XFh8yBzrpJQmNyZzgoTqB","from_did":"8XFh8yBzrpJQmNyZzgoTqB","libindy_offer":"{\"issuer_did\":\"2hoqvcwupRTUNkXn6ArYzs\",\"schema_key\":{\"name\":\"Home Address\",\"version\":\"1.4\",\"did\":\"2hoqvcwupRTUNkXn6ArYzs\"},\"key_correctness_proof\":{\"c\":\"8555253541554245344305351079388313043821365069629297255640200538622329722556\",\"xz_cap\":\"64818256731588984794575029881576438712171978148821994354569423109505883511370051539530363090404289097908646608544866367046312481771587336183036163818849360474523320055058050733772575227932313793985470881830147160471852946598089626822740951538444260248405680001410943962258653118246973446307071417314391910474888369634752642195173997916292806072016186810315308257756689251031806948447462801785007243395079942815166817065271733596477143189406957903952991335446968764832960906258373699575234207180135806072152726528786138816315911998387303385565913657745597433033756984505440643451253917452841385494947936404135348354895376751800590086535707370194450915965147666804363452357419799188104044508109\",\"xr_cap\":{\"address1\":\"8236425893392219787423825014385198460820517586004442204287421088285469674020926840448786131806503567730307555837801319715555107413533966776756997088003362401505821396887204933829958258785093075846810980429322007441122948459832086015057507926262051365966017173045228232337530339680355717180291794733363148324101203340879842496879728996183974739507710337122557429529832639384077022317326079678153237524335334790193774589523155338216849532635731123476861074950940938322358853287805286272076498390452028019829082291826739453475976800681550225322996208089503815975750152834370138410964418644082923687817510140143620366818252076463572791466640135793621279863114074326681043782582123182032344081138\",\"address2\":\"30414471804770994051376437296525278254597585112268783700020054398847238843189530750793146903722533375657200785297557019465948393596156534191847866989266176618709331559949972729939131388887244366321127743968836991526071402029914419405781596054783690896660703606768577825229647587998380728894419570361864769440309185637967429191914824558483741394914212983254247799137730101941670911547714088499696084822272226072237693975774997990116374449197382931059877141968595755981160846810650806105803130004361523114137045586548743326078945833123588843296375692506658736851641735658969617721427932961073974202337608798761064528676757519926255271724266286989825397405029723387126754299497661658557574216867\",\"city\":\"159795636056543233530021344623621334175753173834199599499234503024224170089287815725788337040803537786795901100564559891075793321268703839671526386175533087941057761454903389990043254221508542663884105491028667931433093528378567035675241504608287341705758154859625863922110474313370021277749973041267871971965548396722681397958408458464210449202419266126608057284371794186889175339171087558861231355840830361110708993602208821778313069364112399404445977187422249127909803315019664537899385297653020295835898441614009217452024854561288538496889400595485884757791655246945196819845725103196695608534259378231125159518322706097470964698852674734436475238855630473478573401236177640541599034507313\",\"state\":\"215512468490315112938301657833926278136808116594771729699898320102646611321724434471863048390556908138905125523936043735201882025532772433002153410083708215401917118972375534193847316461794285777665177963351136804949997738950645361626956052973425101611071191598827068821964513860723502996877635652196651818308886110840798493982976675792164313480547213301748933952971154819253513296456319475340952940914757162158069252461973054465657233683514169036627218211903327888618365019366708902832859985119776192696909319524217085945724819529037625577237504453097885607411726308520123962852327787736505753002450290943635652415448032216336431217538662448209579828135627648861641446385394343199453905348086\",\"zip\":\"238413810148929820131063264189691178282858328114757399256193590161266006646670344870416481980522447923115217342582281807424862378687793299109363839238237538377362459559820681904274866049652851183765153471969318096511161665533190643665261284892951569998678113101193901664492159340828270692168345719923300987213287650281559452357368956472066676438018575401605560388568884399190765464134955117933339552804676602790359330495723485338924295339609987825045590507344961620812843451249916254642836938597183261177212672766675968705705261108413829152581548433386403050115216912797280460237259161451733151284615735871654022007177671460429253488906111387740833557450384941388970535365310270275589048348152\"}},\"nonce\":\"45815185447169282124747\"}","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:2471","credential_attrs":{"attr":"value"},"schema_seq_no":0,"claim_name":"credential_name","claim_id":"450220479","msg_ref_id":"zjcynmq"},"msg_uid":"ntc2ytb","agent_did":"U5LXs4U7P9msh647kToezy","agent_vk":"FktSZg8idAVzyQZrdUppK6FTrfAzW3wWVzAjJAfdUvJq","my_did":"8XFh8yBzrpJQmNyZzgoTqB","my_vk":"EkVTa7SCJ5SntpYyX7CSb2pcBhiVGT9kWSagA8a9T69A","their_did":"","their_vk":"","credential":"{\"libindy_cred\":\"{\\\"schema_id\\\":\\\"2hoqvcwupRTUNkXn6ArYzs:2:schema_name:0.0.11\\\",\\\"cred_def_id\\\":\\\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\\\",\\\"rev_reg_id\\\":null,\\\"values\\\":{\\\"height\\\":{\\\"raw\\\":\\\"4'11\\\",\\\"encoded\\\":\\\"25730877424947290072821310314181366395232879096832067784637233452620527354832\\\"},\\\"age\\\":{\\\"raw\\\":\\\"111\\\",\\\"encoded\\\":\\\"111\\\"},\\\"sex\\\":{\\\"raw\\\":\\\"male\\\",\\\"encoded\\\":\\\"5944657099558967239210949258394887428692050081607692519917050011144233115103\\\"},\\\"name\\\":{\\\"raw\\\":\\\"Bob\\\",\\\"encoded\\\":\\\"93006290325627508022776103386395994712401809437930957652111221015872244345185\\\"}},\\\"signature\\\":{\\\"p_credential\\\":{\\\"m_2\\\":\\\"31700338570294708736115754102769589522052428093121126330650183539696104868123\\\",\\\"a\\\":\\\"10777649052904447971899236694871368615157106927137883243983784973724349774915878204190601305259309589996988012735617563373033607709078907060449376941073338535388140957053144620511038735390585352398809313788054894621970622962097379200139814737879331234340443432491207812590825372988648847512086844348645931065426804353485775147746746850653036793108739563282161226029489872217064496590096990996410375663681099302996640966261859643618526555960651408715258210076488491742907031110655225420976262789193112889439595882291621507322209956202063945312604763840144988947123849968934460179482607183670360949359821454772971820091\\\",\\\"e\\\":\\\"259344723055062059907025491480697571938277889515152306249728583105665800713306759149981690559193987143012367913206299323899696942213235956742930226791220947134161266625378239251141\\\",\\\"v\\\":\\\"7160478880681489530685862580760235815690858242009735266356112612110531077619018018744043866754230561900079704139707892346188258175742757433839011445634508511903733556129176372339461109974281812535163844969408357722949237345514578452747464596905366813789049296203267070506446149025051172379040959761841090727724798945098115057584230172106482217166053964970319273092742014147315899348492822710345385893980919314665444664429040406728835710379367961220002388750496482799359536328531598808901788276665120213222621777995199496941581486741108559747481685600546431381718103907044451091043539280123106649794109913982938490727549883865702810163586252395063675836236109438822521688323977901722596298354615024259460544081204452640402841343661689933452404340637850647367306402860427277243229048988096792242220128886520666550722580134\\\"},\\\"r_credential\\\":null},\\\"signature_correctness_proof\\\":{\\\"se\\\":\\\"18062198058440854120810610625451590757963491440128115225422806009942350909306158512388123981508665484690252474351987301071051987945324357904950477248786064911802058100232994530383060574083901579841043178811110977049370234755264015098980663707351501791255018614113725688784339672744140961024678477581256784699212629381680205164276918652123852380815787068178236680303525175583034099258492257694970206425311460126364558914028413305726055746979620971531243376004995305402532327579706724246771202804790956714271731586625803214770535637064539642240021230950311414542750938384933247250254390883187655604134427458185611530857\\\",\\\"c\\\":\\\"7209681799349211936664438159371869376664205836919843273264901864121026304303\\\"},\\\"rev_reg\\\":null,\\\"witness\\\":null}\",\"rev_reg_def_json\":\"\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"msg_type\":\"CLAIM\",\"claim_offer_id\":\"1234\",\"version\":\"0.1\",\"from_did\":\"44oqvcwupRTUNkXn6ArYzs\"}","cred_id":"cred_id","payment_info":{"payment_required":"one-time","payment_addr":"pay:null:J81AxU9hVHYFtJc","price":1},"payment_txn":{"amount":1,"credit":true,"inputs":["pay:null:9UFgyjuJxi1i1HD"],"outputs":[{"recipient":"pay:null:xkIsxem0YNtHrRO","amount":4,"extra":null}]}}}"#; pub const DEFAULT_SERIALIZED_CREDENTIAL_PAYMENT_REQUIRED: &'static str = r#"{"version": "1.0", "data": {"source_id":"test_credential_serialize_deserialize","state":3,"credential_name":null,"credential_request":null,"credential_offer":{"msg_type":"CRED_OFFER","version":"0.1","to_did":"8XFh8yBzrpJQmNyZzgoTqB","from_did":"8XFh8yBzrpJQmNyZzgoTqB","libindy_offer":"{\"schema_id\":\"2hoqvcwupRTUNkXn6ArYzs:2:schema_name:0.0.11\",\"cred_def_id\":\"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766\",\"key_correctness_proof\":{\"c\":\"81455034389059130581506970475392033040313255495112570189348030990050944959723\",\"xz_cap\":\"313645697267968767252234073635675430449902008059550004460259716107399731378591839990019486954341409015811398444145390509019258403747288031702507727573872041899321045924287139508392740014051146807378366748171039375722083582850094590251566094137198468729226768809401256609008814847622114541957109991869490323195581928533376835343922482073783968747913611549869005687592623346914265913612170394649557294382253996246104002213172081216651539025706643350612557508228429410997102814965307308636524874409734625285377555470610010065029649043789306111101285927931757335536116856245613021564584847709796772325323716389295248332887528840195072737364278387101996545501723112970168561425282691953586374723401\",\"xr_cap\":{\"age\":\"882754630824080045376337358848444600715931719237593270810742883245639461185815851876695993155364347227577960272007297643455666310248109151421699898719086697252758726897984721300131927517824869533193272729923436764134176057310403382007926964744387461941410106739551156849252510593074993038770740497381973934250838808938096281745915721201706218145129356389886319652075267352853728443472451999347485331725183791798330085570375973775830893185375873153450320600510970851511952771344003741169784422212142610068911032856394030732377780807267819554991221318614567131747542069695452212861957610989952712388162117309870024706736915145245688230386906705817571265829695877232812698581971245658766976413035\",\"height\":\"987637616420540109240639213457114631238834322455397854134075974962516028070241761486895351636137675737583463907200584608953198912009428606796987435233170230262246507002244616435810064614719873830573727071246389627645604379157359983051337498205555868770767724876429776832782322071025598605854225056296405802351270140259313942108556513054492873024197036931111152136704979025907027537437514085689067466225661223523070057146052814725207863140129032189711026590245299845102901392525049014890473357388530510591717159458757929233202259332009161834669583439224425159885860519286698297401104830776447810193871233628235105641793685350321428066559473844839135685992587694149460959649026855973744322255314\",\"name\":\"1546639434545851623074023662485597065284112939224695559955181790271051962463722945049040324831863838273446566781589598791986646525127962031342679728936610678403807319789934638790962870799709103831307094501191346766422178361730723105585107221227683700136793784629414737866344469139276697568820727798174438114746109084012381033673759358527018948810066386903378176283974585934466197449653414224049202874335628877153172622300824161652402616917051692229112366954543190460604470158025596786552965425465904108943932508335616457348969058666355825158659883154681844070175331759147881082936624886840666700175491257446990494466033687900546604556189308597860524376648979247121908124398665458633017197827236\",\"sex\":\"716474787042335984121980741678479956610893721743783933016481046646620232719875607171626872246169633453851120125820240948330986140162546620706675695953306343625792456607323180362022779776451183315417053730047607706403536921566872327898942782065882640264019040337889347226013768331343768976174940163847488834059250858062959921604207705933170308295671034308248661208253191415678118624962846251281290296191433330052514696549137940098226268222146864337521249047457556625050919427268119508782974114298993324181252788789806496387982332099887944556949042187369539832351477275159404450154234059063271817130338030393531532967222197942953924825232879558249711884940237537025210406407183892784259089230597\"}},\"nonce\":\"161126724054910446992163\"}","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:1766","credential_attrs":{"address1":["101 Tela Lane"],"address2":["101 Wilson Lane"],"city":["SLC"],"state":["UT"],"zip":["87121"]},"schema_seq_no":1487,"claim_name":"Credential","claim_id":"defaultCredentialId","msg_ref_id":"abcd"},"link_secret_alias":"main","msg_uid":null,"agent_did":null,"agent_vk":null,"my_did":null,"my_vk":null,"their_did":null,"their_vk":null,"cred_id":null,"credential":null,"payment_info":{"payment_required":"one-time","payment_addr":"pov:null:OsdjtGKavZDBuG2xFw2QunVwwGs5IB3j","price":1}}}"#; @@ -83,7 +83,7 @@ pub static DEMO_AGENT_PW_SEED: &str = "00000000000000000000001DIRECTION"; pub static DEMO_ISSUER_PW_SEED: &str = "000000000000000000000000Issuer08"; pub static CONSUMER_SEED: &str = "00000000000000000000002DIRECTION"; pub static POOL: &str = "pool1"; -pub static GENESIS_PATH: &str = "/tmp/pool1.txn"; +pub static GENESIS_PATH: &str = "pool1.txn"; pub static DEV_GENESIS_NODE_TXNS: &[&str; 4] = &[ r#"{"data":{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","client_ip":"35.164.240.131","client_port":9702,"node_ip":"35.164.240.131","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv","identifier":"Th7MpTaRZVRYnPiabds81Y","txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62","type":"0"}"#, r#"{"data":{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","client_ip":"35.164.240.131","client_port":9704,"node_ip":"35.164.240.131","node_port":9703,"services":["VALIDATOR"]},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb","identifier":"EbP4aYNeTHL6q385GuVpRV","txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc","type":"0"}"#, @@ -92,6 +92,7 @@ pub static DEV_GENESIS_NODE_TXNS: &[&str; 4] = &[ pub static INDY_PROVER_CRED: &str = r#"{"attrs":{"state_2":[{"referent":"claim::230f2692-f8d2-48fa-8b65-2ef0177996f3","attrs":{"address1":"101TelaLane","zip":"87121","state":"UT","city":"SLC","address2":"101WilsonLane"},"schema_key":{"name":"Home Address","version":"1.4","did":"2hoqvcwupRTUNkXn6ArYzs"},"issuer_did":"2hoqvcwupRTUNkXn6ArYzs","revoc_reg_seq_no":null}],"address1_1":[{"referent":"claim::230f2692-f8d2-48fa-8b65-2ef0177996f3","attrs":{"address1":"101TelaLane","zip":"87121","state":"UT","city":"SLC","address2":"101WilsonLane"},"schema_key":{"name":"Home Address","version":"1.4","did":"2hoqvcwupRTUNkXn6ArYzs"},"issuer_did":"2hoqvcwupRTUNkXn6ArYzs","revoc_reg_seq_no":null}]},"predicates":{}}"#; //--------------------------------------------New Constants---------------------------------------------------------------- +pub static CRED_REV_ID: &str = "1"; pub static SCHEMA_ID: &str = r#"2hoqvcwupRTUNkXn6ArYzs:2:test-licence:4.4.4"#; pub static SCHEMA_CREATE_JSON: &str = r#"{"ver":"1.0","id":"2hoqvcwupRTUNkXn6ArYzs:2:schema_name:0.0.11","name":"schema_name","version":"0.0.11","attrNames":["name","age","height","sex"],"seqNo":null}"#; pub static SCHEMA_REQ: &str = r#"{"reqId":1523972184443268076,"identifier":"2hoqvcwupRTUNkXn6ArYzs","operation":{"type":"101","data":{"name":"schema_name","version":"0.0.11","attr_names":["name","age","sex","height"]}},"protocolVersion":1}"#; @@ -120,6 +121,8 @@ pub static ADDRESS_CRED_DEF_ID: &str = r#"2hoqvcwupRTUNkXn6ArYzs:3:CL:2479"#; pub static ADDRESS_CRED_DEF_JSON: &str = r#"{"ver":"1.0","id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:2479","schemaId":"2479","type":"CL","tag":"tag_1","value":{"primary":{"n":"90226862255330725049624935156831046218530253963751102614605452454614179793866839622286111251032969502072631946495704240811293616535162276527096464375788124429430926251001395353122698379553516898610723518833225131303950350637484236630892165662633043741460138240739182362871523983345614195950828833161052536905525723819311753709821438029317644001432626928258678145602130778757299820720082984921211287570446312038960087317518766664395629696858031264730797736672888160145501532820839190881880303636273534956233769878376800997657252270785754956186397003180942150712065633254160193743673207383306608679540558030200150777209","s":"5611479323423152092798436224232399449287576021804848216467480630808058057186631421569324068281439953876416758679883949251751128997514839328518883916706991815880095492733590116613449063159375534176665576626772878337854577598051867163631051864504877119616754655520722324639810882773237240322708444408109530601392941536146672048807714940622324854333329389247320430912122827406825529188081400547679631746096768715972418952678015274544421079079447028189830654814141593663206477653992085366434330195498225215445593222883919756690990197140978096976519454641287905725449089084620644479588320477216860751745953458107551200541","rms":"22767547575527200823877860609521861223935802871363206905509849499036391956083710387915539898715408511197508232028152886239708315444572585643554158977254570467031605594471522358454305353556024019491590416515780181523594854375557459861800021652833634574274569365055821629174631093611787648708513940784951747542023881790976069186701826954039602421306523149765134331716256688057882823234208603111684002272906018834643566538116472605852591111767184665701684430927909064209161443269990593399581566278975448984301556376868748304099114262512364906579274486201572389081178995232584524358882070864516374739715585901832408847261","r":{"city":"85713385814230908403415776579589685475133559188519630616941999419988271704286772609719026217611206469596950021090312275737234341485958369529180036165925975420156709289472753443654958213157780132808786882007473149908190374421291381089041388818464423270398294380057055695272151811803193358182432195930561445130355749133166185888465437911229226792699167297034732082863296415073829542563154705169436769937535150630493608264203351775409571164181614062057733480273937688689538756790923217733766247005249795613966520287410028316548716134115851547542797620379583952504237119342982651982064968237551842478328127113075892747225","address2":"1206766852087704282620150800601604485091336174976971728566994516607853374164326791646496350307001345523110861029525301419833620705320749257807602595445649302077240365763331079978088940362538995198262965890501270061419734189106944365497752792584337193213250069735762041338016876849284446959046070171620361520071042381902122184756113439895117091312615676785342798753397074743713383047309317645029305895956449585942388148591513587469025780778692727362082751899018772130079025713331168511391768469879642256112078806929820995430263573669200969695738849728634435291127865185744520242701699979573579527257788013599830748624","address1":"13832400255986193755301586588021298761264477767521959053909401273901456219368738086336923756754721098782361926392344509732949150564267631256460637388139159442211479763868098029126012552770471301324737474149693774518779400231191596762876917785136154886781692942754713531948698609140191507036039998680385515949333857893278572816588522002298762662153083967374064794019173071258453135852789621945105907930361433684035596734598665125008907141351500840156002149892942482319777181136166091067521255005320517564015909852872033422579719443863859476410203907217223400314511210520056639460800402253459490374827646011704885152360","zip":"61799871253162245511697515629407483163298961319741641148137106361857894190185956761725574395879681210613746250064660208705372553762835932204213793265198315662120265839390580246353763408292291730696400870314428143112061568226713623285565984571350193015344619550814344408909567606068673763110434881068974092431949151582190649649212231914713811467441439866973030154459748797576306986800260082728033171683023169999692465797895897356068971912472132339605925215046489759722454621330581385523121575622859250709915588193318967255916181388456977200338394412770325918796955299842558419664343828066623818886580680870486096280610","state":"26073839415614973129582312084708839396831394559137083803415037044934005948080805628037381161768626677371755428174295257449693445973412652528699605424365323174058558741019869196802711646814490149141838722288418313896985203965780925431860696142332031201650046087138471439619067568251803216337129731977586098741622231424400574683775498331340317684562550279161443115869255410439887045172323362841594647837780821830931849097786140509319896074145895658700148172515980667975221697598434209394428264713915531385949798623659348013861237963324501250488543850635343060716264413666259251633860681232518381215269016785201227166061"},"rctxt":"81316062379812440579682420473871034065419434685954216112069179607128043693523103114234806582795227535519405908950550152990558709776993403353578508991744227405811594150494004869006849257526865152003053773188802197658451716325924342000734567804457892280831692637849439996651142665929089823331087815155264122840636509210578961965821236617882454512679200976405511238372085527712486786396745468714669030400974135533438450643432736816784602798452150766871187984819558820794888223611991925344769878526285104209816976781673280412052201018090255834456030681892253575940926560534154246381884061079653471832853745138884956232033","z":"38724327388901176310316034980794510266482373527640769305434548269088881953903685678073771979570176342441913457857256848802078400972752070721409695050983353466803729019565239740981443896351790124874033389740642649113108119442267755771200286220588642917993273832840271715811133306896306392571034231582722174300411507975860942907055985573381309036713187292212579489740864018983715708772062589382060088421985665001412950076709120013261067131281036364352986358867466740756883864656417701478690167229707702427311227896973666224212362838224892821312026350931356399285731773936817117560567658599208193228013993276984411309661"}}}"#; pub static ADDRESS_ENCODED_DATA: &str = r#"{ "address1": [ "101 Tela Lane", "63690509275174663089934667471948380740244018358024875547775652380902762701972" ], "address2": [ "101 Wilson Lane", "68086943237164982734333428280784300550565381723532936263016368251445461241953" ], "city": [ "SLC", "101327353979588246869873249766058188995681113722618593621043638294296500696424" ], "state": [ "UT", "93856629670657830351991220989031130499313559332549427637940645777813964461231" ], "zip": [ "87121", "87121" ] }"#; pub static ADDRESS_CRED_ID: &str = "2dea21e2-1404-4f85-966f-d03f403aac71"; +pub static ADDRESS_CRED_REV_ID: &str = "Address Cred Rev Id"; +pub static ADDRESS_REV_REG_ID: &str = "Address Rev Reg Id"; pub static ADDRESS_CRED: &str = r#"{"schema_id":"2hoqvcwupRTUNkXn6ArYzs:2:Home Address:5.5.5","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:2479","rev_reg_id":null,"values":{"zip":{"raw":"87121","encoded":"87121"},"address1":{"raw":"101 Tela Lane","encoded":"63690509275174663089934667471948380740244018358024875547775652380902762701972"},"address2":{"raw":"101 Wilson Lane","encoded":"68086943237164982734333428280784300550565381723532936263016368251445461241953"},"city":{"raw":"SLC","encoded":"101327353979588246869873249766058188995681113722618593621043638294296500696424"},"state":{"raw":"UT","encoded":"93856629670657830351991220989031130499313559332549427637940645777813964461231"}},"signature":{"p_credential":{"m_2":"31700338570294708736115754102769589522052428093121126330650183539696104868123","a":"72350326160820048762064246459735853671064847588738514981890691169999691758147566039623335669172827888052359353807748970090349192554388275605230640889252148385818798591915052383528296788979211001489437577551863908408235488651651752382303483524120053517352920586008639536101164078543484039438169603660367872965542199471114653304754961456170760140570606933378861968239306799447880928903385645850026934455102303365418515353412723463813947311729310205272987472266614917124512060382167204283153526923491371495391008053623811107237327569183444059636754144114444734529852515199195527445970153718991859456401270933465925663696","e":"259344723055062059907025491480697571938277889515152306249728583105665800713306759149981690559193987143012367913206299323899696942213235956742930296983810977789330296216890705977217","v":"9670208438883674175035441018086366493922433413334409757770920546736616467742640326029077062195455492616059425669761134262312511516304411593148000993624087341484981074627709972216060475867277053506253667572165667669010830815854522124053354939798968426121738652582537683800405981991951170946602194133745570817194453758281975737518896619480688925992960521224989623405811301666129665333716572081484681625348473341694316753201327934178079114863457934373627801503124183040984086984963197205702609596549591939418424227250154210599683463484882769311481599772924921037564117675148941610684414842052487364385961648784501949953486672793860025214805689047628846599358099230374764326645584542715062655476807787473691363645940264843548517791722548798608231457227865534031005788070097411860564771509914741462179147155918806392510712312"},"r_credential":null},"signature_correctness_proof":{"se":"11637140943834961892237546293511182470735432357614876824410441064989493099906381936356057726422884972497911216233359595140533244393429043923219125379395446854309044990993668985547335791979600343976066171681977278286632590674606632239438417556781440170398622706830356894488134553245584775638308645402897721226297671586147204246446993796488722368662111430751280423229163634514710911483329745261830521954767764516456957157192616169625144276015092560616750291582727535784570054117697325666052766425884924042041174402259328143550487872570218202771950677703264673949135130462080533723998315383504971327455891815812932883617","c":"102889657000855571672874589021240213141439457797350182309867568844995482659720"},"rev_reg":null,"witness":null}"#; pub static LICENCE_CRED_ID: &str = "92556f60-d290-4b58-9a43-05c25aac214e"; pub static LICENCE_CRED: &str = r#"{"schema_id":"2hoqvcwupRTUNkXn6ArYzs:2:test-licence:4.4.4","cred_def_id":"2hoqvcwupRTUNkXn6ArYzs:3:CL:2471","rev_reg_id":null,"values":{"age":{"raw":"111","encoded":"111"},"sex":{"raw":"male","encoded":"5944657099558967239210949258394887428692050081607692519917050011144233115103"},"height":{"raw":"4'11","encoded":"25730877424947290072821310314181366395232879096832067784637233452620527354832"},"name":{"raw":"Bob","encoded":"93006290325627508022776103386395994712401809437930957652111221015872244345185"}},"signature":{"p_credential":{"m_2":"31700338570294708736115754102769589522052428093121126330650183539696104868123","a":"81960928509079620823343950032969008336391549074884608324517775818898568158758192830324222742417114228228203902794566738832133541043277590087972791512881285867310492031598697867842194658272660790216267605827567653156144194994212077428626164072308381616714460681106901232434875506679983631243405689626097418116467079690328805989253912611851228781463162324372034922981971152816959499965696422019179037584841719982627937439802497502379645996014647348333808221674167875101170534928961737975917670273969292141231226308968639154598912264045541666282915480370869384442192826186346261215780262029893283749269058216344643839503","e":"259344723055062059907025491480697571938277889515152306249728583105665800713306759149981690559193987143012367913206299323899696942213235956742930302596781531071170803058655297671317","v":"7003943637924412988764985072086000118095048595287611313986492240178874921183357936364378361712895532684180518228155827217099970080631339502652949458724398995638525726464206219725450743198010619790630880551811486328653217016849855435657581191318167232478417354743351890312732018064858307281249324839241525069489599880767806291488027527472257479805028163199620079751023262788194387523577687815000547930105970160978982360532796141873160492332648238829725366077913436103725101118591358740266221506301009012054972979815752525992452234196789821409854271003623732984546299835065309455365914274393177397705146623837433009746209922207286522542220100383185457598106478086209111860589557229256423462253695889598648825019225310530002635410754389313822261055900051606362243879818199501368654887162017859345197427086925735003959838923"},"r_credential":null},"signature_correctness_proof":{"se":"11431223809812071191361879028148220777647100610789026493040808255029518976741275883149787473920853063062683810872364990022708984265172669935498280721908373010049079315931590207743789205490987412738884813125642109587425252070402396960371098719424135381781601132971861649579057521357527931362887845539403430341689577272924207693393076024591919974734020560281971595749842184121978511921461113181862008695500532328750011887966998204164107467413093409118885910932729593377733323643109080259236185291922732808539257702801871235377257747608940446179593217663263040102481968096989806892625436511413195333252859906329357193890","c":"82704620743549045002211990344782978499138171223913909991546977545808822681258"},"rev_reg":null,"witness":null}"#; @@ -129,14 +132,44 @@ pub static DEFAULT_SEARCH_HANDLE: u32 = 1; pub static DEFAULT_SEARCH_RECORD: &str = r#"{"id":"RecordId","type":null,"value":"RecordValue","tags":"{\"tagName1\":\"str1\",\"tagName2\":\"5\",\"tagName3\":\"12\"}"}"#; pub static SCHEMA_TXN_TYPE: &str = r#"101"#; pub static CRED_DEF_TXN_TYPE: &str = r#"102"#; +pub static REV_REG_DEF_TXN_TYPE: &str = r#"113"#; +pub static REV_REG_DELTA_TXN_TYPE: &str = r#"114"#; pub static TRANSFER_TXN_TYPE: &str = r#"10001"#; +pub const REVOC_REG_TYPE: &str = "CL_ACCUM"; pub static PROOF_LIBINDY: &str = r#"{"proofs":{"claim::1f927d68-8905-4188-afd6-374b93202802":{"proof":{"primary_proof":{"eq_proof":{"revealed_attrs":{"height":"101","weight":"200"},"a_prime":"96825357504213820414920712887062035178734220080803428497609883672984582907009099983101574047222923191172901087572029807234151946901292592958722247994272968564810499919300106044605207990057917809541832623852323791793311699413524993596221669223340445229137623978342462134206199825853206867063996113501801994264194743641731037981074653346341669505587949133838740152370376461215475461071948757081816711059135548641059460671478570669934528058630540187953747821539169198114058851772920394076402690746410309424689457804467340432629509418396341637312297063848355683710144090865231980347430473575136584749971336607872735221481","e":"173797707086412224638317654877859078924059373314980330653273352384790685281330188710472447391993098340873509685594459760045118633810933189","v":"817471077330446042801182583278289771289939899862029945076522952536065298759596646234441125348749218649517963039993752411760911373696622306417612712541094410891004790314292818814366685563995233608999796109598000161662493062853421565696169350546027944863673676086478166460362895885803634323690475920074417094037040935347402139651274019219402676999841249239965723785316578360113393116610025042363124284525391995329580061841736426328774210022128121295069448914290656014180519168890133233038958063218641899739335907276444414243209025143049431600130541188759223138211506107377349139195417531858438343513980308300691115889309183927808937128403031600964187596017158389035128670751910466244582788345871859741880784391935682362926324291609666439201495908248254759163419830166895575411946245430341531037523316546692349875449961544668569143489718563622163239197265014753082903704824839586079949261854071576781373207187423207921842830","m":{"age":"15822941617894338766233233658363264215333584225107865867255097101337240720962242368328289996604483085044274203376532496405725498102090855037798745873303669426664372253887825720219","name":"13964975736408658520087388652512629489372660995256458553254103444734218937382021087114414237718252264962805304656549104857929447944575961598713806963229381922407043533207465727255"},"m1":"96892808406380415027889979610758682722844380024509794965656695309603144945553873163394888111015064896074982096261748169391443152799015882346651661021879622831679779409251822010294932053550075486870760993659254772491544354732571948365621031241138016035965757649630576402013034966385574374940295922113808748379","m2":"11661093607806638073781188747084292103515742861070700215778059783362149490064162350612272534962281735520949733852364820875657324177187266468853072206402518876096159768752059101257"},"ge_proofs":[{"u":{"2":"13578349425016411853296070984615297374744740853356759535005637919110260401076671653667151106586899689163439312338350934128141247305476662351514147622217966638022724978926219721004","1":"9826801536654035279437804411721354692428821623443482842159853372073568018439342854077273656337145568231528331617294053198372493410882511177276033294945945111573497303544457501728","3":"1037042123153514204573119204948220605299154049076633583354494606925165405121997811285708025281091619836054847337623028945671223408927294913105554993423464283121766578018864123196","0":"12718528291019054839844788454092267738226962302199765676405440941777392322367575064447939193728922414125816500300704366932567255319945007387631305169707929310781367799553235731195"},"r":{"2":"676003009211374935252164028385587930900618111572610399426532998074314176520930974705233431019951593825021806950341323910450419034970606973321513599566350797174538980828130307785786557887300817047726185221834713357185388049771205972344981062426988232787725638212286251011377158986400244422481866675017475958221617542616886523578162467958820668241643670589961050978074077535490218790750363852878560521919793191258571933037651104202430172137316611448318949425860592212666636165975739856428347510362144740067880890894360528173831335810168020561465966403337553765679504833616090358440891118488405211760098270732931764838035175408241309661677257083620331075539644189461637790052172121872006766032436123633898664409978638073","1":"349920139330498666322081874316604276639135453395613764189224988132844853265045879120276342391960567534902476163362661427585506904593292240512436239768343344020840139731013755726350197160348526788473254697708006671949590195528004855851813998600251595425408516191961975148403040078689445518994216611674310364645986083380328389623233149622754428146641794304281871878839456540045792674039433595107726043753004551269064154794115110023958392809750311907103056910478193724397710793243930374968440072989638161331833988373816982213266342530892063408779433568830855447112125083761023018526471994625982947051477089824649064442071004215728834491161129012753324627972041484890033442644393421099298426040030376350168665512471459479","DELTA":"2526861470651903540720320018766930888167900681682572985661381884467392618261641856254430321050624591171634372539030989936575279755283501847530618484185680702377431490667509592453287600128690017511250680484481133961861751059007941559620907769444959808378674078261135597016002423629779764678309550341449689628473308469826002228492041549462958786314803913047193762779808717108120438193021264832085926863710931620643041459463102773527316790458618123142903026612355945473887976952917085200867522116229217560970070697531438042172285209097472270369463486770759423978942812405424200436136331327024144131075040754281213553630388015531456435099854225963455009795976950482619918888522438664319539530239692821118623498424705652688","0":"227303741690308584797477735295198715784450946011850008177335476924050116857528863066627143458345318419409022081275373403345149661090008119849070683784280250685201823571318077869452613406858352540571555672813191272680806756442006396004567813444680548660322777493560315010733507370370161664280035580095533420578643487584761342906033815327063485750670841378883836444706052123766243319539590055884098533366810292531802775218401102860128587806228913886205861632717335037889596809104614549387408469316136746435173165124283115934244156928615362558648611222495646316614605352983318421663202797530744683820376707735248535628241924036161159932614335675040166337188851722591939429381437201923348800017362165521600184137378045300","3":"3782452160435244994305640620230284161266259587201416530630470391027710708201060896177599902317657509626066419632586010723213684427144396790304233645629004486904918218889579976490822963130314560352901741006252157192573268665291014408296857349571599513829377373687890199830766410332168601378519296407733260867717996031978610376955157034921668979895646241395908494759353090391980276896853697572039562508540269169332498254418040610566201842821643971775644086961593615913466915734572607003688651137260706788106040417008493617376835432217197185193923550093974933964025367861102086898081282048543090725604786529286396408208426923343342954201647541710771833352212650429563441418100463235725465955936565304905889131254959216319"},"mj":"15822941617894338766233233658363264215333584225107865867255097101337240720962242368328289996604483085044274203376532496405725498102090855037798745873303669426664372253887825720219","alpha":"34872707441943668555962227729623400706242062517309368451671475803555808473187122063738927425040029300261020414303710039209650320639097613388752346534836205478373404197421118163014327190520168843262674444521462882803672700118424453553908472888130344475236438054360549283772776268640869922694861668712566466484887949507361083049658486343750189393246195656647488079143964161212845625008980862764518649842627453020680924712648193263208528312853679683228786584439975576863302447553405100844483837440953623822117190363576643413897846168067157699019206898112653103033000653475724212201686935687689024186799069317581503304557753696132227445419998169511623645183170393763321474021474958075467971929328636007432251087414982085846113658316577011438437385644862462177079041099232014812219880868911453340614507218114391184041012451427647238636954423819","t":{"DELTA":"41307165120648610210323255658467084452588302969846130774080005528201577710926430139509593597163806485727726321757620805725587238993012402861710253413968045137568893879142473824911402781538120363984548568090293196159021817426447880420077899157810592309532889430989748749212042322667074051035312388704149017546618871610810735892041428534437648254019061553962258578634820738954140745472608119502104487739701641542862157803049040862713586918668540093258564294174369528845162482050479041840521474021843342836399729827428484368223534373219690727249480848630020293513261955840306892859816114010488426893769291815215205630742","2":"62841161458855690996661651614952070328705117022122283350316212662191494402593888806663350453883794826175484795499980021938644983903204992828166594403033230659509880531580187666263705641237995616859688468467613386802320437019449932939897064616566553110257459390946159059302421500358482472933517952960045455017229612538539208134069848925837034454447340658980181834790694456465850853974096220940799699361291520251683551669461390294007400713815067265039052964834756176299612320355263269984123484010851258116715025722655624854990040291762792880651376692064821746681638346056600286274510147910417870117450958869861465104899","1":"24703978606461118787105274354111842894893620834428715915938731240274908551111997585221881006416640821568172482461362275778386250296067233873665795472590400167255066699547396117589752898735251402483444776797066115291089304822000811043791445531767379190577594453868005586497081678504906992895932614822283189035748567383414492415611639449221381930702212102776768096535362890717753305938703607625761918979935187659029267871521564781565601905811572608291644252029147522049737646727602051717123718947045720827732051530300459585591890913538025411047507139522732042367301130637372288499204115179013530369697698354218594721475","0":"65806469094079822737051837922865696200577864864107883279450881789586610718279496879851772473067628842827615462460682005595227318016434368804753625199234729545808425915177309271666399564866366736529856443214583663269313307496418865238919492752930091988186505318922307627810577876406015223604199609319912951876126340656935317188225430904803331926648078715341421077348335918957748469977656446644923975237875910547351861966775766500545717552745804431969361710725386833003295067518704359823179893207876740778265886237227131457770819915147795395535727448356111980197115804613063948383652897499711327385710045228782003512936","3":"31322646464903454693494910691778082184612167667104866741028094713666840341508471387868538560123257236281474016330876597578553272613264509719738069121206685832934379843974913138572244384840932089473855198176658010692215649659329309967499853745027730849426692596913387514954466271796502348182196650439320529805947269694409354754272076934002666758951198589640361711184102691319537066346399151607042152550989492756769996181803310957811031813265690379435194143469156984862424644808054287393681339622619828302442397475709013742545822239900931405276555943268011671508253894537619267643377370399976878254795845211576746634008"},"predicate":{"attr_name":"age","p_type":"GE","value":18,"schema_seq_no":694,"issuer_did":"DunkM3x1y7S4ECgSL4Wkru"}}]},"non_revoc_proof":null},"schema_seq_no":694,"issuer_did":"DunkM3x1y7S4ECgSL4Wkru"}},"aggregated_proof":{"c_hash":"103325140275918938867265803420842782489379566578616035509312119027147548936535","c_list":[[2,255,1,43,219,18,174,224,110,47,48,204,200,108,166,218,236,150,253,40,245,107,249,151,169,23,213,77,132,219,111,189,93,49,128,111,97,179,145,71,54,31,66,185,179,77,166,145,209,119,48,224,231,103,209,111,164,165,115,40,210,186,42,229,211,169,127,72,200,124,224,109,227,124,216,135,243,38,133,132,44,79,215,125,254,12,38,125,140,237,26,97,188,57,16,189,13,124,67,199,101,221,67,14,225,160,229,169,38,143,183,36,63,47,23,237,246,4,69,164,95,175,237,148,16,26,97,174,155,19,244,135,242,237,152,61,100,254,4,252,80,169,46,57,131,97,71,106,126,60,218,2,70,211,188,55,90,37,182,127,64,69,142,173,228,180,216,84,219,211,184,151,43,113,18,207,133,30,198,241,161,27,160,158,27,201,56,23,131,91,221,241,251,136,194,157,243,199,185,44,79,63,64,53,0,64,169,35,153,98,68,249,54,85,76,203,244,70,140,79,3,164,69,38,230,198,241,165,68,10,87,156,39,236,192,215,171,48,148,86,156,3,101,126,229,50,190,186,193,155,107,23,222,53,103,150,233],[2,9,73,163,78,16,195,84,123,149,109,254,233,117,196,207,204,142,208,251,249,144,186,168,40,217,175,177,107,23,54,175,221,146,5,41,110,169,241,186,251,82,215,12,72,225,54,108,152,40,208,184,206,146,180,235,204,239,65,193,120,217,102,238,132,206,216,182,238,131,77,189,92,190,100,126,110,216,81,109,107,40,129,14,125,147,128,99,167,87,144,21,124,35,1,50,77,80,121,150,208,131,87,41,4,142,237,137,61,53,170,7,32,113,157,183,186,223,5,57,106,141,128,198,104,188,103,62,190,184,173,10,78,159,187,186,53,9,21,9,91,179,198,149,28,90,126,254,30,52,255,103,36,85,255,206,188,255,224,159,161,85,226,91,247,55,105,174,66,48,160,239,113,27,143,15,47,238,250,119,65,108,86,164,164,83,160,120,55,102,107,147,187,101,33,10,36,155,20,246,63,98,38,12,183,78,168,28,134,244,159,154,152,117,211,196,104,203,173,92,171,94,129,82,113,88,178,148,68,110,255,161,124,181,38,80,78,173,59,16,61,17,243,165,109,40,151,245,70,188,113,156,194,57,233,102,104],[195,177,117,241,39,31,43,103,4,123,155,155,185,3,157,169,135,13,153,177,142,64,120,109,184,15,93,245,23,215,19,182,204,189,106,207,67,242,60,194,53,77,5,224,96,26,118,224,26,220,52,186,158,165,224,247,61,146,248,144,86,160,129,234,209,178,210,130,127,60,153,174,86,129,84,148,181,203,162,29,194,119,223,5,108,238,168,4,82,111,163,91,112,138,96,137,26,204,136,233,73,52,41,164,7,33,99,249,171,223,149,6,192,64,190,176,167,244,56,186,71,50,230,27,130,76,137,128,59,228,169,183,39,182,251,106,102,116,112,237,29,75,104,38,196,238,38,23,47,196,181,19,146,215,179,136,173,224,35,152,248,166,130,73,116,172,120,25,83,106,81,52,89,201,160,127,145,213,204,70,173,143,162,125,98,104,240,83,134,8,118,201,187,62,165,53,60,181,231,134,246,209,240,6,21,44,51,150,69,230,127,10,178,185,174,58,89,188,136,68,182,54,126,84,131,20,122,190,123,17,243,72,211,34,75,131,189,184,97,31,37,211,171,168,158,114,5,199,146,151,90,102,180,159,222,195],[1,241,204,66,80,252,128,83,100,117,100,132,79,145,93,20,101,39,163,107,252,237,3,107,107,230,109,62,6,167,61,94,12,242,106,117,88,89,153,187,143,81,192,215,24,69,245,141,23,165,126,204,149,10,67,170,209,53,64,7,220,225,23,156,120,250,25,76,77,175,80,113,141,103,109,174,77,151,4,62,53,186,145,104,111,7,187,45,158,210,108,157,175,167,74,35,104,180,92,122,217,97,148,247,197,236,22,202,31,22,145,156,183,59,146,121,58,171,248,150,167,180,208,115,138,206,22,38,216,201,211,218,160,228,116,84,59,209,66,19,234,94,121,236,12,113,144,61,39,7,221,58,167,147,40,238,121,127,249,183,99,169,148,1,177,177,188,178,24,56,231,52,51,107,93,6,107,131,237,67,25,50,120,49,178,142,172,222,20,2,53,207,102,84,88,181,15,114,208,213,199,29,23,110,199,57,165,218,190,236,107,255,190,124,44,24,17,57,27,196,66,240,0,240,59,215,68,94,205,18,152,206,166,29,136,65,24,70,110,231,44,120,104,65,91,162,25,145,191,62,143,169,94,145,92,162,3],[248,31,135,16,9,253,156,61,189,71,113,131,172,238,66,26,77,193,63,68,248,114,19,177,8,54,49,185,168,212,253,22,13,233,162,77,65,26,78,132,204,253,141,123,6,184,36,50,89,139,87,111,127,131,93,193,8,194,45,76,115,115,234,44,235,18,123,228,2,164,247,7,66,97,238,121,171,60,109,190,75,171,114,147,81,88,222,179,119,18,52,76,172,38,253,92,249,13,180,129,231,218,166,96,208,154,186,25,120,63,59,56,88,75,245,246,202,56,130,78,136,64,241,221,246,198,247,198,228,117,60,223,64,104,161,23,63,206,186,192,252,4,53,64,13,167,101,248,23,105,55,24,158,91,121,186,2,111,141,50,153,117,79,231,184,184,128,110,6,230,191,245,4,112,15,206,159,71,77,184,109,61,1,125,35,152,134,28,219,110,90,135,75,18,96,142,14,247,177,169,37,172,131,236,124,176,131,44,128,35,85,11,88,246,196,167,208,105,164,38,234,103,67,137,5,215,123,21,86,70,252,110,167,59,224,98,30,60,82,56,116,231,41,247,124,110,55,170,188,52,231,127,148,83,235,24],[1,71,55,61,51,44,122,177,208,25,203,86,30,135,194,207,116,97,170,229,137,112,155,230,212,255,196,247,61,83,15,69,139,144,157,86,190,140,90,27,227,10,129,121,229,41,240,201,2,149,186,22,136,100,79,71,204,113,85,58,21,170,239,97,25,133,87,172,138,25,154,209,109,116,84,45,30,112,204,76,30,187,4,186,41,63,60,167,129,154,239,75,68,223,15,39,181,75,180,35,144,107,93,91,31,74,249,84,245,171,241,244,48,71,0,204,18,95,230,5,7,124,95,218,229,92,60,119,67,78,185,255,59,181,133,254,210,230,225,189,51,164,163,219,171,190,204,138,36,200,205,7,15,101,61,118,252,9,152,43,84,33,109,178,53,80,198,229,247,183,22,207,29,92,173,206,84,162,243,107,185,8,18,72,21,151,28,33,91,26,185,25,183,109,88,207,39,207,175,129,34,95,211,87,211,5,155,175,244,248,122,187,92,130,172,11,106,52,201,35,232,147,116,112,11,199,124,44,163,219,143,67,9,22,158,72,129,209,165,185,205,32,54,111,33,139,136,137,189,22,131,248,234,115,230,195,22]]},"requested_proof":{"revealed_attrs":{"height_0":["claim::1f927d68-8905-4188-afd6-374b93202802","101","101"],"weight_1":["claim::1f927d68-8905-4188-afd6-374b93202802","200","200"]},"unrevealed_attrs":{},"self_attested_attrs":{},"predicates":{"age_2":"claim::1f927d68-8905-4188-afd6-374b93202802"}}}"#; pub static PROOF_REQUEST: &str = r#"{"name":"proof name","nonce":"2771519439","requested_attrs":{"height_0":{"issuer_did":"DunkM3x1y7S4ECgSL4Wkru","name":"height","schema_seq_no":694},"weight_1":{"issuer_did":"DunkM3x1y7S4ECgSL4Wkru","name":"weight","schema_seq_no":694}},"requested_predicates":{"age_2":{"attr_name":"age","p_type":"GE","issuer_did":"DunkM3x1y7S4ECgSL4Wkru","schema_seq_no":694,"value":18}},"version":"0.1"}"#; pub static REQUESTED_ATTRIBUTES: &str = "requested_attributes"; pub static ATTRS: &str = "attrs"; -pub static PAYMENT_ADDRESS: &str = "pay:sov:2ZrAm5Jc3sP4NAXMQbaWzDxEa12xxJW3VgWjbbPtMPQCoznJyS"; pub static ENTERPRISE_PREFIX: &str = "enterprise"; pub static CONSUMER_PREFIX: &str = "consumer"; pub static DEFAULT_GENERATED_PROOF: &str =r#"{"version":null,"to_did":null,"from_did":"2hoqvcwupRTUNkXn6ArYzs","proof_request_id":null,"libindy_proof":"{\"proof\":{\"proofs\":[{\"primary_proof\":{\"eq_proof\":{\"revealed_attrs\":{\"name\":\"1139481716457488690172217916278103335\"},\"a_prime\":\"53312829942635033213547785663032527700667569977758152702065911726040780590237870482614642520743973046831751397226330629402283915298010755286359042214254186073131293256617522243788869067062459048819049093000861706976559454353054415224217541508251828901230315727452194906707146182038292774837874158123905132204754494099957935893710311307611185556253562731302085643190380093796712150073863236374671766683830116643642814511141387202276677179978778023868191620803031555572096505493695458848336750072872824082946166624025826402185079078955571640643781644608569289737247239944293374495461225509029397867929209294024213709788\",\"e\":\"20682359643412682295831027361890575475838523648741421551903080595188181833333576182907108270431142275883424564833283730774400687766783937\",\"v\":\"977904633616831258258208792044552558313031225274080786369260591379176356693699547546357564320894782538899916819106615861870184406180902549346128003521172715089106402210625380702987862241587585159809860067416270881226844522905301128237139154351788756006744361780087312281145149472912522702788932085436364256473799830420855157934668266924875801216119120004335695991621286240487033787853268010363269151831620402262266602483169804514477708724227545481582471160023611649085383221053639652355027928189779678096568066482567763571624994971564070998443128322674311603044207676915009631014778272133804086604499562982743685276710603982347204200935086324427392193112051934585025409396669790007564450985142207219311632469976008804262561102394462677381575113741321505633197641754405090922962040100369869763363395309722094214098657007292521892941813525965557387184306029245810578685136184682462250087780312322969478679080585625021520210\",\"m\":{\"height\":\"12263289415832681222191231307742005757620106449305717047784670792788875695539753364781375492671454287793766184443302346922042521188980267021306912439837184942463831344267513114539\",\"sex\":\"15037155454094459527731434206481114319240521503794827852070701802307168241949946923083664784355274753205297122386791667526757839001084114446291855325384881755476108903076644102524\",\"age\":\"14501872409940327998412893157081512363089790754079941699437594851467665059803693524100074428544944084570214138897184729758726613071650314480579074556700200366688895565145382360698\"},\"m1\":\"5111614492731222933682238606986742012649186832802695436293583878319992887971581188876806759447594326173957365879113848145931336889892325622590289133581694699335215858805105064331\",\"m2\":\"15455662254366457503819701346580083774039475855758049615942760668169011894662780202836319433863205952152879959998434723106532779215477449781534318996974001599714966396856374581486\"},\"ge_proofs\":[{\"u\":{\"3\":\"13338797419010819430313158414239588911533702998711113636065786974475516880285905693812255129869592972310118234542465190202031458473416955680083762161755097308017613738409014450412\",\"1\":\"799492542075042460468743423224449526404299930570906500607913945716944502802045365895975118206585431769760718077298247129653462146705083199486640323388289350373502832336220747818\",\"2\":\"1410669775663194506029421689725160524313531018451204956432149799559481970811992598634649361849192146578548675891162987371736423348002714852997563863676564228939963027067794874871\",\"0\":\"2284908542447285531642293235205764719596189096401757772990648246811741899742027021760873962759808826767095318153983117478606733551882287443416905369212830402625019520316000619122\"},\"r\":{\"DELTA\":\"446417378686684511234026773355708125239824632634437692777199207510593775769661320517505495782808123901931509966024639039038108997849239457006650910166579521188145804592891114429551884188163168202240716931710467143952184978891694998359503161214624561825833908073711391637139239900433773736886398246516765844798574260038720645282874847988024757269025066849487120769033835284892684827974590847202980928318284802296184879430262352838537995329568347704443032358436401925907006203800781805302411290413797547703643680523816450964907269365740333954767250872005080383786962836349437972233102686007070151913231405673053111357257541070794190346854946155348000938794168313555054935097511280055857357714044575099713604514868026213\",\"0\":\"76323471287537725745058968243946536923132059523832270143088476741530931794292362597818595246023215646685960860543985669003637356653968580726012831272952726648097379707978025827324461370746080302334946615636230982573057929178570795576025377975675772919883441071319109877674255209425751831351871122268677949866093732374914212035903588005718999977836601694274936653297249597377458306018690838897074948900601500608361610629829956778952463888545043329274127468867562886471766759587776471429982222060455628836484851435349858651386947282024263753935919991184370769532443355748040360929886906396781059431869286808165873481291594432375474267943726789479499451113914106577274491433396849021865876595625676087390243000023624762\",\"2\":\"92201512116493836828631529733129001060186027428900226009667207946775663412763049323063566382410298659680809630308918826774715965924345348873964163349957666233303908982512533058477107440041164974471923932525392131507208058972114013554261186876156391013030249940165674350329969469493690172204462521643306554255514954820056300279294082665993982068489632717990288083501332286520044058836966987218446835040483313621165017234567451018319889811119538866717954177080460042489566032046447251130130245574659638664255489998777489482211990568338261294591442065689728409233570738254849320926466856819550224710437157933072455901697612704266158325888789692029073807847963389087595009709947178982240740611685681284283779085698675948\",\"1\":\"523519181672047308247759255710896855210622133048051288689628050530593819825092742868259096958091636388599567602947573803006117544722711419791216490462806808879903445126483144871684220922578271665249669036925968176205614101006831570497324462920653772741371462368258040337051743083703373268865149218215217028092524525773305797542980367455534854526011265982129123432958566815191454606539227183131194637859155089868145241173590901657135733891325388928960829686799252575344385280631185145400972822216509709304106388326226886283646678379038689195399855788521138175316361682508141995206060813895339550522593818086203090245120243475360699742963456947833927949579002835590226242375390852007351288105362306570115755708545985217\",\"3\":\"219708053581575062582533005752631707205208991118487656765616830751022269293827575497929496961405315686245411560943699849420449187007381492241392380392082110189993691561802473698218934318387062653841098498548279928332075909765566959065512235256509146413077084637192127841275265722661868451059419828110871219158575869744195099188903695177096530456644287214222020238239519153912497327047225695946382054980942953751030857203011122068559656187038626791446516654182155158539057712697737764700558352779296500466327830395357680350841458615344128789679867036656697605720376436366435199261670114032178466528256435156834078889201567594491266464345415135571924808730955663963107805898452164603883815760222880803183090122927021906\"},\"mj\":\"14501872409940327998412893157081512363089790754079941699437594851467665059803693524100074428544944084570214138897184729758726613071650314480579074556700200366688895565145382360698\",\"alpha\":\"31918703918424605421867306637529380827987785788405050672774138736166394193904621089524533944750195114129096119755051526846725254763824200066138161138712728191811663989790595399577931777057069644826760716174215502760332823087353208209062750316348096800751400775616367613846591019341998518739176827591884828803457769836022658736894307470228021107390985355341006358063783380352553203686844117554456841862664698030419319060016855160424705460267488204254799487731578966486350864297692169864269632174633849489841974267276169865234681524317353667399250655802076478193790198931703997043279311660619853321692326370677880789301081973803355206050854006163585246822795898668673143707227426024087230394272183289129116861001488380021845460347354339123316270676159384403687413396981497957623652714825893844224460981469334265786569340866948245386177786943\",\"t\":{\"3\":\"37972928040287019966279705290077177120438916881166595729433656845236894764203450825352358745872530678723193673168699261559252347206134931851900792354929811701409594264464224953419079438712468720585420884977482943060379064169436974390111782700278522811285372914014699402037920450145036232607643190702877276047529693903313274481563898145881289947298191322165264501424360596211660104692237473307294793997549168958412186734308994849480325136098603164600244189033368937216041232700684717195143448897309921696037996821682161245633099514032672108362471847287780767536527922125290354007208461534506680429079325673303847122602\",\"1\":\"83797923111124698337190350740625419461331674597317499285711196059201116233696351462219655473974285728417042636321002662540084865059877415988492658002455681892357965734412778441359694363956150504207034364774632269626588616820867786845681629308573877664225545768569004728653608256309649757797799701694734953511407991945606233015704498351349679028096727127592824167470239121617521236284944552022042989195045796550206930535014890946963714532865413773302556921033807408941052143462861253036857235374142831681609638723266113292539696031604138697651663589237083275182589077537865812203675363931276014854720987778657614102744\",\"0\":\"2650503753268559234325045605088774291426714447530920032686699660331132818418294401386458113929015669970054987046869952559938250072323202428595050264148451597342024999195988956825995585576913035057727067574585765007573631661190106325951562647973999556307904156602972256772368626124956359113948479337998473700163736913949914618468786982078961864054155716098967233493298331429094961852050251480937244097084480079338650069474343849653498204836647208425673909949338344039864962930360099888379112227879147124479674454219360564016333692287612795255249839516579685644216601710763951730704414780889479757764771824686121135664\",\"DELTA\":\"43065835375665819440999515421835663370003698766999136081645804528693116242835242268976886541500885372919193595521649742583847412078937558594134652898329531345474973694469474048143077702226876323148384500134900126983776005048815938010984852671864994349715180582574635986767847143457191095540293933564404627275951176669589446874803422805492459886354589921566504955505072907201600897292446445273226759645152347760045030326954742075710148481072174908814490535664213161063279049745367193309329034076163035585786466248661857406761347994603442904391759603262653605643737187511663278904722133109597876198342257959851721834192\",\"2\":\"46628952298959333080121710882308601694841107884016671262481120139852326078270985558474211468413535251365897343039473985423394663439915886543709585947919510897780945029279321912919654098202591041333546305345226891491934752585644557915489535154254673543901496062795297123823959517190269228530111782605034098586928917098782686018936730269712739545898008102022872832813918298315656085362237855944363927676075909182683069003791720095898011148294690599783422365311217737781228088563580874619330671307258995382310169708388804474101048348557353152301570472790186309273164115806835950131701314455074661797762932617450697701058\"},\"predicate\":{\"attr_name\":\"age\",\"p_type\":\"GE\",\"value\":18}}]},\"non_revoc_proof\":null}],\"aggregated_proof\":{\"c_hash\":\"15107591148123921137146194357185316416658106446533633516768364316943089580042\",\"c_list\":[[1,166,81,167,129,168,9,195,206,209,106,181,150,16,195,117,63,177,44,215,8,36,96,16,191,201,123,173,242,90,252,147,29,164,230,22,148,201,70,219,1,174,68,212,172,20,247,106,239,96,84,62,213,205,22,27,56,32,13,87,86,154,47,87,223,133,48,103,181,173,8,101,1,63,95,172,109,254,160,238,44,184,16,143,59,38,30,170,49,125,197,221,222,54,58,210,252,137,145,70,99,142,233,158,162,174,6,107,31,14,50,111,244,137,122,2,16,218,2,88,200,72,40,141,139,188,43,48,237,245,169,162,89,112,81,0,23,46,191,152,221,93,125,105,238,1,222,157,68,61,23,189,7,113,162,61,230,172,143,8,157,13,229,221,214,79,84,246,75,156,240,76,124,93,39,30,167,122,175,246,117,105,6,203,207,87,217,40,215,20,209,188,175,6,250,31,13,64,1,250,64,154,232,64,46,84,7,180,121,52,1,230,122,30,98,146,220,6,168,19,57,78,77,114,84,96,48,162,54,35,30,141,186,163,99,185,123,24,217,139,218,227,141,236,105,160,241,83,201,152,66,98,37,253,162,195,220],[20,254,252,22,231,75,18,170,179,109,220,230,27,219,149,32,214,209,149,133,50,88,217,78,5,96,145,131,250,159,61,108,65,219,94,75,52,84,251,169,192,84,135,58,131,26,36,149,27,224,106,61,5,194,196,247,53,71,217,115,115,132,215,240,231,19,131,106,252,9,88,66,237,19,105,221,127,177,250,4,127,23,167,68,255,182,234,55,202,199,159,66,1,181,22,40,112,144,219,78,251,172,8,193,139,175,3,160,6,255,76,232,215,67,157,239,13,179,173,174,158,120,7,226,48,99,36,129,146,85,194,64,86,26,242,248,192,182,225,193,10,146,113,249,183,64,189,101,69,118,249,46,155,206,85,150,245,66,4,163,212,168,222,76,136,56,135,229,188,125,178,188,21,65,44,234,5,180,140,65,53,166,191,2,189,207,73,50,129,191,82,166,60,187,79,211,63,56,226,25,192,0,128,192,7,238,189,90,86,104,27,109,27,29,173,79,147,84,233,75,239,245,26,179,148,50,134,109,223,59,184,98,107,186,187,38,86,156,133,144,251,188,199,72,236,181,121,83,42,40,1,194,57,1referent76,174,48],[2,151,206,178,220,199,113,118,112,154,103,78,56,113,141,74,10,56,152,93,116,185,146,211,42,2,254,129,120,167,193,111,62,83,136,100,137,60,10,89,85,123,222,79,208,55,202,115,234,43,194,248,210,138,193,144,157,71,101,81,43,33,151,141,55,92,42,114,29,192,189,151,220,131,246,173,109,195,249,125,111,169,33,225,48,222,212,173,45,212,122,65,211,165,171,31,71,92,245,126,6,243,245,205,125,66,2,239,248,10,205,128,15,81,8,193,131,142,211,152,239,47,107,132,165,148,143,146,109,223,120,238,31,28,96,25,152,215,85,135,253,233,19,199,201,99,222,166,79,176,71,41,161,134,175,119,139,9,131,186,181,136,113,138,35,98,110,117,210,238,230,61,190,149,39,225,67,42,138,77,55,246,7,180,41,3,148,146,45,43,130,135,63,53,167,185,242,80,38,15,91,238,13,13,137,124,14,101,150,253,50,47,111,240,104,207,75,127,150,104,108,182,19,6,169,100,100,105,166,122,36,46,179,102,27,75,48,112,36,177,20,50,78,71,60,230,152,74,140,24,66,110,61,196,205,0,216],[1,113,95,89,11,69,152,90,18,216,24,156,66,191,203,117,10,208,99,133,64,42,122,96,194,177,70,138,177,159,33,124,184,183,112,154,58,220,182,81,86,131,189,209,35,124,193,235,128,126,150,198,178,115,184,184,89,33,230,170,166,53,172,221,81,116,196,199,189,160,225,117,248,102,119,136,37,32,43,148,254,173,142,37,231,160,178,147,86,97,179,23,221,199,203,111,144,203,88,58,97,177,251,142,27,254,184,79,127,115,255,220,135,230,244,226,64,155,177,99,31,101,29,137,82,138,130,206,27,214,44,60,123,165,240,93,120,221,175,197,86,209,165,169,126,120,26,87,208,76,147,245,97,146,19,50,122,150,78,122,91,204,43,5,23,165,87,194,156,233,181,194,113,30,41,54,92,56,202,89,193,221,92,170,106,198,86,216,186,29,219,42,25,137,16,252,163,121,104,91,212,8,170,94,57,112,229,235,175,87,146,38,240,143,85,184,221,112,75,2,53,218,71,201,169,19,15,46,154,229,187,41,236,202,20,134,202,154,42,180,167,70,211,31,104,123,255,81,25,51,59,169,127,48,242,182,194],[1,44,205,180,74,73,89,226,22,38,162,169,161,207,183,58,59,73,38,49,235,171,190,130,141,255,139,247,73,23,181,130,100,78,170,42,180,180,45,149,34,47,199,128,32,65,11,41,49,64,154,228,143,180,162,242,111,153,39,240,72,135,156,80,213,119,51,221,200,46,160,251,0,163,1,97,198,190,173,148,231,6,208,5,246,176,236,50,17,251,251,81,211,98,220,156,137,242,110,4,8,33,150,228,60,165,152,86,166,222,198,166,146,84,61,113,100,61,2,172,74,34,220,127,233,119,206,92,107,53,40,124,206,56,181,238,154,45,96,171,219,46,160,7,6,255,55,169,116,170,143,35,128,238,84,206,13,224,149,97,238,195,108,47,67,253,195,103,194,155,52,231,91,57,6,25,123,45,11,68,23,174,108,40,165,39,63,239,46,121,234,1,242,182,75,83,79,218,251,173,227,193,171,30,87,95,28,175,175,134,236,66,29,119,76,224,84,77,215,29,188,12,201,226,22,244,149,30,177,159,181,23,30,77,112,46,180,160,56,93,124,20,39,232,119,38,198,7,235,207,38,197,229,102,158,182,170],[1,85,37,170,71,223,136,209,189,66,85,250,129,32,243,62,118,211,168,5,95,28,44,129,250,185,203,123,147,53,34,245,167,28,169,147,180,42,39,199,220,155,138,79,217,252,145,154,78,61,97,190,121,5,5,87,56,143,166,135,18,135,29,111,74,191,222,74,116,60,88,247,15,151,227,200,233,63,44,167,9,246,72,200,252,80,110,164,15,57,19,45,39,68,207,127,14,192,3,136,233,85,232,79,153,99,57,216,152,158,94,234,76,181,45,199,42,44,54,6,79,78,146,215,194,112,170,95,176,204,167,3,17,51,160,197,17,237,1,125,221,51,229,207,109,211,223,229,5,154,78,163,233,34,93,197,219,178,92,191,229,13,158,203,37,53,197,96,40,159,61,106,74,52,190,14,75,180,8,202,247,84,198,150,104,141,88,55,136,191,17,190,57,210,96,41,44,179,169,57,236,176,30,190,52,97,165,53,51,0,134,82,86,64,115,138,89,11,192,250,161,160,44,94,35,156,249,51,100,246,78,70,48,24,226,63,67,221,216,230,65,28,149,59,77,197,172,189,208,6,195,219,101,83,137,62,208]]}},\"requested_proof\":{\"revealed_attrs\":{\"attr1_referent\":{\"sub_proof_index\":0,\"raw\":\"Alex\",\"encoded\":\"1139481716457488690172217916278103335\"}},\"self_attested_attrs\":{\"attr3_referent\":\"8-800-300\"},\"unrevealed_attrs\":{\"attr2_referent\":{\"sub_proof_index\":0}},\"predicates\":{\"predicate1_referent\":{\"sub_proof_index\":0}}},\"identifiers\":[{\"schema_id\":\"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0\",\"cred_def_id\":\"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0\",\"rev_reg_id\":null,\"timestamp\":null}]}"}"#; + +pub static REV_REG_ID: &str = r#"V4SGRU86Z58d6TV7PBUe6f:4:V4SGRU86Z58d6TV7PBUe6f:3:CL:529:tag1:CL_ACCUM:tag1"#; +pub static REV_REG_DELTA_JSON: &str = r#"{"ver":"1.0","value":{"accum":"2 0A0752AD393CCA8E840459E79BCF48F16ECEF17C00E9B639AC6CE2CCC93954C9 2 242D07E4AE3284C1E499D98E4EDF65ACFC0392E64C2BFF55192AC3AE51C3657C 2 165A2D44CAEE9717F1F52CC1BA6F72F39B21F969B3C4CDCA4FB501880F7AD297 2 1B08C9BB4876353F70E4A639F3B41593488B9964D4A56B61B0E1FF8B0FB0A1E7 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000"}}"#; +pub static REV_STATE_JSON: &str = r#"{"V4SGRU86Z58d6TV7PBUe6f:4:V4SGRU86Z58d6TV7PBUe6f:3:CL:744:tag1:CL_ACCUM:tag1":{"1540930249":{"rev_reg":{"accum":"1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000"},"timestamp":100,"witness":{"omega":"1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000"}}}}"#; +pub static REV_REG_JSON: &str = r#"{"ver":"1.0","value":{"accum":"2 0204F2D2B1F2B705A11AAFEEE73C9BA084C12AF1179294529AC4D14CA54E87F3 2 222BAE38FAF2673F7BCBB86D8DE1A327F5065BDC892E9A122164260C97BC0C63 2 1565105F8BA53037978B66E0CC9F53205F189DEEB6B7168744456DD98D2F4E88 2 1AC9E76B2868141A42329778831C14AEAAF7A9981209C1D96AECA4E69CAFB243 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000"}}"#; +pub static TEST_TAILS_FILE: &str = r#"tails_file"#; + +pub fn rev_def_json() -> String { + use utils::get_temp_dir_path; + json!({ + "ver":"1.0", + "id":"V4SGRU86Z58d6TV7PBUe6f:4:V4SGRU86Z58d6TV7PBUe6f:3:CL:1281:tag1:CL_ACCUM:tag1", + "revocDefType":"CL_ACCUM", + "tag":"tag1", + "credDefId":"V4SGRU86Z58d6TV7PBUe6f:3:CL:1281:tag1", + "value": { + "issuanceType":"ISSUANCE_BY_DEFAULT", + "maxCredNum":10, + "publicKeys": { + "accumKey": { + "z":"4EEB81EBC1FB3E 3D4A7A37B1E6B6 74EE2AEDD94E01 DBAF48D6C2560D 8DBAE37 12DDBAF1B64865 88EDCC2CA57586 10A63A1B47062 54F1F6CEB62EE1 7BBF71 3DE19DA0A8BDB9 DEBDFC534EB8EE 7100F5CF19FEC6 C2D95361A47D7A EDF360 C0C73CDC7C2A19 6DF58C6F098045 CE978219DA72A6 D18AFF556D033A 1F5331A3 497CF9F01A75EB 8B43A9AA2E4B48 5E34FC3A0E218C F4F3A5DAB4C8CD 822F2AC 5537016664C283 29D5F5B2C8D424 31F4D38DEE687D AF3B03B616AE18 A52290D EEE75E47A6F2B4 285A5AAE75EEDF C0CF755C919E5C 93F6ADDE8DBA43 17334552 3FCAFFD73DE1F2 352ECA977634C7 123A365522D7FE 29C0BAA04D1AF4 4AE896E 634639B1B19BCE BEA74B95A4373B 363460F3D9F6BD 74A059EB706EC0 16AA945A 28B24767B63877 3A8351540E9A64 A91F3D98AFFA8C B4640E5879F3C3 C47B6A0 8C68AF26ACCBFC 6506DBB7E800D7 14CA12191E8826 AB44737CCEB207 130C7388 F812A0CC911FB9 10E907A7C81BD5 31BDBC9420AE03 672B6E5BDBAB2B 19CE4AF0" + } + }, + "tailsHash":"5R6BWXL3vPrbJPKe9FsHAVG9hqKdDvVxonBuj3ETYuZh", + "tailsLocation": get_temp_dir_path(Some("tails_file/5R6BWXL3vPrbJPKe9FsHAVG9hqKdDvVxonBuj3ETYuZh")).to_str().unwrap().to_string() + } + }).to_string() +} \ No newline at end of file diff --git a/vcx/libvcx/src/utils/cstring.rs b/vcx/libvcx/src/utils/cstring.rs index 37309506..558515eb 100644 --- a/vcx/libvcx/src/utils/cstring.rs +++ b/vcx/libvcx/src/utils/cstring.rs @@ -21,7 +21,18 @@ impl CStringUtils { } } } + pub fn c_str_to_str<'a>(cstr: *const c_char) -> Result, Utf8Error> { + if cstr.is_null() { + return Ok(None); + } + unsafe { + match CStr::from_ptr(cstr).to_str() { + Ok(s) => Ok(Some(s)), + Err(err) => Err(err) + } + } + } pub fn string_to_cstring(s: String) -> CString { CString::new(s).unwrap() } diff --git a/vcx/libvcx/src/utils/devsetup.rs b/vcx/libvcx/src/utils/devsetup.rs index 9399a4d6..76055c4a 100644 --- a/vcx/libvcx/src/utils/devsetup.rs +++ b/vcx/libvcx/src/utils/devsetup.rs @@ -2,37 +2,37 @@ macro_rules! init { ($x:expr) => ( ::utils::threadpool::init(); - ::settings::set_config_value(::settings::CONFIG_WALLET_KEY,::settings::DEFAULT_WALLET_KEY); - ::settings::set_config_value(::settings::CONFIG_ENABLE_TEST_MODE,"false"); - ::utils::libindy::wallet::tests::delete_test_wallet(::settings::DEFAULT_WALLET_NAME); ::settings::clear_config(); ::settings::set_config_value(::settings::CONFIG_WALLET_KEY,::settings::DEFAULT_WALLET_KEY); + ::settings::set_config_value(::settings::CONFIG_WALLET_KEY_DERIVATION,::settings::DEFAULT_WALLET_KEY_DERIVATION); + ::utils::libindy::wallet::tests::delete_test_wallet(::settings::DEFAULT_WALLET_NAME); match $x { "true" => { ::settings::set_defaults(); ::settings::set_config_value(::settings::CONFIG_ENABLE_TEST_MODE,"true"); - ::utils::libindy::wallet::init_wallet(::settings::DEFAULT_WALLET_NAME).unwrap(); + ::utils::libindy::wallet::init_wallet(::settings::DEFAULT_WALLET_NAME, None).unwrap(); }, "false" => { ::settings::set_defaults(); ::settings::set_config_value(::settings::CONFIG_ENABLE_TEST_MODE,"false"); - ::utils::libindy::wallet::init_wallet(::settings::DEFAULT_WALLET_NAME).unwrap(); + ::utils::libindy::wallet::init_wallet(::settings::DEFAULT_WALLET_NAME, None).unwrap(); }, "indy" => { ::settings::set_defaults(); ::settings::set_config_value(::settings::CONFIG_ENABLE_TEST_MODE,"indy"); - ::utils::libindy::wallet::init_wallet(::settings::DEFAULT_WALLET_NAME).unwrap(); + ::utils::libindy::wallet::init_wallet(::settings::DEFAULT_WALLET_NAME, None).unwrap(); }, "ledger" => { ::settings::set_config_value(::settings::CONFIG_ENABLE_TEST_MODE,"false"); + ::utils::devsetup::tests::init_plugin(::settings::DEFAULT_PAYMENT_PLUGIN, ::settings::DEFAULT_PAYMENT_INIT_FUNCTION); ::utils::devsetup::tests::setup_ledger_env(); }, "agency" => { ::utils::libindy::wallet::tests::delete_test_wallet(&format!("{}_{}", ::utils::constants::ENTERPRISE_PREFIX, ::settings::DEFAULT_WALLET_NAME)); ::utils::libindy::wallet::tests::delete_test_wallet(&format!("{}_{}", ::utils::constants::CONSUMER_PREFIX, ::settings::DEFAULT_WALLET_NAME)); ::utils::libindy::pool::tests::delete_test_pool(); - ::settings::set_config_value(::settings::CONFIG_ENABLE_TEST_MODE,"false"); + ::utils::devsetup::tests::init_plugin(::settings::DEFAULT_PAYMENT_PLUGIN, ::settings::DEFAULT_PAYMENT_INIT_FUNCTION); ::utils::devsetup::tests::setup_local_env(); }, _ => {panic!("Invalid test mode");}, @@ -57,16 +57,23 @@ macro_rules! teardown { #[cfg(test)] pub mod tests { + extern crate rand; extern crate serde_json; + extern crate libloading; + extern crate libc; use utils::constants; use utils::libindy::wallet; use utils::libindy::pool; use settings; + use std; + use utils; use object_cache::ObjectCache; - static mut INSTITUTION_CONFIG: u32 = 0; static mut CONSUMER_CONFIG: u32 = 0; + use indy::ErrorCode; + + static INIT_PLUGIN: std::sync::Once = std::sync::ONCE_INIT; lazy_static! { static ref CONFIG_STRING: ObjectCache = Default::default(); @@ -76,27 +83,84 @@ pub mod tests { /* dev */ /* - pub const AGENCY_ENDPOINT: &'static str = "https://enym-eagency.pdev.evernym.com"; + pub const AGENCY_ENDPOINT: &'static str = "http://int-eas.pdev.evernym.com"; pub const AGENCY_DID: &'static str = "YRuVCckY6vfZfX9kcQZe3u"; pub const AGENCY_VERKEY: &'static str = "J8Yct6FwmarXjrE2khZesUXRVVSVczSoa9sFaGe6AD2v"; - pub const C_AGENCY_ENDPOINT: &'static str = "https://cagency.pdev.evernym.com"; + pub const C_AGENCY_ENDPOINT: &'static str = "http://int-agency.pdev.evernym.com"; pub const C_AGENCY_DID: &'static str = "dTLdJqRZLwMuWSogcKfBT"; pub const C_AGENCY_VERKEY: &'static str = "LsPQTDHi294TexkFmZK9Q9vW4YGtQRuLV8wuyZi94yH"; */ /* sandbox */ - pub const AGENCY_ENDPOINT: &'static str = "http://sbx-eas.pdev.evernym.com"; + /*pub const AGENCY_ENDPOINT: &'static str = "http://sbx-eas.pdev.evernym.com"; pub const AGENCY_DID: &'static str = "HB7qFQyFxx4ptjKqioEtd8"; pub const AGENCY_VERKEY: &'static str = "9pJkfHyfJMZjUjS7EZ2q2HX55CbFQPKpQ9eTjSAUMLU8"; pub const C_AGENCY_ENDPOINT: &'static str = "http://sbx-agency.pdev.evernym.com"; pub const C_AGENCY_DID: &'static str = "Nv9oqGX57gy15kPSJzo2i4"; - pub const C_AGENCY_VERKEY: &'static str = "CwpcjCc6MtVNdQgwoonNMFoR6dhzmRXHHaUCRSrjh8gj"; + pub const C_AGENCY_VERKEY: &'static str = "CwpcjCc6MtVNdQgwoonNMFoR6dhzmRXHHaUCRSrjh8gj";*/ + + /* dummy */ + pub const AGENCY_ENDPOINT: &'static str = "http://localhost:8080"; + pub const AGENCY_DID: &'static str = "VsKV7grR1BUE29mG2Fm2kX"; + pub const AGENCY_VERKEY: &'static str = "Hezce2UWMZ3wUhVkh2LfKSs8nDzWwzs2Win7EzNN3YaR"; + + pub const C_AGENCY_ENDPOINT: &'static str = "http://localhost:8080"; + pub const C_AGENCY_DID: &'static str = "VsKV7grR1BUE29mG2Fm2kX"; + pub const C_AGENCY_VERKEY: &'static str = "Hezce2UWMZ3wUhVkh2LfKSs8nDzWwzs2Win7EzNN3YaR"; pub fn set_trustee_did() { - let (my_did, _) = ::utils::libindy::signus::create_and_store_my_did(Some(TRUSTEE)).unwrap(); - let did = settings::set_config_value(settings::CONFIG_INSTITUTION_DID, &my_did); + let (my_did, my_vk) = ::utils::libindy::signus::create_and_store_my_did(Some(TRUSTEE)).unwrap(); + settings::set_config_value(settings::CONFIG_INSTITUTION_DID, &my_did); + settings::set_config_value(settings::CONFIG_INSTITUTION_VERKEY, &my_vk); + } + + pub fn create_new_seed() -> String { + + let x = rand::random::(); + format!("{:032}", x) + } + + pub fn init_plugin(library: &str, initializer: &str) { + settings::set_config_value(settings::CONFIG_PAYMENT_METHOD, settings::DEFAULT_PAYMENT_METHOD); + + INIT_PLUGIN.call_once(|| { + if let Ok(lib) = _load_lib(library) { + unsafe { + if let Ok(init_func) = lib.get(initializer.as_bytes()) { + let init_func: libloading::Symbol ErrorCode> = init_func; + + match init_func() { + ErrorCode::Success => { + debug!("Plugin has been loaded: {:?}", library); + }, + _ => { + error!("Plugin has not been loaded: {:?}", library); + std::process::exit(123); + } + } + } else { + error!("Init function not found: {:?}", initializer); + std::process::exit(123); + } + } + } else { + error!("Plugin not found: {:?}", library); + std::process::exit(123); + } + }); + } + + #[cfg(all(unix, test))] + fn _load_lib(library: &str) -> libloading::Result { + libloading::os::unix::Library::open(Some(library), libc::RTLD_NOW | libc::RTLD_NODELETE) + .map(libloading::Library::from) + } + + #[cfg(any(not(unix), not(test)))] + fn _load_lib(library: &str) -> libloading::Result { + libloading::Library::new(library) } pub fn setup_ledger_env() { @@ -109,14 +173,19 @@ pub mod tests { settings::set_defaults(); settings::set_config_value(settings::CONFIG_WALLET_KEY,settings::DEFAULT_WALLET_KEY); + settings::set_config_value(settings::CONFIG_WALLET_KEY_DERIVATION,settings::DEFAULT_WALLET_KEY_DERIVATION); settings::set_config_value(settings::CONFIG_WALLET_NAME, settings::DEFAULT_WALLET_NAME); settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "false"); - settings::set_config_value(settings::CONFIG_GENESIS_PATH, settings::DEFAULT_GENESIS_PATH); + settings::set_config_value(settings::CONFIG_GENESIS_PATH, + utils::get_temp_dir_path(Some(settings::DEFAULT_GENESIS_PATH)).to_str().unwrap_or("")); + pool::tests::open_sandbox_pool(); - wallet::init_wallet(settings::DEFAULT_WALLET_NAME).unwrap(); + wallet::init_wallet(settings::DEFAULT_WALLET_NAME, None).unwrap(); + ::utils::libindy::anoncreds::libindy_prover_create_master_secret(settings::DEFAULT_LINK_SECRET_ALIAS).unwrap(); set_trustee_did(); + ::utils::libindy::payments::tests::token_setup(None, None); } @@ -154,51 +223,76 @@ pub mod tests { } pub fn setup_local_env() { + use indy::ledger; + use futures::Future; + settings::clear_config(); settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "false"); settings::set_config_value(settings::CONFIG_WALLET_KEY, settings::DEFAULT_WALLET_KEY); - + settings::set_config_value(settings::CONFIG_WALLET_KEY_DERIVATION, settings::DEFAULT_WALLET_KEY_DERIVATION); let enterprise_wallet_name = format!("{}_{}", constants::ENTERPRISE_PREFIX, settings::DEFAULT_WALLET_NAME); + let seed1 = create_new_seed(); let config = json!({ "agency_url": AGENCY_ENDPOINT.to_string(), "agency_did": AGENCY_DID.to_string(), "agency_verkey": AGENCY_VERKEY.to_string(), "wallet_name": enterprise_wallet_name, "wallet_key": settings::DEFAULT_WALLET_KEY.to_string(), - "enterprise_seed": TRUSTEE.to_string(), + "wallet_key_derivation": settings::DEFAULT_WALLET_KEY_DERIVATION, + "enterprise_seed": seed1, + "agent_seed": seed1, "name": "institution".to_string(), "logo": "http://www.logo.com".to_string(), - "path": constants::GENESIS_PATH.to_string() + "path": constants::GENESIS_PATH.to_string(), }).to_string(); let enterprise_config = ::messages::agent_utils::connect_register_provision(&config).unwrap(); ::api::vcx::vcx_shutdown(false); let consumer_wallet_name = format!("{}_{}", constants::CONSUMER_PREFIX, settings::DEFAULT_WALLET_NAME); + let seed2 = create_new_seed(); let config = json!({ "agency_url": C_AGENCY_ENDPOINT.to_string(), "agency_did": C_AGENCY_DID.to_string(), "agency_verkey": C_AGENCY_VERKEY.to_string(), "wallet_name": consumer_wallet_name, "wallet_key": settings::DEFAULT_WALLET_KEY.to_string(), - "enterprise_seed": TRUSTEE.to_string(), + "wallet_key_derivation": settings::DEFAULT_WALLET_KEY_DERIVATION.to_string(), + "enterprise_seed": seed2, + "agent_seed": seed2, "name": "consumer".to_string(), "logo": "http://www.logo.com".to_string(), - "path": constants::GENESIS_PATH.to_string() + "path": constants::GENESIS_PATH.to_string(), }).to_string(); let consumer_config = ::messages::agent_utils::connect_register_provision(&config).unwrap(); - unsafe { INSTITUTION_CONFIG = CONFIG_STRING.add(_config_with_wallet_handle(&enterprise_wallet_name, &enterprise_config)).unwrap(); } - unsafe { CONSUMER_CONFIG = CONFIG_STRING.add(_config_with_wallet_handle(&consumer_wallet_name, &consumer_config)).unwrap(); } - pool::tests::open_sandbox_pool(); + // grab the generated did and vk from the consumer and enterprise + set_consumer(); + let did2 = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + let vk2 = settings::get_config_value(settings::CONFIG_INSTITUTION_VERKEY).unwrap(); + set_institution(); + let did1 = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + let vk1 = settings::get_config_value(settings::CONFIG_INSTITUTION_VERKEY).unwrap(); + settings::clear_config(); + + // make enterprise and consumer trustees on the ledger + wallet::init_wallet(settings::DEFAULT_WALLET_NAME, None).unwrap(); + let (trustee_did, _) = ::utils::libindy::signus::create_and_store_my_did(Some(TRUSTEE)).unwrap(); + let req_nym = ledger::build_nym_request(&trustee_did, &did1, Some(&vk1), None, Some("TRUSTEE")).wait().unwrap(); + ::utils::libindy::ledger::libindy_sign_and_submit_request(&trustee_did, &req_nym).unwrap(); + let req_nym = ledger::build_nym_request(&trustee_did, &did2, Some(&vk2), None, Some("TRUSTEE")).wait().unwrap(); + ::utils::libindy::ledger::libindy_sign_and_submit_request(&trustee_did, &req_nym).unwrap(); + wallet::delete_wallet(settings::DEFAULT_WALLET_NAME, None).unwrap(); + + // as trustees, mint tokens into each wallet set_consumer(); ::utils::libindy::payments::tests::token_setup(None, None); @@ -207,7 +301,7 @@ pub mod tests { } fn _config_with_wallet_handle(wallet_n: &str, config: &str) -> String { - let wallet_handle = wallet::open_wallet(wallet_n).unwrap(); + let wallet_handle = wallet::open_wallet(wallet_n, None).unwrap(); let mut config: serde_json::Value = serde_json::from_str(config).unwrap(); config[settings::CONFIG_WALLET_HANDLE] = json!(wallet_handle.to_string()); config.to_string() @@ -217,19 +311,19 @@ pub mod tests { #[test] fn test_local_env() { init!("ledger"); - ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS); + ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, false); } pub fn setup_wallet_env(test_name: &str) -> Result { use utils::libindy::wallet::init_wallet; settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE,"false"); - init_wallet(test_name).map_err(|e| format!("Unable to init_wallet in tests: {}", e)) + init_wallet(test_name, None).map_err(|e| format!("Unable to init_wallet in tests: {}", e)) } pub fn cleanup_wallet_env(test_name: &str) -> Result<(), String> { use utils::libindy::wallet::delete_wallet; println!("Deleting Wallet"); - delete_wallet(test_name).or(Err(format!("Unable to delete wallet: {}", test_name))) + delete_wallet(test_name, None).or(Err(format!("Unable to delete wallet: {}", test_name))) } #[cfg(feature = "agency")] @@ -272,12 +366,12 @@ pub mod tests { //wallet::open_wallet(wallet_name).unwrap(); set_institution(); - let alice = build_connection("alice").unwrap(); + let alice = create_connection("alice").unwrap(); connect(alice, Some("{}".to_string())).unwrap(); let details = get_invite_details(alice, false).unwrap(); //BE CONSUMER AND ACCEPT INVITE FROM INSTITUTION ::utils::devsetup::tests::set_consumer(); - let faber = build_connection_with_invite("faber", &details).unwrap(); + let faber = create_connection_with_invite("faber", &details).unwrap(); assert_eq!(VcxStateType::VcxStateRequestReceived as u32, get_state(faber)); connect(faber, Some("{}".to_string())).unwrap(); //BE INSTITUTION AND CHECK THAT INVITE WAS ACCEPTED diff --git a/vcx/libvcx/src/utils/error.rs b/vcx/libvcx/src/utils/error.rs index 5dc69a65..859c159b 100644 --- a/vcx/libvcx/src/utils/error.rs +++ b/vcx/libvcx/src/utils/error.rs @@ -98,6 +98,15 @@ pub static DID_ALREADY_EXISTS_IN_WALLET: Error = Error { code_num: 1083, message pub static DUPLICATE_MASTER_SECRET: Error = Error { code_num: 1084, message: "Attempted to add a Master Secret that already existed in wallet"}; pub static THREAD_ERROR: Error = Error{ code_num: 1085, message: "Unable to create thread"}; pub static INVALID_PROOF_REQUEST: Error = Error{ code_num: 1086, message: "Proof Request Passed into Libindy Call Was Invalid"}; +pub static MISSING_PAYMENT_METHOD: Error = Error{ code_num: 1087, message: "Configuration is missing the Payment Method parameter"}; +pub static DUPLICATE_SCHEMA: Error = Error{ code_num: 1088, message: "Duplicate Schema: Ledger Already Contains Schema For Given DID, Version, and Name Combination"}; +pub static UKNOWN_LIBINDY_TRANSACTION_REJECTION: Error = Error{ code_num: 1089, message: "Unknown Libindy Rejection"}; +pub static LOGGING_ERROR: Error = Error{ code_num: 1090, message: "Logging Error" }; +pub static INVALID_REVOCATION_DETAILS: Error = Error{ code_num: 1091, message: "Invalid Revocation Details"}; +pub static INVALID_REV_ENTRY: Error = Error{ code_num: 1092, message: "Unable to Update Revocation Delta On Ledger"}; +pub static INVALID_REVOCATION_TIMESTAMP: Error = Error{ code_num: 1093, message: "Invalid Credential Revocation timestamp"}; +pub static UNKNOWN_SCHEMA_REJECTION: Error = Error{ code_num: 1094, message: "Unknown Rejection of Schema Creation, refer to libindy documentation"}; +pub static INVALID_REV_REG_DEF_CREATION: Error = Error{ code_num: 1095, message: "Failed to create Revocation Registration Definition"}; lazy_static! { static ref ERROR_C_MESSAGES: HashMap = { @@ -189,6 +198,16 @@ lazy_static! { insert_c_message(&mut m, &INVALID_LEDGER_RESPONSE); insert_c_message(&mut m, &THREAD_ERROR); insert_c_message(&mut m, &INVALID_PROOF_REQUEST); + insert_c_message(&mut m, &INVALID_REVOCATION_DETAILS); + insert_c_message(&mut m, &INVALID_REV_REG_DEF_CREATION); + insert_c_message(&mut m, &INVALID_REVOCATION_TIMESTAMP); + insert_c_message(&mut m, &INVALID_REV_ENTRY); + insert_c_message(&mut m, &DUPLICATE_SCHEMA); + insert_c_message(&mut m, &UNKNOWN_SCHEMA_REJECTION); + insert_c_message(&mut m, &UKNOWN_LIBINDY_TRANSACTION_REJECTION); + insert_c_message(&mut m, &MISSING_PAYMENT_METHOD); + insert_c_message(&mut m, &LOGGING_ERROR); + m }; } diff --git a/vcx/libvcx/src/utils/httpclient.rs b/vcx/libvcx/src/utils/httpclient.rs index fd0b84ed..fc6d7ae7 100644 --- a/vcx/libvcx/src/utils/httpclient.rs +++ b/vcx/libvcx/src/utils/httpclient.rs @@ -2,7 +2,7 @@ use settings; use std::io::Read; use std::sync::Mutex; use reqwest; -use reqwest::header::{ContentType}; +use reqwest::header::{CONTENT_TYPE}; use std::env; lazy_static!{ static ref NEXT_U8_RESPONSE: Mutex>> = Mutex::new(vec![]); @@ -10,9 +10,9 @@ lazy_static!{ //Todo: change this RC to a u32 pub fn post_u8(body_content: &Vec) -> Result,String> { - let url = format!("{}/agency/msg", settings::get_config_value(settings::CONFIG_AGENCY_ENDPOINT).or(Err("Invalid Configuration".to_string()))?); + if settings::test_agency_mode_enabled() {return Ok(NEXT_U8_RESPONSE.lock().unwrap().pop().unwrap_or(Vec::new()));} //Setting SSL Certs location. This is needed on android platform. Or openssl will fail to verify the certs if cfg!(target_os = "android") { info!("::Android code"); @@ -20,8 +20,7 @@ pub fn post_u8(body_content: &Vec) -> Result,String> { } let client = reqwest::ClientBuilder::new().build().or(Err("Preparing Post failed".to_string()))?; debug!("Posting encrypted bundle to: \"{}\"", url); - if settings::test_agency_mode_enabled() {return Ok(NEXT_U8_RESPONSE.lock().unwrap().pop().unwrap_or(Vec::new()));} - let mut response = match client.post(&url).body(body_content.to_owned()).header(ContentType::octet_stream()).send() { + let mut response = match client.post(&url).body(body_content.to_owned()).header(CONTENT_TYPE, "octet_stream").send() { Ok(result) => { trace!("got the result"); result diff --git a/vcx/libvcx/src/utils/libindy/anoncreds.rs b/vcx/libvcx/src/utils/libindy/anoncreds.rs index 87cdf0be..6b84f498 100644 --- a/vcx/libvcx/src/utils/libindy/anoncreds.rs +++ b/vcx/libvcx/src/utils/libindy/anoncreds.rs @@ -1,13 +1,19 @@ extern crate libc; +use futures::Future; use serde_json; use serde_json::{ map::Map, Value}; use settings; -use utils::constants::{ LIBINDY_CRED_OFFER, REQUESTED_ATTRIBUTES, ATTRS}; -use utils::error::{ INVALID_PROOF_REQUEST, INVALID_ATTRIBUTES_STRUCTURE, INVALID_CONFIGURATION } ; +use utils::constants::{ LIBINDY_CRED_OFFER, REQUESTED_ATTRIBUTES, ATTRS, REV_STATE_JSON}; +use utils::error::{ INVALID_PROOF_REQUEST, INVALID_ATTRIBUTES_STRUCTURE, INVALID_CONFIGURATION, INVALID_JSON, DUPLICATE_SCHEMA, UNKNOWN_SCHEMA_REJECTION } ; use utils::libindy::{ error_codes::map_rust_indy_sdk_error_code, mock_libindy_rc, wallet::get_wallet_handle }; -use utils::timeout::TimeoutUtils; -use indy::anoncreds::{ Verifier, Prover, Issuer }; +use utils::libindy::payments::{pay_for_txn, PaymentTxn}; +use utils::constants::{ SCHEMA_ID, SCHEMA_JSON, SCHEMA_TXN_TYPE, CRED_DEF_ID, CRED_DEF_JSON, CRED_DEF_TXN_TYPE, REV_REG_DEF_TXN_TYPE, REV_REG_DELTA_TXN_TYPE, REVOC_REG_TYPE, rev_def_json, REV_REG_ID, REV_REG_DELTA_JSON, REV_REG_JSON}; +use utils::libindy::ledger::{libindy_build_schema_request, libindy_build_get_schema_request, libindy_submit_request, libindy_parse_get_cred_def_response, libindy_parse_get_schema_response, libindy_build_create_credential_def_txn, libindy_build_get_credential_def_txn}; +use indy::anoncreds; +use indy::blob_storage; +use indy::ledger; +use time; pub fn libindy_verifier_verify_proof(proof_req_json: &str, proof_json: &str, @@ -16,28 +22,43 @@ pub fn libindy_verifier_verify_proof(proof_req_json: &str, rev_reg_defs_json: &str, rev_regs_json: &str) -> Result { - Verifier::verify_proof_timeout(proof_req_json, - proof_json, - schemas_json, - credential_defs_json, - rev_reg_defs_json, - rev_regs_json, - TimeoutUtils::long_timeout()) + //TODO there was timeout here (before future-based Rust wrapper) + anoncreds::verifier_verify_proof(proof_req_json, + proof_json, + schemas_json, + credential_defs_json, + rev_reg_defs_json, + rev_regs_json) + .wait() .map_err(map_rust_indy_sdk_error_code) } +pub fn libindy_create_and_store_revoc_reg(issuer_did: &str, cred_def_id: &str, tails_path: &str, max_creds: u32) -> Result<(String, String, String), u32> { + trace!("creating revocation: {}, {}, {}", cred_def_id, tails_path, max_creds); + let tails_config = json!({"base_dir": tails_path,"uri_pattern": ""}).to_string(); + let writer = blob_storage::open_writer("default", &tails_config.to_string()) + .wait() + .map_err(|ec|map_rust_indy_sdk_error_code(ec))?; + let revoc_config = json!({"max_cred_num": max_creds,"issuance_type": "ISSUANCE_BY_DEFAULT"}).to_string(); + + anoncreds::issuer_create_and_store_revoc_reg(get_wallet_handle(), issuer_did, None, "tag1", cred_def_id, &revoc_config, writer) + .wait() + .map_err(|ec|map_rust_indy_sdk_error_code(ec)) +} + pub fn libindy_create_and_store_credential_def(issuer_did: &str, schema_json: &str, tag: &str, sig_type: Option<&str>, config_json: &str) -> Result<(String, String), u32> { - Issuer::create_and_store_credential_def(get_wallet_handle(), - issuer_did, - schema_json, - tag, - sig_type, - config_json) + anoncreds::issuer_create_and_store_credential_def(get_wallet_handle(), + issuer_did, + schema_json, + tag, + sig_type, + config_json) + .wait() .map_err(map_rust_indy_sdk_error_code) } @@ -47,25 +68,36 @@ pub fn libindy_issuer_create_credential_offer(cred_def_id: &str) -> Result, - blob_storage_reader_handle: Option) -> Result<(String, Option, Option), u32>{ + rev_reg_id: Option, + tails_file: Option) -> Result<(String, Option, Option), u32>{ - let blob_storage_reader_handle = blob_storage_reader_handle.unwrap_or(-1); + let revocation = rev_reg_id.as_ref().map(String::as_str); - Issuer::create_credential(get_wallet_handle(), - cred_offer_json, - cred_req_json, - cred_values_json, - rev_reg_id, - blob_storage_reader_handle) + let blob_handle = match tails_file { + Some(x) => { + let tails_config = json!({"base_dir": x,"uri_pattern": ""}).to_string(); + blob_storage::open_reader("default", &tails_config.to_string()) + .wait() + .map_err(map_rust_indy_sdk_error_code)? + }, + None => -1, + }; + anoncreds::issuer_create_credential(get_wallet_handle(), + cred_offer_json, + cred_req_json, + cred_values_json, + revocation, + blob_handle) + .wait() .map_err(map_rust_indy_sdk_error_code) } @@ -76,20 +108,21 @@ pub fn libindy_prover_create_proof(proof_req_json: &str, credential_defs_json: &str, revoc_states_json: Option<&str>) -> Result { let revoc_states_json = revoc_states_json.unwrap_or("{}"); - Prover::create_proof(get_wallet_handle(), - proof_req_json, - requested_credentials_json, - master_secret_id, - schemas_json, - credential_defs_json, - revoc_states_json) + anoncreds::prover_create_proof(get_wallet_handle(), + proof_req_json, + requested_credentials_json, + master_secret_id, + schemas_json, + credential_defs_json, + revoc_states_json) + .wait() .map_err(map_rust_indy_sdk_error_code) } fn fetch_credentials(search_handle: i32, requested_attributes: Map) -> Result { let mut v: Value = json!({}); for item_referent in requested_attributes.keys().into_iter() { - v[ATTRS][item_referent] = serde_json::from_str(&Prover::_fetch_credentials_for_proof_req(search_handle, item_referent, 100) + v[ATTRS][item_referent] = serde_json::from_str(&anoncreds::prover_fetch_credentials_for_proof_req(search_handle, item_referent, 100).wait() .map_err(map_rust_indy_sdk_error_code)?) .map_err(|_| { error!("Invalid Json Parsing of Object Returned from Libindy. Did Libindy change its structure?"); @@ -100,7 +133,7 @@ fn fetch_credentials(search_handle: i32, requested_attributes: Map Result<(), u32> { - Prover::_close_credentials_search_for_proof_req(search_handle).map_err(|ec| { + anoncreds::prover_close_credentials_search_for_proof_req(search_handle).wait().map_err(|ec| { error!("Error closing search handle"); map_rust_indy_sdk_error_code(ec) }) @@ -122,7 +155,9 @@ pub fn libindy_prover_get_credentials_for_proof_req(proof_req: &str) -> Result { - let search_handle = Prover::search_credentials_for_proof_req(wallet_handle, proof_req, None).map_err(|ec| { + let search_handle = anoncreds::prover_search_credentials_for_proof_req(wallet_handle, proof_req, None) + .wait() + .map_err(|ec| { error!("Opening Indy Search for Credentials Failed"); map_rust_indy_sdk_error_code(ec) })?; @@ -145,11 +180,36 @@ pub fn libindy_prover_create_credential_req(prover_did: &str, if settings::test_indy_mode_enabled() { return Ok((::utils::constants::CREDENTIAL_REQ_STRING.to_owned(), String::new())); } let master_secret_name = settings::DEFAULT_LINK_SECRET_ALIAS; - Prover::create_credential_req(get_wallet_handle(), + anoncreds::prover_create_credential_req(get_wallet_handle(), prover_did, credential_offer_json, credential_def_json, master_secret_name) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn libindy_prover_create_revocation_state(rev_reg_def_json: &str, rev_reg_delta_json: &str, cred_rev_id: &str, tails_file: &str) -> Result { + if settings::test_indy_mode_enabled() { return Ok(REV_STATE_JSON.to_string()); } + let tails_config = json!({"base_dir": tails_file,"uri_pattern": ""}).to_string(); + let blob_handle = blob_storage::open_reader("default", &tails_config.to_string()) + .wait() + .map_err(|ec|map_rust_indy_sdk_error_code(ec))?; + + anoncreds::create_revocation_state(blob_handle, rev_reg_def_json, rev_reg_delta_json, 100, cred_rev_id) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn libindy_prover_update_revocation_state(rev_reg_def_json: &str, rev_state_json: &str, rev_reg_delta_json: &str, cred_rev_id: &str, tails_file: &str) -> Result { + if settings::test_indy_mode_enabled() { return Ok(REV_STATE_JSON.to_string()); } + let tails_config = json!({"base_dir": tails_file,"uri_pattern": ""}).to_string(); + let blob_handle = blob_storage::open_reader("default", &tails_config.to_string()) + .wait() + .map_err(|ec|map_rust_indy_sdk_error_code(ec))?; + + anoncreds::update_revocation_state(blob_handle, rev_state_json, rev_reg_def_json, rev_reg_delta_json, 100, cred_rev_id) + .wait() .map_err(map_rust_indy_sdk_error_code) } @@ -157,23 +217,27 @@ pub fn libindy_prover_store_credential(cred_id: Option<&str>, cred_req_meta: &str, cred_json: &str, cred_def_json: &str, - rev_reg_def_json: Option<&str>) -> Result { + rev_reg_def_json: Option) -> Result { if settings::test_indy_mode_enabled() { return Ok("cred_id".to_string()); } - Prover::store_credential(get_wallet_handle(), + let revocation = rev_reg_def_json.as_ref().map(String::as_str); + + anoncreds::prover_store_credential(get_wallet_handle(), cred_id, cred_req_meta, cred_json, cred_def_json, - rev_reg_def_json) + revocation) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_prover_create_master_secret(master_secret_id: &str) -> Result { if settings::test_indy_mode_enabled() { return Ok(settings::DEFAULT_LINK_SECRET_ALIAS.to_string()); } - Prover::create_master_secret(get_wallet_handle(), + anoncreds::prover_create_master_secret(get_wallet_handle(), Some(master_secret_id)) + .wait() .map_err(map_rust_indy_sdk_error_code) } @@ -182,17 +246,241 @@ pub fn libindy_issuer_create_schema(issuer_did: &str, version: &str, attrs: &str) -> Result<(String, String), u32>{ - Issuer::create_schema(issuer_did, + anoncreds::issuer_create_schema(issuer_did, name, version, attrs) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn libindy_issuer_revoke_credential(tails_file: &str, rev_reg_id: &str, cred_rev_id: &str) -> Result { + + let tails_config = json!({"base_dir": tails_file,"uri_pattern": ""}).to_string(); + let blob_handle = blob_storage::open_reader("default", &tails_config) + .wait() + .map_err(map_rust_indy_sdk_error_code)?; + + anoncreds::issuer_revoke_credential(get_wallet_handle(), blob_handle, rev_reg_id, cred_rev_id) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn libindy_build_revoc_reg_def_request(submitter_did: &str, + rev_reg_def_json: &str) -> Result { + ledger::build_revoc_reg_def_request(submitter_did, rev_reg_def_json) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn libindy_build_revoc_reg_entry_request(submitter_did: &str, + rev_reg_id: &str, + rev_def_type: &str, + value: &str) -> Result { + ledger::build_revoc_reg_entry_request(submitter_did, rev_reg_id, rev_def_type, value) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn libindy_build_get_revoc_reg_def_request(submitter_did: &str, rev_reg_id: &str) -> Result { + ledger::build_get_revoc_reg_def_request(Some(submitter_did), rev_reg_id) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn libindy_parse_get_revoc_reg_def_response(rev_reg_def_json: &str) -> Result<(String, String), u32> { + ledger::parse_get_revoc_reg_def_response(rev_reg_def_json) + .wait() .map_err(map_rust_indy_sdk_error_code) } +pub fn libindy_build_get_revoc_reg_delta_request(submitter_did: &str, + rev_reg_id: &str, + from: i64, + to: i64) -> Result { + ledger::build_get_revoc_reg_delta_request(Some(submitter_did), + rev_reg_id, + from, + to) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +fn libindy_build_get_revoc_reg_request(submitter_did: &str, rev_reg_id: &str, timestamp: u64) + -> Result { + ledger::build_get_revoc_reg_request(Some(submitter_did), + rev_reg_id, + timestamp as i64) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +fn libindy_parse_get_revoc_reg_response(get_rev_reg_resp: &str) -> Result<(String, String, u64), u32> { + ledger::parse_get_revoc_reg_response(get_rev_reg_resp) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn libindy_parse_get_revoc_reg_delta_response(get_rev_reg_delta_response: &str) + -> Result<(String, String, u64), u32> { + ledger::parse_get_revoc_reg_delta_response(get_rev_reg_delta_response) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn create_schema(name: &str, version: &str, data: &str) -> Result<(String, Option), u32> { + if settings::test_indy_mode_enabled() { + return Ok((SCHEMA_ID.to_string(), Some(PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap(), ))); + } + + let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; + + let (id, create_schema) = libindy_issuer_create_schema(&submitter_did, name, version, data)?; + + let request = libindy_build_schema_request(&submitter_did, &create_schema)?; + + let (payment, response) = pay_for_txn(&request, SCHEMA_TXN_TYPE)?; + + _check_create_schema_response(&response)?; + + Ok((id, payment)) +} + +fn _check_create_schema_response(response: &str) -> Result<(), u32> { + let response: Value = serde_json::from_str(response).or(Err(INVALID_JSON.code_num))?; + + if let Some(_) = response.get("result") { return Ok(()) }; + + warn!("No result found in ledger txn. Must be Rejected"); + + if response["op"] == json!("REJECT") { + match response.get("reason") { + Some(r) => return Err(DUPLICATE_SCHEMA.code_num), + None => return Err(UNKNOWN_SCHEMA_REJECTION.code_num), + } + } + + Err(UNKNOWN_SCHEMA_REJECTION.code_num) +} + +pub fn get_schema_json(schema_id: &str) -> Result<(String, String), u32> { + if settings::test_indy_mode_enabled() { return Ok((SCHEMA_ID.to_string(), SCHEMA_JSON.to_string()))} + + let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; + libindy_build_get_schema_request(&submitter_did, schema_id) + .and_then(|req| libindy_submit_request(&req)) + .and_then(|response| libindy_parse_get_schema_response(&response)) +} + +pub fn create_cred_def(issuer_did: &str, + schema_json: &str, + tag: &str, + sig_type: Option<&str>, + support_revocation: Option) -> Result<(String, Option), u32> { + if settings::test_indy_mode_enabled() { + return Ok((CRED_DEF_ID.to_string(), Some(PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap()))); + } + + let config_json = json!({"support_revocation": support_revocation.unwrap_or(false)}).to_string(); + + let (id, cred_def_json) = libindy_create_and_store_credential_def(issuer_did, + schema_json, + tag, + sig_type, + &config_json)?; + + let cred_def_req = libindy_build_create_credential_def_txn(issuer_did, &cred_def_json)?; + + let (payment, response) = pay_for_txn(&cred_def_req, CRED_DEF_TXN_TYPE)?; + + Ok((id, payment)) +} + +pub fn get_cred_def_json(cred_def_id: &str) -> Result<(String, String), u32> { + if settings::test_indy_mode_enabled() { return Ok((CRED_DEF_ID.to_string(), CRED_DEF_JSON.to_string())); } + + libindy_build_get_credential_def_txn(cred_def_id) + .and_then(|req| libindy_submit_request(&req)) + .and_then(|response| libindy_parse_get_cred_def_response(&response)) +} + +pub fn create_rev_reg_def(issuer_did: &str, cred_def_id: &str, tails_file: &str, max_creds: u32) + -> Result<(String, String, String, Option), u32> { + debug!("creating revocation registry definition with issuer_did: {}, cred_def_id: {}, tails_file_path: {}, max_creds: {}", + issuer_did, cred_def_id, tails_file, max_creds); + if settings::test_indy_mode_enabled() { return Ok((REV_REG_ID.to_string(), rev_def_json(), "".to_string(), None)); } + + let (rev_reg_id, rev_reg_def_json, rev_reg_entry_json) = libindy_create_and_store_revoc_reg( + issuer_did, + cred_def_id, + tails_file, + max_creds + )?; + + let rev_reg_def_req = libindy_build_revoc_reg_def_request(issuer_did, &rev_reg_def_json)?; + + let (payment, _) = pay_for_txn(&rev_reg_def_req, REV_REG_DEF_TXN_TYPE)?; + + Ok((rev_reg_id, rev_reg_def_json, rev_reg_entry_json, payment)) +} + +pub fn get_rev_reg_def_json(rev_reg_id: &str) -> Result<(String, String), u32> { + if settings::test_indy_mode_enabled() { return Ok((REV_REG_ID.to_string(), rev_def_json())); } + + let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; + + libindy_build_get_revoc_reg_def_request(&submitter_did, rev_reg_id) + .and_then(|req| libindy_submit_request(&req)) + .and_then(|response| libindy_parse_get_revoc_reg_def_response(&response)) +} + +pub fn post_rev_reg_delta(issuer_did: &str, rev_reg_id: &str, rev_reg_entry_json: &str) + -> Result<(Option, String), u32> { + libindy_build_revoc_reg_entry_request(issuer_did, rev_reg_id, REVOC_REG_TYPE, rev_reg_entry_json) + .and_then(|req| pay_for_txn(&req, REV_REG_DELTA_TXN_TYPE)) +} + +pub fn get_rev_reg_delta_json(rev_reg_id: &str, from: Option, to: Option) + -> Result<(String, String, u64), u32> { + if settings::test_indy_mode_enabled() { return Ok((REV_REG_ID.to_string(), REV_REG_DELTA_JSON.to_string(), 1)); } + + let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; + let from: i64 = if let Some(_from) = from { _from as i64 } else { -1 }; + let to = if let Some(_to) = to { _to as i64 } else { time::get_time().sec }; + + libindy_build_get_revoc_reg_delta_request(&submitter_did, rev_reg_id, from, to) + .and_then(|req| libindy_submit_request(&req)) + .and_then(|response| libindy_parse_get_revoc_reg_delta_response(&response)) +} + +pub fn get_rev_reg(rev_reg_id: &str, timestamp: u64) -> Result<(String, String, u64), u32> { + if settings::test_indy_mode_enabled() { return Ok((REV_REG_ID.to_string(), REV_REG_JSON.to_string(), 1)); } + let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; + + libindy_build_get_revoc_reg_request(&submitter_did, rev_reg_id, timestamp) + .and_then(|req| libindy_submit_request(&req)) + .and_then(|response| libindy_parse_get_revoc_reg_response(&response)) +} + +pub fn revoke_credential(tails_file: &str, rev_reg_id: &str, cred_rev_id: &str) + -> Result<(Option, String), u32> { + if settings::test_indy_mode_enabled() { + return Ok((Some(PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap()), REV_REG_DELTA_JSON.to_string())); + } + + let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; + + let delta = libindy_issuer_revoke_credential(tails_file, rev_reg_id, cred_rev_id)?; + let (payment, _) = post_rev_reg_delta(&submitter_did, rev_reg_id, &delta)?; + + Ok((payment, delta)) +} + #[cfg(test)] pub mod tests { use super::*; + use utils::get_temp_dir_path; extern crate serde_json; extern crate rand; use rand::Rng; @@ -200,9 +488,13 @@ pub mod tests { use utils::constants::*; use std::thread; use std::time::Duration; + #[cfg(feature = "pool_tests")] + use utils::error::LIBINDY_INVALID_STRUCTURE; + #[cfg(feature = "pool_tests")] + use utils::constants::{TEST_TAILS_FILE}; + pub fn create_schema(attr_list: &str) -> (String, String) { - let data = DEFAULT_SCHEMA_ATTRS.to_string(); let data = attr_list.to_string(); let schema_name: String = rand::thread_rng().gen_ascii_chars().take(25).collect::(); let schema_version: String = format!("{}.{}", rand::thread_rng().gen::().to_string(), @@ -229,7 +521,7 @@ pub mod tests { (schema_id, schema_json) } - pub fn create_and_store_credential_def(attr_list: &str) -> (String, String, String, String) { + pub fn create_and_store_credential_def(attr_list: &str, support_rev: bool) -> (String, String, String, String, u32, Option) { /* create schema */ let (schema_id, schema_json) = create_and_write_test_schema(attr_list); @@ -237,50 +529,63 @@ pub mod tests { let institution_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); /* create cred-def */ + let mut revocation_details = json!({"support_revocation":support_rev}); + if support_rev { + revocation_details["tails_file"] = json!(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()); + revocation_details["max_creds"] = json!(10); + } let handle = ::credential_def::create_new_credentialdef("1".to_string(), name, institution_did.clone(), schema_id.clone(), "tag1".to_string(), - r#"{"support_revocation":false}"#.to_string()).unwrap(); + revocation_details.to_string()).unwrap(); thread::sleep(Duration::from_millis(1000)); let cred_def_id = ::credential_def::get_cred_def_id(handle).unwrap(); thread::sleep(Duration::from_millis(1000)); - let (_, cred_def_json) = ::credential_def::retrieve_credential_def(&cred_def_id).unwrap(); - (schema_id, schema_json, cred_def_id, cred_def_json) + let (_, cred_def_json) = get_cred_def_json(&cred_def_id).unwrap(); + let rev_reg_id = ::credential_def::get_rev_reg_id(handle).unwrap(); + (schema_id, schema_json, cred_def_id, cred_def_json, handle, rev_reg_id) } - pub fn create_credential_offer(attr_list: &str) -> (String, String, String, String, String) { - let (schema_id, schema_json, cred_def_id, cred_def_json) = create_and_store_credential_def(attr_list); + pub fn create_credential_offer(attr_list: &str, revocation: bool) -> (String, String, String, String, String, Option) { + let (schema_id, schema_json, cred_def_id, cred_def_json, _, rev_reg_id) = create_and_store_credential_def(attr_list, revocation); let offer = ::utils::libindy::anoncreds::libindy_issuer_create_credential_offer(&cred_def_id).unwrap(); - (schema_id, schema_json, cred_def_id, cred_def_json, offer) + (schema_id, schema_json, cred_def_id, cred_def_json, offer, rev_reg_id) } - pub fn create_credential_req(attr_list: &str) -> (String, String, String, String, String, String, String) { - let (schema_id, schema_json, cred_def_id, cred_def_json, offer) = create_credential_offer(attr_list); + pub fn create_credential_req(attr_list: &str, revocation: bool) -> (String, String, String, String, String, String, String, Option) { + let (schema_id, schema_json, cred_def_id, cred_def_json, offer, rev_reg_id) = create_credential_offer(attr_list, revocation); let institution_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let (req, req_meta) = ::utils::libindy::anoncreds::libindy_prover_create_credential_req(&institution_did, &offer, &cred_def_json).unwrap(); - (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta) + (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta, rev_reg_id) } - pub fn create_and_store_credential(attr_list: &str) -> (String, String, String, String, String, String, String, String) { + pub fn create_and_store_credential(attr_list: &str, revocation: bool) -> (String, String, String, String, String, String, String, String, Option, Option) { - let (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta) = create_credential_req(attr_list); + let (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta, rev_reg_id) = create_credential_req(attr_list, revocation); /* create cred */ let credential_data = r#"{"address1": ["123 Main St"], "address2": ["Suite 3"], "city": ["Draper"], "state": ["UT"], "zip": ["84000"]}"#; let encoded_attributes = ::issuer_credential::encode_attributes(&credential_data).unwrap(); - let (cred, _, _) = ::utils::libindy::anoncreds::libindy_issuer_create_credential(&offer, &req, &encoded_attributes, None, None).unwrap(); + let (rev_def_json, tails_file) = if revocation { + let (id, json) = get_rev_reg_def_json(&rev_reg_id.clone().unwrap()).unwrap(); + (Some(json), Some(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string().to_string())) + + } else { (None, None) }; + + let (cred, cred_rev_id, _) = ::utils::libindy::anoncreds::libindy_issuer_create_credential(&offer, &req, &encoded_attributes, rev_reg_id.clone(), tails_file).unwrap(); /* store cred */ - let cred_id = ::utils::libindy::anoncreds::libindy_prover_store_credential(None, &req_meta, &cred, &cred_def_json, None).unwrap(); - (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta, cred_id) + let cred_id = ::utils::libindy::anoncreds::libindy_prover_store_credential(None, &req_meta, &cred, &cred_def_json, rev_def_json).unwrap(); + (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta, cred_id, rev_reg_id, cred_rev_id) } pub fn create_proof() -> (String, String, String, String) { let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); - let (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta, cred_id) = create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS); + let (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta, cred_id, _, _) + = create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, false); let proof_req = json!({ "nonce":"123432421212", @@ -426,4 +731,158 @@ pub mod tests { assert_eq!(result_malformed_json.err(), Some(INVALID_ATTRIBUTES_STRUCTURE.code_num)); } + #[cfg(feature = "pool_tests")] + #[test] + fn test_issuer_revoke_credential(){ + init!("ledger"); + let rc = libindy_issuer_revoke_credential(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap(), "", ""); + assert!(rc.is_err()); + + let (_, _, cred_def_id, _, _, _, _, cred_id, rev_reg_id, cred_rev_id) + = create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, true); + let rc = ::utils::libindy::anoncreds::libindy_issuer_revoke_credential(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap(), &rev_reg_id.unwrap(), &cred_rev_id.unwrap()); + + assert!(rc.is_ok()); + } + + #[test] + fn test_create_cred_def() { + init!("true"); + let (id, _) = create_cred_def("did", SCHEMAS_JSON, "tag_1", None, Some(false)).unwrap(); + assert_eq!(id, CRED_DEF_ID); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_create_cred_def_real() { + init!("ledger"); + + let data = r#"["address1","address2","zip","city","state"]"#.to_string(); + let (schema_id, _) = ::utils::libindy::anoncreds::tests::create_and_write_test_schema(::utils::constants::DEFAULT_SCHEMA_ATTRS); + let (_, schema_json) = get_schema_json(&schema_id).unwrap(); + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + + let revocation_details = json!({ + "support_revocation": true, + "tails_file": get_temp_dir_path(Some("tails.txt")).to_str().unwrap(), + "max_creds": 2 + }).to_string(); + create_cred_def(&did, &schema_json, "tag_1", None, Some(true)).unwrap(); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_rev_reg_def_fails_for_cred_def_created_without_revocation() { + let wallet_name = "test_create_revocable_fails_with_no_tails_file"; + init!("ledger"); + + let data = r#"["address1","address2","zip","city","state"]"#.to_string(); + // Cred def is created with support_revocation=false, + // revoc_reg_def will fail in libindy because cred_Def doesn't have revocation keys + let (_, _, cred_def_id, _, _, _) = ::utils::libindy::anoncreds::tests::create_and_store_credential_def(::utils::constants::DEFAULT_SCHEMA_ATTRS, false); + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + let rc = create_rev_reg_def(&did, &cred_def_id, get_temp_dir_path(Some("path.txt")).to_str().unwrap(), 2); + + assert_eq!(rc, Err(LIBINDY_INVALID_STRUCTURE.code_num)); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_create_rev_reg_def() { + init!("ledger"); + + let data = r#"["address1","address2","zip","city","state"]"#.to_string(); + let (schema_id, _) = ::utils::libindy::anoncreds::tests::create_and_write_test_schema(::utils::constants::DEFAULT_SCHEMA_ATTRS); + let (_, schema_json) = get_schema_json(&schema_id).unwrap(); + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + + let revocation_details = json!({"support_revocation": true, "tails_file": get_temp_dir_path(Some("tails.txt")).to_str().unwrap(), "max_creds": 2}).to_string(); + let (id, payment) = create_cred_def(&did, &schema_json, "tag_1", None, Some(true)).unwrap(); + create_rev_reg_def(&did, &id, "tails.txt", 2).unwrap(); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_get_rev_reg_def_json() { + init!("ledger"); + let attrs = r#"["address1","address2","city","state","zip"]"#; + let (_, _, _, _, _, rev_reg_id) = + ::utils::libindy::anoncreds::tests::create_and_store_credential_def(attrs, true); + + let rev_reg_id = rev_reg_id.unwrap(); + let (id, json) = get_rev_reg_def_json(&rev_reg_id).unwrap(); + assert_eq!(id, rev_reg_id); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_get_rev_reg_delta_json() { + init!("ledger"); + let attrs = r#"["address1","address2","city","state","zip"]"#; + let (_, _, _, _, _, rev_reg_id) = + ::utils::libindy::anoncreds::tests::create_and_store_credential_def(attrs, true); + let rev_reg_id = rev_reg_id.unwrap(); + + let (id, delta, timestamp) = get_rev_reg_delta_json(&rev_reg_id, None, None).unwrap(); + assert_eq!(id, rev_reg_id); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_get_rev_reg() { + init!("ledger"); + let attrs = r#"["address1","address2","city","state","zip"]"#; + let (_, _, _, _, _, rev_reg_id) = + ::utils::libindy::anoncreds::tests::create_and_store_credential_def(attrs, true); + let rev_reg_id = rev_reg_id.unwrap(); + + let (id, rev_reg, timestamp) = get_rev_reg(&rev_reg_id, time::get_time().sec as u64).unwrap(); + assert_eq!(id, rev_reg_id); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn from_pool_ledger_with_id(){ + use settings; + init!("ledger"); + let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); + let (schema_id, schema_json) = ::utils::libindy::anoncreds::tests::create_and_write_test_schema(::utils::constants::DEFAULT_SCHEMA_ATTRS); + + let rc = get_schema_json(&schema_id); + + let (id, retrieved_schema) = rc.unwrap(); + assert!(retrieved_schema.contains(&schema_id)); + + } + + #[test] + fn from_ledger_schema_id(){ + init!("true"); + let (id, retrieved_schema) = get_schema_json(SCHEMA_ID).unwrap(); + assert_eq!(&retrieved_schema, SCHEMA_JSON); + assert_eq!(&id, SCHEMA_ID); + } + + #[cfg(feature = "pool_tests")] + #[test] + fn test_revoke_credential(){ + init!("ledger"); + let (_, _, cred_def_id, _, _, _, _, cred_id, rev_reg_id, cred_rev_id) + = ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, true); + + let rev_reg_id = rev_reg_id.unwrap(); + let (_, first_rev_reg_delta, first_timestamp) = get_rev_reg_delta_json(&rev_reg_id, None, None).unwrap(); + let (_, test_same_delta, test_same_timestamp) = get_rev_reg_delta_json(&rev_reg_id, None, None).unwrap(); + + assert_eq!(first_rev_reg_delta, test_same_delta); + assert_eq!(first_timestamp, test_same_timestamp); + + let (payment, revoked_rev_reg_delta) = revoke_credential(get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap(), &rev_reg_id, cred_rev_id.unwrap().as_str()).unwrap(); + + // Delta should change after revocation + let (_, second_rev_reg_delta, _) = get_rev_reg_delta_json(&rev_reg_id, Some(first_timestamp+1), None).unwrap(); + + assert!(payment.is_some()); + assert_ne!(first_rev_reg_delta, second_rev_reg_delta); + } } diff --git a/vcx/libvcx/src/utils/libindy/cache.rs b/vcx/libvcx/src/utils/libindy/cache.rs new file mode 100644 index 00000000..077d3c43 --- /dev/null +++ b/vcx/libvcx/src/utils/libindy/cache.rs @@ -0,0 +1,191 @@ +extern crate serde_json; + +use utils::libindy::wallet::{add_record, get_record, update_record_value}; + +static CACHE_TYPE: &str = "cache"; +static REV_REG_CACHE_PREFIX: &str = "rev_reg:"; + +/// +/// Cache object for rev reg cache +/// +#[derive(Serialize, Deserialize, Debug, Default, PartialEq)] +pub struct RevRegCache { + pub rev_state: Option, +} + +/// +/// Rev reg delta object. +/// +#[derive(Serialize, Deserialize, Debug, PartialEq)] +pub struct RevState { + pub timestamp: u64, + pub value: String, +} + +/// +/// Returns the rev reg cache. +/// In case of error returns empty cache and silently ignores error. +/// +/// # Arguments +/// `rev_reg_id`: revocation registry id +/// +pub fn get_rev_reg_cache(rev_reg_id: &str) -> RevRegCache { + let wallet_id = format!("{}{}", REV_REG_CACHE_PREFIX, rev_reg_id); + match get_record(CACHE_TYPE, &wallet_id, &json!({"retrieveType": false, "retrieveValue": true, "retrieveTags": false}).to_string()) { + Ok(json) => { + match serde_json::from_str(&json) + .and_then(|x: serde_json::Value| { + serde_json::from_str(x.get("value").unwrap_or(&serde_json::Value::Null).as_str().unwrap_or("")) + }) + { + Ok(cache) => cache, + Err(err) => { + warn!("Unable to convert rev reg cache for rev_reg_id: {}, json: {}, error: {}", rev_reg_id, json, err); + RevRegCache::default() + } + } + }, + Err(err) => { + warn!("Unable to get rev_reg cache for rev_reg_id: {}, error: {}", rev_reg_id, err); + RevRegCache::default() + } + } +} + +/// +/// Saves rev reg cache. +/// Errors are silently ignored. +/// +/// # Arguments +/// `rev_reg_id`: revocation registry id. +/// `cache`: Cache object. +/// +pub fn set_rev_reg_cache(rev_reg_id: &str, cache: &RevRegCache) { + match serde_json::to_string(cache) { + Ok(json) => { + let wallet_id = format!("{}{}", REV_REG_CACHE_PREFIX, rev_reg_id); + let result = update_record_value(CACHE_TYPE, &wallet_id, &json) + .or(add_record(CACHE_TYPE, &wallet_id, &json, None)); + if result.is_err() { + warn!("Error when saving rev reg cache {:?}, error: {:?}", cache, result); + } + }, + Err(err) => { + warn!("Unable to convert to JSON rev reg cache {:?}, error: {:?}", cache, err); + } + } +} + + +#[cfg(test)] +pub mod tests { + use super::*; + + struct Init; + + impl Init { + fn new() -> Self { + init!("false"); + Init + } + } + + impl Drop for Init { + fn drop(&mut self) { + teardown!("false") + } + } + + #[test] + fn test_get_credential_cache_returns_default_when_not_exists_in_wallet() { + let init = Init::new(); + + let result = get_rev_reg_cache("test-id"); + assert_eq!(result, RevRegCache::default()); + } + + #[test] + fn test_get_credential_cache_returns_default_when_invalid_data_in_the_wallet() { + let init = Init::new(); + + let rev_reg_id = "test-id"; + + add_record(CACHE_TYPE, rev_reg_id, "some invalid json", None).unwrap(); + + let result = get_rev_reg_cache(rev_reg_id); + assert_eq!(result, RevRegCache::default()); + } + + #[test] + fn test_credential_cache_set_than_get_works() { + let init = Init::new(); + + let rev_reg_id = "test-id"; + + let data = RevRegCache { + rev_state: Some(RevState { + timestamp: 1000, + value: "{\"key\": \"value1\"}".to_string(), + }) + }; + + set_rev_reg_cache(rev_reg_id, &data); + + let result = get_rev_reg_cache(rev_reg_id); + + assert_eq!(result, data); + } + + #[test] + fn test_credential_cache_set_than_double_get_works() { + let init = Init::new(); + + let rev_reg_id = "test-id"; + + let data = RevRegCache { + rev_state: Some(RevState { + timestamp: 1000, + value: "{\"key\": \"value1\"}".to_string(), + }) + }; + + set_rev_reg_cache(rev_reg_id, &data); + + let result = get_rev_reg_cache(rev_reg_id); + assert_eq!(result, data); + + let result = get_rev_reg_cache(rev_reg_id); + assert_eq!(result, data); + } + + #[test] + fn test_credential_cache_overwrite_works() { + let init = Init::new(); + + let rev_reg_id = "test-id"; + + let data1 = RevRegCache { + rev_state: Some(RevState { + timestamp: 1000, + value: "{\"key\": \"value1\"}".to_string(), + }) + }; + + let data2 = RevRegCache { + rev_state: Some(RevState { + timestamp: 2000, + value: "{\"key\": \"value2\"}".to_string(), + }) + }; + + set_rev_reg_cache(rev_reg_id, &data1); + let result = get_rev_reg_cache(rev_reg_id); + assert_eq!(result, data1); + + // overwrite + set_rev_reg_cache(rev_reg_id, &data2); + let result = get_rev_reg_cache(rev_reg_id); + assert_eq!(result, data2); + } + +} \ No newline at end of file diff --git a/vcx/libvcx/src/utils/libindy/crypto.rs b/vcx/libvcx/src/utils/libindy/crypto.rs index 0186b140..3119db30 100644 --- a/vcx/libvcx/src/utils/libindy/crypto.rs +++ b/vcx/libvcx/src/utils/libindy/crypto.rs @@ -1,42 +1,59 @@ /* test isn't ready until > libindy 1.0.1 */ extern crate libc; +use futures::Future; + use utils::libindy::{ mock_libindy_rc}; use utils::libindy::error_codes::map_rust_indy_sdk_error_code; use settings; -use indy::crypto::Crypto; +use indy::crypto; -pub fn prep_msg(wallet_handle: i32, sender_vk: &str, recipient_vk: &str, msg: &[u8]) -> Result, u32> { +pub fn prep_msg(sender_vk: &str, recipient_vk: &str, msg: &[u8]) -> Result, u32> { if settings::test_indy_mode_enabled() { let rc = mock_libindy_rc(); if rc != 0 { return Err(rc) }; return Ok(Vec::from(msg).to_owned()); } - Crypto::auth_crypt(wallet_handle, sender_vk, recipient_vk, msg) + crypto::auth_crypt(::utils::libindy::wallet::get_wallet_handle(), sender_vk, recipient_vk, msg) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn prep_anonymous_msg(recipient_vk: &str, msg: &[u8]) -> Result, u32> { if settings::test_indy_mode_enabled() {return Ok(Vec::from(msg).to_owned())} - Crypto::anon_crypt(recipient_vk, msg).map_err(map_rust_indy_sdk_error_code) + crypto::anon_crypt(recipient_vk, msg) + .wait() + .map_err(map_rust_indy_sdk_error_code) } pub fn parse_msg(recipient_vk: &str, msg: &[u8]) -> Result<(String, Vec), u32> { if settings::test_indy_mode_enabled() { return Ok((::utils::constants::VERKEY.to_string(), Vec::from(msg).to_owned())) } - Crypto::auth_decrypt(::utils::libindy::wallet::get_wallet_handle(), recipient_vk, msg).map_err(map_rust_indy_sdk_error_code) + crypto::auth_decrypt(::utils::libindy::wallet::get_wallet_handle(), recipient_vk, msg) + .wait() + .map_err(map_rust_indy_sdk_error_code) } -pub fn parse_anonymous_msg(wallet_handle: i32, recipient_vk: &str, msg: &[u8]) -> Result, u32> { +pub fn parse_anonymous_msg(recipient_vk: &str, msg: &[u8]) -> Result, u32> { if settings::test_indy_mode_enabled() { return Ok(Vec::from(msg).to_owned()) } - Crypto::anon_decrypt(wallet_handle, recipient_vk, msg).map_err(map_rust_indy_sdk_error_code) + crypto::anon_decrypt(::utils::libindy::wallet::get_wallet_handle(), recipient_vk, msg) + .wait() + .map_err(map_rust_indy_sdk_error_code) } -pub fn sign(wallet_handle: i32, my_vk: &str, msg: &[u8]) -> Result, u32> { +pub fn sign(my_vk: &str, msg: &[u8]) -> Result, u32> { if settings::test_indy_mode_enabled() {return Ok(Vec::from(msg).to_owned())} - Crypto::sign(wallet_handle, my_vk, msg).map_err(map_rust_indy_sdk_error_code) + crypto::sign(::utils::libindy::wallet::get_wallet_handle(), my_vk, msg) + .wait() + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn verify(vk: &str, msg: &str, signature: &[u8]) -> Result { + crypto::verify(vk, msg.as_bytes(), signature) + .wait() + .map_err(map_rust_indy_sdk_error_code) } diff --git a/vcx/libvcx/src/utils/libindy/ledger.rs b/vcx/libvcx/src/utils/libindy/ledger.rs index 63abda09..f1694a9c 100644 --- a/vcx/libvcx/src/utils/libindy/ledger.rs +++ b/vcx/libvcx/src/utils/libindy/ledger.rs @@ -1,4 +1,8 @@ extern crate libc; +extern crate time; +extern crate serde_json; + +use futures::Future; use settings; use utils::libindy::{ @@ -6,17 +10,18 @@ use utils::libindy::{ wallet::get_wallet_handle, }; use utils::error; -use indy::ledger::Ledger; +use indy::ledger; use utils::libindy::error_codes::map_rust_indy_sdk_error_code; -use utils::timeout::TimeoutUtils; pub fn multisign_request(did: &str, request: &str) -> Result { - Ledger::multi_sign_request(get_wallet_handle(), did, request) + ledger::multi_sign_request(get_wallet_handle(), did, request) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_sign_request(did: &str, request: &str) -> Result { - Ledger::sign_request(get_wallet_handle(), did, request) + ledger::sign_request(get_wallet_handle(), did, request) + .wait() .map_err(map_rust_indy_sdk_error_code) } @@ -25,44 +30,59 @@ pub fn libindy_sign_and_submit_request(issuer_did: &str, request_json: &str) -> let pool_handle = get_pool_handle().or(Err(error::NO_POOL_OPEN.code_num))?; let wallet_handle = get_wallet_handle(); - Ledger::sign_and_submit_request(pool_handle, wallet_handle, issuer_did, request_json) + ledger::sign_and_submit_request(pool_handle, wallet_handle, issuer_did, request_json) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_submit_request(request_json: &str) -> Result { let pool_handle = get_pool_handle().or(Err(error::NO_POOL_OPEN.code_num))?; - Ledger::submit_request_timeout(pool_handle, request_json, TimeoutUtils::long_timeout()).map_err(map_rust_indy_sdk_error_code) + //TODO there was timeout here (before future-based Rust wrapper) + ledger::submit_request(pool_handle, request_json) + .wait() + .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_build_get_txn_request(submitter_did: &str, sequence_num: i32) -> Result { - Ledger::build_get_txn_request(Some(submitter_did), None, sequence_num) + ledger::build_get_txn_request(Some(submitter_did), None, sequence_num) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_build_schema_request(submitter_did: &str, data: &str) -> Result { - Ledger::build_schema_request(submitter_did, data) + ledger::build_schema_request(submitter_did, data) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_build_get_schema_request(submitter_did: &str, schema_id: &str) -> Result { - Ledger::build_get_schema_request(Some(submitter_did), schema_id) + ledger::build_get_schema_request(Some(submitter_did), schema_id) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_parse_get_schema_response(get_schema_response: &str) -> Result<(String, String), u32> { - Ledger::parse_get_schema_response(get_schema_response).map_err(map_rust_indy_sdk_error_code) + ledger::parse_get_schema_response(get_schema_response) + .wait() + .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_parse_get_cred_def_response(get_cred_def_response: &str) -> Result<(String, String), u32> { - Ledger::parse_get_cred_def_response(get_cred_def_response).map_err(map_rust_indy_sdk_error_code) + ledger::parse_get_cred_def_response(get_cred_def_response) + .wait() + .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_build_get_credential_def_txn(cred_def_id: &str) -> Result{ let submitter_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; - Ledger::build_get_cred_def_request(Some(&submitter_did), cred_def_id).map_err(map_rust_indy_sdk_error_code) + ledger::build_get_cred_def_request(Some(&submitter_did), cred_def_id) + .wait() + .map_err(map_rust_indy_sdk_error_code) } pub fn libindy_build_create_credential_def_txn(submitter_did: &str, credential_def_json: &str) -> Result{ - Ledger::build_cred_def_request(submitter_did, credential_def_json).map_err(map_rust_indy_sdk_error_code) + ledger::build_cred_def_request(submitter_did, credential_def_json) + .wait() + .map_err(map_rust_indy_sdk_error_code) } diff --git a/vcx/libvcx/src/utils/libindy/logger.rs b/vcx/libvcx/src/utils/libindy/logger.rs new file mode 100644 index 00000000..f061505a --- /dev/null +++ b/vcx/libvcx/src/utils/libindy/logger.rs @@ -0,0 +1,14 @@ +extern crate log; + +use indy::logger; +use utils::libindy::error_codes::map_rust_indy_sdk_error_code; + +pub fn set_logger(logger: &'static log::Log) -> Result<(), u32> { + logger::set_logger(logger) + .map_err(map_rust_indy_sdk_error_code) +} + +pub fn set_default_logger(patter: Option<&str>) -> Result<(), u32> { + logger::set_default_logger(patter) + .map_err(map_rust_indy_sdk_error_code) +} \ No newline at end of file diff --git a/vcx/libvcx/src/utils/libindy/mod.rs b/vcx/libvcx/src/utils/libindy/mod.rs index 543b1167..6a78b3b2 100644 --- a/vcx/libvcx/src/utils/libindy/mod.rs +++ b/vcx/libvcx/src/utils/libindy/mod.rs @@ -4,13 +4,13 @@ pub mod signus; pub mod wallet; pub mod callback; pub mod callback_u32; -pub mod return_types; -pub mod return_types_u32; pub mod pool; pub mod crypto; pub mod payments; +pub mod cache; +pub mod logger; -mod error_codes; +pub mod error_codes; extern crate libc; @@ -28,15 +28,17 @@ pub fn set_libindy_rc(rc: u32) {NEXT_LIBINDY_RC.lock().unwrap().push(rc as i32); static COMMAND_HANDLE_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; -fn next_i32_command_handle() -> i32 { +pub fn next_i32_command_handle() -> i32 { (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32 } -fn next_u32_command_handle() -> u32 { +pub fn next_u32_command_handle() -> u32 { (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as u32 } pub fn init_pool() -> Result<(), u32> { + trace!("init_pool >>>"); + if settings::test_indy_mode_enabled() {return Ok (()); } let pool_name = settings::get_config_value(settings::CONFIG_POOL_NAME) @@ -71,6 +73,6 @@ mod tests { wallet::close_wallet().unwrap(); pool::close().unwrap(); init_pool().unwrap(); - wallet::init_wallet(settings::DEFAULT_WALLET_NAME).unwrap(); + wallet::init_wallet(settings::DEFAULT_WALLET_NAME, None).unwrap(); } } diff --git a/vcx/libvcx/src/utils/libindy/payments.rs b/vcx/libvcx/src/utils/libindy/payments.rs index eaa664ae..7bf3a506 100644 --- a/vcx/libvcx/src/utils/libindy/payments.rs +++ b/vcx/libvcx/src/utils/libindy/payments.rs @@ -1,8 +1,10 @@ extern crate libc; extern crate serde_json; +use futures::Future; + use utils::libindy::wallet::get_wallet_handle; -use utils::constants::{ SUBMIT_SCHEMA_RESPONSE, TRANSFER_TXN_TYPE }; +use utils::constants::{SUBMIT_SCHEMA_RESPONSE, TRANSFER_TXN_TYPE}; use utils::libindy::error_codes::map_rust_indy_sdk_error_code; #[allow(unused_imports)] use utils::libindy::ledger::{libindy_submit_request, libindy_sign_and_submit_request, libindy_sign_request}; @@ -10,18 +12,13 @@ use utils::error; use error::payment::PaymentError; use error::ToErrorCode; -use indy::payments::Payment; +use indy::payments; use std::fmt; -use std::sync::{Once, ONCE_INIT}; use std::collections::HashMap; use serde_json::Value; use settings; -static EMPTY_CONFIG: &str = "{}"; -static DEFAULT_FEES: &str = r#"{"0":0, "1":0, "101":2, "10001":0, "102":42, "103":0, "104":0, "105":0, "107":0, "108":0, "109":0, "110":0, "111":0, "112":0, "113":0, "114":0, "115":0, "116":0, "117":0, "118":0, "119":0}"#; -static PARSED_TXN_PAYMENT_RESPONSE: &str = r#"[{"amount":4,"extra":null,"input":"["pov:null:1","pov:null:2"]"}]"#; - -static PAYMENT_INIT: Once = ONCE_INIT; +static DEFAULT_FEES: &str = r#"{"0":0, "1":0, "101":2, "10001":0, "102":42, "103":0, "104":0, "105":0, "107":0, "108":0, "109":0, "110":0, "111":0, "112":0, "113":2, "114":2, "115":0, "116":0, "117":0, "118":0, "119":0}"#; #[derive(Serialize, Deserialize, Debug)] pub struct WalletInfo { @@ -35,6 +32,7 @@ impl WalletInfo { self.balance } } + #[derive(Serialize, Deserialize, Debug)] pub struct AddressInfo { pub address: String, @@ -61,47 +59,13 @@ pub struct Output { impl fmt::Display for WalletInfo { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match serde_json::to_string(&self){ + match serde_json::to_string(&self) { Ok(s) => write!(f, "{}", s), Err(e) => write!(f, "null"), } } } -/// libnullpay -#[cfg(feature = "nullpay")] -extern { fn nullpay_init() -> i32; } - -#[cfg(feature = "nullpay")] -fn pay_init() -> i32 { unsafe { nullpay_init() } } - -#[cfg(feature = "nullpay")] -static PAYMENT_METHOD_NAME: &str = "null"; - -/// libsovtoken -#[cfg(feature = "sovtoken")] -extern { fn sovtoken_init() -> i32; } - -#[cfg(feature = "sovtoken")] -fn pay_init() -> i32 { unsafe { sovtoken_init() } } - -#[cfg(feature = "sovtoken")] -static PAYMENT_METHOD_NAME: &str = "sov"; - -pub fn init_payments() -> Result<(), u32> { - let mut rc = 0; - - PAYMENT_INIT.call_once(|| { - rc = pay_init(); - }); - - if rc != 0 { - Err(rc as u32) - } else { - Ok(()) - } -} - #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct PaymentTxn { pub amount: u64, @@ -113,11 +77,9 @@ pub struct PaymentTxn { impl PaymentTxn { pub fn from_parts(inputs: &str, outputs: &str, amount: u64, credit: bool) -> Result { let inputs: Vec = serde_json::from_str(&inputs) - .map_err(|err| {error::INVALID_JSON.code_num})?; - + .map_err(|err| { error::INVALID_JSON.code_num })?; let outputs: Vec = serde_json::from_str(&outputs) - .map_err(|err| {error::INVALID_JSON.code_num})?; - + .map_err(|err| { error::INVALID_JSON.code_num })?; Ok(PaymentTxn { amount, credit, @@ -127,32 +89,61 @@ impl PaymentTxn { } } +pub fn build_test_address(address: &str) -> String { + format!("pay:{}:{}", ::settings::get_payment_method(), address) +} + pub fn create_address(seed: Option) -> Result { - if settings::test_indy_mode_enabled() { return Ok(r#"pay:null:J81AxU9hVHYFtJc"#.to_string()); } + trace!("create_address >>> seed: {:?}", seed); + + if settings::test_indy_mode_enabled() { + return Ok(build_test_address("J81AxU9hVHYFtJc")); + } let config = match seed { Some(x) => format!("{{\"seed\":\"{}\"}}", x), None => format!("{{}}"), }; - Payment::create_payment_address(get_wallet_handle() as i32, PAYMENT_METHOD_NAME, &config) + payments::create_payment_address(get_wallet_handle() as i32, settings::get_payment_method().as_str(), &config) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn get_address_info(address: &str) -> Result { if settings::test_indy_mode_enabled() { - let utxo: Vec = serde_json::from_str(r#"[{"source":"pov:null:1","paymentAddress":"pay:null:zR3GN9lfbCVtHjp","amount":1,"extra":"yqeiv5SisTeUGkw"},{"source":"pov:null:2","paymentAddress":"pay:null:zR3GN9lfbCVtHjp","amount":2,"extra":"Lu1pdm7BuAN2WNi"}]"#).unwrap(); - return Ok(AddressInfo { address: address.to_string(), balance: _address_balance(&utxo), utxo}) + let utxos = json!( + [ + { + "source": build_test_address("1"), + "paymentAddress": build_test_address("zR3GN9lfbCVtHjp"), + "amount": 1, + "extra": "yqeiv5SisTeUGkw" + }, + { + "source": build_test_address("2"), + "paymentAddress": build_test_address("zR3GN9lfbCVtHjp"), + "amount": 2, + "extra": "Lu1pdm7BuAN2WNi" + } + ] + ); + + let utxo: Vec = serde_json::from_value(utxos).unwrap(); + + return Ok(AddressInfo { address: address.to_string(), balance: _address_balance(&utxo), utxo }); } let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID)?; - let (txn, _) = Payment::build_get_payment_sources_request(get_wallet_handle() as i32, Some(&did), address) + let (txn, _) = payments::build_get_payment_sources_request(get_wallet_handle() as i32, Some(&did), address) + .wait() .map_err(map_rust_indy_sdk_error_code)?; let response = libindy_sign_and_submit_request(&did, &txn)?; - let response = Payment::parse_get_payment_sources_response(PAYMENT_METHOD_NAME, &response) + let response = payments::parse_get_payment_sources_response(settings::get_payment_method().as_str(), &response) + .wait() .map_err(map_rust_indy_sdk_error_code)?; trace!("indy_parse_get_utxo_response() --> {}", response); @@ -163,10 +154,15 @@ pub fn get_address_info(address: &str) -> Result { pub fn list_addresses() -> Result, u32> { if settings::test_indy_mode_enabled() { - return Ok(serde_json::from_str(r#"["pay:null:9UFgyjuJxi1i1HD","pay:null:zR3GN9lfbCVtHjp"]"#).unwrap()); + let addresses = json!([ + build_test_address("9UFgyjuJxi1i1HD"), + build_test_address("zR3GN9lfbCVtHjp") + ]); + return Ok(serde_json::from_value(addresses).unwrap()); } - let addresses = Payment::list_payment_addresses(get_wallet_handle() as i32) + let addresses = payments::list_payment_addresses(get_wallet_handle() as i32) + .wait() .map_err(map_rust_indy_sdk_error_code)?; trace!("--> {}", addresses); @@ -174,6 +170,8 @@ pub fn list_addresses() -> Result, u32> { } pub fn get_wallet_token_info() -> Result { + trace!("get_wallet_token_info >>>"); + let addresses = list_addresses()?; let mut balance = 0; @@ -187,30 +185,49 @@ pub fn get_wallet_token_info() -> Result { wallet_info.push(info); } - Ok(WalletInfo { balance, balance_str: format!("{}", balance), addresses: wallet_info }) + let info = WalletInfo { balance, balance_str: format!("{}", balance), addresses: wallet_info }; + + trace!("get_wallet_token_info <<< info: {:?}", info); + ; + + Ok(info) } pub fn get_ledger_fees() -> Result { + trace!("get_ledger_fees >>>"); + if settings::test_indy_mode_enabled() { return Ok(DEFAULT_FEES.to_string()); } let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).or(Err(error::INVALID_CONFIGURATION.code_num))?; - let response = match Payment::build_get_txn_fees_req(get_wallet_handle() as i32, Some(&did), PAYMENT_METHOD_NAME) { + let response = match payments::build_get_txn_fees_req(get_wallet_handle() as i32, Some(&did), settings::get_payment_method().as_str()).wait() { Ok(txn) => libindy_sign_and_submit_request(&did, &txn)?, Err(x) => return Err(map_rust_indy_sdk_error_code(x)), }; - let res = Payment::parse_get_txn_fees_response(PAYMENT_METHOD_NAME, &response) + let res = payments::parse_get_txn_fees_response(settings::get_payment_method().as_str(), &response) + .wait() .map_err(map_rust_indy_sdk_error_code); res } pub fn pay_for_txn(req: &str, txn_type: &str) -> Result<(Option, String), u32> { debug!("pay_for_txn(req: {}, txn_type: {})", req, txn_type); - if settings::test_indy_mode_enabled() { return Ok((Some(PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap()), SUBMIT_SCHEMA_RESPONSE.to_string())); } + if settings::test_indy_mode_enabled() { + let inputs = format!(r#"["{}"]"#, build_test_address("9UFgyjuJxi1i1HD")); - let txn_price = get_txn_price(txn_type)?; + let outputs = format!(r#"[ + {{ + "amount": 1, + "extra": null, + "recipient": "{}" + }} + ]"#, build_test_address("xkIsxem0YNtHrRO")); + + return Ok((Some(PaymentTxn::from_parts(&inputs, &outputs, 1, false).unwrap()), SUBMIT_SCHEMA_RESPONSE.to_string())); + } + let txn_price = get_txn_price(txn_type)?; if txn_price == 0 { let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).or(Err(error::INVALID_CONFIGURATION.code_num))?; let txn_response = libindy_sign_and_submit_request(&did, req)?; @@ -232,19 +249,19 @@ fn _submit_fees_request(req: &str, inputs: &str, outputs: &str) -> Result<(Strin let req = libindy_sign_request(&did, req)?; - let (response, payment_method) = match Payment::add_request_fees(get_wallet_handle(), - Some(&did), - &req, - &inputs, - &outputs, - None) { + let (response, payment_method) = match payments::add_request_fees(get_wallet_handle(), + Some(&did), + &req, + &inputs, + &outputs, + None).wait() { Ok((req, payment_method)) => { (libindy_submit_request(&req)?, payment_method) - }, + } Err(x) => return Err(map_rust_indy_sdk_error_code(x)), }; - let parsed_response = match Payment::parse_response_with_fees(&payment_method, &response) { + let parsed_response = match payments::parse_response_with_fees(&payment_method, &response).wait() { Ok(x) => x, Err(x) => return Err(error::INVALID_LEDGER_RESPONSE.code_num), }; @@ -253,33 +270,46 @@ fn _submit_fees_request(req: &str, inputs: &str, outputs: &str) -> Result<(Strin } pub fn pay_a_payee(price: u64, address: &str) -> Result<(PaymentTxn, String), PaymentError> { - info!("sending {} tokens to address {}", price, address); + trace!("pay_a_payee >>> price: {}, address {}", price, address); + debug!("sending {} tokens to address {}", price, address); let ledger_cost = get_txn_price(TRANSFER_TXN_TYPE).map_err(|e| PaymentError::CommonError(e))?; let (remainder, input, refund_address) = inputs(price + ledger_cost)?; let output = outputs(remainder, &refund_address, Some(address.to_string()), Some(price))?; - let payment = PaymentTxn::from_parts(&input, &output, price, false).map_err(|e|PaymentError::CommonError(e))?; + let payment = PaymentTxn::from_parts(&input, &output, price, false).map_err(|e| PaymentError::CommonError(e))?; let my_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).or(Err(PaymentError::CommonError(error::INVALID_CONFIGURATION.code_num)))?; - if settings::test_indy_mode_enabled() { return Ok((PaymentTxn::from_parts(r#"["pay:null:9UFgyjuJxi1i1HD"]"#,r#"[{"amount":4,"extra":null,"recipient":"pay:null:xkIsxem0YNtHrRO"}]"#,1, false).unwrap(), SUBMIT_SCHEMA_RESPONSE.to_string())); } + if settings::test_indy_mode_enabled() { + let inputs = format!(r#"["{}"]"#, build_test_address("9UFgyjuJxi1i1HD")); + + let outputs = format!(r#"[ + {{ + "amount": 1, + "extra": null, + "recipient": "{}" + }} + ]"#, build_test_address("xkIsxem0YNtHrRO")); - match Payment::build_payment_req(get_wallet_handle(), Some(&my_did), &input, &output, None) { + return Ok((PaymentTxn::from_parts(&inputs, &outputs, 1, false).unwrap(), SUBMIT_SCHEMA_RESPONSE.to_string())); + } + + match payments::build_payment_req(get_wallet_handle(), Some(&my_did), &input, &output, None).wait() { Ok((request, payment_method)) => { - let result = libindy_submit_request( &request).map_err(|ec| PaymentError::CommonError(ec))?; + let result = libindy_submit_request(&request).map_err(|ec| PaymentError::CommonError(ec))?; Ok((payment, result)) - }, + } Err(ec) => { error!("error: {:?}", ec); Err(PaymentError::CommonError(ec as u32)) - }, + } } } fn get_txn_price(txn_type: &str) -> Result { let ledger_fees = get_ledger_fees()?; - let fees: HashMap = serde_json::from_str(&ledger_fees) .or(Err(error::INVALID_JSON.code_num))?; + let fees: HashMap = serde_json::from_str(&ledger_fees).or(Err(error::INVALID_JSON.code_num))?; match fees.get(txn_type) { Some(x) => Ok(*x), @@ -340,6 +370,9 @@ pub fn outputs(remainder: u64, refund_address: &str, payee_address: Option, tokens_per_address: Option, fees: Option, seed: Option) -> Result<(), u32> { + trace!("mint_tokens_and_set_fees >>> number_of_addresses: {:?}, tokens_per_address: {:?}, fees: {:?}, seed: {:?}", + number_of_addresses, tokens_per_address, fees, seed); + let did_1 = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let fees = if fees.is_some() { @@ -366,8 +399,7 @@ pub fn mint_tokens_and_set_fees(number_of_addresses: Option, tokens_per_add json!( { "recipient": payment_address, "amount": tokens_per_address } ) ).collect(); let outputs = serde_json::to_string(&mint).unwrap(); - - let (req, _) = Payment::build_mint_req(get_wallet_handle() as i32, Some(&did_1), &outputs, None).unwrap(); + let (req, _) = payments::build_mint_req(get_wallet_handle() as i32, Some(&did_1), &outputs, None).wait().unwrap(); let sign1 = ::utils::libindy::ledger::multisign_request(&did_1, &req).unwrap(); let sign2 = ::utils::libindy::ledger::multisign_request(&did_2, &sign1).unwrap(); @@ -381,7 +413,8 @@ pub fn mint_tokens_and_set_fees(number_of_addresses: Option, tokens_per_add } if fees.is_some() { - let txn = Payment::build_set_txn_fees_req(get_wallet_handle() as i32, Some(&did_1), PAYMENT_METHOD_NAME, fees.unwrap()) + let txn = payments::build_set_txn_fees_req(get_wallet_handle() as i32, Some(&did_1), settings::get_payment_method().as_str(), fees.unwrap()) + .wait() .map_err(map_rust_indy_sdk_error_code)?; let sign1 = ::utils::libindy::ledger::multisign_request(&did_1, &txn).unwrap(); @@ -394,49 +427,42 @@ pub fn mint_tokens_and_set_fees(number_of_addresses: Option, tokens_per_add Ok(()) } - + fn add_new_trustee_did() -> Result<(String, String), u32> { - use indy::ledger::Ledger; + use indy::ledger; let institution_did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap(); let (did, verkey) = ::utils::libindy::signus::create_and_store_my_did(None).unwrap(); - let req_nym = Ledger::build_nym_request(&institution_did, &did, Some(&verkey), None, Some("TRUSTEE")).map_err(map_rust_indy_sdk_error_code)?; + let req_nym = ledger::build_nym_request(&institution_did, &did, Some(&verkey), None, Some("TRUSTEE")) + .wait() + .map_err(map_rust_indy_sdk_error_code)?; ::utils::libindy::ledger::libindy_sign_and_submit_request(&institution_did, &req_nym)?; Ok((did, verkey)) } - + #[cfg(test)] pub mod tests { use super::*; pub fn token_setup(number_of_addresses: Option, tokens_per_address: Option) { - init_payments().unwrap_or(()); mint_tokens_and_set_fees(number_of_addresses, tokens_per_address, Some(DEFAULT_FEES.to_string()), None).unwrap(); } fn get_my_balance() -> u64 { - let info:WalletInfo = get_wallet_token_info().unwrap(); + let info: WalletInfo = get_wallet_token_info().unwrap(); info.balance } - #[test] - fn test_init_payments() { - init!("true"); - init_payments().unwrap(); - } - #[test] fn test_create_address() { init!("true"); - init_payments().unwrap(); create_address(None).unwrap(); } #[test] fn test_get_addresses() { init!("true"); - init_payments().unwrap(); create_address(None).unwrap(); let addresses = list_addresses().unwrap(); } @@ -446,7 +472,53 @@ pub mod tests { init!("true"); create_address(None).unwrap(); let balance = get_wallet_token_info().unwrap().to_string(); - assert_eq!(balance, r#"{"balance":6,"balance_str":"6","addresses":[{"address":"pay:null:9UFgyjuJxi1i1HD","balance":3,"utxo":[{"source":"pov:null:1","paymentAddress":"pay:null:zR3GN9lfbCVtHjp","amount":1,"extra":"yqeiv5SisTeUGkw"},{"source":"pov:null:2","paymentAddress":"pay:null:zR3GN9lfbCVtHjp","amount":2,"extra":"Lu1pdm7BuAN2WNi"}]},{"address":"pay:null:zR3GN9lfbCVtHjp","balance":3,"utxo":[{"source":"pov:null:1","paymentAddress":"pay:null:zR3GN9lfbCVtHjp","amount":1,"extra":"yqeiv5SisTeUGkw"},{"source":"pov:null:2","paymentAddress":"pay:null:zR3GN9lfbCVtHjp","amount":2,"extra":"Lu1pdm7BuAN2WNi"}]}]}"#); + + let expected_balance = json!({ + "balance":6, + "balance_str":"6", + "addresses":[ + { + "address": build_test_address("9UFgyjuJxi1i1HD"), + "balance":3, + "utxo":[ + { + "source": build_test_address("1"), + "paymentAddress":build_test_address("zR3GN9lfbCVtHjp"), + "amount":1, + "extra":"yqeiv5SisTeUGkw" + }, + { + "source":build_test_address("2"), + "paymentAddress":build_test_address("zR3GN9lfbCVtHjp"), + "amount":2, + "extra":"Lu1pdm7BuAN2WNi" + } + ] + }, + { + "address":build_test_address("zR3GN9lfbCVtHjp"), + "balance":3, + "utxo":[ + { + "source":build_test_address("1"), + "paymentAddress":build_test_address("zR3GN9lfbCVtHjp"), + "amount":1, + "extra":"yqeiv5SisTeUGkw" + }, + { + "source":build_test_address("2"), + "paymentAddress":build_test_address("zR3GN9lfbCVtHjp"), + "amount":2, + "extra":"Lu1pdm7BuAN2WNi" + } + ] + } + ] + }); + + let balance: serde_json::Value = serde_json::from_str(&balance).unwrap(); + + assert_eq!(balance, expected_balance); } #[cfg(feature = "pool_tests")] @@ -477,8 +549,8 @@ pub mod tests { #[test] fn test_address_balance() { let addresses = vec![ - UTXO { source: Some("pov::null:2".to_string()), recipient: "pay:null:J81AxU9hVHYFtJc".to_string(), amount: 2, extra: Some("abcde".to_string()) }, - UTXO { source: Some("pov::null:3".to_string()), recipient: "pay:null:J81AxU9hVHYFtJc".to_string(), amount: 3, extra: Some("bcdef".to_string()) } + UTXO { source: Some(build_test_address("2")), recipient: build_test_address("J81AxU9hVHYFtJc"), amount: 2, extra: Some("abcde".to_string()) }, + UTXO { source: Some(build_test_address("3")), recipient: build_test_address("J81AxU9hVHYFtJc"), amount: 3, extra: Some("bcdef".to_string()) } ]; assert_eq!(_address_balance(&addresses), 5); @@ -488,14 +560,20 @@ pub mod tests { fn test_inputs() { init!("true"); + let pay_addr_1 = build_test_address("1"); + let pay_addr_2 = build_test_address("2"); + // Success - Exact amount - assert_eq!(inputs(6).unwrap(), (0, r#"["pov:null:1","pov:null:2","pov:null:1","pov:null:2"]"#.to_string(), "pay:null:zR3GN9lfbCVtHjp".to_string())); + let expected_inputs = format!(r#"["{}","{}","{}","{}"]"#, pay_addr_1, pay_addr_2, pay_addr_1, pay_addr_2); + assert_eq!(inputs(6).unwrap(), (0, expected_inputs, build_test_address("zR3GN9lfbCVtHjp"))); // Success - utxo with remainder tokens - assert_eq!(inputs(5).unwrap(), (1, r#"["pov:null:1","pov:null:2","pov:null:1","pov:null:2"]"#.to_string(), "pay:null:zR3GN9lfbCVtHjp".to_string())); + let expected_inputs = format!(r#"["{}","{}","{}","{}"]"#, pay_addr_1, pay_addr_2, pay_addr_1, pay_addr_2); + assert_eq!(inputs(5).unwrap(), (1, expected_inputs, build_test_address("zR3GN9lfbCVtHjp"))); // Success - requesting amount that partial address (1 of 2 utxos) can satisfy - assert_eq!(inputs(1).unwrap(), (0, r#"["pov:null:1"]"#.to_string(), "pay:null:9UFgyjuJxi1i1HD".to_string())); + let expected_inputs = format!(r#"["{}"]"#, pay_addr_1); + assert_eq!(inputs(1).unwrap(), (0, expected_inputs, build_test_address("9UFgyjuJxi1i1HD"))); // Err - request more than wallet contains assert_eq!(inputs(7).err(), Some(PaymentError::InsufficientFunds())); @@ -523,10 +601,10 @@ pub mod tests { init!("true"); let payee_amount = 11; - let payee_address = r#"pay:null:payee_address"#.to_string(); - let refund_address = r#"pay:null:refund_address"#; + let payee_address = build_test_address("payee_address"); + let refund_address = build_test_address("refund_address"); let expected_output = format!(r#"[{{"amount":4,"recipient":"{}"}},{{"amount":11,"recipient":"{}"}}]"#, refund_address, payee_address); - assert_eq!(outputs(4, refund_address, Some(payee_address), Some(payee_amount)).unwrap(), expected_output); + assert_eq!(outputs(4, refund_address.as_str(), Some(payee_address), Some(payee_amount)).unwrap(), expected_output); } #[test] @@ -574,7 +652,7 @@ pub mod tests { let (_, schema_json) = ::utils::libindy::anoncreds::tests::create_schema(::utils::constants::DEFAULT_SCHEMA_ATTRS); let create_schema_req = ::utils::libindy::anoncreds::tests::create_schema_req(&schema_json); - let rc= pay_for_txn(&create_schema_req, "101"); + let rc = pay_for_txn(&create_schema_req, "101"); assert!(rc.is_err()); } @@ -582,33 +660,51 @@ pub mod tests { #[cfg(feature = "pool_tests")] #[test] fn test_build_payment_request() { - use utils::constants::PAYMENT_ADDRESS; - ::utils::logger::LoggerUtils::init_test_logging("trace"); init!("ledger"); + + let payment_address = build_test_address("2ZrAm5Jc3sP4NAXMQbaWzDxEa12xxJW3VgWjbbPtMPQCoznJyS"); + let payment_address = payment_address.as_str(); + let price = get_my_balance(); - let result_from_paying = pay_a_payee(price, PAYMENT_ADDRESS); + let result_from_paying = pay_a_payee(price, payment_address); assert!(result_from_paying.is_ok()); assert_eq!(get_my_balance(), 0); mint_tokens_and_set_fees(None, None, None, None).unwrap(); assert_eq!(get_my_balance(), 50000000000); let price = get_my_balance() - 5; - let result_from_paying = pay_a_payee(price, PAYMENT_ADDRESS); + let result_from_paying = pay_a_payee(price, payment_address); assert!(result_from_paying.is_ok()); assert_eq!(get_my_balance(), 5); let price = get_my_balance() + 5; - let result_from_paying = pay_a_payee(price, PAYMENT_ADDRESS); + let result_from_paying = pay_a_payee(price, payment_address); assert_eq!(result_from_paying.err(), Some(PaymentError::InsufficientFunds())); assert_eq!(get_my_balance(), 5); } + // this test if failing to to both changes in error codes being produced + // by master libindy and how wallets are deleted. + #[cfg(feature = "pool_tests")] + #[test] + #[ignore] + fn test_build_payment_request_bogus_payment_method() { + init!("ledger"); + let payment_address = "pay:bogus:123"; + let result_from_paying = pay_a_payee(0, payment_address); + + assert!(result_from_paying.is_err()); + assert_eq!(result_from_paying.err(), Some(PaymentError::CommonError(error::UNKNOWN_LIBINDY_ERROR.code_num))); + } + #[cfg(feature = "pool_tests")] #[test] fn test_fees_transferring_tokens() { - use utils::constants::PAYMENT_ADDRESS; init!("ledger"); + let payment_address = build_test_address("2ZrAm5Jc3sP4NAXMQbaWzDxEa12xxJW3VgWjbbPtMPQCoznJyS"); + let payment_address = payment_address.as_str(); + let initial_wallet_balance = 100000000000; let transfer_fee = 5; let ledger_fees = json!({"10001": transfer_fee}).to_string(); @@ -619,7 +715,7 @@ pub mod tests { // Transfer everything besides 50. Remaining balance will be 50 - ledger fees let balance_after_transfer = 50; let price = get_my_balance() - balance_after_transfer; - let result_from_paying = pay_a_payee(price, PAYMENT_ADDRESS); + let result_from_paying = pay_a_payee(price, payment_address); assert!(result_from_paying.is_ok()); assert_eq!(get_my_balance(), balance_after_transfer - transfer_fee); @@ -627,7 +723,7 @@ pub mod tests { let not_enough_for_ledger_fee = transfer_fee - 1; let price = get_my_balance() - not_enough_for_ledger_fee; assert!(price > 0); - let result_from_paying = pay_a_payee(price, PAYMENT_ADDRESS); + let result_from_paying = pay_a_payee(price, payment_address); assert_eq!(result_from_paying.err(), Some(PaymentError::CommonError(error::INSUFFICIENT_TOKEN_AMOUNT.code_num))); } @@ -650,12 +746,11 @@ pub mod tests { let rc = _submit_fees_request(&req, &inputs, &output); } - #[cfg(feature = "nullpay")] #[cfg(feature = "pool_tests")] #[test] fn test_pay_for_txn_with_empty_outputs_success() { init!("ledger"); - let (_, schema_json) = ::utils::libindy::anoncreds::tests::create_schema(); + let (_, schema_json) = ::utils::libindy::anoncreds::tests::create_schema(::utils::constants::DEFAULT_SCHEMA_ATTRS); let req = ::utils::libindy::anoncreds::tests::create_schema_req(&schema_json); let cost = 45; diff --git a/vcx/libvcx/src/utils/libindy/pool.rs b/vcx/libvcx/src/utils/libindy/pool.rs index b3c0f094..ddf46d9d 100644 --- a/vcx/libvcx/src/utils/libindy/pool.rs +++ b/vcx/libvcx/src/utils/libindy/pool.rs @@ -1,9 +1,11 @@ extern crate libc; -use utils::{ error, timeout::TimeoutUtils }; +use futures::Future; + +use utils::error; use std::sync::RwLock; use settings; -use indy::pool::Pool; +use indy::pool; use indy::ErrorCode; use utils::libindy::error_codes::map_rust_indy_sdk_error_code; @@ -17,7 +19,7 @@ pub fn change_pool_handle(handle: Option){ } pub fn set_protocol_version() -> u32 { - match Pool::set_protocol_version(2) { + match pool::set_protocol_version(settings::get_protocol_version()).wait() { Ok(_) => error::SUCCESS.code_num, Err(_) => error::UNKNOWN_LIBINDY_ERROR.code_num, } @@ -26,7 +28,7 @@ pub fn set_protocol_version() -> u32 { pub fn create_pool_ledger_config(pool_name: &str, path: &str) -> Result<(), u32> { let pool_config = format!(r#"{{"genesis_txn":"{}"}}"#, path); - match Pool::create_ledger_config(pool_name, Some(&pool_config)) { + match pool::create_pool_ledger_config(pool_name, Some(&pool_config)).wait() { Ok(_) => Ok(()), Err(x) => if x != ErrorCode::PoolLedgerConfigAlreadyExistsError { Err(error::UNKNOWN_LIBINDY_ERROR.code_num) @@ -40,7 +42,8 @@ pub fn open_pool_ledger(pool_name: &str, config: Option<&str>) -> Result { change_pool_handle(Some(x)); Ok(x as u32) @@ -52,16 +55,19 @@ pub fn open_pool_ledger(pool_name: &str, config: Option<&str>) -> Result Result<(), u32> { let handle = get_pool_handle()?; change_pool_handle(None); - Pool::close_timeout(handle, TimeoutUtils::medium_timeout()).map_err(map_rust_indy_sdk_error_code) + //TODO there was timeout here (before future-based Rust wrapper) + pool::close_pool_ledger(handle).wait().map_err(map_rust_indy_sdk_error_code) } pub fn delete(pool_name: &str) -> Result<(), u32> { + trace!("delete >>> pool_name: {}", pool_name); + if settings::test_indy_mode_enabled() { change_pool_handle(None); return Ok(()) } - Pool::delete(pool_name).map_err(map_rust_indy_sdk_error_code) + pool::delete_pool_ledger(pool_name).wait().map_err(map_rust_indy_sdk_error_code) } pub fn get_pool_handle() -> Result { @@ -73,7 +79,10 @@ pub mod tests { use super::*; use std::fs; use std::io::Write; - use utils::constants::{POOL, GENESIS_PATH}; + use utils::{ + constants::{POOL, GENESIS_PATH}, + get_temp_dir_path + }; pub fn delete_test_pool() { match delete(POOL) { @@ -84,7 +93,7 @@ pub mod tests { pub fn open_sandbox_pool() -> u32 { create_genesis_txn_file(); - create_pool_ledger_config(POOL, GENESIS_PATH).unwrap(); + create_pool_ledger_config(POOL, get_temp_dir_path(Some(GENESIS_PATH)).to_str().unwrap()).unwrap(); open_pool_ledger(POOL, None).unwrap() } @@ -96,11 +105,12 @@ pub mod tests { } pub fn create_genesis_txn_file() { - let test_pool_ip = "127.0.0.1".to_string(); + let test_pool_ip = ::std::env::var("TEST_POOL_IP").unwrap_or("127.0.0.1".to_string()); + let node_txns = get_txns(&test_pool_ip); let txn_file_data = node_txns[0..4].join("\n"); - let mut f = fs::File::create(GENESIS_PATH).unwrap(); + let mut f = fs::File::create(get_temp_dir_path(Some(GENESIS_PATH)).to_str().unwrap()).unwrap(); f.write_all(txn_file_data.as_bytes()).unwrap(); f.flush().unwrap(); f.sync_all().unwrap(); diff --git a/vcx/libvcx/src/utils/libindy/return_types.rs b/vcx/libvcx/src/utils/libindy/return_types.rs deleted file mode 100644 index 4e0f4b19..00000000 --- a/vcx/libvcx/src/utils/libindy/return_types.rs +++ /dev/null @@ -1,375 +0,0 @@ -extern crate libc; - -use self::libc::c_char; -use std::sync::mpsc::Receiver; -use std::sync::mpsc::RecvTimeoutError; -use utils::libindy::next_i32_command_handle; -use utils::libindy::callback; -use utils::libindy::error_codes::map_indy_error; -use utils::timeout::TimeoutUtils; -use utils::error; -use std::sync::mpsc::channel; -use std::fmt::Display; -use std::time::Duration; -use std::collections::HashMap; -use std::sync::Mutex; -use std::ops::Deref; - -fn log_error(e: T) { - warn!("Unable to send through libindy callback in vcx: {}", e); -} - -fn insert_closure(closure: T, map: &Mutex>) -> i32 { - let command_handle = next_i32_command_handle(); - { - let mut callbacks = map.lock().expect(callback::POISON_MSG); - callbacks.insert(command_handle, closure); - } - command_handle -} - -pub fn receive(receiver: &Receiver, timeout: Option) -> Result{ - let timeout_val = timeout.unwrap_or(TimeoutUtils::medium_timeout()); - - match receiver.recv_timeout(timeout_val) { - Ok(t) => Ok(t), - Err(e) => match e { - RecvTimeoutError::Timeout => { - warn!("Timed Out waiting for libindy to call back"); - Err(error::TIMEOUT_LIBINDY_ERROR.code_num) - }, - RecvTimeoutError::Disconnected => { - warn!("Channel to libindy was disconnected unexpectedly"); - Err(error::TIMEOUT_LIBINDY_ERROR.code_num) - } - } - } -} - -#[allow(non_camel_case_types)] -pub struct Return_I32 { - pub command_handle: i32, - pub receiver: Receiver, -} - -impl Return_I32 { - pub fn new() -> Result { - let (sender, receiver) = channel(); - let closure: Box = Box::new(move |err | { - sender.send(err).unwrap_or_else(log_error); - }); - - let command_handle = insert_closure(closure, callback::CALLBACKS_I32.deref()); - - Ok(Return_I32 { - command_handle, - receiver, - }) - } - - pub fn get_callback(&self) -> extern fn(command_handle: i32, arg1: i32) { - callback::call_cb_i32 - } - - pub fn receive(&self, timeout: Option) -> Result<(), u32> { - let err = receive(&self.receiver, timeout)?; - map_indy_error((), err) - } -} - -#[allow(non_camel_case_types)] -pub struct Return_I32_I32 { - pub command_handle: i32, - pub receiver: Receiver<(i32, i32)>, -} -impl Return_I32_I32 { - pub fn new() -> Result { - let (sender, receiver) = channel(); - let closure: Box = Box::new(move |err, arg1 | { - sender.send((err, arg1)).unwrap_or_else(log_error); - }); - - let command_handle = insert_closure(closure, callback::CALLBACKS_I32_I32.deref()); - - Ok(Return_I32_I32 { - command_handle, - receiver, - }) - } - - pub fn get_callback(&self) -> extern fn (command_handle: i32, arg1: i32, arg2: i32) { - callback::call_cb_i32_i32 - } - - pub fn receive(&self, timeout: Option) -> Result { - let (err, arg1) = receive(&self.receiver, timeout)?; - - map_indy_error(arg1, err) - } -} - - -#[allow(non_camel_case_types)] -pub struct Return_I32_STR { - pub command_handle: i32, - pub receiver: Receiver<(i32, Option)>, -} -impl Return_I32_STR { - pub fn new() -> Result { - let (sender, receiver) = channel(); - let closure:Box) + Send> = Box::new(move |err, str | { - sender.send((err, str)).unwrap_or_else(log_error); - }); - - let command_handle = insert_closure(closure, callback::CALLBACKS_I32_STR.deref()); - - Ok(Return_I32_STR { - command_handle, - receiver, - }) - } - - pub fn get_callback(&self) -> extern fn(command_handle: i32, arg1: i32, arg2: *const c_char) { - callback::call_cb_i32_str - } - - pub fn receive(&self, timeout: Option) -> Result, u32> { - let (err, str1) = receive(&self.receiver, timeout)?; - map_indy_error(str1, err) - } -} - -#[allow(non_camel_case_types)] -pub struct Return_I32_STR_STR { - pub command_handle: i32, - receiver: Receiver<(i32, Option, Option)>, -} -impl Return_I32_STR_STR { - pub fn new() -> Result { - let (sender, receiver) = channel(); - let closure:Box, Option) + Send> = Box::new(move |err, str1, str2 | { - sender.send((err, str1, str2)).unwrap_or_else(log_error); - }); - - let command_handle = insert_closure(closure, callback::CALLBACKS_I32_STR_STR.deref()); - - Ok(Return_I32_STR_STR { - command_handle, - receiver, - }) - } - - pub fn get_callback(&self) -> extern fn(command_handle: i32, - arg1: i32, - arg2: *const c_char, - arg3: *const c_char) { - callback::call_cb_i32_str_str - } - - pub fn receive(&self, timeout: Option) -> Result<(Option, Option), u32> { - let (err, mut str1, mut str2) = receive(&self.receiver, timeout)?; - - str1 = map_indy_error(str1, err)?; - str2 = map_indy_error(str2, err)?; - Ok((str1, str2)) - } -} - -#[allow(non_camel_case_types)] -pub struct Return_I32_STR_STR_STR { - pub command_handle: i32, - receiver: Receiver<(i32, Option, Option, Option)>, -} -impl Return_I32_STR_STR_STR { - pub fn new() -> Result { - let (sender, receiver) = channel(); - let closure:Box, Option, Option) + Send> = Box::new(move |err, str1, str2, str3 | { - sender.send((err, str1, str2, str3)).unwrap_or_else(log_error); - }); - - let command_handle = insert_closure(closure, callback::CALLBACKS_I32_STR_STR_STR.deref()); - - Ok(Return_I32_STR_STR_STR { - command_handle, - receiver, - }) - } - - pub fn get_callback(&self) -> extern fn(command_handle: i32, - arg1: i32, - arg2: *const c_char, - arg3: *const c_char, - arg4: *const c_char) { - callback::call_cb_i32_str_str_str - } - - pub fn receive(&self, timeout: Option) -> Result<(Option, Option, Option), u32> { - let (err, mut str1, mut str2, mut str3) = receive(&self.receiver, timeout)?; - - str1 = map_indy_error(str1, err)?; - str2 = map_indy_error(str2, err)?; - str3 = map_indy_error(str3, err)?; - Ok((str1, str2, str3)) - } -} - -#[allow(non_camel_case_types)] -pub struct Return_I32_BOOL { - pub command_handle: i32, - receiver: Receiver<(i32, bool)>, -} - -impl Return_I32_BOOL { - pub fn new() -> Result { - let (sender, receiver) = channel(); - let closure: Box = Box::new(move |err, arg1 | { - sender.send((err, arg1)).unwrap_or_else(log_error); - }); - - let command_handle = insert_closure(closure, callback::CALLBACKS_I32_BOOL.deref()); - - Ok(Return_I32_BOOL { - command_handle, - receiver, - }) - } - - pub fn get_callback(&self) -> extern fn (command_handle: i32, arg1: i32, arg2: bool) { - callback::call_cb_i32_bool - } - - pub fn receive(&self, timeout: Option) -> Result { - let (err, arg1) = receive(&self.receiver, timeout)?; - - map_indy_error(arg1, err)?; - Ok(arg1) - } -} - -#[allow(non_camel_case_types)] -pub struct Return_I32_BIN { - pub command_handle: i32, - receiver: Receiver<(i32, Vec)>, -} - -impl Return_I32_BIN { - pub fn new() -> Result { - let (sender, receiver) = channel(); - let closure: Box) + Send> = Box::new(move |err, arg1| { - sender.send((err, arg1)).unwrap_or_else(log_error); - }); - - let command_handle = insert_closure(closure, callback::CALLBACKS_I32_BIN.deref()); - - Ok(Return_I32_BIN { - command_handle, - receiver, - }) - } - - pub fn get_callback(&self) -> extern fn (command_handle: i32, arg1: i32, *const u8, u32) { - callback::call_cb_i32_bin - } - - pub fn receive(&self, timeout: Option) -> Result, u32> { - let (err, arg1) = receive(&self.receiver, timeout)?; - - map_indy_error(arg1, err) - } -} - -#[allow(non_camel_case_types)] -pub struct Return_I32_OPTSTR_BIN { - pub command_handle: i32, - receiver: Receiver<(i32, Option, Vec)>, -} - -impl Return_I32_OPTSTR_BIN { - pub fn new() -> Result { - let (sender, receiver) = channel(); - let closure: Box, Vec) + Send> = Box::new(move |err, arg1, arg2| { - sender.send((err, arg1, arg2)).unwrap_or_else(log_error); - }); - - let command_handle = insert_closure(closure, callback::CALLBACKS_I32_OPTSTR_BIN.deref()); - - Ok(Return_I32_OPTSTR_BIN { - command_handle, - receiver, - }) - } - - pub fn get_callback(&self) -> extern fn (command_handle: i32, arg1: i32, arg2: *const c_char, arg3: *const u8, arg4: u32) { - callback::call_cb_i32_str_bin - } - - pub fn receive(&self, timeout: Option) -> Result<(Option, Vec), u32> { - let (err, arg1, mut arg2) = receive(&self.receiver, timeout)?; - - arg2 = map_indy_error(arg2, err)?; - Ok((arg1, arg2)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::ffi::CString; - use std::ptr; - - fn cstring(str_val: &String) -> CString { - CString::new(str_val.clone()).unwrap() - } - - #[test] - fn test_return_i32() { - let rtn = Return_I32::new().unwrap(); - rtn.get_callback()(rtn.command_handle, 0); - let val = rtn.receive(None); - assert!(val.is_ok()); - - let rtn = Return_I32::new().unwrap(); - rtn.get_callback()(rtn.command_handle, 123); - let val = rtn.receive(None); - assert!(val.is_err()); - } - - #[test] - fn test_return_i32_i32() { - let test_val = 23455; - - let rtn = Return_I32_I32::new().unwrap(); - rtn.get_callback()(rtn.command_handle, 0, test_val); - let val = rtn.receive(None); - assert!(val.is_ok()); - assert_eq!(val.unwrap(), test_val); - - let rtn = Return_I32_I32::new().unwrap(); - rtn.get_callback()(rtn.command_handle, 123, test_val); - let val = rtn.receive(None); - assert!(val.is_err()); - } - - #[test] - fn test_return_i32_str() { - let test_str = "Journey before destination".to_string(); - - let rtn = Return_I32_STR::new().unwrap(); - rtn.get_callback()(rtn.command_handle, 0, cstring(&test_str).as_ptr()); - let val = rtn.receive(None); - assert!(val.is_ok()); - assert_eq!(val.unwrap(), Some(test_str.clone())); - - let rtn = Return_I32_STR::new().unwrap(); - rtn.get_callback()(rtn.command_handle, 0, ptr::null()); - let val = rtn.receive(None); - assert!(val.is_ok()); - assert_eq!(val.unwrap(), None); - - let rtn = Return_I32_STR::new().unwrap(); - rtn.get_callback()(rtn.command_handle, 123, cstring(&test_str).as_ptr()); - let val = rtn.receive(None); - assert!(val.is_err()); - } - -} diff --git a/vcx/libvcx/src/utils/libindy/signus.rs b/vcx/libvcx/src/utils/libindy/signus.rs index f6674017..fdd364f1 100644 --- a/vcx/libvcx/src/utils/libindy/signus.rs +++ b/vcx/libvcx/src/utils/libindy/signus.rs @@ -1,8 +1,10 @@ extern crate libc; +use futures::Future; + use settings; use utils::libindy::error_codes::map_rust_indy_sdk_error_code; -use indy::did::Did; +use indy::did; pub fn create_and_store_my_did(seed: Option<&str>) -> Result<(String, String), u32> { if settings::test_indy_mode_enabled() { @@ -10,7 +12,9 @@ pub fn create_and_store_my_did(seed: Option<&str>) -> Result<(String, String), u } let my_did_json = seed.map_or("{}".to_string(), |seed| format!("{{\"seed\":\"{}\" }}", seed)); - Did::new(::utils::libindy::wallet::get_wallet_handle(), &my_did_json).map_err(map_rust_indy_sdk_error_code) + did::create_and_store_my_did(::utils::libindy::wallet::get_wallet_handle(), &my_did_json) + .wait() + .map_err(map_rust_indy_sdk_error_code) } pub fn get_local_verkey(did: &str) -> Result { @@ -18,5 +22,7 @@ pub fn get_local_verkey(did: &str) -> Result { return Ok(::utils::constants::VERKEY.to_string()); } - Did::get_ver_key_local(::utils::libindy::wallet::get_wallet_handle(), did).map_err(map_rust_indy_sdk_error_code) + did::key_for_local_did(::utils::libindy::wallet::get_wallet_handle(), did) + .wait() + .map_err(map_rust_indy_sdk_error_code) } diff --git a/vcx/libvcx/src/utils/libindy/wallet.rs b/vcx/libvcx/src/utils/libindy/wallet.rs index ae82cb53..12b9b396 100644 --- a/vcx/libvcx/src/utils/libindy/wallet.rs +++ b/vcx/libvcx/src/utils/libindy/wallet.rs @@ -1,23 +1,28 @@ extern crate libc; extern crate serde_json; +use futures::Future; + use settings; use utils::libindy::error_codes::map_rust_indy_sdk_error_code; use utils::error; use error::wallet::WalletError; -use indy::wallet::Wallet; +use indy::wallet; use indy::ErrorCode; use std::path::Path; pub static mut WALLET_HANDLE: i32 = 0; pub fn get_wallet_handle() -> i32 { unsafe { WALLET_HANDLE } } -pub fn create_wallet(wallet_name: &str) -> Result<(), u32> { +pub fn create_wallet(wallet_name: &str, wallet_type: Option<&str>) -> Result<(), u32> { trace!("creating wallet: {}", wallet_name); - let config = format!(r#"{{"id":"{}"}}"#, wallet_name); + let config = json!({ + "id": wallet_name, + "storage_type": wallet_type + }).to_string(); - match Wallet::create(&config, &settings::get_wallet_credentials()) { + match wallet::create_wallet(&config, &settings::get_wallet_credentials()).wait() { Ok(x) => Ok(()), Err(x) => if x != ErrorCode::WalletAlreadyExistsError && x != ErrorCode::Success { warn!("could not create wallet {}: {:?}", wallet_name, x); @@ -29,43 +34,51 @@ pub fn create_wallet(wallet_name: &str) -> Result<(), u32> { } } -pub fn open_wallet(wallet_name: &str) -> Result { - trace!("opening wallet: {}", wallet_name); +pub fn open_wallet(wallet_name: &str, wallet_type: Option<&str>) -> Result { + trace!("open_wallet >>> wallet_name: {}", wallet_name); if settings::test_indy_mode_enabled() { unsafe {WALLET_HANDLE = 1;} return Ok(1); } - let config = format!(r#"{{"id":"{}"}}"#, wallet_name); + let config = json!({ + "id": wallet_name, + "storage_type": wallet_type + }).to_string(); - let handle = Wallet::open(&config, &settings::get_wallet_credentials()) + let handle = wallet::open_wallet(&config, &settings::get_wallet_credentials()) + .wait() .map_err(map_rust_indy_sdk_error_code)?; unsafe { WALLET_HANDLE = handle; } Ok(handle) } -pub fn init_wallet(wallet_name: &str) -> Result { +pub fn init_wallet(wallet_name: &str, wallet_type: Option<&str>) -> Result { if settings::test_indy_mode_enabled() { unsafe {WALLET_HANDLE = 1;} return Ok(1); } - create_wallet(wallet_name)?; - open_wallet(wallet_name) + create_wallet(wallet_name, wallet_type)?; + open_wallet(wallet_name, wallet_type) } pub fn close_wallet() -> Result<(), u32> { + trace!("close_wallet >>>"); + if settings::test_indy_mode_enabled() { unsafe { WALLET_HANDLE = 0; } return Ok(()); } - let result = Wallet::close(get_wallet_handle()).map_err(map_rust_indy_sdk_error_code); + let result = wallet::close_wallet(get_wallet_handle()).wait().map_err(map_rust_indy_sdk_error_code); unsafe { WALLET_HANDLE = 0; } result } -pub fn delete_wallet(wallet_name: &str) -> Result<(), u32> { +pub fn delete_wallet(wallet_name: &str, wallet_type: Option<&str>) -> Result<(), u32> { + trace!("delete_wallet >>> wallet_name: {}", wallet_name); + if settings::test_indy_mode_enabled() { unsafe { WALLET_HANDLE = 0;} return Ok(()) @@ -76,49 +89,69 @@ pub fn delete_wallet(wallet_name: &str) -> Result<(), u32> { Err(x) => (), }; - let config = format!(r#"{{"id":"{}"}}"#, wallet_name); - Wallet::delete(&config,&settings::get_wallet_credentials()).map_err(map_rust_indy_sdk_error_code) + let config = json!({ + "id": wallet_name, + "storage_type": wallet_type + }).to_string(); + + wallet::delete_wallet(&config,&settings::get_wallet_credentials()).wait().map_err(map_rust_indy_sdk_error_code) } -pub fn add_record(xtype: &str, id: &str, value: &str, tags: &str) -> Result<(), u32> { +pub fn add_record(xtype: &str, id: &str, value: &str, tags: Option<&str>) -> Result<(), u32> { + trace!("add_record >>> xtype: {}, id: {}, value: {}, tags: {:?}", xtype, id, value, tags); + if settings::test_indy_mode_enabled() { return Ok(()) } - Wallet::add_record(get_wallet_handle(), xtype, id, value, Some(tags)) + wallet::add_wallet_record(get_wallet_handle(), xtype, id, value, tags) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn get_record(xtype: &str, id: &str, options: &str) -> Result { + trace!("get_record >>> xtype: {}, id: {}, options: {}", xtype, id, options); + if settings::test_indy_mode_enabled() { return Ok(r#"{"id":"123","type":"record type","value":"record value","tags":null}"#.to_string()) } - Wallet::get_record(get_wallet_handle(), xtype, id, options) + wallet::get_wallet_record(get_wallet_handle(), xtype, id, options) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn delete_record(xtype: &str, id: &str) -> Result<(), u32> { + trace!("delete_record >>> xtype: {}, id: {}", xtype, id); + if settings::test_indy_mode_enabled() { return Ok(()) } - Wallet::delete_record(get_wallet_handle(), xtype, id) + wallet::delete_wallet_record(get_wallet_handle(), xtype, id) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn update_record_value(xtype: &str, id: &str, value: &str) -> Result<(), u32> { + trace!("update_record_value >>> xtype: {}, id: {}, value: {}", xtype, id, value); + if settings::test_indy_mode_enabled() { return Ok(()) } - Wallet::update_record_value(get_wallet_handle(), xtype, id, value) + wallet::update_wallet_record_value(get_wallet_handle(), xtype, id, value) + .wait() .map_err(map_rust_indy_sdk_error_code) } pub fn export(wallet_handle: i32, path: &Path, backup_key: &str) -> Result<(), WalletError> { + trace!("export >>> wallet_handle: {}, path: {:?}, backup_key: ****", wallet_handle, path); + let export_config = json!({ "key": backup_key, "path": &path}).to_string(); - match Wallet::export(wallet_handle, &export_config) { + match wallet::export_wallet(wallet_handle, &export_config).wait() { Ok(_) => Ok(()), Err(e) => Err(WalletError::CommonError(map_rust_indy_sdk_error_code(e))), } } pub fn import(config: &str) -> Result<(), WalletError> { + trace!("import >>> config {}", config); + settings::process_config_string(config).map_err(|e| WalletError::CommonError(e))?; let key = settings::get_config_value(settings::CONFIG_WALLET_KEY) @@ -137,7 +170,7 @@ pub fn import(config: &str) -> Result<(), WalletError> { let credentials = settings::get_wallet_credentials(); let import_config = json!({"key": backup_key, "path": exported_wallet_path }).to_string(); - match Wallet::import(&config, &credentials, &import_config) { + match wallet::import_wallet(&config, &credentials, &import_config).wait() { Ok(_) => Ok(()), Err(e) => Err(WalletError::CommonError(map_rust_indy_sdk_error_code(e))), } @@ -146,7 +179,7 @@ pub fn import(config: &str) -> Result<(), WalletError> { #[cfg(test)] pub mod tests { use super::*; - use utils::error; + use utils::{get_temp_dir_path, error}; use std::thread; use std::time::Duration; use utils::devsetup::tests::setup_wallet_env; @@ -167,7 +200,7 @@ pub mod tests { let xtype = "type1"; let id = "id1"; let value = "value1"; - add_record(xtype, id, value, "{}").unwrap(); + add_record(xtype, id, value, None).unwrap(); export(handle, &dir, &backup_key).unwrap(); dir @@ -184,7 +217,7 @@ pub mod tests { Err(_) => (), }; - match delete_wallet(name) { + match delete_wallet(name, None) { Ok(_) => (), Err(_) => (), }; @@ -194,7 +227,13 @@ pub mod tests { fn test_wallet() { init!("false"); assert!( get_wallet_handle() > 0); - assert_eq!(error::INVALID_WALLET_CREATION.code_num, init_wallet(&String::from("")).unwrap_err()); + assert_eq!(error::INVALID_WALLET_CREATION.code_num, init_wallet(&String::from(""), None).unwrap_err()); + } + + #[test] + fn test_wallet_for_unknown_type() { + init!("false"); + assert_eq!(error::INVALID_WALLET_CREATION.code_num, init_wallet("test_wallet_for_unknown_type", Some("UNKNOWN_WALLET_TYPE")).unwrap_err()); } #[test] @@ -202,33 +241,36 @@ pub mod tests { teardown!("false"); ::api::vcx::vcx_shutdown(true); let wallet_n = settings::DEFAULT_WALLET_NAME; + settings::set_config_value(settings::CONFIG_WALLET_KEY, settings::DEFAULT_WALLET_KEY); settings::set_config_value(settings::CONFIG_WALLET_KEY_DERIVATION, settings::DEFAULT_WALLET_KEY_DERIVATION); - create_wallet(wallet_n).unwrap(); + create_wallet(wallet_n, None).unwrap(); // Open fails without Wallet Key Derivation set ::api::vcx::vcx_shutdown(false); - assert_eq!(open_wallet(wallet_n), Err(error::UNKNOWN_LIBINDY_ERROR.code_num)); + assert_eq!(open_wallet(wallet_n, None), Err(error::UNKNOWN_LIBINDY_ERROR.code_num)); // Open works when set + settings::set_config_value(settings::CONFIG_WALLET_KEY, settings::DEFAULT_WALLET_KEY); settings::set_config_value(settings::CONFIG_WALLET_KEY_DERIVATION, settings::DEFAULT_WALLET_KEY_DERIVATION); - assert!(open_wallet(wallet_n).is_ok()); + assert!(open_wallet(wallet_n, None).is_ok()); // Delete fails ::api::vcx::vcx_shutdown(false); - assert_eq!(delete_wallet(wallet_n), Err(error::UNKNOWN_LIBINDY_ERROR.code_num)); + assert_eq!(delete_wallet(wallet_n, None), Err(error::UNKNOWN_LIBINDY_ERROR.code_num)); // Delete works + settings::set_config_value(settings::CONFIG_WALLET_KEY, settings::DEFAULT_WALLET_KEY); settings::set_config_value(settings::CONFIG_WALLET_KEY_DERIVATION, settings::DEFAULT_WALLET_KEY_DERIVATION); - assert!(delete_wallet(wallet_n).is_ok()); + assert!(delete_wallet(wallet_n, None).is_ok()); } #[test] fn test_wallet_import_export() { settings::set_defaults(); teardown!("false"); - let exported_path = format!(r#"/tmp/{}"#, settings::DEFAULT_WALLET_NAME); - let dir = export_test_wallet(); + let export_path = export_test_wallet(); + let xtype = "type1"; let id = "id1"; let value = "value1"; @@ -239,17 +281,17 @@ pub mod tests { let import_config = json!({ settings::CONFIG_WALLET_NAME: settings::DEFAULT_WALLET_NAME, settings::CONFIG_WALLET_KEY: settings::DEFAULT_WALLET_KEY, - settings::CONFIG_EXPORTED_WALLET_PATH: exported_path, + settings::CONFIG_EXPORTED_WALLET_PATH: export_path, settings::CONFIG_WALLET_BACKUP_KEY: settings::DEFAULT_WALLET_BACKUP_KEY, }).to_string(); import(&import_config).unwrap(); - open_wallet(&settings::DEFAULT_WALLET_NAME).unwrap(); + open_wallet(&settings::DEFAULT_WALLET_NAME, None).unwrap(); // If wallet was successfully imported, there will be an error trying to add this duplicate record - assert_eq!(add_record(xtype, id, value, "{}"), Err(error::DUPLICATE_WALLET_RECORD.code_num)); + assert_eq!(add_record(xtype, id, value, None), Err(error::DUPLICATE_WALLET_RECORD.code_num)); thread::sleep(Duration::from_secs(1)); ::api::vcx::vcx_shutdown(true); - delete_import_wallet_path(dir); + delete_import_wallet_path(export_path); } #[test] @@ -271,7 +313,9 @@ pub mod tests { // Missing exported_wallet_path assert_eq!(import(&config.to_string()), Err(WalletError::CommonError(error::MISSING_EXPORTED_WALLET_PATH.code_num))); - config[settings::CONFIG_EXPORTED_WALLET_PATH] = serde_json::to_value(settings::DEFAULT_EXPORTED_WALLET_PATH).unwrap(); + config[settings::CONFIG_EXPORTED_WALLET_PATH] = serde_json::to_value( + get_temp_dir_path(Some(settings::DEFAULT_EXPORTED_WALLET_PATH)).to_str().unwrap() + ).unwrap(); // Missing backup_key assert_eq!(import(&config.to_string()), Err(WalletError::CommonError(error::MISSING_BACKUP_KEY.code_num))); @@ -280,24 +324,19 @@ pub mod tests { #[test] fn test_import_wallet_fails_with_existing_wallet() { settings::set_defaults(); - let wallet_name = "test_import_wallet_fails_with_existing_wallet"; - settings::set_config_value(settings::CONFIG_WALLET_NAME, wallet_name); - let exported_path = format!(r#"/tmp/{}"#, wallet_name); - let wallet_key = settings::get_config_value(settings::CONFIG_WALLET_KEY).unwrap(); - let backup_key = settings::get_config_value(settings::CONFIG_WALLET_BACKUP_KEY).unwrap(); - let dir = export_test_wallet(); + let export_path = export_test_wallet(); let import_config = json!({ - settings::CONFIG_WALLET_NAME: wallet_name, - settings::CONFIG_WALLET_KEY: wallet_key, - settings::CONFIG_EXPORTED_WALLET_PATH: exported_path, - settings::CONFIG_WALLET_BACKUP_KEY: backup_key, + settings::CONFIG_WALLET_NAME: settings::DEFAULT_WALLET_NAME, + settings::CONFIG_WALLET_KEY: settings::DEFAULT_WALLET_KEY, + settings::CONFIG_EXPORTED_WALLET_PATH: export_path, + settings::CONFIG_WALLET_BACKUP_KEY: settings::DEFAULT_WALLET_BACKUP_KEY, }).to_string(); assert_eq!(import(&import_config), Err(WalletError::CommonError(error::WALLET_ALREADY_EXISTS.code_num))); ::api::vcx::vcx_shutdown(true); - delete_import_wallet_path(dir); + delete_import_wallet_path(export_path); } #[test] @@ -305,7 +344,6 @@ pub mod tests { settings::set_defaults(); let wallet_name = "test_import_wallet_fails_with_invalid_path"; settings::set_config_value(settings::CONFIG_WALLET_NAME, wallet_name); - let exported_path = format!(r#"/tmp/{}"#, wallet_name); let wallet_key = settings::get_config_value(settings::CONFIG_WALLET_KEY).unwrap(); let backup_key = settings::get_config_value(settings::CONFIG_WALLET_BACKUP_KEY).unwrap(); @@ -329,22 +367,22 @@ pub mod tests { settings::set_defaults(); teardown!("false"); - let exported_path = format!(r#"/tmp/{}"#, settings::DEFAULT_WALLET_NAME); let bad_backup = "456"; - let dir = export_test_wallet(); + let export_path = export_test_wallet(); + ::api::vcx::vcx_shutdown(true); let import_config = json!({ settings::CONFIG_WALLET_NAME: settings::DEFAULT_WALLET_NAME, settings::CONFIG_WALLET_KEY: settings::DEFAULT_WALLET_KEY, - settings::CONFIG_EXPORTED_WALLET_PATH: exported_path, + settings::CONFIG_EXPORTED_WALLET_PATH: export_path, settings::CONFIG_WALLET_BACKUP_KEY: bad_backup, }).to_string(); assert_eq!(import(&import_config), Err(WalletError::CommonError(error::LIBINDY_INVALID_STRUCTURE.code_num))); ::api::vcx::vcx_shutdown(true); - delete_import_wallet_path(dir); + delete_import_wallet_path(export_path); } #[test] @@ -356,7 +394,7 @@ pub mod tests { let id = "123"; let wallet_n = "test_add_new_record_with_no_tag"; - add_record(record_type, id, record, "{}").unwrap(); + add_record(record_type, id, record, None).unwrap(); } #[test] @@ -368,8 +406,8 @@ pub mod tests { let id = "123"; let wallet_n = "test_add_duplicate_record_fails"; - add_record(record_type, id, record, "{}").unwrap(); - let rc = add_record(record_type, id, record, "{}"); + add_record(record_type, id, record, None).unwrap(); + let rc = add_record(record_type, id, record, None); assert_eq!(rc, Err(error::DUPLICATE_WALLET_RECORD.code_num)); } @@ -383,8 +421,8 @@ pub mod tests { let id = "123"; let wallet_n = "test_add_duplicate_record_fails"; - add_record(record_type, id, record, "{}").unwrap(); - add_record(record_type2, id, record, "{}").unwrap(); + add_record(record_type, id, record, None).unwrap(); + add_record(record_type2, id, record, None).unwrap(); } #[test] @@ -419,7 +457,7 @@ pub mod tests { }).to_string(); let expected_retrieved_record = format!(r#"{{"type":"{}","id":"{}","value":"{}","tags":null}}"#, record_type, id, record); - add_record(record_type, id, record, "{}").unwrap(); + add_record(record_type, id, record, None).unwrap(); let retrieved_record = get_record(record_type, id, &options).unwrap(); assert_eq!(retrieved_record, expected_retrieved_record); @@ -428,12 +466,12 @@ pub mod tests { #[test] fn test_delete_record_fails_with_no_record() { init!("false"); - let wallet_n = "test_delete_record_fails_with_no_record"; let record_type = "Type"; let id = "123"; let rc = delete_record(record_type, id); assert_eq!(rc, Err(error::WALLET_RECORD_NOT_FOUND.code_num)); + } #[test] @@ -450,7 +488,7 @@ pub mod tests { "retrieveTags": false }).to_string(); - add_record(record_type, id, record, "{}").unwrap(); + add_record(record_type, id, record, None).unwrap(); delete_record(record_type, id).unwrap(); let rc = get_record(record_type, id, &options); assert_eq!(rc, Err(error::WALLET_RECORD_NOT_FOUND.code_num)); @@ -486,7 +524,7 @@ pub mod tests { let expected_initial_record = format!(r#"{{"type":"{}","id":"{}","value":"{}","tags":null}}"#, record_type, id, initial_record); let expected_updated_record = format!(r#"{{"type":"{}","id":"{}","value":"{}","tags":null}}"#, record_type, id, changed_record); - add_record(record_type, id, initial_record, "{}").unwrap(); + add_record(record_type, id, initial_record, None).unwrap(); let initial_record = get_record(record_type, id, &options).unwrap(); update_record_value(record_type, id, changed_record).unwrap(); let changed_record = get_record(record_type, id, &options).unwrap(); diff --git a/vcx/libvcx/src/utils/logger.rs b/vcx/libvcx/src/utils/logger.rs index 6c3d4ad0..1fe76a38 100644 --- a/vcx/libvcx/src/utils/logger.rs +++ b/vcx/libvcx/src/utils/logger.rs @@ -2,24 +2,126 @@ extern crate env_logger; extern crate log; extern crate log4rs; extern crate log_panics; +extern crate libc; +extern crate indy_sys; + #[cfg(target_os = "android")] extern crate android_logger; -#[cfg(target_os = "ios")] -use self::log::LevelFilter; -#[cfg(target_os = "ios")] -use std::io::Write; -use settings; +use std::io::Write; +use self::env_logger::Builder as EnvLoggerBuilder; +use self::log::{Level, LevelFilter, Metadata, Record}; use std::sync::{Once, ONCE_INIT}; +use self::libc::{c_char}; use std::env; +use std::ptr; +pub use self::indy_sys::{CVoid, logger::{EnabledCB, LogCB, FlushCB}}; +use std::ffi::CString; + #[allow(unused_imports)] -use self::log::{Level}; #[cfg(target_os = "android")] use self::android_logger::Filter; +use utils::cstring::CStringUtils; +use utils::error::LOGGING_ERROR; -pub struct LoggerUtils {} +use utils::libindy; +pub static mut LOGGER_STATE: LoggerState = LoggerState::Default; static LOGGER_INIT: Once = ONCE_INIT; +static mut CONTEXT: *const CVoid = ptr::null(); +static mut ENABLED_CB: Option = None; +static mut LOG_CB: Option = None; +static mut FLUSH_CB: Option = None; + +#[derive(Debug, PartialEq)] +pub enum LoggerState { + Default, + Custom, +} + +impl LoggerState { + pub fn get(&self) -> (*const CVoid, Option, Option, Option) { + match self { + LoggerState::Default => (ptr::null(), Some(LibvcxDefaultLogger::enabled), Some(LibvcxDefaultLogger::log), Some(LibvcxDefaultLogger::flush)), + LoggerState::Custom => unsafe { (CONTEXT, ENABLED_CB, LOG_CB, FLUSH_CB) }, + } + } +} + +pub struct LibvcxLogger { + context: *const CVoid, + enabled: Option, + log: LogCB, + flush: Option, +} + +impl LibvcxLogger { + fn new(context: *const CVoid, enabled: Option, log: LogCB, flush: Option) -> Self { + LibvcxLogger { context, enabled, log, flush } + } + + pub fn init(context: *const CVoid, enabled: Option, log: LogCB, flush: Option) -> Result<(), u32> { + trace!("LibvcxLogger::init >>>"); + let logger = LibvcxLogger::new(context, enabled, log, flush); + log::set_boxed_logger(Box::new(logger)).map_err(|_| LOGGING_ERROR.code_num)?; + log::set_max_level(LevelFilter::Trace); + libindy::logger::set_logger(log::logger()).map_err(|_| LOGGING_ERROR.code_num)?; + unsafe { + LOGGER_STATE = LoggerState::Custom; + CONTEXT = context; + ENABLED_CB = enabled; + LOG_CB = Some(log); + FLUSH_CB = flush + } + + Ok(()) + } +} + +unsafe impl Sync for LibvcxLogger {} + +unsafe impl Send for LibvcxLogger {} + +impl log::Log for LibvcxLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + if let Some(enabled_cb) = self.enabled { + let level = metadata.level() as u32; + let target = CString::new(metadata.target()).unwrap(); + + enabled_cb(self.context, + level, + target.as_ptr(), + ) + } else { true } + } + + fn log(&self, record: &Record) { + let log_cb = self.log; + + let level = record.level() as u32; + let target = CString::new(record.target()).unwrap(); + let message = CString::new(record.args().to_string()).unwrap(); + + let module_path = record.module_path().map(|a| CString::new(a).unwrap()); + let file = record.file().map(|a| CString::new(a).unwrap()); + let line = record.line().unwrap_or(0); + + log_cb(self.context, + level, + target.as_ptr(), + message.as_ptr(), + module_path.as_ref().map(|p| p.as_ptr()).unwrap_or(ptr::null()), + file.as_ref().map(|p| p.as_ptr()).unwrap_or(ptr::null()), + line, + ) + } + + fn flush(&self) { + if let Some(flush_cb) = self.flush { + flush_cb(self.context) + } + } +} // From: https://www.tutorialspoint.com/log4j/log4j_logging_levels.htm // @@ -30,88 +132,177 @@ static LOGGER_INIT: Once = ONCE_INIT; //OFF The highest possible rank and is intended to turn off logging. //TRACE Designates finer-grained informational events than the DEBUG. //WARN Designates potentially harmful situations. +pub struct LibvcxDefaultLogger; +impl LibvcxDefaultLogger { + pub fn init_testing_logger() { + trace!("LibvcxDefaultLogger::init_testing_logger >>>"); + + // ensures that the test that is calling this wont fail simply because + // the user did not set the RUST_LOG env var. + let pattern = Some(env::var("RUST_LOG").unwrap_or("debug".to_string())); + match LibvcxDefaultLogger::init(pattern) { + Ok(_) => (), + Err(_) => (), + } + } -impl LoggerUtils { - pub fn init_test_logging(level: &str) { - // logger for testing purposes, sends to stdout (set env RUST_LOG to configure log level - let level = match env::var("RUST_LOG") { - Err(_) => level.to_string(), - Ok(value) => value, - }; - env::set_var("RUST_LOG", &level); - LOGGER_INIT.call_once(|| { - env_logger::init(); - }); - } - - pub fn init() { - - match settings::get_config_value(settings::CONFIG_ENABLE_TEST_MODE) { - Ok(_) => return LoggerUtils::init_test_logging("off"), - Err(x) => (), - }; - - // turn libindy logging off if RUST_LOG is not specified - - match env::var("RUST_LOG") { - Err(_) => { - env::set_var("RUST_LOG", "off"); - }, - Ok(value) => (), - }; - - LOGGER_INIT.call_once(|| { - // Logging of panics is essential for android. As android does not log to stdout for native code - log_panics::init(); - if cfg!(target_os = "android") { - #[cfg(target_os = "android")] - let log_filter = match env::var("RUST_LOG") { - Ok(val) => match val.to_lowercase().as_ref(){ - "error" => Filter::default().with_min_level(log::Level::Error), - "warn" => Filter::default().with_min_level(log::Level::Warn), - "info" => Filter::default().with_min_level(log::Level::Info), - "debug" => Filter::default().with_min_level(log::Level::Debug), - "trace" => Filter::default().with_min_level(log::Level::Trace), - _ => Filter::default().with_min_level(log::Level::Error) - } - Err(..) => Filter::default().with_min_level(log::Level::Error) - }; - - #[cfg(target_os = "android")] - android_logger::init_once(log_filter); - info!("Logging for Android"); - } else if cfg!(target_os = "ios") { - #[cfg(target_os = "ios")] - env_logger::Builder::new() - .format(|buf, record| writeln!(buf, "{:>5}|{:<30}|{:>35}:{:<4}| {}", record.level(), record.target(), record.file().get_or_insert(""), record.line().get_or_insert(0), record.args())) - .filter(None, LevelFilter::Off) - .parse(env::var("RUST_LOG").as_ref().map(String::as_str).unwrap_or("")) - .try_init() - .ok(); - info!("Logging for iOS"); - } else { - match settings::get_config_value(settings::CONFIG_LOG_CONFIG) { - Err(_) => {/* NO-OP - no logging configured */}, - Ok(x) => { - match log4rs::init_file(&x, Default::default()) { - Err(e) => println!("invalid log configuration: {}", e), - Ok(_) => {}, - } - } + pub fn init(pattern: Option) -> Result<(), u32> { + trace!("LibvcxDefaultLogger::init >>> pattern: {:?}", pattern); + + let pattern = pattern.or(env::var("RUST_LOG").ok()); + if cfg!(target_os = "android") { + #[cfg(target_os = "android")] + let log_filter = match pattern.as_ref() { + Some(val) => match val.to_lowercase().as_ref() { + "error" => Filter::default().with_min_level(log::Level::Error), + "warn" => Filter::default().with_min_level(log::Level::Warn), + "info" => Filter::default().with_min_level(log::Level::Info), + "debug" => Filter::default().with_min_level(log::Level::Debug), + "trace" => Filter::default().with_min_level(log::Level::Trace), + _ => Filter::default().with_min_level(log::Level::Error), + }, + None => Filter::default().with_min_level(log::Level::Error) + }; + + //Set logging to off when deploying production android app. + #[cfg(target_os = "android")] + android_logger::init_once(log_filter); + info!("Logging for Android"); + } else { + // This calls + // log::set_max_level(logger.filter()); + // log::set_boxed_logger(Box::new(logger)) + // which are what set the logger. + match EnvLoggerBuilder::new() + .format(|buf, record| writeln!(buf, "{:>5}|{:<30}|{:>35}:{:<4}| {}", record.level(), record.target(), record.file().get_or_insert(""), record.line().get_or_insert(0), record.args())) + .filter(None, LevelFilter::Off) + .parse(pattern.as_ref().map(String::as_str).unwrap_or("warn")) + .try_init() { + Ok(_) => {} + Err(e) => { + error!("Error in logging init: {:?}", e); + return Err(LOGGING_ERROR.code_num); } } - }); + } + libindy::logger::set_default_logger(pattern.as_ref().map(String::as_str)) + } + + extern fn enabled(_context: *const CVoid, + level: u32, + target: *const c_char) -> bool { + let level = get_level(level); + let target = CStringUtils::c_str_to_str(target).unwrap().unwrap(); + + let metadata: Metadata = Metadata::builder() + .level(level) + .target(target) + .build(); + + log::logger().enabled(&metadata) + } + + extern fn log(_context: *const CVoid, + level: u32, + target: *const c_char, + args: *const c_char, + module_path: *const c_char, + file: *const c_char, + line: u32) { + let target = CStringUtils::c_str_to_str(target).unwrap().unwrap(); + let args = CStringUtils::c_str_to_str(args).unwrap().unwrap(); + let module_path = CStringUtils::c_str_to_str(module_path).unwrap(); + let file = CStringUtils::c_str_to_str(file).unwrap(); + + let level = get_level(level); + + log::logger().log( + &Record::builder() + .args(format_args!("{}", args)) + .level(level) + .target(target) + .module_path(module_path) + .file(file) + .line(Some(line)) + .build(), + ); + } + + extern fn flush(_context: *const CVoid) { + log::logger().flush() + } +} + +fn get_level(level: u32) -> Level { + match level { + 1 => Level::Error, + 2 => Level::Warn, + 3 => Level::Info, + 4 => Level::Debug, + 5 => Level::Trace, + _ => unreachable!(), } } #[cfg(test)] mod tests { - use super::*; + fn get_custom_context() -> *const CVoid { + ptr::null() + } + + static mut CHANGED: Option = None; + static mut COUNT: u32 = 0; + + extern fn custom_enabled(context: *const CVoid, level: u32, target: *const c_char) -> bool { true } + + extern fn custom_flush(context: *const CVoid) {} + + extern fn custom_log(context: *const CVoid, + level: u32, + target: *const c_char, + message: *const c_char, + module_path: *const c_char, + file: *const c_char, + line: u32) { + let message = CStringUtils::c_str_to_string(message).unwrap(); + unsafe { COUNT = COUNT + 1 } + } + + #[ignore] #[test] - fn test_logger() { - LoggerUtils::init(); + fn test_logging_get_logger() { + LibvcxDefaultLogger::init(Some("debug".to_string())).unwrap(); + unsafe { + let (context, enabled_cb, log_cb, flush_cb) = LOGGER_STATE.get(); + assert_eq!(context, ptr::null()); + let target = CStringUtils::string_to_cstring("target".to_string()); + let level = 1; + let b = LibvcxDefaultLogger::enabled(ptr::null(), 1, target.as_ptr()); + + assert_eq!(enabled_cb.unwrap()(ptr::null(), level, target.as_ptr()), b); + } } -} + + // Can only have one test that initializes logging. + #[ignore] + #[test] + fn test_custom_logger() { + LibvcxLogger::init(get_custom_context(), + Some(custom_enabled), + custom_log, + Some(custom_flush)).unwrap(); + error!("error level message"); // first call of log function + unsafe { + assert_eq!(COUNT, 2) // second-time log function was called inside libindy + } + } + + #[test] + fn test_logger_for_testing() { + LibvcxDefaultLogger::init_testing_logger(); + LibvcxDefaultLogger::init_testing_logger(); + } +} \ No newline at end of file diff --git a/vcx/libvcx/src/utils/mod.rs b/vcx/libvcx/src/utils/mod.rs index e2eb3c55..d1243e72 100644 --- a/vcx/libvcx/src/utils/mod.rs +++ b/vcx/libvcx/src/utils/mod.rs @@ -18,9 +18,11 @@ pub mod openssl; pub mod json; pub mod libindy; pub mod threadpool; -pub mod serde_utils; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use std::path::PathBuf; +use std::env; + lazy_static! { static ref COMMAND_HANDLE_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; } @@ -30,5 +32,11 @@ pub fn generate_command_handle() -> i32 { command_handle } +pub fn get_temp_dir_path(filename: Option<&str>) -> PathBuf { + let mut path = env::temp_dir(); + path.push(filename.unwrap_or("")); + path +} + #[macro_use] pub mod logger; diff --git a/vcx/libvcx/src/utils/serde_utils.rs b/vcx/libvcx/src/utils/serde_utils.rs deleted file mode 100644 index 7e6d2e01..00000000 --- a/vcx/libvcx/src/utils/serde_utils.rs +++ /dev/null @@ -1,15 +0,0 @@ -extern crate serde_json; - -use ::utils::error; -use serde_json::{Value}; - -pub fn get_value_to_string(key: &str, map: &Value) -> Result { - Ok( - map.get(key) - .ok_or(error::INVALID_JSON.code_num)? - .as_str() - .ok_or(error::INVALID_JSON.code_num)? - .to_string() - ) -} - diff --git a/vcx/libvcx/tests/integration.rs b/vcx/libvcx/tests/integration.rs deleted file mode 100644 index eddc1ce6..00000000 --- a/vcx/libvcx/tests/integration.rs +++ /dev/null @@ -1,253 +0,0 @@ -extern crate vcx; -extern crate serde; -extern crate rand; -extern crate indy; - -#[macro_use] -extern crate serde_json; - -#[cfg(test)] -mod tests { - use super::*; - use rand::Rng; - use vcx::utils::cstring::CStringUtils; - use std::ffi::CString; - use vcx::utils::libindy::return_types_u32; - use std::fs; - use std::path::PathBuf; - use std::io::Write; - use std::ptr; - use std::time::Duration; - use vcx::settings; - use vcx::utils::constants::GENESIS_PATH; - use vcx::api::utils::vcx_agent_provision_async; - use vcx::api::vcx::{ vcx_init_with_config, vcx_shutdown }; - use vcx::utils::error; - use vcx::api::wallet; - - pub fn get_details(agency:&str) -> serde_json::Value { - match agency { - "consumer" => json!({ - "url": "https://agency-ea-sandbox.evernym.com", - "did": "HB7qFQyFxx4ptjKqioEtd8", - "verkey": "9pJkfHyfJMZjUjS7EZ2q2HX55CbFQPKpQ9eTjSAUMLU8", - "seed": "000000000000000000000000Trustee1" - }), - "enterprise" => json!({ - "url": "https://enym-eagency.pdev.evernym.com", - "did": "dTLdJqRZLwMuWSogcKfBT", - "verkey": "LsPQTDHi294TexkFmZK9Q9vW4YGtQRuLV8wuyZi94yH", - "seed": "000000000000000000000000Trustee1" - }), - &_ => json!({}), - } - } - - pub fn create_genesis_txn_file(test_pool_ip:&str) { - let node_txns = vec![format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip), - format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip), - format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip), - format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip)]; - - let txn_file_data = node_txns[0..4].join("\n"); - - let mut f = fs::File::create(GENESIS_PATH).unwrap(); - f.write_all(txn_file_data.as_bytes()).unwrap(); - f.flush().unwrap(); - f.sync_all().unwrap(); - } - - fn provision_agent() -> Result { - use vcx::settings; - let mut rng = rand::thread_rng(); - let settings = get_details("consumer"); - let config = json!({ - "wallet_name": settings::DEFAULT_WALLET_NAME, - "agent_seed": format!("HANKHILL{}00000000001DIRECTION", rng.gen_range(1000,9999)), - "enterprise_seed": settings["seed"], - "wallet_key": settings::DEFAULT_WALLET_KEY, - "agency_url": settings["url"], - "agency_did": settings["did"], - "agency_verkey": settings["verkey"], - }); - let config = CStringUtils::string_to_cstring(config.to_string()); - let cb = return_types_u32::Return_U32_STR::new().unwrap(); - vcx_agent_provision_async(cb.command_handle, config.as_ptr(), Some(cb.get_callback())); - let vcx_config = cb.receive(Some(Duration::from_secs(10)))?.unwrap(); - let mut vcx_config:serde_json::Value = serde_json::from_str(&vcx_config).unwrap(); - let vcx_config = vcx_config.as_object_mut().unwrap(); - vcx_config.insert( "institution_logo_url".to_string(), json!("https://robohash.org/hankhill")); - vcx_config.insert( "institution_name".to_string(), json!("Harlan Gas")); - vcx_config.insert( "genesis_path".to_string(), json!(GENESIS_PATH)); - match serde_json::to_string(&vcx_config) { - Ok(s) => Ok(s), - Err(_) => Err(1), - } - } - - fn delete_indy_client(){ - use std::fs::remove_dir_all; - use std::env::home_dir; - use std::path::PathBuf; - let p = match home_dir() { - Some(path) => path, - None => panic!("Cannot find home directory"), - }; - let mut path = PathBuf::new(); - path.push(p); - path.push(".indy_client"); - path.push("wallet"); - remove_dir_all(path).unwrap_or(()); - } - - fn init_vcx(vcx_config: &str) -> Result<(), u32> { - let cb = return_types_u32::Return_U32::new().unwrap(); - let err = vcx_init_with_config(cb.command_handle, - CString::new(vcx_config).unwrap().as_ptr(), - Some(cb.get_callback())); - assert_eq!(err, error::SUCCESS.code_num); - cb.receive(Some(Duration::from_secs(10))) - } - - fn get_token_info() -> String { - let cb = return_types_u32::Return_U32_STR::new().unwrap(); - assert_eq!(wallet::vcx_wallet_get_token_info(cb.command_handle, - 0, - Some(cb.get_callback())), - error::SUCCESS.code_num); - cb.receive(Some(Duration::from_secs(10))).unwrap().unwrap() - } - fn export_wallet(path: std::path::PathBuf) { - let cb = return_types_u32::Return_U32::new().unwrap(); - assert_eq!(wallet::vcx_wallet_export(cb.command_handle, - CString::new(path.to_str().unwrap()).unwrap().as_ptr(), - CString::new(settings::DEFAULT_WALLET_BACKUP_KEY).unwrap().as_ptr(), - Some(cb.get_callback())), error::SUCCESS.code_num); - cb.receive(Some(Duration::from_secs(10))).unwrap(); - } - - fn send_tokens(amt:u32, addr: Option<&str>) -> Result, u32> { - let cb = return_types_u32::Return_U32_STR::new().unwrap(); - let dest_addr = match addr { - Some(a) => a, - None => "pay:sov:22UFLTPu1MagmX6b6g2ZXy9n98dA52Kd1VH8Hjjf82L7zZEnC5", - }; - wallet::vcx_wallet_send_tokens(cb.command_handle, - 0, - CString::new(amt.to_string()).unwrap().as_ptr(), - CString::new(dest_addr).unwrap().as_ptr(), - Some(cb.get_callback())); - cb.receive(Some(Duration::from_secs(10))) - } - - fn import_wallet(path: std::path::PathBuf) { - let cb = return_types_u32::Return_U32::new().unwrap(); - let import_config = json!({ - settings::CONFIG_WALLET_NAME: settings::DEFAULT_WALLET_NAME, - settings::CONFIG_WALLET_KEY: settings::DEFAULT_WALLET_KEY, - settings::CONFIG_EXPORTED_WALLET_PATH: path.to_str().unwrap(), - settings::CONFIG_WALLET_BACKUP_KEY: settings::DEFAULT_WALLET_BACKUP_KEY, - }).to_string(); - - let import_config_c = CString::new(import_config).unwrap(); - assert_eq!(wallet::vcx_wallet_import(cb.command_handle, - import_config_c.as_ptr(), - Some(cb.get_callback())), error::SUCCESS.code_num); - - match cb.receive(Some(Duration::from_secs(5))) { - Ok(_) => (), - Err(e) => println!("ERROR: {}", e), - }; - } - - fn create_path_and_file_name() -> std::path::PathBuf { - let mut path = PathBuf::new(); - let export_wallet_name = "backup.wallet"; - path.push("/tmp"); - path.push(export_wallet_name); - fs::remove_file(path.clone()).unwrap_or(()); - path - } - - fn get_fees() -> Result, u32> { - use vcx::api::utils::vcx_ledger_get_fees; - let cb = return_types_u32::Return_U32_STR::new().unwrap(); - let _err = vcx_ledger_get_fees(cb.command_handle, Some(cb.get_callback())); - cb.receive(Some(Duration::from_secs(10))) - } - - #[cfg(feature = "agency")] - #[cfg(feature = "pool_tests")] - #[test] - fn test_error_codes() { - settings::set_defaults(); - settings::set_config_value(settings::CONFIG_ENABLE_TEST_MODE, "false"); - settings::set_config_value(settings::CONFIG_WALLET_KEY, settings::DEFAULT_WALLET_KEY); - delete_indy_client(); - create_genesis_txn_file("127.0.0.1"); - let vcx_config = provision_agent().unwrap(); - init_vcx(&vcx_config).unwrap(); - vcx_shutdown(false); - assert_eq!(provision_agent().err(), Some(error::DID_ALREADY_EXISTS_IN_WALLET.code_num)); - vcx_shutdown(true); - } - - #[cfg(feature = "agency")] - #[cfg(feature = "sovtoken")] - #[cfg(feature = "pool_tests")] - #[test] - fn test_token_balance() { - use vcx::api::vcx::vcx_mint_tokens; - delete_indy_client(); - create_genesis_txn_file("127.0.0.1"); - let vcx_config = provision_agent().unwrap(); - init_vcx(&vcx_config).unwrap(); - vcx_mint_tokens(ptr::null_mut(),ptr::null_mut()); - send_tokens(1500, None).unwrap(); - let token_info2 = get_token_info(); - let path = create_path_and_file_name(); - export_wallet(path.clone()); - assert_eq!(vcx_shutdown(true), error::SUCCESS.code_num); - settings::clear_config(); - import_wallet(path.clone()); - init_vcx(&vcx_config).unwrap(); - let token_info3 = get_token_info(); - let token_info2: serde_json::Value = serde_json::from_str(&token_info2).unwrap(); - let token_info3: serde_json::Value = serde_json::from_str(&token_info3).unwrap(); - assert_eq!(token_info2["balance_str"], token_info3["balance_str"]); - } - -/// This will mint the standard amount of sovatoms into your wallet (500000000) and -/// then you can send those to an address. -/// Provide the ip address of your ledger (for the generic genesis txn file), the -/// payment address to receive the sovatoms, and the amout of sovatoms you wish -/// to send to the address. - #[ignore] - #[cfg(feature = "agency")] - #[cfg(feature = "sovtoken")] - #[test] - fn test_sandbox_token_balance() { - use vcx::api::vcx::vcx_mint_tokens; - let sovatoms = 1234567890; - let receiving_address = Some("pay:sov:jsPfjNn9GULzrhSqDWC3swx1uFjUgutSHwr32GTSMZ8kwA7VT"); - let ip = "34.212.206.9"; - create_genesis_txn_file(ip); - let vcx_config = provision_agent().unwrap(); - init_vcx(&vcx_config).unwrap(); - vcx_mint_tokens(ptr::null_mut(),ptr::null_mut()); - send_tokens(sovatoms, receiving_address).unwrap(); - } - - /// this will simply get fees from a ledger at the given ip address - #[ignore] - #[cfg(feature = "sovtoken")] - #[cfg(feature = "agency")] - #[test] - fn test_get_fees() { - let ip="127.0.0.1"; - create_genesis_txn_file(ip); - let vcx_config = provision_agent().unwrap(); - init_vcx(&vcx_config).unwrap(); - println!("{:?}", get_fees().unwrap()); - } -} diff --git a/vcx/libvcx/tests/logging.rs b/vcx/libvcx/tests/logging.rs new file mode 100644 index 00000000..cfc61f5f --- /dev/null +++ b/vcx/libvcx/tests/logging.rs @@ -0,0 +1,96 @@ +extern crate vcx; +extern crate indyrs as indy; +extern crate libc; +#[macro_use] +extern crate log; +extern crate futures; + +use self::libc::{c_void, c_char}; +use std::ptr::null; +use vcx::api::logger::*; +use vcx::utils::logger::{LOGGER_STATE, LoggerState}; +use indy::wallet; +use vcx::utils::cstring::CStringUtils; +use vcx::api::logger::vcx_set_logger; + +/// These tests can only be run individually as initing the log crate can happen +/// only once. +/// +/// These tests usually need to be run manually to verify that the standard +/// logging is outputting to stdout. +mod log_tests { + use super::*; + use vcx::api::vcx::vcx_error_c_message; + use indy::future::Future; + + static mut COUNT: u32 = 0; + extern fn custom_log(_context: *const c_void, + _level: u32, + _target: *const c_char, + message: *const c_char, + _module_path: *const c_char, + _file: *const c_char, + _line: u32) { + let _message = CStringUtils::c_str_to_string(message).unwrap(); + unsafe { COUNT = COUNT + 1 } + } + #[test] + fn test_logging_default_debug() { + // this test should output a single debug line + // and a single info line (from the vcx_error_c_message call) + + let pattern = CStringUtils::string_to_cstring("debug".to_string()); + assert_eq!(vcx_set_default_logger(pattern.as_ptr()), 0); + debug!("testing debug"); + vcx_error_c_message(1000); + + } + + #[ignore] + #[test] + fn test_logging_default_is_warn() { + // this test should output a single warning line + assert_eq!(vcx_set_default_logger(null()), 0); + unsafe { assert_eq!(LOGGER_STATE, LoggerState::Default); } + warn!("testing warning"); + } + + #[ignore] + #[test] + fn test_logging_env_var() { + // this test should output a single info line + use std::env::set_var; + set_var("RUST_LOG", "info"); + assert_eq!(vcx_set_default_logger(null()), 0); + info!("testing info"); + } + + /// This test depends on some modifications to the indy code. + /// By adding a indy_set_default_logger(null()) to the indy_create_wallet function, + /// it tests that both calls to log::init an occur and not conflict + #[ignore] + #[test] + fn test_works_with_libindy() { + pub const DEFAULT_WALLET_CONFIG: &'static str = r#"{"id":"wallet_1","storage_type":"default"}"#; + pub const WALLET_CREDENTIALS: &'static str = r#"{"key":"8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY", "key_derivation_method":"RAW"}"#; + wallet::create_wallet(DEFAULT_WALLET_CONFIG, WALLET_CREDENTIALS).wait().unwrap(); + let pattern = CStringUtils::string_to_cstring("debug".to_string()); + assert_eq!(vcx_set_default_logger(pattern.as_ptr()), 0); + debug!("testing debug"); + trace!("testing trace"); + } + + #[ignore] + #[test] + fn test_set_logger() { + unsafe { assert_eq!(COUNT, 0);} + let _err = vcx_set_logger(null(), None, Some(custom_log), None); + debug!("testing debug"); + unsafe { assert!(COUNT > 1); } + + } + +} + + + diff --git a/vcx/wrappers/java/ci/android.dockerfile b/vcx/wrappers/java/ci/android.dockerfile index 15bc457e..56a308c8 100644 --- a/vcx/wrappers/java/ci/android.dockerfile +++ b/vcx/wrappers/java/ci/android.dockerfile @@ -7,10 +7,10 @@ RUN usermod -aG sudo android RUN apt-get update -y && apt-get install -y \ openjdk-8-jdk \ maven - -# Install Android SDK and NDK + +# Install Android SDK and NDK RUN mkdir -m 777 /home/android/android-sdk-linux -RUN wget https://dl.google.com/android/repository/tools_r25.2.3-linux.zip -P /home/android/android-sdk-linux +RUN wget -q https://dl.google.com/android/repository/tools_r25.2.3-linux.zip -P /home/android/android-sdk-linux RUN unzip /home/android/android-sdk-linux/tools_r25.2.3-linux.zip -d /home/android/android-sdk-linux RUN ls -al /home/android/android-sdk-linux RUN yes | .//home/android/android-sdk-linux/tools/android update sdk --no-ui @@ -18,8 +18,8 @@ RUN yes | .//home/android/android-sdk-linux/tools/bin/sdkmanager "ndk-bundle" -RUN echo "android ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers +RUN echo "android ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers USER android -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.27.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.31.1 ENV PATH /home/android/.cargo/bin:$PATH \ No newline at end of file diff --git a/vcx/wrappers/node/package-lock.json b/vcx/wrappers/node/package-lock.json index 6e041d4e..1f306c24 100644 --- a/vcx/wrappers/node/package-lock.json +++ b/vcx/wrappers/node/package-lock.json @@ -1358,4 +1358,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/wrappers/rust/.gitignore b/wrappers/rust/.gitignore new file mode 100644 index 00000000..c2ee46f3 --- /dev/null +++ b/wrappers/rust/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock +/indy-sys/Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# IDE specific ignores +.idea/ diff --git a/wrappers/rust/Cargo.toml b/wrappers/rust/Cargo.toml new file mode 100644 index 00000000..2be9f4e8 --- /dev/null +++ b/wrappers/rust/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "indy" +version = "1.7.0" +description = "A library for assisting developers using LibIndy API" +authors = ["Mike Lodder ", + "Matt Raffel ", + "Darien Hess ", + "Stephen Felt ", + "Cam Parra ", + "Brent Zundel "] +homepage = "https://github.com/evernym/rust-libindy-wrapper" +repository = "https://github.com/evernym/rust-libindy-wrapper" +categories = ["api-bindings", "development-tools"] +license = "MIT/Apache-2.0" +readme = "README.md" +exclude = [ + "tests/*", + ] + +[lib] +name = "indyrs" +path = "src/lib.rs" +crate-type = ["rlib"] + +[dependencies] +failure = "0.1.2" +futures = "0.1.24" +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.7.0" } +libc = "=0.2.41" + +[dev-dependencies] +bs58 = {version = "0.2.2", features = ["check"]} +rand = "0.5.5" +serde_json = "1.0.22" +serde_derive = "1.0.76" +serde = "1.0.76" +rmp-serde = "0.13.6" +byteorder = "1.0.0" +dirs = "1.0.4" + +[features] +timeout_tests = [] +tests_to_fix = [] +extended_api_types = [] \ No newline at end of file diff --git a/wrappers/rust/LICENSE-APACHE b/wrappers/rust/LICENSE-APACHE new file mode 100644 index 00000000..b4422e6f --- /dev/null +++ b/wrappers/rust/LICENSE-APACHE @@ -0,0 +1,196 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + diff --git a/wrappers/rust/LICENSE-MIT b/wrappers/rust/LICENSE-MIT new file mode 100644 index 00000000..39d4bdb5 --- /dev/null +++ b/wrappers/rust/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/wrappers/rust/README.md b/wrappers/rust/README.md new file mode 100644 index 00000000..033f3ac1 --- /dev/null +++ b/wrappers/rust/README.md @@ -0,0 +1,22 @@ +# indy + +[LibIndy](https://github.com/hyperledger/indy-sdk/tree/master/libindy) major artifact of the SDK is a C-callable library that provides the basic building blocks for the creation of applications on the top of Hyperledger Indy, which provides a distributed-ledger-based foundation for self-sovereign identity. + +**indy** is a library for assisting developers using LibIndy API. + +## Using indy +- **indy** does not include LibIndy. Install native "indy" library: + * Ubuntu: https://repo.sovrin.org/lib/apt/xenial/ + * Windows: https://repo.sovrin.org/windows/libindy/ + +- Add **indy** to Cargo.toml +``` +[dependencies] +indy = "1.6.7" +``` + +# Note +This library is currently in experimental state. + +# License +Released under Apache 2.0 and MIT. See license files in git repo. \ No newline at end of file diff --git a/wrappers/rust/indy-sys/Cargo.toml b/wrappers/rust/indy-sys/Cargo.toml new file mode 100644 index 00000000..1c615975 --- /dev/null +++ b/wrappers/rust/indy-sys/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "indy-sys" +description = "FFI bindings to Libindy C API" +version = "1.7.0" +authors = ["Mike Lodder "] +build = "build.rs" +links = "indy" +license = "MIT/Apache-2.0" + +[dependencies] +libc = "=0.2.41" + +[build-dependencies] +pkg-config = "0.3.9" +regex = "1.0.0" + +[target.'cfg(target_env = "msvc")'.build-dependencies] +vcpkg = "0.2" \ No newline at end of file diff --git a/wrappers/rust/indy-sys/build.rs b/wrappers/rust/indy-sys/build.rs new file mode 100644 index 00000000..0e579005 --- /dev/null +++ b/wrappers/rust/indy-sys/build.rs @@ -0,0 +1,61 @@ +#[cfg(not(target_env = "msvc"))] +extern crate pkg_config; +extern crate regex; +#[cfg(target_env = "msvc")] +extern crate vcpkg; + +use std::env; + +fn main() { + println!("cargo:rerun-if-env-changed=LIBINDY_DIR"); + println!("cargo:rerun-if-env-changed=LIBINDY_STATIC"); + println!("cargo:rerun-if-env-changed=LIBINDY_PKG"); + + if cfg!(target_env = "msvc") { + // vcpkg requires to set env VCPKGRS_DYNAMIC + println!("cargo:rerun-if-env-changed=VCPKGRS_DYNAMIC"); + } + + let use_static = cfg!(any(target_os="android", target_os="ios")) || env::var("LIBINDY_STATIC").is_ok(); + let use_dir = env::var("LIBINDY_DIR").is_ok(); + let use_pkg = env::var("LIBINDY_USE_PKG_CONFIG").is_ok(); + + if use_dir && use_pkg { + panic!("LIBINDY_DIR is incompatible with LIBINDY_USE_PKG_CONFIG. Set the only one env variable"); + } + + if use_pkg { + find_pkg(use_static) + } else { + find_dir(env::var("LIBINDY_DIR").ok(), use_static) + } +} + +fn find_dir(dir_name: Option, use_static: bool) { + match (use_static, cfg!(windows)) { + (true, true) => println!("cargo:rustc-link-lib=indy"), + (true, false) => println!("cargo:rustc-link-lib=static=indy"), + (false, true) => println!("cargo:rustc-link-lib=indy.dll"), + (false, false) => println!("cargo:rustc-link-lib=dylib=indy"), + }; + + if let Some(dir_name) = dir_name { + println!("cargo:rustc-link-search=native={}", dir_name); + } +} + +#[cfg(not(target_env = "msvc"))] +fn find_pkg(use_static: bool) { + match pkg_config::Config::new().statik(use_static).probe("libindy") { + Ok(_) => println!("cargo:warning=Libindy found in pkgcfg tree."), + Err(e) => panic!(format!("Error: {:?}", e)), + } +} + +#[cfg(target_env = "msvc")] +fn find_pkg(_use_static: bool) { + match vcpkg::Config::new().emit_includes(true).lib_name("libindy").probe("indy") { + Ok(_) => println!("cargo:warning=Libindy found in vcpkg tree."), + Err(e) => panic!(format!("Error: {:?}", e)), + } +} \ No newline at end of file diff --git a/wrappers/rust/indy-sys/src/anoncreds.rs b/wrappers/rust/indy-sys/src/anoncreds.rs new file mode 100644 index 00000000..ff49cce6 --- /dev/null +++ b/wrappers/rust/indy-sys/src/anoncreds.rs @@ -0,0 +1,185 @@ +use super::*; + +use {CString, Error, Handle}; + +extern { + + #[no_mangle] + pub fn indy_issuer_create_schema(command_handle: Handle, + issuer_did: CString, + name: CString, + version: CString, + attrs: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_issuer_create_and_store_credential_def(command_handle: Handle, + wallet_handle: Handle, + issuer_did: CString, + schema_json: CString, + tag: CString, + signature_type: CString, + config_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_issuer_create_and_store_revoc_reg(command_handle: Handle, + wallet_handle: Handle, + issuer_did: CString, + revoc_def_type: CString, + tag: CString, + cred_def_id: CString, + config_json: CString, + tails_writer_handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_issuer_create_credential_offer(command_handle: Handle, + wallet_handle: Handle, + cred_def_id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_issuer_create_credential(command_handle: Handle, + wallet_handle: Handle, + cred_offer_json: CString, + cred_req_json: CString, + cred_values_json: CString, + rev_reg_id: CString, + blob_storage_reader_handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_issuer_revoke_credential(command_handle: Handle, + wallet_handle: Handle, + blob_storage_reader_cfg_handle: Handle, + rev_reg_id: CString, + cred_revoc_id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_issuer_merge_revocation_registry_deltas(command_handle: Handle, + rev_reg_delta_json: CString, + other_rev_reg_delta_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_create_master_secret(command_handle: Handle, + wallet_handle: Handle, + master_secret_id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_create_credential_req(command_handle: Handle, + wallet_handle: Handle, + prover_did: CString, + cred_offer_json: CString, + cred_def_json: CString, + master_secret_id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_store_credential(command_handle: Handle, + wallet_handle: Handle, + cred_id: CString, + cred_req_metadata_json: CString, + cred_json: CString, + cred_def_json: CString, + rev_reg_def_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_get_credential(command_handle: Handle, + wallet_handle: Handle, + cred_id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_get_credentials(command_handle: Handle, + wallet_handle: Handle, + filter_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_search_credentials(command_handle: Handle, + wallet_handle: Handle, + query_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_fetch_credentials(command_handle: Handle, + search_handle: Handle, + count: usize, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_close_credentials_search(command_handle: Handle, + search_handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_get_credentials_for_proof_req(command_handle: Handle, + wallet_handle: Handle, + proof_request_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_search_credentials_for_proof_req(command_handle: Handle, + wallet_handle: Handle, + proof_request_json: CString, + extra_query_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_fetch_credentials_for_proof_req(command_handle: Handle, + search_handle: Handle, + item_referent: CString, + count: usize, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_close_credentials_search_for_proof_req(command_handle: Handle, + search_handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_prover_create_proof(command_handle: Handle, + wallet_handle: Handle, + proof_req_json: CString, + requested_credentials_json: CString, + master_secret_id: CString, + schemas_json: CString, + credential_defs_json: CString, + rev_states_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_verifier_verify_proof(command_handle: Handle, + proof_request_json: CString, + proof_json: CString, + schemas_json: CString, + credential_defs_json: CString, + rev_reg_defs_json: CString, + rev_regs_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_create_revocation_state(command_handle: Handle, + blob_storage_reader_handle: Handle, + rev_reg_def_json: CString, + rev_reg_delta_json: CString, + timestamp: u64, + cred_rev_id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_update_revocation_state(command_handle: Handle, + blob_storage_reader_handle: Handle, + rev_state_json: CString, + rev_reg_def_json: CString, + rev_reg_delta_json: CString, + timestamp: u64, + cred_rev_id: CString, + cb: Option) -> Error; +} + diff --git a/wrappers/rust/indy-sys/src/blob_storage.rs b/wrappers/rust/indy-sys/src/blob_storage.rs new file mode 100644 index 00000000..a22a528c --- /dev/null +++ b/wrappers/rust/indy-sys/src/blob_storage.rs @@ -0,0 +1,19 @@ +use super::*; + +use {CString, Error, Handle}; + +extern { + + #[no_mangle] + pub fn indy_open_blob_storage_reader(command_handle: Handle, + type_: CString, + config_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_open_blob_storage_writer(command_handle: Handle, + type_: CString, + config_json: CString, + cb: Option) -> Error; +} + diff --git a/wrappers/rust/indy-sys/src/crypto.rs b/wrappers/rust/indy-sys/src/crypto.rs new file mode 100644 index 00000000..4510b28e --- /dev/null +++ b/wrappers/rust/indy-sys/src/crypto.rs @@ -0,0 +1,75 @@ +use super::*; + +use {BString, CString, Error, Handle}; + +extern { + + #[no_mangle] + pub fn indy_create_key(command_handle: Handle, + wallet_handle: Handle, + key_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_set_key_metadata(command_handle: Handle, + wallet_handle: Handle, + verkey: CString, + metadata: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_get_key_metadata(command_handle: Handle, + wallet_handle: Handle, + verkey: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_crypto_sign(command_handle: Handle, + wallet_handle: Handle, + signer_vk: CString, + message_raw: BString, + message_len: u32, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_crypto_verify(command_handle: Handle, + signer_vk: CString, + message_raw: BString, + message_len: u32, + signature_raw: BString, + signature_len: u32, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_crypto_auth_crypt(command_handle: Handle, + wallet_handle: Handle, + sender_vk: CString, + recipient_vk: CString, + msg_data: BString, + msg_len: u32, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_crypto_auth_decrypt(command_handle: Handle, + wallet_handle: Handle, + recipient_vk: CString, + encrypted_msg: BString, + encrypted_len: u32, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_crypto_anon_crypt(command_handle: Handle, + recipient_vk: CString, + msg_data: BString, + msg_len: u32, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_crypto_anon_decrypt(command_handle: Handle, + wallet_handle: Handle, + recipient_vk: CString, + encrypted_msg: BString, + encrypted_len: u32, + cb: Option) -> Error; +} + diff --git a/wrappers/rust/indy-sys/src/did.rs b/wrappers/rust/indy-sys/src/did.rs new file mode 100644 index 00000000..f6230a95 --- /dev/null +++ b/wrappers/rust/indy-sys/src/did.rs @@ -0,0 +1,90 @@ +use super::*; + +use {CString, Error, Handle}; + +extern { + + #[no_mangle] + pub fn indy_create_and_store_my_did(command_handle: Handle, + wallet_handle: Handle, + did_info: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_replace_keys_start(command_handle: Handle, + wallet_handle: Handle, + did: CString, + key_info: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_replace_keys_apply(command_handle: Handle, + wallet_handle: Handle, + did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_store_their_did(command_handle: Handle, + wallet_handle: Handle, + identity_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_key_for_did(command_handle: Handle, + pool_handle: Handle, + wallet_handle: Handle, + did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_key_for_local_did(command_handle: Handle, + wallet_handle: Handle, + did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_set_endpoint_for_did(command_handle: Handle, + wallet_handle: Handle, + did: CString, + address: CString, + transport_key: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_get_endpoint_for_did(command_handle: Handle, + wallet_handle: Handle, + pool_handle: Handle, + did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_set_did_metadata(command_handle: Handle, + wallet_handle: Handle, + did: CString, + metadata: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_get_did_metadata(command_handle: Handle, + wallet_handle: Handle, + did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_get_my_did_with_meta(command_handle: Handle, + wallet_handle: Handle, + my_did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_list_my_dids_with_meta(command_handle: Handle, + wallet_handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_abbreviate_verkey(command_handle: Handle, + did: CString, + full_verkey: CString, + cb: Option) -> Error; +} + diff --git a/wrappers/rust/indy-sys/src/ledger.rs b/wrappers/rust/indy-sys/src/ledger.rs new file mode 100644 index 00000000..f7662028 --- /dev/null +++ b/wrappers/rust/indy-sys/src/ledger.rs @@ -0,0 +1,227 @@ +use super::*; + +use {CString, Error, Handle}; + +extern { + #[no_mangle] + pub fn indy_sign_and_submit_request(command_handle: Handle, + pool_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + request_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_submit_request(command_handle: Handle, + pool_handle: Handle, + request_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_submit_action(command_handle: Handle, + pool_handle: Handle, + request_json: CString, + nodes: CString, + timeout: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_sign_request(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + request_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_multi_sign_request(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + request_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_ddo_request(command_handle: Handle, + submitter_did: CString, + target_did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_nym_request(command_handle: Handle, + submitter_did: CString, + target_did: CString, + verkey: CString, + alias: CString, + role: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_nym_request(command_handle: Handle, + submitter_did: CString, + target_did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_attrib_request(command_handle: Handle, + submitter_did: CString, + target_did: CString, + hash: CString, + raw: CString, + enc: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_attrib_request(command_handle: Handle, + submitter_did: CString, + target_did: CString, + raw: CString, + hash: CString, + enc: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_schema_request(command_handle: Handle, + submitter_did: CString, + data: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_schema_request(command_handle: Handle, + submitter_did: CString, + id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_get_schema_response(command_handle: Handle, + get_schema_response: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_cred_def_request(command_handle: Handle, + submitter_did: CString, + data: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_cred_def_request(command_handle: Handle, + submitter_did: CString, + id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_get_cred_def_response(command_handle: Handle, + get_cred_def_response: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_node_request(command_handle: Handle, + submitter_did: CString, + target_did: CString, + data: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_validator_info_request(command_handle: Handle, + submitter_did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_txn_request(command_handle: Handle, + submitter_did: CString, + ledger_type: CString, + seq_no: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_pool_config_request(command_handle: Handle, + submitter_did: CString, + writes: bool, + force: bool, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_pool_restart_request(command_handle: Handle, + submitter_did: CString, + action: CString, + datetime: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_pool_upgrade_request(command_handle: Handle, + submitter_did: CString, + name: CString, + version: CString, + action: CString, + sha256: CString, + timeout: Handle, + schedule: CString, + justification: CString, + reinstall: bool, + force: bool, + package: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_revoc_reg_def_request(command_handle: Handle, + submitter_did: CString, + data: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_revoc_reg_def_request(command_handle: Handle, + submitter_did: CString, + id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_get_revoc_reg_def_response(command_handle: Handle, + get_revoc_reg_def_response: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_revoc_reg_entry_request(command_handle: Handle, + submitter_did: CString, + revoc_reg_def_id: CString, + rev_def_type: CString, + value: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_revoc_reg_request(command_handle: Handle, + submitter_did: CString, + revoc_reg_def_id: CString, + timestamp: i64, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_get_revoc_reg_response(command_handle: Handle, + get_revoc_reg_response: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_revoc_reg_delta_request(command_handle: Handle, + submitter_did: CString, + revoc_reg_def_id: CString, + from: i64, + to: i64, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_get_revoc_reg_delta_response(command_handle: Handle, + get_revoc_reg_delta_response: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_register_transaction_parser_for_sp(command_handle: Handle, + txn_type: CString, + parser: Option, + free: Option, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_get_response_metadata(command_handle: Handle, + response: CString, + cb: Option) -> Error; +} + +pub type CustomTransactionParser = extern fn(reply_from_node: CString, parsed_sp: *mut CString) -> Error; +pub type CustomFree = extern fn(data: CString) -> Error; diff --git a/wrappers/rust/indy-sys/src/lib.rs b/wrappers/rust/indy-sys/src/lib.rs new file mode 100644 index 00000000..55849dc0 --- /dev/null +++ b/wrappers/rust/indy-sys/src/lib.rs @@ -0,0 +1,37 @@ +extern crate libc; + +pub mod anoncreds; +pub mod blob_storage; +pub mod crypto; +pub mod did; +pub mod ledger; +pub mod non_secrets; +pub mod pairwise; +pub mod payments; +pub mod pool; +pub mod wallet; +pub mod logger; + +use self::libc::{c_void, c_char}; + +pub type CVoid = c_void; +pub type BString = *const u8; +pub type CString = *const c_char; +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 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); +pub type ResponseStringStringCB = extern fn(xcommand_handle: Handle, err: Error, str1: CString, str2: CString); +pub type ResponseStringStringStringCB = extern fn(xcommand_handle: Handle, err: Error, str1: CString, str2: CString, str3: CString); +pub type ResponseSliceCB = extern fn(xcommand_handle: Handle, err: Error, raw: BString, len: u32); +pub type ResponseStringSliceCB = extern fn(xcommand_handle: Handle, err: Error, str1: CString, raw: BString, len: u32); +pub type ResponseStringStringU64CB = extern fn(xcommand_handle: Handle, err: Error, arg1: CString, arg2: CString, arg3: u64); + +extern { + #[no_mangle] + pub fn indy_set_runtime_config(config: CString) -> Error; +} \ No newline at end of file diff --git a/wrappers/rust/indy-sys/src/logger.rs b/wrappers/rust/indy-sys/src/logger.rs new file mode 100644 index 00000000..9ee8f935 --- /dev/null +++ b/wrappers/rust/indy-sys/src/logger.rs @@ -0,0 +1,34 @@ +use {CString, CVoid, Error}; + +extern { + + #[no_mangle] + pub fn indy_set_logger(context: *const CVoid, + enabled: Option, + log: Option, + flush: Option) -> Error; + + #[no_mangle] + pub fn indy_set_default_logger(pattern: CString) -> Error; + + #[no_mangle] + pub fn indy_get_logger(context_p: *mut CVoid, + enabled_cb_p: *mut Option, + log_cb_p: *mut Option, + flush_cb_p: *mut Option) -> Error; +} + +pub type EnabledCB = extern fn(context: *const CVoid, + level: u32, + target: CString) -> bool; + +pub type LogCB = extern fn(context: *const CVoid, + level: u32, + target: CString, + message: CString, + module_path: CString, + file: CString, + line: u32); + +pub type FlushCB = extern fn(context: *const CVoid); + diff --git a/wrappers/rust/indy-sys/src/non_secrets.rs b/wrappers/rust/indy-sys/src/non_secrets.rs new file mode 100644 index 00000000..caa10c55 --- /dev/null +++ b/wrappers/rust/indy-sys/src/non_secrets.rs @@ -0,0 +1,83 @@ +use super::*; + +use {CString, Error, Handle}; + +extern { + + #[no_mangle] + pub fn indy_add_wallet_record(command_handle: Handle, + wallet_handle: Handle, + type_: CString, + id: CString, + value: CString, + tags_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_update_wallet_record_value(command_handle: Handle, + wallet_handle: Handle, + type_: CString, + id: CString, + value: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_update_wallet_record_tags(command_handle: Handle, + wallet_handle: Handle, + type_: CString, + id: CString, + tags_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_add_wallet_record_tags(command_handle: Handle, + wallet_handle: Handle, + type_: CString, + id: CString, + tags_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_delete_wallet_record_tags(command_handle: Handle, + wallet_handle: Handle, + type_: CString, + id: CString, + tag_names_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_delete_wallet_record(command_handle: Handle, + wallet_handle: Handle, + type_: CString, + id: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_get_wallet_record(command_handle: Handle, + wallet_handle: Handle, + type_: CString, + id: CString, + options_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_open_wallet_search(command_handle: Handle, + wallet_handle: Handle, + type_: CString, + query_json: CString, + options_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_fetch_wallet_search_next_records(command_handle: Handle, + wallet_handle: Handle, + wallet_search_handle: Handle, + count: usize, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_close_wallet_search(command_handle: Handle, + wallet_search_handle: Handle, + cb: Option) -> Error; +} + diff --git a/wrappers/rust/indy-sys/src/pairwise.rs b/wrappers/rust/indy-sys/src/pairwise.rs new file mode 100644 index 00000000..e8dc77bf --- /dev/null +++ b/wrappers/rust/indy-sys/src/pairwise.rs @@ -0,0 +1,39 @@ +use super::*; + +use {CString, Error, Handle}; + +extern { + + #[no_mangle] + pub fn indy_is_pairwise_exists(command_handle: Handle, + wallet_handle: Handle, + their_did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_create_pairwise(command_handle: Handle, + wallet_handle: Handle, + their_did: CString, + my_did: CString, + metadata: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_list_pairwise(command_handle: Handle, + wallet_handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_get_pairwise(command_handle: Handle, + wallet_handle: Handle, + their_did: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_set_pairwise_metadata(command_handle: Handle, + wallet_handle: Handle, + their_did: CString, + metadata: CString, + cb: Option) -> Error; +} + diff --git a/wrappers/rust/indy-sys/src/payments.rs b/wrappers/rust/indy-sys/src/payments.rs new file mode 100644 index 00000000..7b34227e --- /dev/null +++ b/wrappers/rust/indy-sys/src/payments.rs @@ -0,0 +1,208 @@ +use super::*; + +use {CString, Error, Handle}; + +extern { + + #[no_mangle] + pub fn indy_register_payment_method(command_handle: Handle, + payment_method: CString, + create_payment_address: Option, + add_request_fees: Option, + parse_response_with_fees: Option, + build_get_payment_sources_request: Option, + parse_get_payment_sources_response: Option, + build_payment_req: Option, + parse_payment_response: Option, + build_mint_req: Option, + build_set_txn_fees_req: Option, + build_get_txn_fees_req: Option, + parse_get_txn_fees_response: Option, + build_verify_payment_req: Option, + parse_verify_payment_response: Option, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_create_payment_address(command_handle: Handle, + wallet_handle: Handle, + payment_method: CString, + config: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_list_payment_addresses(command_handle: Handle, + wallet_handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_add_request_fees(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + req_json: CString, + inputs_json: CString, + outputs_json: CString, + extra: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_response_with_fees(command_handle: Handle, + payment_method: CString, + resp_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_payment_sources_request(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + payment_address: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_get_payment_sources_response(command_handle: Handle, + payment_method: CString, + resp_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_payment_req(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + inputs_json: CString, + outputs_json: CString, + extra: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_payment_response(command_handle: Handle, + payment_method: CString, + resp_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_mint_req(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + outputs_json: CString, + extra: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_set_txn_fees_req(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + payment_method: CString, + fees_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_get_txn_fees_req(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + payment_method: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_get_txn_fees_response(command_handle: Handle, + payment_method: CString, + resp_json: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_build_verify_payment_req(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + receipt: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_parse_verify_payment_response(command_handle: Handle, + payment_method: CString, + resp_json: CString, + cb: Option) -> Error; +} + +pub type CreatePaymentAddressCB = extern fn(command_handle: Handle, + wallet_handle: Handle, + config: CString, + cb: Option Error>) -> Error; +pub type AddRequestFeesCB = extern fn(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + req_json: CString, + inputs_json: CString, + outputs_json: CString, + extra: CString, + cb: Option Error>) -> Error; +pub type ParseResponseWithFeesCB = extern fn(command_handle: Handle, + resp_json: CString, + cb: Option Error>) -> Error; +pub type BuildGetPaymentSourcesRequestCB = extern fn(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + payment_address: CString, + cb: Option Error>) -> Error; +pub type ParseGetPaymentSourcesResponseCB = extern fn(command_handle: Handle, + resp_json: CString, + cb: Option Error>) -> Error; +pub type BuildPaymentReqCB = extern fn(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + inputs_json: CString, + outputs_json: CString, + extra: CString, + cb: Option Error>) -> Error; +pub type ParsePaymentResponseCB = extern fn(command_handle: Handle, + resp_json: CString, + cb: Option Error>) -> Error; +pub type BuildMintReqCB = extern fn(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + outputs_json: CString, + extra: CString, + cb: Option Error>) -> Error; +pub type BuildSetTxnFeesReqCB = extern fn(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + fees_json: CString, + cb: Option Error>) -> Error; +pub type BuildGetTxnFeesReqCB = extern fn(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + cb: Option Error>) -> Error; +pub type ParseGetTxnFeesResponseCB = extern fn(command_handle: Handle, + resp_json: CString, + cb: Option Error>) -> Error; +pub type BuildVerifyPaymentReqCB = extern fn(command_handle: Handle, + wallet_handle: Handle, + submitter_did: CString, + receipt: CString, + cb: Option Error>) -> Error; +pub type ParseVerifyPaymentResponseCB = extern fn(command_handle: Handle, + resp_json: CString, + cb: Option Error>) -> Error; diff --git a/wrappers/rust/indy-sys/src/pool.rs b/wrappers/rust/indy-sys/src/pool.rs new file mode 100644 index 00000000..8e536dd8 --- /dev/null +++ b/wrappers/rust/indy-sys/src/pool.rs @@ -0,0 +1,43 @@ +use super::*; + +use {CString, Error, Handle}; + +extern { + + #[no_mangle] + pub fn indy_create_pool_ledger_config(command_handle: Handle, + config_name: CString, + config: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_open_pool_ledger(command_handle: Handle, + config_name: CString, + config: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_refresh_pool_ledger(command_handle: Handle, + handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_list_pools(command_handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_close_pool_ledger(command_handle: Handle, + handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_delete_pool_ledger_config(command_handle: Handle, + config_name: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_set_protocol_version(command_handle: Handle, + protocol_version: usize, + cb: Option) -> Error; +} + diff --git a/wrappers/rust/indy-sys/src/wallet.rs b/wrappers/rust/indy-sys/src/wallet.rs new file mode 100644 index 00000000..e9340fde --- /dev/null +++ b/wrappers/rust/indy-sys/src/wallet.rs @@ -0,0 +1,157 @@ +use super::*; + +use {BString, CString, Error, Handle}; + +extern { + + #[no_mangle] + pub fn indy_register_wallet_storage(command_handle: Handle, + type_: CString, + create: Option, + open: Option, + close: Option, + delete: Option, + add_record: Option, + update_record_value: Option, + update_record_tags: Option, + add_record_tags: Option, + delete_record_tags: Option, + delete_record: Option, + get_record: Option, + get_record_id: Option, + get_record_type: Option, + get_record_value: Option, + get_record_tags: Option, + free_record: Option, + get_storage_metadata: Option, + set_storage_metadata: Option, + free_storage_metadata: Option, + search_records: Option, + search_all_records: Option, + get_search_total_count: Option, + fetch_search_next_record: Option, + free_search: Option, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_create_wallet(command_handle: Handle, + config: CString, + credentials: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_open_wallet(command_handle: Handle, + config: CString, + credentials: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_export_wallet(command_handle: Handle, + wallet_handle: Handle, + export_config: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_import_wallet(command_handle: Handle, + config: CString, + credentials: CString, + import_config: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_close_wallet(command_handle: Handle, + wallet_handle: Handle, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_delete_wallet(command_handle: Handle, + config: CString, + credentials: CString, + cb: Option) -> Error; + + #[no_mangle] + pub fn indy_generate_wallet_key(command_handle: Handle, + config: CString, + cb: Option) -> Error; +} + +pub type WalletCreate = extern fn(name: CString, + config: CString, + credentials_json: CString, + metadata: CString) -> Error; +pub type WalletOpen = extern fn(name: CString, + config: CString, + credentials_json: CString, + storage_handle_p: *mut Handle) -> Error; +pub type WalletClose = extern fn(storage_handle: Handle) -> Error; +pub type WalletDelete = extern fn(name: CString, + config: CString, + credentials_json: CString) -> Error; +pub type WalletAddRecord = extern fn(storage_handle: Handle, + type_: CString, + id: CString, + value: BString, + value_len: usize, + tags_json: CString) -> Error; +pub type WalletUpdateRecordValue = extern fn(storage_handle: Handle, + type_: CString, + id: CString, + value: BString, + value_len: usize, ) -> Error; +pub type WalletUpdateRecordTags = extern fn(storage_handle: Handle, + type_: CString, + id: CString, + tags_json: CString) -> Error; +pub type WalletAddRecordTags = extern fn(storage_handle: Handle, + type_: CString, + id: CString, + tags_json: CString) -> Error; +pub type WalletDeleteRecordTags = extern fn(storage_handle: Handle, + type_: CString, + id: CString, + tag_names_json: CString) -> Error; +pub type WalletDeleteRecord = extern fn(storage_handle: Handle, + type_: CString, + id: CString) -> Error; +pub type WalletGetRecord = extern fn(storage_handle: Handle, + type_: CString, + id: CString, + options_json: CString, + record_handle_p: *mut Handle) -> Error; +pub type WalletGetRecordId = extern fn(storage_handle: Handle, + record_handle: Handle, + record_id_p: *mut CString) -> Error; +pub type WalletGetRecordType = extern fn(storage_handle: Handle, + record_handle: Handle, + record_type_p: *mut CString) -> Error; +pub type WalletGetRecordValue = extern fn(storage_handle: Handle, + record_handle: Handle, + record_value_p: *mut BString, + record_value_len_p: *mut usize) -> Error; +pub type WalletGetRecordTags = extern fn(storage_handle: Handle, + record_handle: Handle, + record_tags_p: *mut CString) -> Error; +pub type WalletFreeRecord = extern fn(storage_handle: Handle, + record_handle: Handle) -> Error; +pub type WalletGetStorageMetadata = extern fn(storage_handle: Handle, + metadata_p: *mut CString, + metadata_handle: *mut Handle) -> Error; +pub type WalletSetStorageMetadata = extern fn(storage_handle: Handle, + metadata_p: CString) -> Error; +pub type WalletFreeStorageMetadata = extern fn(storage_handle: Handle, + metadata_handle: Handle) -> Error; +pub type WalletSearchRecords = extern fn(storage_handle: Handle, + type_: CString, + query_json: CString, + options_json: CString, + search_handle_p: *mut Handle) -> Error; +pub type WalletSearchAllRecords = extern fn(storage_handle: Handle, + search_handle_p: *mut Handle) -> Error; +pub type WalletGetSearchTotalCount = extern fn(storage_handle: Handle, + search_handle: Handle, + total_count_p: *mut usize) -> Error; +pub type WalletFetchSearchNextRecord = extern fn(storage_handle: Handle, + search_handle: Handle, + record_handle_p: *mut Handle) -> Error; +pub type WalletFreeSearch = extern fn(storage_handle: Handle, + search_handle: Handle) -> Error; diff --git a/wrappers/rust/scripts/gen_ffi.pl b/wrappers/rust/scripts/gen_ffi.pl new file mode 100644 index 00000000..c4b5a4ca --- /dev/null +++ b/wrappers/rust/scripts/gen_ffi.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl + +use v5.18; + +my $text = $ARGV[0]; + +if (-f $text) +{ + open(my $FH, $text) or die("Unable to open file $text"); + binmode($FH); + read($FH, $text, -s $FH); + close($FH); +} + +my @usings = qw(Error); + +$text =~ s{//.*$}{}mg; +$text =~ s{/\*.*?\*/}{}sg; +$text =~ s/(?:\r?\n)+/\n/g; +if ($text =~ s/\*const c_char/CString/g) +{ + push(@usings, "CString"); +} +if ($text =~ s/\*const u8/BString/g) +{ + push(@usings, "BString"); +} +if ($text =~ s/i32/Handle/g) +{ + push(@usings, "Handle"); +} +if ($text =~ s/\*const c_void/CVoid/g) +{ + push(@usings, "CVoid"); +} + +$text =~ s/(?<=Error)Code(?:\b|$)//g; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*,\s*\w+:\s*Error\))(?=[>])/ResponseEmptyCB/sg; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*,\s*\w+:\s*Error\s*,\s*\w+:\s*bool\))(?=[>])/ResponseBoolCB/sg; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*,\s*\w+:\s*Error\s*,\s*\w+:\s*Handle\))(?=[>])/ResponseI32CB/sg; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*.\s*\w+:\s*Error\s*,\s*\w+:\s*Handle\s*,\s*\w+:\s*usize\))(?=[>])/ResponseI32UsizeCB/sg; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*,\s*\w+:\s*Error\s*,\s*\w+:\s*CString\))(?=[>])/ResponseStringCB/sg; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*,\s*\w+:\s*Error\s*,\s*\w+:\s*CString,\s*\w+:\s*CString\))(?=[>])/ResponseStringStringCB/sg; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*,\s*\w+:\s*Error\s*,\s*\w+:\s*CString,\s*\w+:\s*CString,\s*\w+:\s*CString\))(?=[>])/ResponseStringStringStringCB/sg; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*,\s*\w+:\s*Error\s*,\s*\w+:\s*BString,\s*\w+:\s*u32\))(?=[>])/ResponseSliceCB/sg; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*,\s*\w+:\s*Error\s*,\s*\w+:\s*CString,\s*\w+:\s*BString,\s*\w+:\s*u32\))(?=[>])/ResponseStringSliceCB/sg; +$text =~ s/(?<=Option<)(extern fn\(\s*\w+:\s*Handle\s*,\s*\w+:\s*Error\s*,\s*\w+:\s*CString,\s*\w+:\s*CString,\s*\w+:\s*u64\))(?=[>])/ResponseStringStringU64CB/sg; + +say "use super::*;\n"; +say "use {" . join(", ", sort @usings) . "};\n"; +say "extern {"; +while ($text =~ m/\bpub\s+extern\s+fn\s+(indy_\w+\s*\(.+?\)\s+->\s+Error)/sgo) +{ + my $fn = $1; + + my ($len) = $fn =~ m/^([^(]+)/go; + my $whitespace = ' ' x (length($len) + length(" pub fn ")); + $fn =~ s/^\s+(?=\w)/$whitespace/mgo; + say ""; + say " #[no_mangle]"; + say " pub fn $fn;"; +} +say "}\n"; + +while ($text =~ m/\b(pub\s+type\s+\w+\s+=\s+extern\s+fn.+?Error;)/sgo) +{ + say $1; +} diff --git a/wrappers/rust/scripts/gen_from_ffi.pl b/wrappers/rust/scripts/gen_from_ffi.pl new file mode 100644 index 00000000..0b0acefb --- /dev/null +++ b/wrappers/rust/scripts/gen_from_ffi.pl @@ -0,0 +1,180 @@ +#!/usr/bin/perl + +use v5.18; + +my $namespace = $ARGV[0]; +my $text = $ARGV[1]; + +if (-f $text) +{ + open(my $FH, $text) or die("Unable to open file $text"); + binmode($FH); + read($FH, $text, -s $FH); + close($FH); +} + +my $body = ""; +my $ffi_namespace = lc($namespace); +my @ffi_callbacks = (); +my %used_ffi_callbacks = (); +while ($text =~ m/(pub fn \w+\([^)]+\)\s*->\s*Error;)/go) +{ + my $method = $1; + my ($name, $params) = $method =~ m/pub fn (\w+)\(([^)]+)\)/g; + $method =~ s/\s+/ /go; + $method =~ s/indy_//go; + my $method_name = $name; + $name =~ s/indy_//go; + $name =~ s/_?\Q$namespace\E//goi; + $params =~ s/\s+/ /go; + $params =~ s/CString/&str/go; + $params =~ s/CVoid//go; + $params =~ s/\bHandle\b/IndyHandle/go; + my $simple_params = $params; + $simple_params =~ s/command_handle:\s*\w+,\s*//go; + $simple_params =~ s/\s*,\s*cb:\s*[<>\w]+//go; + + my $params_no_types = $simple_params; + $params_no_types =~ s/:\s*[\[\]&<>\w]+(?=,|$)//go; + + my ($ffi_callback, $callback_result) = $params =~ m/Option<(Response(\w+)CB)>/goi; + if (!exists $used_ffi_callbacks{$ffi_callback}) + { + $used_ffi_callbacks{$ffi_callback} = 1; + push(@ffi_callbacks, $ffi_callback); + } + my $closure_handler = ""; + my $result_handler = lc($callback_result); + if ($callback_result eq "Empty") + { + $callback_result = "()"; + } + else + { + $closure_handler = $callback_result =~ s/([A-Z])/_$1/gro; + $closure_handler = lc($closure_handler); + + $callback_result =~ s/([A-Z])/, $1/go; + $callback_result = substr($callback_result, 2); + $callback_result =~ s/Bool/bool/go; + $callback_result =~ s/I(\d\d)/i$1/go; + $callback_result =~ s/U(\d\d)/u$1/go; + my @count = $callback_result =~ m/,/go; + if (@count == 0) + { + $result_handler = "one"; + } + elsif (@count == 1) + { + $result_handler = "two"; + $callback_result = "($callback_result)"; + } + elsif (@count == 2) + { + $result_handler = "three"; + $callback_result = "($callback_result)"; + } + else + { + die("Unknown result handler ". @count); + } + } + + $body .= " pub fn $name($simple_params) -> Result<$callback_result, ErrorCode> {\n"; + $body .= " let (receiver, command_handle, cb) = ClosureHandler::cb_ec$closure_handler();\n"; + $body .= "\n"; + $body .= " let err = $namespace" ."::_". $name . "(command_handle, $params_no_types, cb);\n"; + $body .= "\n"; + $body .= " ResultHandler::$result_handler(err, receiver)\n"; + $body .= " }\n"; + $body .= "\n"; + $body .= " /// * `timeout` - the maximum time this function waits for a response\n"; + $body .= " pub fn $name\_timeout($simple_params, timeout: Duration) -> Result<$callback_result, ErrorCode> {\n"; + $body .= " let (receiver, command_handle, cb) = ClosureHandler::cb_ec$closure_handler();\n"; + $body .= "\n"; + $body .= " let err = $namespace" ."::_". $name . "(command_handle, $params_no_types, cb);\n"; + $body .= "\n"; + $body .= " ResultHandler::$result_handler\_timeout(err, receiver, timeout)\n"; + $body .= " }\n"; + $body .= "\n"; + $body .= " /// * `closure` - the closure that is called when finished\n"; + $body .= " ///\n"; + $body .= " /// # Returns\n"; + $body .= " /// * `errorcode` - errorcode from calling ffi function. The closure receives the return result\n"; + if ($callback_result =~ m/^\(/o) + { + $callback_result = substr($callback_result, 1); + chop($callback_result); + } + if ($result_handler eq "empty") + { + $body .= " pub fn $name\_async($simple_params, closure: F) -> ErrorCode where F: FnMut(ErrorCode) + Send {\n"; + } + else + { + $body .= " pub fn $name\_async($simple_params, closure: F) -> ErrorCode where F: FnMut(ErrorCode, $callback_result) + Send {\n"; + } + $body .= " let (command_handle, cb) = ClosureHandler::convert_cb_ec$closure_handler(Box::new(closure));\n"; + $body .= "\n"; + $body .= " $namespace\::_$name(command_handle, $params_no_types, cb)\n"; + $body .= " }\n\n"; + $body .= " fn _$name($params) -> ErrorCode {\n"; + while ($params =~ m/(\w+):\s*\&str/go) + { + $body .= " let $1 = c_str!($1);\n"; + } + while ($params =~ m/(\w+):\s*Option<\&str>/go) + { + $body .= " let $1\_str = opt_c_str!($1);\n"; + } + $body .= "\n"; + $body .= " ErrorCode::from(unsafe {\n"; + $body .= " $ffi_namespace\::$method_name("; + while ($params =~ m/(\w+):\s*([&\[\]<>\w]+)(,|$)/go) + { + my $param_name = $1; + my $param_type = $2; + my $delimiter = $3; + + if ($param_type eq "&str") + { + $body .= "$1.as_ptr()$delimiter"; + } + elsif ($param_type eq "Option<&str>") + { + $body .= "opt_c_ptr!($1,$1\_str)$delimiter"; + } + elsif ($param_type eq "&[u8]") + { + $body .= "$1.as_ptr() as *const u8, $1.len() as u32$delimiter"; + } + else + { + $body .= "$1$delimiter"; + } + if ($delimiter) + { + $body .= " "; + } + } + $body .= ")\n"; + $body .= " })\n"; + $body .= " }\n\n"; +} + +say "\n\n"; +say "use ffi::". lc($namespace) . ";"; +if (@ffi_callbacks > 1) +{ + say "use ffi::{" . join(", ", @ffi_callbacks) . "};"; +} +else +{ + say "use ffi::". $ffi_callbacks[0] . ";"; +} +say "\n"; +say "pub struct $namespace {}\n"; +say "impl $namespace {"; +$body =~ s/\s+$//g; +say $body; +say "}"; diff --git a/wrappers/rust/src/anoncreds.rs b/wrappers/rust/src/anoncreds.rs new file mode 100644 index 00000000..51d4acad --- /dev/null +++ b/wrappers/rust/src/anoncreds.rs @@ -0,0 +1,1133 @@ +use {ErrorCode, IndyHandle}; + +use std::ffi::CString; +use std::ptr::null; + +use futures::Future; + +use utils::callbacks::{ClosureHandler, ResultHandler}; + +use ffi::anoncreds; +use ffi::{ResponseStringStringCB, + ResponseI32UsizeCB, + ResponseStringStringStringCB, + ResponseStringCB, + ResponseI32CB, + ResponseEmptyCB, + ResponseBoolCB}; + +/// Create credential schema entity that describes credential attributes list and allows credentials +/// interoperability. +/// +/// Schema is public and intended to be shared with all anoncreds workflow actors usually by publishing SCHEMA transaction +/// to Indy distributed ledger. +/// +/// It is IMPORTANT for current version POST Schema in Ledger and after that GET it from Ledger +/// with correct seq_no to save compatibility with Ledger. +/// After that can call create_and_store_credential_def to build corresponding Credential Definition. +/// +/// # Arguments +/// * `pool_handle` - pool handle (created by Pool::open_ledger). +/// * `issuer_did`: DID of schema issuer +/// * `name`: a name the schema +/// * `version`: a version of the schema +/// * `attrs`: a list of schema attributes descriptions (the number of attributes should be less or equal than 125) +/// +/// # Returns +/// * `schema_id`: identifier of created schema +/// * `schema_json`: schema as json +pub fn issuer_create_schema(issuer_did: &str, name: &str, version: &str, attrs: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _issuer_create_schema(command_handle, issuer_did, name, version, attrs, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _issuer_create_schema(command_handle: IndyHandle, issuer_did: &str, name: &str, version: &str, attrs: &str, cb: Option) -> ErrorCode { + let issuer_did = c_str!(issuer_did); + let name = c_str!(name); + let version = c_str!(version); + let attrs = c_str!(attrs); + + ErrorCode::from(unsafe { + anoncreds::indy_issuer_create_schema(command_handle, issuer_did.as_ptr(), name.as_ptr(), version.as_ptr(), attrs.as_ptr(), cb) + }) +} + +/// Create credential definition entity that encapsulates credentials issuer DID, credential schema, secrets used for signing credentials +/// and secrets used for credentials revocation. +/// +/// Credential definition entity contains private and public parts. Private part will be stored in the wallet. Public part +/// will be returned as json intended to be shared with all anoncreds workflow actors usually by publishing CRED_DEF transaction +/// to Indy distributed ledger. +/// +/// It is IMPORTANT for current version GET Schema from Ledger with correct seq_no to save compatibility with Ledger. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `issuer_did`: a DID of the issuer signing cred_def transaction to the Ledger +/// * `schema_json`: credential schema as a json +/// * `tag`: allows to distinct between credential definitions for the same issuer and schema +/// * `signature_type`: credential definition type (optional, 'CL' by default) that defines credentials signature and revocation math. Supported types are: +/// - 'CL': Camenisch-Lysyanskaya credential signature type +/// * `config_json`: (optional) type-specific configuration of credential definition as json: +/// - 'CL': +/// - support_revocation: whether to request non-revocation credential (optional, default false) +/// +/// # Returns +/// * `cred_def_id`: identifier of created credential definition +/// * `cred_def_json`: public part of created credential definition +pub fn issuer_create_and_store_credential_def(wallet_handle: IndyHandle, issuer_did: &str, schema_json: &str, tag: &str, signature_type: Option<&str>, config_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _issuer_create_and_store_credential_def(command_handle, wallet_handle, issuer_did, schema_json, tag, signature_type, config_json, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _issuer_create_and_store_credential_def(command_handle: IndyHandle, wallet_handle: IndyHandle, issuer_did: &str, schema_json: &str, tag: &str, signature_type: Option<&str>, config_json: &str, cb: Option) -> ErrorCode { + let issuer_did = c_str!(issuer_did); + let schema_json = c_str!(schema_json); + let tag = c_str!(tag); + let signature_type_str = opt_c_str!(signature_type); + let config_json = c_str!(config_json); + + ErrorCode::from(unsafe { + anoncreds::indy_issuer_create_and_store_credential_def(command_handle, wallet_handle, issuer_did.as_ptr(), schema_json.as_ptr(), tag.as_ptr(), opt_c_ptr!(signature_type, signature_type_str), config_json.as_ptr(), cb) + }) +} + +/// Create a new revocation registry for the given credential definition as tuple of entities +/// - Revocation registry definition that encapsulates credentials definition reference, revocation type specific configuration and +/// secrets used for credentials revocation +/// - Revocation registry state that stores the information about revoked entities in a non-disclosing way. The state can be +/// represented as ordered list of revocation registry entries were each entry represents the list of revocation or issuance operations. +/// +/// Revocation registry definition entity contains private and public parts. Private part will be stored in the wallet. Public part +/// will be returned as json intended to be shared with all anoncreds workflow actors usually by publishing REVOC_REG_DEF transaction +/// to Indy distributed ledger. +/// +/// Revocation registry state is stored on the wallet and also intended to be shared as the ordered list of REVOC_REG_ENTRY transactions. +/// This call initializes the state in the wallet and returns the initial entry. +/// +/// Some revocation registry types (for example, 'CL_ACCUM') can require generation of binary blob called tails used to hide information about revoked credentials in public +/// revocation registry and intended to be distributed out of leger (REVOC_REG_DEF transaction will still contain uri and hash of tails). +/// This call requires access to pre-configured blob storage writer instance handle that will allow to write generated tails. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `issuer_did`: a DID of the issuer signing transaction to the Ledger +/// * `revoc_def_type`: revocation registry type (optional, default value depends on credential definition type). Supported types are: +/// - 'CL_ACCUM': Type-3 pairing based accumulator. Default for 'CL' credential definition type +/// * `tag`: allows to distinct between revocation registries for the same issuer and credential definition +/// * `cred_def_id`: id of stored in ledger credential definition +/// * `config_json`: type-specific configuration of revocation registry as json: +/// - 'CL_ACCUM': { +/// "issuance_type": (optional) type of issuance. Currently supported: +/// 1) ISSUANCE_BY_DEFAULT: all indices are assumed to be issued and initial accumulator is calculated over all indices; +/// Revocation Registry is updated only during revocation. +/// 2) ISSUANCE_ON_DEMAND: nothing is issued initially accumulator is 1 (used by default); +/// "max_cred_num": maximum number of credentials the new registry can process (optional, default 100000) +/// } +/// * `tails_writer_handle`: handle of blob storage to store tails +/// +/// # Returns +/// * `revoc_reg_id`: identifier of created revocation registry definition +/// * `revoc_reg_def_json`: public part of revocation registry definition +/// * `revoc_reg_entry_json`: revocation registry entry that defines initial state of revocation registry +pub fn issuer_create_and_store_revoc_reg(wallet_handle: IndyHandle, issuer_did: &str, revoc_def_type: Option<&str>, tag: &str, cred_def_id: &str, config_json: &str, tails_writer_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string_string(); + + let err = _issuer_create_and_store_revoc_reg(command_handle, wallet_handle, issuer_did, revoc_def_type, tag, cred_def_id, config_json, tails_writer_handle, cb); + + ResultHandler::str_str_str(command_handle, err, receiver) +} + +fn _issuer_create_and_store_revoc_reg(command_handle: IndyHandle, wallet_handle: IndyHandle, issuer_did: &str, revoc_def_type: Option<&str>, tag: &str, cred_def_id: &str, config_json: &str, tails_writer_handle: IndyHandle, cb: Option) -> ErrorCode { + let issuer_did = c_str!(issuer_did); + let revoc_def_type_str = opt_c_str!(revoc_def_type); + let tag = c_str!(tag); + let cred_def_id = c_str!(cred_def_id); + let config_json = c_str!(config_json); + + ErrorCode::from(unsafe { + anoncreds::indy_issuer_create_and_store_revoc_reg(command_handle, wallet_handle, issuer_did.as_ptr(), opt_c_ptr!(revoc_def_type, revoc_def_type_str), tag.as_ptr(), cred_def_id.as_ptr(), config_json.as_ptr(), tails_writer_handle, cb) + }) +} + +/// Create credential offer that will be used by Prover for +/// credential request creation. Offer includes nonce and key correctness proof +/// for authentication between protocol steps and integrity checking. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet) +/// * `cred_def_id`: id of credential definition stored in the wallet +/// +/// # Returns +/// * `credential_offer_json` - { +/// "schema_id": string, +/// "cred_def_id": string, +/// // Fields below can depend on Cred Def type +/// "nonce": string, +/// "key_correctness_proof" : +/// } +pub fn issuer_create_credential_offer(wallet_handle: IndyHandle, cred_def_id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _issuer_create_credential_offer(command_handle, wallet_handle, cred_def_id, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _issuer_create_credential_offer(command_handle: IndyHandle, wallet_handle: IndyHandle, cred_def_id: &str, cb: Option) -> ErrorCode { + let cred_def_id = c_str!(cred_def_id); + + ErrorCode::from(unsafe { + anoncreds::indy_issuer_create_credential_offer(command_handle, wallet_handle, cred_def_id.as_ptr(), cb) + }) +} + +/// Check Cred Request for the given Cred Offer and issue Credential for the given Cred Request. +/// +/// Cred Request must match Cred Offer. The credential definition and revocation registry definition +/// referenced in Cred Offer and Cred Request must be already created and stored into the wallet. +/// +/// Information for this credential revocation will be store in the wallet as part of revocation registry under +/// generated cred_revoc_id local for this wallet. +/// +/// This call returns revoc registry delta as json file intended to be shared as REVOC_REG_ENTRY transaction. +/// Note that it is possible to accumulate deltas to reduce ledger load. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `cred_offer_json`: a cred offer created by create_credential_offer +/// * `cred_req_json`: a credential request created by store_credential +/// * `cred_values_json`: a credential containing attribute values for each of requested attribute names. +/// Example: +/// { +/// "attr1" : {"raw": "value1", "encoded": "value1_as_int" }, +/// "attr2" : {"raw": "value1", "encoded": "value1_as_int" } +/// } +/// * `rev_reg_id`: id of revocation registry stored in the wallet +/// * `blob_storage_reader_handle`: configuration of blob storage reader handle that will allow to read revocation tails +/// +/// # Returns +/// * `cred_json`: Credential json containing signed credential values +/// { +/// "schema_id": string, +/// "cred_def_id": string, +/// "rev_reg_def_id", Optional, +/// "values": , +/// // Fields below can depend on Cred Def type +/// "signature": , +/// "signature_correctness_proof": +/// } +/// * `cred_revoc_id`: local id for revocation info (Can be used for revocation of this credential) +/// * `revoc_reg_delta_json`: Revocation registry delta json with a newly issued credential +pub fn issuer_create_credential(wallet_handle: IndyHandle, cred_offer_json: &str, cred_req_json: &str, cred_values_json: &str, rev_reg_id: Option<&str>, blob_storage_reader_handle: IndyHandle) -> Box, Option), Error=ErrorCode>> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_opt_string_opt_string(); + + let err = _issuer_create_credential(command_handle, wallet_handle, cred_offer_json, cred_req_json, cred_values_json, rev_reg_id, blob_storage_reader_handle, cb); + + ResultHandler::str_optstr_optstr(command_handle, err, receiver) +} + +fn _issuer_create_credential(command_handle: IndyHandle, wallet_handle: IndyHandle, cred_offer_json: &str, cred_req_json: &str, cred_values_json: &str, rev_reg_id: Option<&str>, blob_storage_reader_handle: IndyHandle, cb: Option) -> ErrorCode { + let cred_offer_json = c_str!(cred_offer_json); + let cred_req_json = c_str!(cred_req_json); + let cred_values_json = c_str!(cred_values_json); + let rev_reg_id_str = opt_c_str!(rev_reg_id); + + ErrorCode::from(unsafe { + anoncreds::indy_issuer_create_credential(command_handle, wallet_handle, cred_offer_json.as_ptr(), cred_req_json.as_ptr(), cred_values_json.as_ptr(), opt_c_ptr!(rev_reg_id, rev_reg_id_str), blob_storage_reader_handle, cb) + }) +} + +/// Revoke a credential identified by a cred_revoc_id (returned by indy_issuer_create_credential). +/// +/// The corresponding credential definition and revocation registry must be already +/// created an stored into the wallet. +/// +/// This call returns revoc registry delta as json file intended to be shared as REVOC_REG_ENTRY transaction. +/// Note that it is possible to accumulate deltas to reduce ledger load. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `blob_storage_reader_cfg_handle`: configuration of blob storage reader handle that will allow to read revocation tails +/// * `rev_reg_id: id of revocation` registry stored in wallet +/// * `cred_revoc_id`: local id for revocation info +/// +/// # Returns +/// * `revoc_reg_delta_json`: Revocation registry delta json with a revoked credential +pub fn issuer_revoke_credential(wallet_handle: IndyHandle, blob_storage_reader_cfg_handle: IndyHandle, rev_reg_id: &str, cred_revoc_id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _issuer_revoke_credential(command_handle, wallet_handle, blob_storage_reader_cfg_handle, rev_reg_id, cred_revoc_id, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _issuer_revoke_credential(command_handle: IndyHandle, wallet_handle: IndyHandle, blob_storage_reader_cfg_handle: IndyHandle, rev_reg_id: &str, cred_revoc_id: &str, cb: Option) -> ErrorCode { + let rev_reg_id = c_str!(rev_reg_id); + let cred_revoc_id = c_str!(cred_revoc_id); + + ErrorCode::from(unsafe { + anoncreds::indy_issuer_revoke_credential(command_handle, wallet_handle, blob_storage_reader_cfg_handle, rev_reg_id.as_ptr(), cred_revoc_id.as_ptr(), cb) + }) +} + +/// Merge two revocation registry deltas (returned by create_credential or revoke_credential) to accumulate common delta. +/// Send common delta to ledger to reduce the load. +/// +/// # Arguments +/// * `rev_reg_delta_json`: revocation registry delta. +/// * `other_rev_reg_delta_json`: revocation registry delta for which PrevAccum value is equal to current accum value of rev_reg_delta_json. +/// +/// # Returns +/// * `merged_rev_reg_delta` - Merged revocation registry delta +pub fn issuer_merge_revocation_registry_deltas(rev_reg_delta_json: &str, other_rev_reg_delta_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _issuer_merge_revocation_registry_deltas(command_handle, rev_reg_delta_json, other_rev_reg_delta_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _issuer_merge_revocation_registry_deltas(command_handle: IndyHandle, rev_reg_delta_json: &str, other_rev_reg_delta_json: &str, cb: Option) -> ErrorCode { + let rev_reg_delta_json = c_str!(rev_reg_delta_json); + let other_rev_reg_delta_json = c_str!(other_rev_reg_delta_json); + + ErrorCode::from(unsafe { + anoncreds::indy_issuer_merge_revocation_registry_deltas(command_handle, rev_reg_delta_json.as_ptr(), other_rev_reg_delta_json.as_ptr(), cb) + }) +} + + +/// Creates a master secret with a given id and stores it in the wallet. +/// The id must be unique. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `master_secret_id`: (optional, if not present random one will be generated) new master id +/// +/// # Returns +/// * `out_master_secret_id` - Id of generated master secret +pub fn prover_create_master_secret(wallet_handle: IndyHandle, master_secret_id: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _prover_create_master_secret(command_handle, wallet_handle, master_secret_id, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _prover_create_master_secret(command_handle: IndyHandle, wallet_handle: IndyHandle, master_secret_id: Option<&str>, cb: Option) -> ErrorCode { + let master_secret_id_str = opt_c_str!(master_secret_id); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_create_master_secret(command_handle, wallet_handle, opt_c_ptr!(master_secret_id, master_secret_id_str), cb) + }) +} + +/// Gets human readable credential by the given id. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `cred_id`: Identifier by which requested credential is stored in the wallet +/// +/// # Returns +/// * `credential_json` - { +/// "referent": string, // cred_id in the wallet +/// "attrs": {"key1":"raw_value1", "key2":"raw_value2"}, +/// "schema_id": string, +/// "cred_def_id": string, +/// "rev_reg_id": Optional, +/// "cred_rev_id": Optional +/// } +pub fn prover_get_credential(wallet_handle: IndyHandle, cred_id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _prover_get_credential(command_handle, wallet_handle, cred_id, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _prover_get_credential(command_handle: IndyHandle, wallet_handle: IndyHandle, cred_id: &str, cb: Option) -> ErrorCode { + let cred_id = c_str!(cred_id); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_get_credential(command_handle, wallet_handle, cred_id.as_ptr(), cb) + }) +} + +/// Creates a credential request for the given credential offer. +/// +/// The method creates a blinded master secret for a master secret identified by a provided name. +/// The master secret identified by the name must be already stored in the secure wallet (see create_master_secret) +/// The blinded master secret is a part of the credential request. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by open_wallet) +/// * `prover_did`: a DID of the prover +/// * `cred_offer_json`: credential offer as a json containing information about the issuer and a credential +/// * `cred_def_json`: credential definition json related to in +/// * `master_secret_id`: the id of the master secret stored in the wallet +/// +/// # Returns +/// * `cred_req_json`: Credential request json for creation of credential by Issuer +/// { +/// "prover_did" : string, +/// "cred_def_id" : string, +/// // Fields below can depend on Cred Def type +/// "blinded_ms" : , +/// "blinded_ms_correctness_proof" : , +/// "nonce": string +/// } +/// * `cred_req_metadata_json`: Credential request metadata json for further processing of received form Issuer credential. +pub fn prover_create_credential_req(wallet_handle: IndyHandle, prover_did: &str, cred_offer_json: &str, cred_def_json: &str, master_secret_id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _prover_create_credential_req(command_handle, wallet_handle, prover_did, cred_offer_json, cred_def_json, master_secret_id, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _prover_create_credential_req(command_handle: IndyHandle, wallet_handle: IndyHandle, prover_did: &str, cred_offer_json: &str, cred_def_json: &str, master_secret_id: &str, cb: Option) -> ErrorCode { + let prover_did = c_str!(prover_did); + let cred_offer_json = c_str!(cred_offer_json); + let cred_def_json = c_str!(cred_def_json); + let master_secret_id = c_str!(master_secret_id); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_create_credential_req(command_handle, wallet_handle, prover_did.as_ptr(), cred_offer_json.as_ptr(), cred_def_json.as_ptr(), master_secret_id.as_ptr(), cb) + }) +} + +/// Check credential provided by Issuer for the given credential request, +/// updates the credential by a master secret and stores in a secure wallet. +/// +/// To support efficient and flexible search the following tags will be created for stored credential: +/// { +/// "schema_id": , +/// "schema_issuer_did": , +/// "schema_name": , +/// "schema_version": , +/// "issuer_did": , +/// "cred_def_id": , +/// "rev_reg_id": , // "None" as string if not present +/// // for every attribute in +/// "attr::::marker": "1", +/// "attr::::value": , +/// } +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by open_wallet). +/// * `cred_id`: (optional, default is a random one) identifier by which credential will be stored in the wallet +/// * `cred_req_metadata_json`: a credential request metadata created by create_credential_req +/// * `cred_json`: credential json received from issuer +/// * `cred_def_json`: credential definition json related to in +/// * `rev_reg_def_json`: revocation registry definition json related to in +/// +/// # Returns +/// * `out_cred_id` - identifier by which credential is stored in the wallet +pub fn prover_store_credential(wallet_handle: IndyHandle, cred_id: Option<&str>, cred_req_metadata_json: &str, cred_json: &str, cred_def_json: &str, rev_reg_def_json: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _prover_store_credential(command_handle, wallet_handle, cred_id, cred_req_metadata_json, cred_json, cred_def_json, rev_reg_def_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _prover_store_credential(command_handle: IndyHandle, wallet_handle: IndyHandle, cred_id: Option<&str>, cred_req_metadata_json: &str, cred_json: &str, cred_def_json: &str, rev_reg_def_json: Option<&str>, cb: Option) -> ErrorCode { + let cred_id_str = opt_c_str!(cred_id); + let cred_req_metadata_json = c_str!(cred_req_metadata_json); + let cred_json = c_str!(cred_json); + let cred_def_json = c_str!(cred_def_json); + let rev_reg_def_json_str = opt_c_str!(rev_reg_def_json); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_store_credential(command_handle, wallet_handle, opt_c_ptr!(cred_id, cred_id_str), cred_req_metadata_json.as_ptr(), cred_json.as_ptr(), cred_def_json.as_ptr(), opt_c_ptr!(rev_reg_def_json, rev_reg_def_json_str), cb) + }) +} + +/// Gets human readable credentials according to the filter. +/// If filter is NULL, then all credentials are returned. +/// Credentials can be filtered by Issuer, credential_def and/or Schema. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by open_wallet). +/// * `filter_json`: filter for credentials { +/// "schema_id": string, (Optional) +/// "schema_issuer_did": string, (Optional) +/// "schema_name": string, (Optional) +/// "schema_version": string, (Optional) +/// "issuer_did": string, (Optional) +/// "cred_def_id": string, (Optional) +/// } +/// +/// # Returns +/// * `credentials_json` - [{ +/// "referent": string, // cred_id in the wallet +/// "attrs": {"key1":"raw_value1", "key2":"raw_value2"}, +/// "schema_id": string, +/// "cred_def_id": string, +/// "rev_reg_id": Optional, +/// "cred_rev_id": Optional +/// }] +pub fn prover_get_credentials(wallet_handle: IndyHandle, filter_json: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _prover_get_credentials(command_handle, wallet_handle, filter_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _prover_get_credentials(command_handle: IndyHandle, wallet_handle: IndyHandle, filter_json: Option<&str>, cb: Option) -> ErrorCode { + let filter_json_str = opt_c_str!(filter_json); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_get_credentials(command_handle, wallet_handle, opt_c_ptr!(filter_json, filter_json_str), cb) + }) +} + +/// Search for credentials stored in wallet. +/// Credentials can be filtered by tags created during saving of credential. +/// +/// Instead of immediately returning of fetched credentials +/// this call returns search_handle that can be used later +/// to fetch records by small batches (with fetch_credentials). +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `query_json`: Wql query filter for credentials searching based on tags. +/// where query: indy-sdk/doc/design/011-wallet-query-language/README.md +/// +/// # Returns +/// * `search_handle`: Search handle that can be used later to fetch records by small batches (with fetch_credentials) +/// * `total_count`: Total count of records +pub fn prover_search_credentials(wallet_handle: IndyHandle, query_json: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_handle_usize(); + + let err = _prover_search_credentials(command_handle, wallet_handle, query_json, cb); + + ResultHandler::handle_usize(command_handle, err, receiver) +} + +fn _prover_search_credentials(command_handle: IndyHandle, wallet_handle: IndyHandle, query_json: Option<&str>, cb: Option) -> ErrorCode { + let query_json_str = opt_c_str!(query_json); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_search_credentials(command_handle, wallet_handle, opt_c_ptr!(query_json, query_json_str), cb) + }) +} + +/// Fetch next credentials for search. +/// +/// # Arguments +/// * `search_handle`: Search handle (created by search_credentials) +/// * `count`: Count of credentials to fetch +/// +/// # Returns +/// * `credentials_json`: List of human readable credentials: +/// [{ +/// "referent": string, // cred_id in the wallet +/// "attrs": {"key1":"raw_value1", "key2":"raw_value2"}, +/// "schema_id": string, +/// "cred_def_id": string, +/// "rev_reg_id": Optional, +/// "cred_rev_id": Optional +/// }] +pub fn prover_fetch_credentials(search_handle: IndyHandle, count: usize) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _prover_fetch_credentials(command_handle, search_handle, count, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _prover_fetch_credentials(command_handle: IndyHandle, search_handle: IndyHandle, count: usize, cb: Option) -> ErrorCode { + + ErrorCode::from(unsafe { + anoncreds::indy_prover_fetch_credentials(command_handle, search_handle, count, cb) + }) +} + +/// Close credentials search (make search handle invalid) +/// +/// # Arguments +/// * `search_handle`: Search handle (created by search_credentials) +pub fn prover_close_credentials_search(search_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _prover_close_credentials_search(command_handle, search_handle, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _prover_close_credentials_search(command_handle: IndyHandle, search_handle: IndyHandle, cb: Option) -> ErrorCode { + + ErrorCode::from(unsafe { + anoncreds::indy_prover_close_credentials_search(command_handle, search_handle, cb) + }) +} + +/// Gets human readable credentials matching the given proof request. +/// +/// NOTE: This method is deprecated because immediately returns all fetched credentials. +/// Use to fetch records by small batches. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `proof_request_json`: proof request json +/// { +/// "name": string, +/// "version": string, +/// "nonce": string, +/// "requested_attributes": { // set of requested attributes +/// "": , // see below +/// ..., +/// }, +/// "requested_predicates": { // set of requested predicates +/// "": , // see below +/// ..., +/// }, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval for each attribute +/// // (can be overridden on attribute level) +/// } +/// +/// where +/// `attr_referent`: Proof-request local identifier of requested attribute +/// `attr_info`: Describes requested attribute +/// { +/// "name": string, // attribute name, (case insensitive and ignore spaces) +/// "restrictions": Optional, // see above +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// `predicate_referent`: Proof-request local identifier of requested attribute predicate +/// `predicate_info`: Describes requested attribute predicate +/// { +/// "name": attribute name, (case insensitive and ignore spaces) +/// "p_type": predicate type (Currently ">=" only) +/// "p_value": int predicate value +/// "restrictions": Optional, // see above +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// `non_revoc_interval`: Defines non-revocation interval +/// { +/// "from": Optional, // timestamp of interval beginning +/// "to": Optional, // timestamp of interval ending +/// } +/// +/// # Returns +/// * `credentials_json`: json with credentials for the given proof request. +/// { +/// "requested_attrs": { +/// "": [{ cred_info: , interval: Optional }], +/// ..., +/// }, +/// "requested_predicates": { +/// "requested_predicates": [{ cred_info: , timestamp: Optional }, { cred_info: , timestamp: Optional }], +/// "requested_predicate_2_referent": [{ cred_info: , timestamp: Optional }] +/// } +/// }, where credential is +/// { +/// "referent": , +/// "attrs": {"attr_name" : "attr_raw_value"}, +/// "schema_id": string, +/// "cred_def_id": string, +/// "rev_reg_id": Optional, +/// "cred_rev_id": Optional, +/// } +pub fn prover_get_credentials_for_proof_req(wallet_handle: IndyHandle, proof_request_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _prover_get_credentials_for_proof_req(command_handle, wallet_handle, proof_request_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _prover_get_credentials_for_proof_req(command_handle: IndyHandle, wallet_handle: IndyHandle, proof_request_json: &str, cb: Option) -> ErrorCode { + let proof_request_json = c_str!(proof_request_json); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_get_credentials_for_proof_req(command_handle, wallet_handle, proof_request_json.as_ptr(), cb) + }) +} + +/// Search for credentials matching the given proof request. +/// +/// Instead of immediately returning of fetched credentials +/// this call returns search_handle that can be used later +/// to fetch records by small batches (with fetch_credentials_for_proof_req). +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `proof_request_json`: proof request json +/// { +/// "name": string, +/// "version": string, +/// "nonce": string, +/// "requested_attributes": { // set of requested attributes +/// "": , // see below +/// ..., +/// }, +/// "requested_predicates": { // set of requested predicates +/// "": , // see below +/// ..., +/// }, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval for each attribute +/// // (can be overridden on attribute level) +/// } +/// * `extra_query_json`: (Optional) List of extra queries that will be applied to correspondent attribute/predicate: +/// { +/// "": , +/// "": , +/// } +/// where wql query: indy-sdk/doc/design/011-wallet-query-language/README.md +/// +/// where +/// `attr_referent`: Proof-request local identifier of requested attribute +/// `attr_info`: Describes requested attribute +/// { +/// "name": string, // attribute name, (case insensitive and ignore spaces) +/// "restrictions": Optional, // see above +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// `predicate_referent`: Proof-request local identifier of requested attribute predicate +/// `predicate_info`: Describes requested attribute predicate +/// { +/// "name": attribute name, (case insensitive and ignore spaces) +/// "p_type": predicate type (Currently ">=" only) +/// "p_value": int predicate value +/// "restrictions": Optional, // see above +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// `non_revoc_interval`: Defines non-revocation interval +/// { +/// "from": Optional, // timestamp of interval beginning +/// "to": Optional, // timestamp of interval ending +/// } +/// +/// # Returns +/// * `search_handle`: Search handle that can be used later to fetch records by small batches (with fetch_credentials_for_proof_req) +pub fn prover_search_credentials_for_proof_req(wallet_handle: IndyHandle, proof_request_json: &str, extra_query_json: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_handle(); + + let err = _prover_search_credentials_for_proof_req(command_handle, wallet_handle, proof_request_json, extra_query_json, cb); + + ResultHandler::handle(command_handle, err, receiver) +} + +fn _prover_search_credentials_for_proof_req(command_handle: IndyHandle, wallet_handle: IndyHandle, proof_request_json: &str, extra_query_json: Option<&str>, cb: Option) -> ErrorCode { + let proof_request_json = c_str!(proof_request_json); + let extra_query_json_str = opt_c_str!(extra_query_json); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_search_credentials_for_proof_req(command_handle, wallet_handle, proof_request_json.as_ptr(), opt_c_ptr!(extra_query_json, extra_query_json_str), cb) + }) +} + +/// Fetch next credentials for the requested item using proof request search +/// handle (created by search_credentials_for_proof_req). +/// +/// # Arguments +/// * `search_handle`: Search handle (created by search_credentials_for_proof_req) +/// * `item_referent`: Referent of attribute/predicate in the proof request +/// * `count`: Count of credentials to fetch +/// +/// # Returns +/// * `credentials_json`: List of credentials for the given proof request. +/// [{ +/// cred_info: , +/// interval: Optional +/// }] +/// where +/// `credential_info`: +/// { +/// "referent": , +/// "attrs": {"attr_name" : "attr_raw_value"}, +/// "schema_id": string, +/// "cred_def_id": string, +/// "rev_reg_id": Optional, +/// "cred_rev_id": Optional, +/// } +/// `non_revoc_interval`: +/// { +/// "from": Optional, // timestamp of interval beginning +/// "to": Optional, // timestamp of interval ending +/// } +/// NOTE: The list of length less than the requested count means that search iterator +/// correspondent to the requested is completed. +pub fn prover_fetch_credentials_for_proof_req(search_handle: IndyHandle, item_referent: &str, count: usize) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _prover_fetch_credentials_for_proof_req(command_handle, search_handle, item_referent, count, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _prover_fetch_credentials_for_proof_req(command_handle: IndyHandle, search_handle: IndyHandle, item_referent: &str, count: usize, cb: Option) -> ErrorCode { + let item_referent = c_str!(item_referent); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_fetch_credentials_for_proof_req(command_handle, search_handle, item_referent.as_ptr(), count, cb) + }) +} + +/// Close credentials search for proof request (make search handle invalid) +/// +/// # Arguments +/// * `search_handle`: Search handle (created by search_credentials_for_proof_req) +pub fn prover_close_credentials_search_for_proof_req(search_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _prover_close_credentials_search_for_proof_req(command_handle, search_handle, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _prover_close_credentials_search_for_proof_req(command_handle: IndyHandle, search_handle: IndyHandle, cb: Option) -> ErrorCode { + + ErrorCode::from(unsafe { + anoncreds::indy_prover_close_credentials_search_for_proof_req(command_handle, search_handle, cb) + }) +} + +/// Creates a proof according to the given proof request +/// Either a corresponding credential with optionally revealed attributes or self-attested attribute must be provided +/// for each requested attribute (see indy_prover_get_credentials_for_pool_req). +/// A proof request may request multiple credentials from different schemas and different issuers. +/// All required schemas, public keys and revocation registries must be provided. +/// The proof request also contains nonce. +/// The proof contains either proof or self-attested attribute value for each requested attribute. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `proof_request_json`: proof request json +/// { +/// "name": string, +/// "version": string, +/// "nonce": string, +/// "requested_attributes": { // set of requested attributes +/// "": , // see below +/// ..., +/// }, +/// "requested_predicates": { // set of requested predicates +/// "": , // see below +/// ..., +/// }, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval for each attribute +/// // (can be overridden on attribute level) +/// } +/// * `requested_credentials_json`: either a credential or self-attested attribute for each requested attribute +/// { +/// "self_attested_attributes": { +/// "self_attested_attribute_referent": string +/// }, +/// "requested_attributes": { +/// "requested_attribute_referent_1": {"cred_id": string, "timestamp": Optional, revealed: }}, +/// "requested_attribute_referent_2": {"cred_id": string, "timestamp": Optional, revealed: }} +/// }, +/// "requested_predicates": { +/// "requested_predicates_referent_1": {"cred_id": string, "timestamp": Optional }}, +/// } +/// } +/// * `master_secret_id`: the id of the master secret stored in the wallet +/// * `schemas_json`: all schemas json participating in the proof request +/// { +/// : , +/// : , +/// : , +/// } +/// * `credential_defs_json`: all credential definitions json participating in the proof request +/// { +/// "cred_def1_id": , +/// "cred_def2_id": , +/// "cred_def3_id": , +/// } +/// * `rev_states_json`: all revocation states json participating in the proof request +/// { +/// "rev_reg_def1_id": { +/// "timestamp1": , +/// "timestamp2": , +/// }, +/// "rev_reg_def2_id": { +/// "timestamp3": +/// }, +/// "rev_reg_def3_id": { +/// "timestamp4": +/// }, +/// } +/// +/// where +/// where wql query: indy-sdk/doc/design/011-wallet-query-language/README.md +/// attr_referent: Proof-request local identifier of requested attribute +/// attr_info: Describes requested attribute +/// { +/// "name": string, // attribute name, (case insensitive and ignore spaces) +/// "restrictions": Optional, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// predicate_referent: Proof-request local identifier of requested attribute predicate +/// predicate_info: Describes requested attribute predicate +/// { +/// "name": attribute name, (case insensitive and ignore spaces) +/// "p_type": predicate type (Currently >= only) +/// "p_value": predicate value +/// "restrictions": Optional, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval this attribute +/// // (overrides proof level interval) +/// } +/// non_revoc_interval: Defines non-revocation interval +/// { +/// "from": Optional, // timestamp of interval beginning +/// "to": Optional, // timestamp of interval ending +/// } +/// +/// # Returns +/// * `proof_json` - proof json +/// For each requested attribute either a proof (with optionally revealed attribute value) or +/// self-attested attribute value is provided. +/// Each proof is associated with a credential and corresponding schema_id, cred_def_id, rev_reg_id and timestamp. +/// There is also aggregated proof part common for all credential proofs. +/// { +/// "requested": { +/// "revealed_attrs": { +/// "requested_attr1_id": {sub_proof_index: number, raw: string, encoded: string}, +/// "requested_attr4_id": {sub_proof_index: number: string, encoded: string}, +/// }, +/// "unrevealed_attrs": { +/// "requested_attr3_id": {sub_proof_index: number} +/// }, +/// "self_attested_attrs": { +/// "requested_attr2_id": self_attested_value, +/// }, +/// "requested_predicates": { +/// "requested_predicate_1_referent": {sub_proof_index: int}, +/// "requested_predicate_2_referent": {sub_proof_index: int}, +/// } +/// } +/// "proof": { +/// "proofs": [ , , ], +/// "aggregated_proof": +/// } +/// "identifiers": [{schema_id, cred_def_id, Optional, Optional}] +/// } +pub fn prover_create_proof(wallet_handle: IndyHandle, proof_req_json: &str, requested_credentials_json: &str, master_secret_id: &str, schemas_json: &str, credential_defs_json: &str, rev_states_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _prover_create_proof(command_handle, wallet_handle, proof_req_json, requested_credentials_json, master_secret_id, schemas_json, credential_defs_json, rev_states_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _prover_create_proof(command_handle: IndyHandle, wallet_handle: IndyHandle, proof_req_json: &str, requested_credentials_json: &str, master_secret_id: &str, schemas_json: &str, credential_defs_json: &str, rev_states_json: &str, cb: Option) -> ErrorCode { + let proof_req_json = c_str!(proof_req_json); + let requested_credentials_json = c_str!(requested_credentials_json); + let master_secret_id = c_str!(master_secret_id); + let schemas_json = c_str!(schemas_json); + let credential_defs_json = c_str!(credential_defs_json); + let rev_states_json = c_str!(rev_states_json); + + ErrorCode::from(unsafe { + anoncreds::indy_prover_create_proof(command_handle, wallet_handle, proof_req_json.as_ptr(), requested_credentials_json.as_ptr(), master_secret_id.as_ptr(), schemas_json.as_ptr(), credential_defs_json.as_ptr(), rev_states_json.as_ptr(), cb) + }) +} + + +/// Verifies a proof (of multiple credential). +/// All required schemas, public keys and revocation registries must be provided. +/// +/// # Arguments +/// * `wallet_handle`: wallet handler (created by Wallet::open_wallet). +/// * `proof_request_json`: proof request json +/// { +/// "name": string, +/// "version": string, +/// "nonce": string, +/// "requested_attributes": { // set of requested attributes +/// "": , // see below +/// ..., +/// }, +/// "requested_predicates": { // set of requested predicates +/// "": , // see below +/// ..., +/// }, +/// "non_revoked": Optional<>, // see below, +/// // If specified prover must proof non-revocation +/// // for date in this interval for each attribute +/// // (can be overridden on attribute level) +/// } +/// * `proof_json`: created for request proof json +/// { +/// "requested": { +/// "revealed_attrs": { +/// "requested_attr1_id": {sub_proof_index: number, raw: string, encoded: string}, +/// "requested_attr4_id": {sub_proof_index: number: string, encoded: string}, +/// }, +/// "unrevealed_attrs": { +/// "requested_attr3_id": {sub_proof_index: number} +/// }, +/// "self_attested_attrs": { +/// "requested_attr2_id": self_attested_value, +/// }, +/// "requested_predicates": { +/// "requested_predicate_1_referent": {sub_proof_index: int}, +/// "requested_predicate_2_referent": {sub_proof_index: int}, +/// } +/// } +/// "proof": { +/// "proofs": [ , , ], +/// "aggregated_proof": +/// } +/// "identifiers": [{schema_id, cred_def_id, Optional, Optional}] +/// } +/// * `schemas_json`: all schema jsons participating in the proof +/// { +/// : , +/// : , +/// : , +/// } +/// * `credential_defs_json`: all credential definitions json participating in the proof +/// { +/// "cred_def1_id": , +/// "cred_def2_id": , +/// "cred_def3_id": , +/// } +/// * `rev_reg_defs_json`: all revocation registry definitions json participating in the proof +/// { +/// "rev_reg_def1_id": , +/// "rev_reg_def2_id": , +/// "rev_reg_def3_id": , +/// } +/// * `rev_regs_json`: all revocation registries json participating in the proof +/// { +/// "rev_reg_def1_id": { +/// "timestamp1": , +/// "timestamp2": , +/// }, +/// "rev_reg_def2_id": { +/// "timestamp3": +/// }, +/// "rev_reg_def3_id": { +/// "timestamp4": +/// }, +/// } +/// +/// # Returns +/// * `valid`: true - if signature is valid, false - otherwise +pub fn verifier_verify_proof(proof_request_json: &str, proof_json: &str, schemas_json: &str, credential_defs_json: &str, rev_reg_defs_json: &str, rev_regs_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_bool(); + + let err = _verifier_verify_proof(command_handle, proof_request_json, proof_json, schemas_json, credential_defs_json, rev_reg_defs_json, rev_regs_json, cb); + + ResultHandler::bool(command_handle, err, receiver) +} + +fn _verifier_verify_proof(command_handle: IndyHandle, proof_request_json: &str, proof_json: &str, schemas_json: &str, credential_defs_json: &str, rev_reg_defs_json: &str, rev_regs_json: &str, cb: Option) -> ErrorCode { + let proof_request_json = c_str!(proof_request_json); + let proof_json = c_str!(proof_json); + let schemas_json = c_str!(schemas_json); + let credential_defs_json = c_str!(credential_defs_json); + let rev_reg_defs_json = c_str!(rev_reg_defs_json); + let rev_regs_json = c_str!(rev_regs_json); + + ErrorCode::from(unsafe { + anoncreds::indy_verifier_verify_proof(command_handle, proof_request_json.as_ptr(), proof_json.as_ptr(), schemas_json.as_ptr(), credential_defs_json.as_ptr(), rev_reg_defs_json.as_ptr(), rev_regs_json.as_ptr(), cb) + }) +} + + +/// Create revocation state for a credential in the particular time moment. +/// +/// # Arguments +/// * `blob_storage_reader_handle`: configuration of blob storage reader handle that will allow to read revocation tails +/// * `rev_reg_def_json`: revocation registry definition json +/// * `rev_reg_delta_json`: revocation registry definition delta json +/// * `timestamp`: time represented as a total number of seconds from Unix Epoch +/// * `cred_rev_id`: user credential revocation id in revocation registry +/// +/// # Returns +/// * `revocation_state_json`: +/// { +/// "rev_reg": , +/// "witness": , +/// "timestamp" : integer +/// } +pub fn create_revocation_state(blob_storage_reader_handle: IndyHandle, rev_reg_def_json: &str, rev_reg_delta_json: &str, timestamp: u64, cred_rev_id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _create_revocation_state(command_handle, blob_storage_reader_handle, rev_reg_def_json, rev_reg_delta_json, timestamp, cred_rev_id, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _create_revocation_state(command_handle: IndyHandle, blob_storage_reader_handle: IndyHandle, rev_reg_def_json: &str, rev_reg_delta_json: &str, timestamp: u64, cred_rev_id: &str, cb: Option) -> ErrorCode { + let rev_reg_def_json = c_str!(rev_reg_def_json); + let rev_reg_delta_json = c_str!(rev_reg_delta_json); + let cred_rev_id = c_str!(cred_rev_id); + + ErrorCode::from(unsafe { + anoncreds::indy_create_revocation_state(command_handle, blob_storage_reader_handle, rev_reg_def_json.as_ptr(), rev_reg_delta_json.as_ptr(), timestamp, cred_rev_id.as_ptr(), cb) + }) +} + +/// Create new revocation state for a credential based on existed state +/// at the particular time moment (to reduce calculation time). +/// +/// # Arguments +/// * `blob_storage_reader_handle`: configuration of blob storage reader handle that will allow to read revocation tails +/// * `rev_state_json`: revocation registry state json +/// * `rev_reg_def_json`: revocation registry definition json +/// * `rev_reg_delta_json`: revocation registry definition delta json +/// * `timestamp`: time represented as a total number of seconds from Unix Epoch +/// * `cred_rev_id`: user credential revocation id in revocation registry +/// +/// # Returns +/// * `revocation_state_json`: +/// { +/// "rev_reg": , +/// "witness": , +/// "timestamp" : integer +/// } +pub fn update_revocation_state(blob_storage_reader_handle: IndyHandle, rev_state_json: &str, rev_reg_def_json: &str, rev_reg_delta_json: &str, timestamp: u64, cred_rev_id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _update_revocation_state(command_handle, blob_storage_reader_handle, rev_state_json, rev_reg_def_json, rev_reg_delta_json, timestamp, cred_rev_id, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _update_revocation_state(command_handle: IndyHandle, blob_storage_reader_handle: IndyHandle, rev_state_json: &str, rev_reg_def_json: &str, rev_reg_delta_json: &str, timestamp: u64, cred_rev_id: &str, cb: Option) -> ErrorCode { + let rev_state_json = c_str!(rev_state_json); + let rev_reg_def_json = c_str!(rev_reg_def_json); + let rev_reg_delta_json = c_str!(rev_reg_delta_json); + let cred_rev_id = c_str!(cred_rev_id); + + ErrorCode::from(unsafe { + anoncreds::indy_update_revocation_state(command_handle, blob_storage_reader_handle, rev_state_json.as_ptr(), rev_reg_def_json.as_ptr(), rev_reg_delta_json.as_ptr(), timestamp, cred_rev_id.as_ptr(), cb) + }) +} diff --git a/wrappers/rust/src/blob_storage.rs b/wrappers/rust/src/blob_storage.rs new file mode 100644 index 00000000..721c614e --- /dev/null +++ b/wrappers/rust/src/blob_storage.rs @@ -0,0 +1,40 @@ +use futures::Future; + +use {ErrorCode, IndyHandle}; + +use std::ffi::CString; + +use ffi::blob_storage; +use ffi::ResponseI32CB; + +use utils::callbacks::{ClosureHandler, ResultHandler}; + +pub fn open_reader(xtype: &str, config_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_handle(); + + let err = _open_reader(command_handle, xtype, config_json, cb); + + ResultHandler::handle(command_handle, err, receiver) +} + +fn _open_reader(command_handle: IndyHandle, xtype: &str, config_json: &str, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let config_json = c_str!(config_json); + + ErrorCode::from(unsafe { blob_storage::indy_open_blob_storage_reader(command_handle, xtype.as_ptr(), config_json.as_ptr(), cb) }) +} + +pub fn open_writer(xtype: &str, config_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_handle(); + + let err = _open_writer(command_handle, xtype, config_json, cb); + + ResultHandler::handle(command_handle, err, receiver) +} + +fn _open_writer(command_handle: IndyHandle, xtype: &str, config_json: &str, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let config_json = c_str!(config_json); + + ErrorCode::from(unsafe { blob_storage::indy_open_blob_storage_writer(command_handle, xtype.as_ptr(), config_json.as_ptr(), cb) }) +} diff --git a/wrappers/rust/src/crypto.rs b/wrappers/rust/src/crypto.rs new file mode 100644 index 00000000..ced6cfe4 --- /dev/null +++ b/wrappers/rust/src/crypto.rs @@ -0,0 +1,276 @@ +use ffi::crypto; +use ffi::{ResponseEmptyCB, + ResponseStringCB, + ResponseSliceCB, + ResponseBoolCB, + ResponseStringSliceCB}; + +use futures::Future; + +use std::ffi::CString; + +use {ErrorCode, IndyHandle}; +use utils::callbacks::{ClosureHandler, ResultHandler}; + +/// Creates key pair in wallet +/// # Arguments +/// * `wallet_handle` - wallet handle (created by Wallet::open) +/// * `my_key_json` - Optional key information as json. If none then defaults are used. +/// +/// # Example +/// my_key_json +/// { +/// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). +/// Can be UTF-8, base64 or hex string. +/// "crypto_type": string, // Optional (if not set then ed25519 curve is used); Currently only 'ed25519' value is supported for this field. +/// } +/// # Returns +/// verkey of generated key pair, also used as key identifier +pub fn create_key(wallet_handle: IndyHandle, my_key_json: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _create_key(command_handle, wallet_handle, my_key_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _create_key(command_handle: IndyHandle, wallet_handle: IndyHandle, my_key_json: Option<&str>, cb: Option) -> ErrorCode { + let my_key_json = opt_c_str_json!(my_key_json); + + ErrorCode::from(unsafe { crypto::indy_create_key(command_handle, wallet_handle, my_key_json.as_ptr(), cb) }) +} + +/// Saves/replaces the metadata for the `verkey` in the wallet +/// # Arguments +/// * `wallet_handle` - wallet handle (created by Wallet::open) +/// * `verkey` - the public key or key id where to store the metadata +/// * `metadata` - the metadata that will be stored with the key, can be empty string +pub fn set_key_metadata(wallet_handle: IndyHandle, verkey: &str, metadata: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _set_key_metadata(command_handle, wallet_handle, verkey, metadata, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _set_key_metadata(command_handle: IndyHandle, wallet_handle: IndyHandle, verkey: &str, metadata: &str, cb: Option) -> ErrorCode { + let verkey = c_str!(verkey); + let metadata = c_str!(metadata); + + ErrorCode::from(unsafe { crypto::indy_set_key_metadata(command_handle, wallet_handle, verkey.as_ptr(), metadata.as_ptr(), cb) }) +} + +/// Retrieves the metadata for the `verkey` in the wallet +/// # Argument +/// * `wallet_handle` - wallet handle (created by Wallet::open) +/// * `verkey` - the public key or key id to retrieve metadata +/// # Returns +/// metadata currently stored with the key; Can be empty if no metadata was saved for this key +pub fn get_key_metadata(wallet_handle: IndyHandle, verkey: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _get_key_metadata(command_handle, wallet_handle, verkey, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _get_key_metadata(command_handle: IndyHandle, wallet_handle: IndyHandle, verkey: &str, cb: Option) -> ErrorCode { + let verkey = c_str!(verkey); + + ErrorCode::from(unsafe { crypto::indy_get_key_metadata(command_handle, wallet_handle, verkey.as_ptr(), cb) }) +} + +/// Signs a message with a key +/// # Arguments +/// * `wallet_handle` - wallet handle (created by Wallet::open) +/// * `signer_vk` - key id or verkey of my key. The key must be created by calling create_key or Did::new +/// * `message` - the data to be signed +/// # Returns +/// the signature +pub fn sign(wallet_handle: IndyHandle, signer_vk: &str, message: &[u8]) -> Box, Error=ErrorCode>> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_slice(); + + let err = _sign(command_handle, wallet_handle, signer_vk, message, cb); + + ResultHandler::slice(command_handle, err, receiver) +} + +fn _sign(command_handle: IndyHandle, wallet_handle: IndyHandle, signer_vk: &str, message: &[u8], cb: Option) -> ErrorCode { + let signer_vk = c_str!(signer_vk); + ErrorCode::from(unsafe { + crypto::indy_crypto_sign(command_handle, wallet_handle, signer_vk.as_ptr(), + message.as_ptr() as *const u8, + message.len() as u32, + cb) + }) +} + +/// Verify a signature with a verkey +/// # Arguments +/// * `wallet_handle` - wallet handle (created by Wallet::open) +/// * `signer_vk` - key id or verkey of my key. The key must be created by calling create_key or Did::new +/// * `message` - the data that was signed +/// * `signature` - the signature to verify +/// # Returns +/// true if signature is valid, false otherwise +pub fn verify(signer_vk: &str, message: &[u8], signature: &[u8]) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_bool(); + + let err = _verify(command_handle, signer_vk, message, signature, cb); + + ResultHandler::bool(command_handle, err, receiver) +} + +fn _verify(command_handle: IndyHandle, signer_vk: &str, message: &[u8], signature: &[u8], cb: Option) -> ErrorCode { + let signer_vk = c_str!(signer_vk); + + ErrorCode::from(unsafe { + crypto::indy_crypto_verify(command_handle, signer_vk.as_ptr(), + message.as_ptr() as *const u8, message.len() as u32, + signature.as_ptr() as *const u8, signature.len() as u32, cb) + }) +} + +/// Encrypt a message by authenticated-encryption scheme. +/// +/// Sender can encrypt a confidential message specifically for Recipient, using Sender's public key. +/// Using Recipient's public key, Sender can compute a shared secret key. +/// Using Sender's public key and his secret key, Recipient can compute the exact same shared secret key. +/// That shared secret key can be used to verify that the encrypted message was not tampered with, +/// before eventually decrypting it. +/// +/// Note to use DID keys with this function you can call Did::get_ver_key to get key id (verkey) +/// for specific DID. +/// # Arguments +/// * `wallet_handle` - wallet handle (created by Wallet::open) +/// * `signer_vk` - key id or verkey of my key. The key must be created by calling create_key or Did::new +/// * `recipient_vk` - key id or verkey of the other party's key +/// * `message` - the data to be encrypted +/// # Returns +/// the encrypted message +pub fn auth_crypt(wallet_handle: IndyHandle, sender_vk: &str, recipient_vk: &str, message: &[u8]) -> Box, Error=ErrorCode>> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_slice(); + + let err = _auth_crypt(command_handle, wallet_handle, sender_vk, recipient_vk, message, cb); + + ResultHandler::slice(command_handle, err, receiver) +} + +fn _auth_crypt(command_handle: IndyHandle, wallet_handle: IndyHandle, sender_vk: &str, recipient_vk: &str, message: &[u8], cb: Option) -> ErrorCode { + let sender_vk = c_str!(sender_vk); + let recipient_vk = c_str!(recipient_vk); + ErrorCode::from(unsafe { + crypto::indy_crypto_auth_crypt(command_handle, wallet_handle, + sender_vk.as_ptr(), + recipient_vk.as_ptr(), + message.as_ptr() as *const u8, + message.len() as u32, cb) + }) +} + +/// Decrypt a message by authenticated-encryption scheme. +/// +/// Sender can encrypt a confidential message specifically for Recipient, using Sender's public key. +/// Using Recipient's public key, Sender can compute a shared secret key. +/// Using Sender's public key and his secret key, Recipient can compute the exact same shared secret key. +/// That shared secret key can be used to verify that the encrypted message was not tampered with, +/// before eventually decrypting it. +/// +/// Note to use DID keys with this function you can call Did::get_ver_key to get key id (verkey) +/// for specific DID. +/// +/// # Arguments +/// * `wallet_handle`: wallet handle (created by Wallet::open) +/// * `recipient_vk`: key id or verkey of my key. The key must be created by calling create_key or Did::new +/// * `encrypted_message`: the message to be decrypted +/// # Returns +/// sender's verkey and decrypted message +pub fn auth_decrypt(wallet_handle: IndyHandle, recipient_vk: &str, encrypted_message: &[u8]) -> Box), Error=ErrorCode>> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_slice(); + + let err = _auth_decrypt(command_handle, wallet_handle, recipient_vk, encrypted_message, cb); + + ResultHandler::str_slice(command_handle, err, receiver) +} + +fn _auth_decrypt(command_handle: IndyHandle, wallet_handle: IndyHandle, recipient_vk: &str, encrypted_message: &[u8], cb: Option) -> ErrorCode { + let recipient_vk = c_str!(recipient_vk); + ErrorCode::from(unsafe { + crypto::indy_crypto_auth_decrypt(command_handle, + wallet_handle, + recipient_vk.as_ptr(), + encrypted_message.as_ptr() as *const u8, + encrypted_message.len() as u32, cb) + }) +} + +/// Encrypts a message by anonymous-encryption scheme. +/// +/// Sealed boxes are designed to anonymously send messages to a Recipient given its public key. +/// Only the Recipient can decrypt these messages, using its private key. +/// While the Recipient can verify the integrity of the message, it cannot verify the identity of the Sender. +/// +/// Note to use DID keys with this function you can call Did::get_ver_key to get key id (verkey) +/// for specific DID. +/// +/// # Arguments +/// * `wallet_handle`: wallet handle (created by Wallet::open) +/// * `recipient_vk`: verkey of message recipient +/// * `message`: a pointer to first byte of message that to be encrypted +/// +/// # Returns +/// the encrypted message +pub fn anon_crypt(recipient_vk: &str, message: &[u8]) -> Box, Error=ErrorCode>> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_slice(); + + let err = _anon_crypt(command_handle, recipient_vk, message, cb); + + ResultHandler::slice(command_handle, err, receiver) +} + +fn _anon_crypt(command_handle: IndyHandle, recipient_vk: &str, message: &[u8], cb: Option) -> ErrorCode { + let recipient_vk = c_str!(recipient_vk); + ErrorCode::from(unsafe { + crypto::indy_crypto_anon_crypt(command_handle, + recipient_vk.as_ptr(), + message.as_ptr() as *const u8, + message.len() as u32, + cb) + }) +} + +/// Decrypts a message by anonymous-encryption scheme. +/// +/// Sealed boxes are designed to anonymously send messages to a Recipient given its public key. +/// Only the Recipient can decrypt these messages, using its private key. +/// While the Recipient can verify the integrity of the message, it cannot verify the identity of the Sender. +/// +/// Note to use DID keys with this function you can call Did::get_ver_key to get key id (verkey) +/// for specific DID. +/// +/// # Arguments +/// * `wallet_handle`: wallet handle (created by Wallet::open). +/// * `recipient_vk`: key id or verkey of my key. The key must be created by calling create_key or Did::new +/// * `encrypted_message`: a pointer to first byte of message that to be decrypted +/// +/// # Returns +/// decrypted message +pub fn anon_decrypt(wallet_handle: IndyHandle, recipient_vk: &str, encrypted_message: &[u8]) -> Box, Error=ErrorCode>> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_slice(); + + let err = _anon_decrypt(command_handle, wallet_handle, recipient_vk, encrypted_message, cb); + + ResultHandler::slice(command_handle, err, receiver) +} + +fn _anon_decrypt(command_handle: IndyHandle, wallet_handle: IndyHandle, recipient_vk: &str, encrypted_message: &[u8], cb: Option) -> ErrorCode { + let recipient_vk = c_str!(recipient_vk); + ErrorCode::from(unsafe { + crypto::indy_crypto_anon_decrypt(command_handle, + wallet_handle, + recipient_vk.as_ptr(), + encrypted_message.as_ptr() as *const u8, + encrypted_message.len() as u32, cb) + }) +} + diff --git a/wrappers/rust/src/did.rs b/wrappers/rust/src/did.rs new file mode 100644 index 00000000..30a58d78 --- /dev/null +++ b/wrappers/rust/src/did.rs @@ -0,0 +1,358 @@ +use {ErrorCode, IndyHandle}; + +use std::ffi::CString; + +use futures::Future; + +use ffi::did; +use ffi::{ResponseEmptyCB, + ResponseStringCB, + ResponseStringStringCB}; + +use utils::callbacks::{ClosureHandler, ResultHandler}; + +/// Creates keys (signing and encryption keys) for a new +/// DID (owned by the caller of the library). +/// Identity's DID must be either explicitly provided, or taken as the first 16 bit of verkey. +/// Saves the Identity DID with keys in a secured Wallet, so that it can be used to sign +/// and encrypt transactions. +/// +/// # Arguments +/// * `wallet_handle` - wallet handler (created by Wallet::open). +/// * `did_json` - Identity information as json. +/// +/// # Examples +/// `did_json` +/// { +/// "did": string, (optional; +/// if not provided and cid param is false then the first 16 bit of the verkey will be used as a new DID; +/// if not provided and cid is true then the full verkey will be used as a new DID; +/// if provided, then keys will be replaced - key rotation use case) +/// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). +/// Can be UTF-8, base64 or hex string. +/// "crypto_type": string, (optional; if not set then ed25519 curve is used; +/// currently only 'ed25519' value is supported for this field) +/// "cid": bool, (optional; if not set then false is used;) +/// } +/// +/// # Returns +/// * `did` - DID generated and stored in the wallet +/// * `verkey` - The DIDs verification key +pub fn create_and_store_my_did(wallet_handle: IndyHandle, did_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _create_and_store_my_did(command_handle, wallet_handle, did_json, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _create_and_store_my_did(command_handle: IndyHandle, wallet_handle: IndyHandle, did_json: &str, cb: Option) -> ErrorCode { + let did_json = c_str!(did_json); + + ErrorCode::from(unsafe { did::indy_create_and_store_my_did(command_handle, wallet_handle, did_json.as_ptr(), cb) }) +} + +/// Generated temporary keys (signing and encryption keys) for an existing +/// DID (owned by the caller of the library). +/// +/// # Arguments +/// * `wallet_handle` - wallet handler (created by Wallet::open). +/// * `tgt_did` - DID to replace keys. +/// * `identity_json` - Identity information as json. +/// # Example +/// * `identity_json`- +/// { +/// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). +/// Can be UTF-8, base64 or hex string. +/// "crypto_type": string, (optional; if not set then ed25519 curve is used; +/// currently only 'ed25519' value is supported for this field) +/// } +/// +/// # Returns +/// * `verkey` - The DIDs verification key +pub fn replace_keys_start(wallet_handle: IndyHandle, tgt_did: &str, identity_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _replace_keys_start(command_handle, wallet_handle, tgt_did, identity_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _replace_keys_start(command_handle: IndyHandle, wallet_handle: IndyHandle, tgt_did: &str, identity_json: &str, cb: Option) -> ErrorCode { + let tgt_did = c_str!(tgt_did); + let identity_json = c_str!(identity_json); + + ErrorCode::from(unsafe { did::indy_replace_keys_start(command_handle, wallet_handle, tgt_did.as_ptr(), identity_json.as_ptr(), cb) }) +} + +/// Apply temporary keys as main for an existing DID (owned by the caller of the library). +/// +/// # Arguments +/// * `wallet_handle` - wallet handler (created by Wallet::open). +/// * `tgt_did` - DID stored in the wallet +pub fn replace_keys_apply(wallet_handle: IndyHandle, tgt_did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _replace_keys_apply(command_handle, wallet_handle, tgt_did, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _replace_keys_apply(command_handle: IndyHandle, wallet_handle: IndyHandle, tgt_did: &str, cb: Option) -> ErrorCode { + let tgt_did = c_str!(tgt_did); + + ErrorCode::from(unsafe { did::indy_replace_keys_apply(command_handle, wallet_handle, tgt_did.as_ptr(), cb) }) +} + +/// Saves their DID for a pairwise connection in a secured Wallet, +/// so that it can be used to verify transaction. +/// +/// # Arguments +/// * `wallet_handle` - wallet handler (created by Wallet::open). +/// * `identity_json` - Identity information as json. +/// # Example: +/// * `identity_json` +/// { +/// "did": string, (required) +/// "verkey": string (optional, can be avoided if did is cryptonym: did == verkey), +/// } +pub fn store_their_did(wallet_handle: IndyHandle, identity_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _store_their_did(command_handle, wallet_handle, identity_json, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _store_their_did(command_handle: IndyHandle, wallet_handle: IndyHandle, identity_json: &str, cb: Option) -> ErrorCode { + let identity_json = c_str!(identity_json); + + ErrorCode::from(unsafe { did::indy_store_their_did(command_handle, wallet_handle, identity_json.as_ptr(), cb) }) +} + +/// Returns ver key (key id) for the given DID. +/// +/// "get_ver_key" call follow the idea that we resolve information about their DID from +/// the ledger with cache in the local wallet. The "indy_Wallet::open" call has freshness parameter +/// that is used for checking the freshness of cached pool value. +/// +/// Note if you don't want to resolve their DID info from the ledger you can use +/// "get_ver_key" call instead that will look only to the local wallet and skip +/// freshness checking. +/// +/// Note that "new" makes similar wallet record as "Key::create_key". +/// As result we can use returned ver key in all generic crypto and messaging functions. +/// +/// # Arguments +/// * `pool_handle` - Pool handle (created by Pool::open). +/// * `wallet_handle` - Wallet handle (created by Wallet::open). +/// * `did` - The DID to resolve key. +/// +/// # Returns +/// * `key` - The DIDs ver key (key id). +pub fn key_for_did(pool_handle: IndyHandle, wallet_handle: IndyHandle, did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _key_for_did(command_handle, pool_handle, wallet_handle, did, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _key_for_did(command_handle: IndyHandle, pool_handle: IndyHandle, wallet_handle: IndyHandle, did: &str, cb: Option) -> ErrorCode { + let did = c_str!(did); + + ErrorCode::from(unsafe { did::indy_key_for_did(command_handle, pool_handle, wallet_handle, did.as_ptr(), cb) }) +} + +/// Returns ver key (key id) for the given DID. +/// +/// "get_ver_key_did" call looks data stored in the local wallet only and skips freshness +/// checking. +/// +/// Note if you want to get fresh data from the ledger you can use "get_ver_key" call +/// instead. +/// +/// Note that "new" makes similar wallet record as "Key::create_key". +/// As result we can use returned ver key in all generic crypto and messaging functions. +/// +/// # Arguments +/// * `wallet_handle` - Wallet handle (created by Wallet::open). +/// * `did` - The DID to resolve key. +/// +/// # Returns +/// * `key` - The DIDs ver key (key id). +pub fn key_for_local_did(wallet_handle: IndyHandle, did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _key_for_local_did(command_handle, wallet_handle, did, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _key_for_local_did(command_handle: IndyHandle, wallet_handle: IndyHandle, did: &str, cb: Option) -> ErrorCode { + let did = c_str!(did); + + ErrorCode::from(unsafe { did::indy_key_for_local_did(command_handle, wallet_handle, did.as_ptr(), cb) }) +} + +/// Set/replaces endpoint information for the given DID. +/// +/// # Arguments +/// * `wallet_handle` - Wallet handle (created by Wallet::open). +/// * `did` - The DID to resolve endpoint. +/// * `address` - The DIDs endpoint address. +/// * `transport_key` - The DIDs transport key (ver key, key id). +pub fn set_endpoint_for_did(wallet_handle: IndyHandle, did: &str, address: &str, transport_key: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _set_endpoint_for_did(command_handle, wallet_handle, did, address, transport_key, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _set_endpoint_for_did(command_handle: IndyHandle, wallet_handle: IndyHandle, did: &str, address: &str, transport_key: &str, cb: Option) -> ErrorCode { + let did = c_str!(did); + let address = c_str!(address); + let transport_key = c_str!(transport_key); + + ErrorCode::from(unsafe { did::indy_set_endpoint_for_did(command_handle, wallet_handle, did.as_ptr(), address.as_ptr(), transport_key.as_ptr(), cb) }) +} + +/// Returns endpoint information for the given DID. +/// +/// # Arguments +/// * `wallet_handle` - Wallet handle (created by Wallet::open). +/// * `did` - The DID to resolve endpoint. +/// +/// # Returns +/// * `endpoint` - The DIDs endpoint. +/// * `transport_vk` - The DIDs transport key (ver key, key id). +pub fn get_endpoint_for_did(wallet_handle: IndyHandle, pool_handle: IndyHandle, did: &str) -> Box), Error=ErrorCode>> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_opt_string(); + + let err = _get_endpoint_for_did(command_handle, wallet_handle, pool_handle, did, cb); + + ResultHandler::str_optstr(command_handle, err, receiver) +} + +fn _get_endpoint_for_did(command_handle: IndyHandle, wallet_handle: IndyHandle, pool_handle: IndyHandle, did: &str, cb: Option) -> ErrorCode { + let did = c_str!(did); + + ErrorCode::from(unsafe { did::indy_get_endpoint_for_did(command_handle, wallet_handle, pool_handle, did.as_ptr(), cb) }) +} + +/// Saves/replaces the meta information for the giving DID in the wallet. +/// +/// # Arguments +/// * `wallet_handle` - Wallet handle (created by Wallet::open). +/// * `did` - the DID to store metadata. +/// * `metadata` - the meta information that will be store with the DID. +pub fn set_did_metadata(wallet_handle: IndyHandle, tgt_did: &str, metadata: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _set_did_metadata(command_handle, wallet_handle, tgt_did, metadata, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _set_did_metadata(command_handle: IndyHandle, wallet_handle: IndyHandle, tgt_did: &str, metadata: &str, cb: Option) -> ErrorCode { + let tgt_did = c_str!(tgt_did); + let metadata = c_str!(metadata); + + ErrorCode::from(unsafe { did::indy_set_did_metadata(command_handle, wallet_handle, tgt_did.as_ptr(), metadata.as_ptr(), cb) }) +} + +/// Retrieves the meta information for the giving DID in the wallet. +/// +/// # Arguments +/// * `wallet_handle` - Wallet handle (created by Wallet::open). +/// * `did` - The DID to retrieve metadata. +/// +/// #Returns +/// * `metadata` - The meta information stored with the DID; Can be null if no metadata was saved for this DID. +pub fn get_did_metadata(wallet_handle: IndyHandle, tgt_did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _get_did_metadata(command_handle, wallet_handle, tgt_did, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _get_did_metadata(command_handle: IndyHandle, wallet_handle: IndyHandle, tgt_did: &str, cb: Option) -> ErrorCode { + let tgt_did = c_str!(tgt_did); + + ErrorCode::from(unsafe { did::indy_get_did_metadata(command_handle, wallet_handle, tgt_did.as_ptr(), cb) }) +} + +/// Retrieves the information about the giving DID in the wallet. +/// +/// # Arguments +/// * `wallet_handle` - Wallet handle (created by Wallet::open). +/// * `did` - The DID to retrieve information. +/// +/// # Returns +/// * `did_with_meta` - { +/// "did": string - DID stored in the wallet, +/// "verkey": string - The DIDs transport key (ver key, key id), +/// "metadata": string - The meta information stored with the DID +/// } +pub fn get_my_did_with_metadata(wallet_handle: IndyHandle, my_did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _get_my_did_with_metadata(command_handle, wallet_handle, my_did, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _get_my_did_with_metadata(command_handle: IndyHandle, wallet_handle: IndyHandle, my_did: &str, cb: Option) -> ErrorCode { + let my_did = c_str!(my_did); + + ErrorCode::from(unsafe { did::indy_get_my_did_with_meta(command_handle, wallet_handle, my_did.as_ptr(), cb) }) +} + +/// Retrieves the information about all DIDs stored in the wallet. +/// +/// # Arguments +/// * `wallet_handle` - Wallet handle (created by Wallet::open). +/// +/// # Returns +/// * `dids` - [{ +/// "did": string - DID stored in the wallet, +/// "verkey": string - The DIDs transport key (ver key, key id)., +/// "tempVerkey": string - Temporary DIDs transport key (will be active after key rotation). +/// "metadata": string - The meta information stored with the DID +/// }] +pub fn list_my_dids_with_metadata(wallet_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _list_my_dids_with_metadata(command_handle, wallet_handle, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _list_my_dids_with_metadata(command_handle: IndyHandle, wallet_handle: IndyHandle, cb: Option) -> ErrorCode { + ErrorCode::from(unsafe { did::indy_list_my_dids_with_meta(command_handle, wallet_handle, cb) }) +} + +/// Retrieves abbreviated verkey if it is possible otherwise return full verkey. +/// +/// # Arguments +/// * `tgt_did` - DID. +/// * `full_verkey` - The DIDs verification key, +/// +/// #Returns +/// * `verkey` - The DIDs verification key in either abbreviated or full form +pub fn abbreviate_verkey(tgt_did: &str, verkey: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _abbreviate_verkey(command_handle, tgt_did, verkey, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _abbreviate_verkey(command_handle: IndyHandle, tgt_did: &str, verkey: &str, cb: Option) -> ErrorCode { + let tgt_did = c_str!(tgt_did); + let verkey = c_str!(verkey); + + ErrorCode::from(unsafe { did::indy_abbreviate_verkey(command_handle, tgt_did.as_ptr(), verkey.as_ptr(), cb) }) +} diff --git a/wrappers/rust/src/ledger.rs b/wrappers/rust/src/ledger.rs new file mode 100644 index 00000000..09322b29 --- /dev/null +++ b/wrappers/rust/src/ledger.rs @@ -0,0 +1,994 @@ +use {ErrorCode, IndyHandle}; + +use std::ffi::CString; +use std::ptr::null; + +use futures::Future; + +use ffi::ledger; +use ffi::{ResponseStringCB, + ResponseStringStringCB, + ResponseStringStringU64CB}; + +use utils::callbacks::{ClosureHandler, ResultHandler}; + +/// Signs and submits request message to validator pool. +/// +/// Adds submitter information to passed request json, signs it with submitter +/// sign key (see Crypto::sign), and sends signed request message +/// to validator pool (see Pool::write_request). +/// +/// # Arguments +/// * `pool_handle` - pool handle (created by Pool::open_ledger). +/// * `wallet_handle` - wallet handle (created by Wallet::open). +/// * `submitter_did` - Id of Identity stored in secured Wallet. +/// * `request_json` - Request data json. +/// +/// # Returns +/// Request result as json. +pub fn sign_and_submit_request(pool_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: &str, request_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _sign_and_submit_request(command_handle, pool_handle, wallet_handle, submitter_did, request_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _sign_and_submit_request(command_handle: IndyHandle, pool_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: &str, request_json: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let request_json = c_str!(request_json); + + ErrorCode::from(unsafe { + ledger::indy_sign_and_submit_request(command_handle, + pool_handle, + wallet_handle, + submitter_did.as_ptr(), + request_json.as_ptr(), + cb) + }) +} + +/// Publishes request message to validator pool (no signing, unlike sign_and_submit_request). +/// +/// The request is sent to the validator pool as is. It's assumed that it's already prepared. +/// +/// # Arguments +/// * `pool_handle` - pool handle (created by Pool::open_ledger). +/// * `request_json` - Request data json. +/// +/// # Returns +/// Request result as json. +pub fn submit_request(pool_handle: IndyHandle, request_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _submit_request(command_handle, pool_handle, request_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _submit_request(command_handle: IndyHandle, pool_handle: IndyHandle, request_json: &str, cb: Option) -> ErrorCode { + let request_json = c_str!(request_json); + + ErrorCode::from(unsafe { ledger::indy_submit_request(command_handle, pool_handle, request_json.as_ptr(), cb) }) +} + +pub fn submit_action(pool_handle: IndyHandle, request_json: &str, nodes: Option<&str>, wait_timeout: Option) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _submit_action(command_handle, pool_handle, request_json, nodes, wait_timeout, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _submit_action(command_handle: IndyHandle, pool_handle: IndyHandle, request_json: &str, nodes: Option<&str>, wait_timeout: Option, cb: Option) -> ErrorCode { + let request_json = c_str!(request_json); + let nodes_str = opt_c_str!(nodes); + + ErrorCode::from(unsafe { + ledger::indy_submit_action(command_handle, pool_handle, request_json.as_ptr(), opt_c_ptr!(nodes, nodes_str), wait_timeout.unwrap_or(-1), cb) + }) +} + +/// Signs request message. +/// +/// Adds submitter information to passed request json, signs it with submitter +/// sign key (see Crypto::sign). +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by Wallet::open). +/// * `submitter_did` - Id of Identity stored in secured Wallet. +/// * `request_json` - Request data json. +/// +/// # Returns +/// Signed request json. +pub fn sign_request(wallet_handle: IndyHandle, submitter_did: &str, request_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _sign_request(command_handle, wallet_handle, submitter_did, request_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _sign_request(command_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: &str, request_json: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let request_json = c_str!(request_json); + + ErrorCode::from(unsafe { ledger::indy_sign_request(command_handle, wallet_handle, submitter_did.as_ptr(), request_json.as_ptr(), cb) }) +} + +/// Multi signs request message. +/// +/// Adds submitter information to passed request json, signs it with submitter +/// sign key (see Crypto::sign). +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by Wallet::open). +/// * `submitter_did` - Id of Identity stored in secured Wallet. +/// * `request_json` - Request data json. +/// +/// # Returns +/// Signed request json. +pub fn multi_sign_request(wallet_handle: IndyHandle, submitter_did: &str, request_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _multi_sign_request(command_handle, wallet_handle, submitter_did, request_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _multi_sign_request(command_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: &str, request_json: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let request_json = c_str!(request_json); + + ErrorCode::from(unsafe { ledger::indy_multi_sign_request(command_handle, wallet_handle, submitter_did.as_ptr(), request_json.as_ptr(), cb) }) +} + +/// Builds a request to get a DDO. +/// +/// # Arguments +/// * `submitter_did` - Id of Identity stored in secured Wallet +/// * `target_did` - Id of Identity stored in secured Wallet. +/// +/// # Returns +/// Request result as json. +pub fn build_get_ddo_request(submitter_did: Option<&str>, target_did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_ddo_request(command_handle, submitter_did, target_did, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_ddo_request(command_handle: IndyHandle, submitter_did: Option<&str>, target_did: &str, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let target_did = c_str!(target_did); + + ErrorCode::from(unsafe { ledger::indy_build_get_ddo_request(command_handle, opt_c_ptr!(submitter_did, submitter_did_str), target_did.as_ptr(), cb) }) +} + +/// Builds a NYM request. Request to create a new NYM record for a specific user. +/// +/// # Arguments +/// * `submitter_did` - DID of the submitter stored in secured Wallet. +/// * `target_did` - Target DID as base58-encoded string for 16 or 32 bit DID value. +/// * `verkey` - Target identity verification key as base58-encoded string. +/// * `data` +/// * `role` - Role of a user NYM record: +/// null (common USER) +/// TRUSTEE +/// STEWARD +/// TRUST_ANCHOR +/// empty string to reset role +/// +/// # Returns +/// Request result as json. +pub fn build_nym_request(submitter_did: &str, target_did: &str, verkey: Option<&str>, data: Option<&str>, role: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_nym_request(command_handle, submitter_did, target_did, verkey, data, role, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_nym_request(command_handle: IndyHandle, + submitter_did: &str, + target_did: &str, + verkey: Option<&str>, + data: Option<&str>, + role: Option<&str>, + cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let target_did = c_str!(target_did); + + let verkey_str = opt_c_str!(verkey); + let data_str = opt_c_str!(data); + let role_str = opt_c_str!(role); + + ErrorCode::from(unsafe { + ledger::indy_build_nym_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + opt_c_ptr!(verkey, verkey_str), + opt_c_ptr!(data, data_str), + opt_c_ptr!(role, role_str), + cb) + }) +} + +/// Builds a GET_NYM request. Request to get information about a DID (NYM). +/// +/// # Arguments +/// * `submitter_did` - DID of the read request sender. +/// * `target_did` - Target DID as base58-encoded string for 16 or 32 bit DID value. +/// +/// # Returns +/// Request result as json. +pub fn build_get_nym_request(submitter_did: Option<&str>, target_did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_nym_request(command_handle, submitter_did, target_did, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_nym_request(command_handle: IndyHandle, submitter_did: Option<&str>, target_did: &str, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let target_did = c_str!(target_did); + + ErrorCode::from(unsafe { ledger::indy_build_get_nym_request(command_handle, opt_c_ptr!(submitter_did, submitter_did_str), target_did.as_ptr(), cb) }) +} + +/// Builds a GET_TXN request. Request to get any transaction by its seq_no. +/// +/// # Arguments +/// * `submitter_did` - DID of the request submitter. +/// * `ledger_type` - (Optional) type of the ledger the requested transaction belongs to: +/// DOMAIN - used default, +/// POOL, +/// CONFIG +/// * `seq_no` - seq_no of transaction in ledger. +/// +/// # Returns +/// Request result as json. +pub fn build_get_txn_request(submitter_did: Option<&str>, ledger_type: Option<&str>, seq_no: i32) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_txn_request(command_handle, submitter_did, ledger_type, seq_no, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_txn_request(command_handle: IndyHandle, submitter_did: Option<&str>, ledger_type: Option<&str>, seq_no: i32, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let ledger_type_str = opt_c_str!(ledger_type); + + ErrorCode::from(unsafe { ledger::indy_build_get_txn_request(command_handle, opt_c_ptr!(submitter_did, submitter_did_str), opt_c_ptr!(ledger_type, ledger_type_str), seq_no, cb) }) +} + +/// Builds an ATTRIB request. Request to add attribute to a NYM record. +/// +/// # Arguments +/// * `submitter_did` - DID of the submitter stored in secured Wallet. +/// * `target_did` - Target DID as base58-encoded string for 16 or 32 bit DID value. +/// * `hash` - (Optional) Hash of attribute data. +/// * `raw` - (Optional) Json, where key is attribute name and value is attribute value. +/// * `enc` - (Optional) Encrypted value attribute data. +/// +/// # Returns +/// Request result as json. +pub fn build_attrib_request(submitter_did: &str, target_did: &str, hash: Option<&str>, raw: Option<&str>, enc: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_attrib_request(command_handle, submitter_did, target_did, hash, raw, enc, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_attrib_request(command_handle: IndyHandle, submitter_did: &str, target_did: &str, hash: Option<&str>, raw: Option<&str>, enc: Option<&str>, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let target_did = c_str!(target_did); + + let hash_str = opt_c_str!(hash); + let raw_str = opt_c_str!(raw); + let enc_str = opt_c_str!(enc); + + ErrorCode::from(unsafe { + ledger::indy_build_attrib_request(command_handle, + submitter_did.as_ptr(), + target_did.as_ptr(), + opt_c_ptr!(hash, hash_str), + opt_c_ptr!(raw, raw_str), + opt_c_ptr!(enc, enc_str), + cb) + }) +} + +/// Builds a GET_ATTRIB request. Request to get information about an Attribute for the specified DID. +/// +/// # Arguments +/// * `submitter_did` - DID of the read request sender. +/// * `target_did` - Target DID as base58-encoded string for 16 or 32 bit DID value. +/// * `raw` - (Optional) Requested attribute name. +/// * `hash` - (Optional) Requested attribute hash. +/// * `enc` - (Optional) Requested attribute encrypted value. +/// +/// # Returns +/// Request result as json. +pub fn build_get_attrib_request(submitter_did: Option<&str>, target_did: &str, raw: Option<&str>, hash: Option<&str>, enc: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_attrib_request(command_handle, submitter_did, target_did, raw, hash, enc, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_attrib_request(command_handle: IndyHandle, submitter_did: Option<&str>, target_did: &str, raw: Option<&str>, hash: Option<&str>, enc: Option<&str>, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let target_did = c_str!(target_did); + + let raw_str = opt_c_str!(raw); + let hash_str = opt_c_str!(hash); + let enc_str = opt_c_str!(enc); + + ErrorCode::from(unsafe { + ledger::indy_build_get_attrib_request(command_handle, + opt_c_ptr!(submitter_did, submitter_did_str), + target_did.as_ptr(), + opt_c_ptr!(raw, raw_str), + opt_c_ptr!(hash, hash_str), + opt_c_ptr!(enc, enc_str), + cb) + }) +} + +/// Builds a SCHEMA request. Request to add Credential's schema. +/// +/// # Arguments +/// * `submitter_did` - DID of the submitter stored in secured Wallet. +/// * `data` - Credential schema. +/// { +/// id: identifier of schema +/// attrNames: array of attribute name strings (the number of attributes should be less or equal than 125) +/// name: Schema's name string +/// version: Schema's version string, +/// ver: Version of the Schema json +/// } +/// +/// # Returns +/// Request result as json. +pub fn build_schema_request(submitter_did: &str, data: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_schema_request(command_handle, submitter_did, data, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_schema_request(command_handle: IndyHandle, submitter_did: &str, data: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let data = c_str!(data); + + ErrorCode::from(unsafe { ledger::indy_build_schema_request(command_handle, submitter_did.as_ptr(), data.as_ptr(), cb) }) +} + +/// Builds a GET_SCHEMA request. Request to get Credential's Schema. +/// +/// # Arguments +/// * `submitter_did` - DID of the read request sender. +/// * `id` - Schema ID in ledger +/// +/// # Returns +/// Request result as json. +pub fn build_get_schema_request(submitter_did: Option<&str>, id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_schema_request(command_handle, submitter_did, id, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_schema_request(command_handle: IndyHandle, submitter_did: Option<&str>, id: &str, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let id = c_str!(id); + + ErrorCode::from(unsafe { ledger::indy_build_get_schema_request(command_handle, opt_c_ptr!(submitter_did, submitter_did_str), id.as_ptr(), cb) }) +} + +/// Parse a GET_SCHEMA response to get Schema in the format compatible with Anoncreds API. +/// +/// # Arguments +/// * `get_schema_response` - response of GET_SCHEMA request. +/// +/// # Returns +/// Schema Id and Schema json. +/// { +/// id: identifier of schema +/// attrNames: array of attribute name strings +/// name: Schema's name string +/// version: Schema's version string +/// ver: Version of the Schema json +/// } +pub fn parse_get_schema_response(get_schema_response: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _parse_get_schema_response(command_handle, get_schema_response, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _parse_get_schema_response(command_handle: IndyHandle, get_schema_response: &str, cb: Option) -> ErrorCode { + let get_schema_response = c_str!(get_schema_response); + + ErrorCode::from(unsafe { ledger::indy_parse_get_schema_response(command_handle, get_schema_response.as_ptr(), cb) }) +} + +/// Builds an CRED_DEF request. Request to add a Credential Definition (in particular, public key), +/// that Issuer creates for a particular Credential Schema. +/// +/// # Arguments +/// * `submitter_did` - DID of the submitter stored in secured Wallet. +/// * `data` - credential definition json +/// { +/// id: string - identifier of credential definition +/// schemaId: string - identifier of stored in ledger schema +/// type: string - type of the credential definition. CL is the only supported type now. +/// tag: string - allows to distinct between credential definitions for the same issuer and schema +/// value: Dictionary with Credential Definition's data: { +/// primary: primary credential public key, +/// Optional: revocation credential public key +/// }, +/// ver: Version of the CredDef json +/// } +/// +/// # Returns +/// Request result as json. +pub fn build_cred_def_request(submitter_did: &str, data: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_cred_def_request(command_handle, submitter_did, data, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_cred_def_request(command_handle: IndyHandle, submitter_did: &str, data: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let data = c_str!(data); + + ErrorCode::from(unsafe { ledger::indy_build_cred_def_request(command_handle, submitter_did.as_ptr(), data.as_ptr(), cb) }) +} + +/// Builds a GET_CRED_DEF request. Request to get a Credential Definition (in particular, public key), +/// that Issuer creates for a particular Credential Schema. +/// +/// # Arguments +/// * `submitter_did` - DID of the read request sender. +/// * `id` - Credential Definition ID in ledger. +/// +/// # Returns +/// Request result as json. +pub fn build_get_cred_def_request(submitter_did: Option<&str>, id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_cred_def_request(command_handle, submitter_did, id, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_cred_def_request(command_handle: IndyHandle, submitter_did: Option<&str>, id: &str, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let id = c_str!(id); + + ErrorCode::from(unsafe { ledger::indy_build_get_cred_def_request(command_handle, opt_c_ptr!(submitter_did, submitter_did_str), id.as_ptr(), cb) }) +} + +/// Parse a GET_CRED_DEF response to get Credential Definition in the format compatible with Anoncreds API. +/// +/// # Arguments +/// * `get_cred_def_response` - response of GET_CRED_DEF request. +/// +/// # Returns +/// Credential Definition Id and Credential Definition json. +/// { +/// id: string - identifier of credential definition +/// schemaId: string - identifier of stored in ledger schema +/// type: string - type of the credential definition. CL is the only supported type now. +/// tag: string - allows to distinct between credential definitions for the same issuer and schema +/// value: Dictionary with Credential Definition's data: { +/// primary: primary credential public key, +/// Optional: revocation credential public key +/// }, +/// ver: Version of the Credential Definition json +/// } +pub fn parse_get_cred_def_response(get_cred_def_response: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _parse_get_cred_def_response(command_handle, get_cred_def_response, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _parse_get_cred_def_response(command_handle: IndyHandle, get_cred_def_response: &str, cb: Option) -> ErrorCode { + let get_cred_def_response = c_str!(get_cred_def_response); + + ErrorCode::from(unsafe { ledger::indy_parse_get_cred_def_response(command_handle, get_cred_def_response.as_ptr(), cb) }) +} + +/// Builds a NODE request. Request to add a new node to the pool, or updates existing in the pool. +/// +/// # Arguments +/// * `submitter_did` - DID of the submitter stored in secured Wallet. +/// * `target_did` - Target Node's DID. It differs from submitter_did field. +/// * `data` - Data associated with the Node: { +/// alias: string - Node's alias +/// blskey: string - (Optional) BLS multi-signature key as base58-encoded string. +/// client_ip: string - (Optional) Node's client listener IP address. +/// client_port: string - (Optional) Node's client listener port. +/// node_ip: string - (Optional) The IP address other Nodes use to communicate with this Node. +/// node_port: string - (Optional) The port other Nodes use to communicate with this Node. +/// services: array - (Optional) The service of the Node. VALIDATOR is the only supported one now. +/// } +/// +/// # Returns +/// Request result as json. +pub fn build_node_request(submitter_did: &str, target_did: &str, data: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_node_request(command_handle, submitter_did, target_did, data, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_node_request(command_handle: IndyHandle, submitter_did: &str, target_did: &str, data: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let target_did = c_str!(target_did); + let data = c_str!(data); + + ErrorCode::from(unsafe { ledger::indy_build_node_request(command_handle, submitter_did.as_ptr(), target_did.as_ptr(), data.as_ptr(), cb) }) +} + +/// Builds a GET_VALIDATOR_INFO request. +/// +/// # Arguments +/// * `submitter_did` - Id of Identity stored in secured Wallet. +/// +/// # Returns +/// Request result as json. +pub fn build_get_validator_info_request(submitter_did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_validator_info_request(command_handle, submitter_did, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_validator_info_request(command_handle: IndyHandle, submitter_did: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + + ErrorCode::from(unsafe { + ledger::indy_build_get_validator_info_request(command_handle, submitter_did.as_ptr(), cb) + }) +} + +/// Builds a POOL_CONFIG request. Request to change Pool's configuration. +/// +/// # Arguments +/// * `submitter_did` - DID of the submitter stored in secured Wallet. +/// * `writes` - Whether any write requests can be processed by the pool +/// (if false, then pool goes to read-only state). True by default. +/// * `force` - Whether we should apply transaction (for example, move pool to read-only state) +/// without waiting for consensus of this transaction. +/// +/// # Returns +/// Request result as json. +pub fn build_pool_config_request(submitter_did: &str, writes: bool, force: bool) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_pool_config_request(command_handle, submitter_did, writes, force, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_pool_config_request(command_handle: IndyHandle, submitter_did: &str, writes: bool, force: bool, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + + ErrorCode::from(unsafe { ledger::indy_build_pool_config_request(command_handle, submitter_did.as_ptr(), writes, force, cb) }) +} + +/// Builds a POOL_RESTART request. +/// +/// # Arguments +/// * `submitter_did` - Id of Identity stored in secured Wallet. +/// * `action`- +/// * `datetime`- +/// +/// # Returns +/// Request result as json. +pub fn build_pool_restart_request(submitter_did: &str, action: &str, datetime: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_pool_restart_request(command_handle, submitter_did, action, datetime, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_pool_restart_request(command_handle: IndyHandle, submitter_did: &str, action: &str, datetime: Option<&str>, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let action = c_str!(action); + let datetime_str = opt_c_str!(datetime); + + ErrorCode::from(unsafe { + ledger::indy_build_pool_restart_request(command_handle, + submitter_did.as_ptr(), + action.as_ptr(), + opt_c_ptr!(datetime, datetime_str), + cb) + }) +} + +/// Builds a POOL_UPGRADE request. Request to upgrade the Pool (sent by Trustee). +/// It upgrades the specified Nodes (either all nodes in the Pool, or some specific ones). +/// +/// # Arguments +/// * `submitter_did` - DID of the submitter stored in secured Wallet. +/// * `name` - Human-readable name for the upgrade. +/// * `version` - The version of indy-node package we perform upgrade to. +/// Must be greater than existing one (or equal if reinstall flag is True). +/// * `action` - Either start or cancel. +/// * `sha256` - sha256 hash of the package. +/// * `upgrade_timeout` - (Optional) Limits upgrade time on each Node. +/// * `schedule` - (Optional) Schedule of when to perform upgrade on each node. Map Node DIDs to upgrade time. +/// * `justification` - (Optional) justification string for this particular Upgrade. +/// * `reinstall` - Whether it's allowed to re-install the same version. False by default. +/// * `force` - Whether we should apply transaction (schedule Upgrade) without waiting +/// for consensus of this transaction. +/// +/// # Returns +/// Request result as json. +pub fn build_pool_upgrade_request(submitter_did: &str, + name: &str, + version: &str, + action: &str, + sha256: &str, + upgrade_timeout: Option, + schedule: Option<&str>, + justification: Option<&str>, + reinstall: bool, + force: bool, + package: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_pool_upgrade_request(command_handle, submitter_did, name, version, action, sha256, upgrade_timeout, schedule, justification, reinstall, force, package, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_pool_upgrade_request(command_handle: IndyHandle, + submitter_did: &str, + name: &str, + version: &str, + action: &str, + sha256: &str, + upgrade_timeout: Option, + schedule: Option<&str>, + justification: Option<&str>, + reinstall: bool, + force: bool, + package: Option<&str>, + cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let name = c_str!(name); + let version = c_str!(version); + let action = c_str!(action); + let sha256 = c_str!(sha256); + let upgrade_timeout = upgrade_timeout.map(|t| t as i32).unwrap_or(-1); + + let schedule_str = opt_c_str!(schedule); + let justification_str = opt_c_str!(justification); + let package_str = opt_c_str!(package); + + ErrorCode::from(unsafe { + ledger::indy_build_pool_upgrade_request(command_handle, + submitter_did.as_ptr(), + name.as_ptr(), + version.as_ptr(), + action.as_ptr(), + sha256.as_ptr(), + upgrade_timeout, + opt_c_ptr!(schedule, schedule_str), + opt_c_ptr!(justification, justification_str), + reinstall, + force, + opt_c_ptr!(package, package_str), + cb) + }) +} + +/// Builds a REVOC_REG_DEF request. Request to add the definition of revocation registry +/// to an exists credential definition. +/// +/// # Arguments +/// * `submitter_did` - DID of the submitter stored in secured Wallet. +/// * `data` - Revocation Registry data: +/// { +/// "id": string - ID of the Revocation Registry, +/// "revocDefType": string - Revocation Registry type (only CL_ACCUM is supported for now), +/// "tag": string - Unique descriptive ID of the Registry, +/// "credDefId": string - ID of the corresponding CredentialDefinition, +/// "value": Registry-specific data { +/// "issuanceType": string - Type of Issuance(ISSUANCE_BY_DEFAULT or ISSUANCE_ON_DEMAND), +/// "maxCredNum": number - Maximum number of credentials the Registry can serve. +/// "tailsHash": string - Hash of tails. +/// "tailsLocation": string - Location of tails file. +/// "publicKeys": - Registry's public key. +/// }, +/// "ver": string - version of revocation registry definition json. +/// } +/// +/// # Returns +/// Request result as json. +pub fn build_revoc_reg_def_request(submitter_did: &str, data: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_revoc_reg_def_request(command_handle, submitter_did, data, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_revoc_reg_def_request(command_handle: IndyHandle, submitter_did: &str, data: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let data = c_str!(data); + + ErrorCode::from(unsafe { ledger::indy_build_revoc_reg_def_request(command_handle, submitter_did.as_ptr(), data.as_ptr(), cb) }) +} + +/// Builds a GET_REVOC_REG_DEF request. Request to get a revocation registry definition, +/// that Issuer creates for a particular Credential Definition. +/// +/// # Arguments +/// * `submitter_did` - DID of the read request sender. +/// * `id` - ID of Revocation Registry Definition in ledger. +/// +/// # Returns +/// Request result as json. +pub fn build_get_revoc_reg_def_request(submitter_did: Option<&str>, id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_revoc_reg_def_request(command_handle, submitter_did, id, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_revoc_reg_def_request(command_handle: IndyHandle, submitter_did: Option<&str>, id: &str, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let id = c_str!(id); + + ErrorCode::from(unsafe { ledger::indy_build_get_revoc_reg_def_request(command_handle, opt_c_ptr!(submitter_did, submitter_did_str), id.as_ptr(), cb) }) +} + +/// Parse a GET_REVOC_REG_DEF response to get Revocation Registry Definition in the format +/// compatible with Anoncreds API. +/// +/// #Params +/// * `get_revoc_reg_def_response` - response of GET_REVOC_REG_DEF request. +/// +/// # Returns +/// Revocation Registry Definition Id and Revocation Registry Definition json. +/// { +/// "id": string - ID of the Revocation Registry, +/// "revocDefType": string - Revocation Registry type (only CL_ACCUM is supported for now), +/// "tag": string - Unique descriptive ID of the Registry, +/// "credDefId": string - ID of the corresponding CredentialDefinition, +/// "value": Registry-specific data { +/// "issuanceType": string - Type of Issuance(ISSUANCE_BY_DEFAULT or ISSUANCE_ON_DEMAND), +/// "maxCredNum": number - Maximum number of credentials the Registry can serve. +/// "tailsHash": string - Hash of tails. +/// "tailsLocation": string - Location of tails file. +/// "publicKeys": - Registry's public key. +/// }, +/// "ver": string - version of revocation registry definition json. +/// } +pub fn parse_get_revoc_reg_def_response(get_revoc_reg_def_response: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _parse_get_revoc_reg_def_response(command_handle, get_revoc_reg_def_response, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _parse_get_revoc_reg_def_response(command_handle: IndyHandle, get_revoc_reg_def_response: &str, cb: Option) -> ErrorCode { + let get_revoc_reg_def_response = c_str!(get_revoc_reg_def_response); + + ErrorCode::from(unsafe { ledger::indy_parse_get_revoc_reg_def_response(command_handle, get_revoc_reg_def_response.as_ptr(), cb) }) +} + +/// Builds a REVOC_REG_ENTRY request. Request to add the RevocReg entry containing +/// the new accumulator value and issued/revoked indices. +/// This is just a delta of indices, not the whole list. +/// So, it can be sent each time a new credential is issued/revoked. +/// +/// # Arguments +/// * `submitter_did` - DID of the submitter stored in secured Wallet. +/// * `revoc_reg_def_id` - ID of the corresponding RevocRegDef. +/// * `rev_def_type` - Revocation Registry type (only CL_ACCUM is supported for now). +/// * `value` - Registry-specific data: { +/// value: { +/// prevAccum: string - previous accumulator value. +/// accum: string - current accumulator value. +/// issued: array - an array of issued indices. +/// revoked: array an array of revoked indices. +/// }, +/// ver: string - version revocation registry entry json +/// +/// } +/// +/// # Returns +/// Request result as json. +pub fn build_revoc_reg_entry_request(submitter_did: &str, revoc_reg_def_id: &str, rev_def_type: &str, value: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_revoc_reg_entry_request(command_handle, submitter_did, revoc_reg_def_id, rev_def_type, value, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_revoc_reg_entry_request(command_handle: IndyHandle, submitter_did: &str, revoc_reg_def_id: &str, rev_def_type: &str, value: &str, cb: Option) -> ErrorCode { + let submitter_did = c_str!(submitter_did); + let revoc_reg_def_id = c_str!(revoc_reg_def_id); + let rev_def_type = c_str!(rev_def_type); + let value = c_str!(value); + + ErrorCode::from(unsafe { ledger::indy_build_revoc_reg_entry_request(command_handle, submitter_did.as_ptr(), revoc_reg_def_id.as_ptr(), rev_def_type.as_ptr(), value.as_ptr(), cb) }) +} + +/// Builds a GET_REVOC_REG request. Request to get the accumulated state of the Revocation Registry +/// by ID. The state is defined by the given timestamp. +/// +/// # Arguments +/// * `submitter_did` - DID of the read request sender. +/// * `revoc_reg_def_id` - ID of the corresponding Revocation Registry Definition in ledger. +/// * `timestamp` - Requested time represented as a total number of seconds from Unix Epoch +/// +/// # Returns +/// Request result as json. +pub fn build_get_revoc_reg_request(submitter_did: Option<&str>, revoc_reg_def_id: &str, timestamp: i64) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_revoc_reg_request(command_handle, submitter_did, revoc_reg_def_id, timestamp, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_revoc_reg_request(command_handle: IndyHandle, submitter_did: Option<&str>, revoc_reg_def_id: &str, timestamp: i64, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let revoc_reg_def_id = c_str!(revoc_reg_def_id); + + ErrorCode::from(unsafe { ledger::indy_build_get_revoc_reg_request(command_handle, opt_c_ptr!(submitter_did, submitter_did_str), revoc_reg_def_id.as_ptr(), timestamp, cb) }) +} + +/// Parse a GET_REVOC_REG response to get Revocation Registry in the format compatible with Anoncreds API. +/// +/// # Arguments +/// * `get_revoc_reg_response` - response of GET_REVOC_REG request. +/// +/// # Returns +/// Revocation Registry Definition Id, Revocation Registry json and Timestamp. +/// { +/// "value": Registry-specific data { +/// "accum": string - current accumulator value. +/// }, +/// "ver": string - version revocation registry json +/// } +pub fn parse_get_revoc_reg_response(get_revoc_reg_response: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string_u64(); + + let err = _parse_get_revoc_reg_response(command_handle, get_revoc_reg_response, cb); + + ResultHandler::str_str_u64(command_handle, err, receiver) +} + +fn _parse_get_revoc_reg_response(command_handle: IndyHandle, get_revoc_reg_response: &str, cb: Option) -> ErrorCode { + let get_revoc_reg_response = c_str!(get_revoc_reg_response); + + ErrorCode::from(unsafe { ledger::indy_parse_get_revoc_reg_response(command_handle,get_revoc_reg_response.as_ptr(), cb) }) +} + +/// Builds a GET_REVOC_REG_DELTA request. Request to get the delta of the accumulated state of the Revocation Registry. +/// The Delta is defined by from and to timestamp fields. +/// If from is not specified, then the whole state till to will be returned. +/// +/// # Arguments +/// * `submitter_did` - DID of the read request sender. +/// * `revoc_reg_def_id` - ID of the corresponding Revocation Registry Definition in ledger. +/// * `from` - Requested time represented as a total number of seconds from Unix Epoch +/// * `to` - Requested time represented as a total number of seconds from Unix Epoch +/// +/// # Returns +/// Request result as json. +pub fn build_get_revoc_reg_delta_request(submitter_did: Option<&str>, revoc_reg_def_id: &str, from: i64, to: i64) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_revoc_reg_delta_request(command_handle, submitter_did, revoc_reg_def_id, from, to, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_revoc_reg_delta_request(command_handle: IndyHandle, submitter_did: Option<&str>, revoc_reg_def_id: &str, from: i64, to: i64, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let revoc_reg_def_id = c_str!(revoc_reg_def_id); + + ErrorCode::from(unsafe { ledger::indy_build_get_revoc_reg_delta_request(command_handle, opt_c_ptr!(submitter_did, submitter_did_str), revoc_reg_def_id.as_ptr(), from, to, cb) }) +} + +/// Parse a GET_REVOC_REG_DELTA response to get Revocation Registry Delta in the format compatible with Anoncreds API. +/// +/// # Arguments +/// * `get_revoc_reg_response` - response of GET_REVOC_REG_DELTA request. +/// +/// # Returns +/// Revocation Registry Definition Id, Revocation Registry Delta json and Timestamp. +/// { +/// "value": Registry-specific data { +/// prevAccum: string - previous accumulator value. +/// accum: string - current accumulator value. +/// issued: array - an array of issued indices. +/// revoked: array an array of revoked indices. +/// }, +/// "ver": string - version revocation registry delta json +/// } +pub fn parse_get_revoc_reg_delta_response(get_revoc_reg_delta_response: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string_u64(); + + let err = _parse_get_revoc_reg_delta_response(command_handle, get_revoc_reg_delta_response, cb); + + ResultHandler::str_str_u64(command_handle, err, receiver) +} + +fn _parse_get_revoc_reg_delta_response(command_handle: IndyHandle, get_revoc_reg_delta_response: &str, cb: Option) -> ErrorCode { + let get_revoc_reg_delta_response = c_str!(get_revoc_reg_delta_response); + + ErrorCode::from(unsafe { ledger::indy_parse_get_revoc_reg_delta_response(command_handle,get_revoc_reg_delta_response.as_ptr(), cb) }) +} + +/// Parse transaction response to fetch metadata. +/// The important use case for this method is validation of Node's response freshens. +/// +/// Distributed Ledgers can reply with outdated information for consequence read request after write. +/// To reduce pool load libindy sends read requests to one random node in the pool. +/// Consensus validation is performed based on validation of nodes multi signature for current ledger Merkle Trie root. +/// This multi signature contains information about the latest ldeger's transaction ordering time and sequence number that this method returns. +/// +/// If node that returned response for some reason is out of consensus and has outdated ledger +/// it can be caught by analysis of the returned latest ledger's transaction ordering time and sequence number. +/// +/// There are two ways to filter outdated responses: +/// 1) based on "seqNo" - sender knows the sequence number of transaction that he consider as a fresh enough. +/// 2) based on "txnTime" - sender knows the timestamp that he consider as a fresh enough. +/// +/// Note: response of GET_VALIDATOR_INFO request isn't supported +/// +/// # Arguments +/// * `response` - response of write or get request. +/// +/// Note: response of GET_VALIDATOR_INFO request isn't supported +/// +/// # Returns +/// response metadata +/// { +/// "seqNo": Option - transaction sequence number, +/// "txnTime": Option - transaction ordering time, +/// "lastSeqNo": Option - the latest transaction seqNo for particular Node, +/// "lastTxnTime": Option - the latest transaction ordering time for particular Node +/// } +pub fn get_response_metadata(response: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _get_response_metadata(command_handle, response, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _get_response_metadata(command_handle: IndyHandle, response: &str, cb: Option) -> ErrorCode { + let response = c_str!(response); + + ErrorCode::from(unsafe { ledger::indy_get_response_metadata(command_handle,response.as_ptr(), cb) }) +} diff --git a/wrappers/rust/src/lib.rs b/wrappers/rust/src/lib.rs new file mode 100644 index 00000000..2d2b9868 --- /dev/null +++ b/wrappers/rust/src/lib.rs @@ -0,0 +1,301 @@ +extern crate futures; +#[macro_use] +extern crate lazy_static; +extern crate log; +extern crate libc; +#[macro_use] +extern crate failure; +extern crate num_traits; +#[macro_use] +extern crate num_derive; + +extern crate indy_sys as ffi; + +#[macro_use] +mod macros; + +pub use futures::future; + +pub mod anoncreds; +pub mod blob_storage; +pub mod crypto; +pub mod did; +pub mod ledger; +pub mod logger; +pub mod payments; +pub mod pairwise; +pub mod pool; +pub mod wallet; +mod utils; + +use std::ffi::CString; + +pub type IndyHandle = i32; + +/// Set libindy runtime configuration. Can be optionally called to change current params. +/// +/// # Arguments +/// * `config` - { +/// "crypto_thread_pool_size": - size of thread pool for the most expensive crypto operations. (4 by default) +/// } +pub fn set_runtime_config(config: &str) -> ErrorCode { + let config = c_str!(config); + + ErrorCode::from(unsafe { + ffi::indy_set_runtime_config(config.as_ptr()) + }) +} + +#[derive(Fail, Debug, PartialEq, Copy, Clone, FromPrimitive, ToPrimitive)] +#[repr(i32)] +#[allow(dead_code)] +pub enum ErrorCode +{ + #[fail(display = "Success")] + Success = 0, + // Common errors + + // Caller passed invalid value as param 1 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam1")] + CommonInvalidParam1 = 100, + // Caller passed invalid value as param 2 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam2")] + CommonInvalidParam2 = 101, + // Caller passed invalid value as param 3 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam3")] + CommonInvalidParam3 = 102, + // Caller passed invalid value as param 4 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam4")] + CommonInvalidParam4 = 103, + + // Caller passed invalid value as param 5 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam5")] + CommonInvalidParam5 = 104, + // Caller passed invalid value as param 6 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam6")] + CommonInvalidParam6 = 105, + // Caller passed invalid value as param 7 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam7")] + CommonInvalidParam7 = 106, + // Caller passed invalid value as param 8 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam8")] + CommonInvalidParam8 = 107, + // Caller passed invalid value as param 9 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam9")] + CommonInvalidParam9 = 108, + + // Caller passed invalid value as param 10 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam10")] + CommonInvalidParam10 = 109, + // Caller passed invalid value as param 11 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam11")] + CommonInvalidParam11 = 110, + // Caller passed invalid value as param 11 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam12")] + CommonInvalidParam12 = 111, + // Invalid library state was detected in runtime. It signals library bug + #[fail(display = "CommonInvalidState")] + CommonInvalidState = 112, + // Object (json, config, key, credential and etc...) passed by library caller has invalid structure + #[fail(display = "CommonInvalidStructure")] + CommonInvalidStructure = 113, + + // IO Error + #[fail(display = "CommonIOError")] + CommonIOError = 114, + // Caller passed invalid value as param 13 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam13")] + CommonInvalidParam13 = 115, + // Caller passed invalid value as param 14 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam14")] + CommonInvalidParam14 = 116, + // Caller passed invalid value as param 15 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam15")] + CommonInvalidParam15 = 117, + // Caller passed invalid value as param 16 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam16")] + CommonInvalidParam16 = 118, + + // Caller passed invalid value as param 17 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam17")] + CommonInvalidParam17 = 119, + // Caller passed invalid value as param 18 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam18")] + CommonInvalidParam18 = 120, + // Caller passed invalid value as param 19 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam19")] + CommonInvalidParam19 = 121, + // Caller passed invalid value as param 20 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam20")] + CommonInvalidParam20 = 122, + // Caller passed invalid value as param 21 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam21")] + CommonInvalidParam21 = 123, + + // Caller passed invalid value as param 22 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam22")] + CommonInvalidParam22 = 124, + // Caller passed invalid value as param 23 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam23")] + CommonInvalidParam23 = 125, + // Caller passed invalid value as param 24 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam24")] + CommonInvalidParam24 = 126, + // Caller passed invalid value as param 25 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam25")] + CommonInvalidParam25 = 127, + // Caller passed invalid value as param 26 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam26")] + CommonInvalidParam26 = 128, + + // Caller passed invalid value as param 27 (null, invalid json and etc..) + #[fail(display = "CommonInvalidParam27")] + CommonInvalidParam27 = 129, + // Wallet errors + // Caller passed invalid wallet handle + #[fail(display = "WalletInvalidHandle")] + WalletInvalidHandle = 200, + // Unknown type of wallet was passed on create_wallet + #[fail(display = "WalletUnknownTypeError")] + WalletUnknownTypeError = 201, + // Attempt to register already existing wallet type + #[fail(display = "WalletTypeAlreadyRegisteredError")] + WalletTypeAlreadyRegisteredError = 202, + // Attempt to create wallet with name used for another exists wallet + #[fail(display = "WalletAlreadyExistsError")] + WalletAlreadyExistsError = 203, + + // Requested entity id isn't present in wallet + #[fail(display = "WalletNotFoundError")] + WalletNotFoundError = 204, + // Trying to use wallet with pool that has different name + #[fail(display = "WalletIncompatiblePoolError")] + WalletIncompatiblePoolError = 205, + // Trying to open wallet that was opened already + #[fail(display = "WalletAlreadyOpenedError")] + WalletAlreadyOpenedError = 206, + // Attempt to open encrypted wallet with invalid credentials + #[fail(display = "WalletAccessFailed")] + WalletAccessFailed = 207, + // Input provided to wallet operations is considered not valid + #[fail(display = "WalletInputError")] + WalletInputError = 208, + + // Decoding of wallet data during input/output failed + #[fail(display = "WalletDecodingError")] + WalletDecodingError = 209, + // Storage error occurred during wallet operation + #[fail(display = "WalletStorageError")] + WalletStorageError = 210, + // Error during encryption-related operations + #[fail(display = "WalletEncryptionError")] + WalletEncryptionError = 211, + // Requested wallet item not found + #[fail(display = "WalletItemNotFound")] + WalletItemNotFound = 212, + // Returned if wallet's add_record operation is used with record name that already exists + #[fail(display = "WalletItemAlreadyExists")] + WalletItemAlreadyExists = 213, + + // Returned if provided wallet query is invalid + #[fail(display = "WalletQueryError")] + WalletQueryError = 214, + // Ledger errors + // Trying to open pool ledger that wasn't created before + #[fail(display = "PoolLedgerNotCreatedError")] + PoolLedgerNotCreatedError = 300, + // Caller passed invalid pool ledger handle + #[fail(display = "PoolLedgerInvalidPoolHandle")] + PoolLedgerInvalidPoolHandle = 301, + // Pool ledger terminated + #[fail(display = "PoolLedgerTerminated")] + PoolLedgerTerminated = 302, + // No concensus during ledger operation + #[fail(display = "LedgerNoConsensusError")] + LedgerNoConsensusError = 303, + + // Attempt to parse invalid transaction response + #[fail(display = "LedgerInvalidTransaction")] + LedgerInvalidTransaction = 304, + // Attempt to send transaction without the necessary privileges + #[fail(display = "LedgerSecurityError")] + LedgerSecurityError = 305, + // Attempt to create pool ledger config with name used for another existing pool + #[fail(display = "PoolLedgerConfigAlreadyExistsError")] + PoolLedgerConfigAlreadyExistsError = 306, + // Timeout for action + #[fail(display = "PoolLedgerTimeout")] + PoolLedgerTimeout = 307, + // Attempt to open Pool for witch Genesis Transactions are not compatible with set Protocol version. + // Call pool.indy_set_protocol_version to set correct Protocol version. + #[fail(display = "PoolIncompatibleProtocolVersion")] + PoolIncompatibleProtocolVersion = 308, + + // Item not found on ledger. + #[fail(display = "LedgerNotFound")] + LedgerNotFound = 309, + + // Revocation registry is full and creation of new registry is necessary + #[fail(display = "AnoncredsRevocationRegistryFullError")] + AnoncredsRevocationRegistryFullError = 400, + #[fail(display = "AnoncredsInvalidUserRevocId")] + AnoncredsInvalidUserRevocId = 401, + // Attempt to generate master secret with duplicated name + #[fail(display = "AnoncredsMasterSecretDuplicateNameError")] + AnoncredsMasterSecretDuplicateNameError = 404, + #[fail(display = "AnoncredsProofRejected")] + AnoncredsProofRejected = 405, + #[fail(display = "AnoncredsCredentialRevoked")] + AnoncredsCredentialRevoked = 406, + + // Attempt to create credential definition with duplicated did schema pair + #[fail(display = "AnoncredsCredDefAlreadyExistsError")] + AnoncredsCredDefAlreadyExistsError = 407, + // Signus errors + // Unknown format of DID entity keys + #[fail(display = "UnknownCryptoTypeError")] + UnknownCryptoTypeError = 500, + // Attempt to create duplicate did + #[fail(display = "DidAlreadyExistsError")] + DidAlreadyExistsError = 600, + // Unknown payment method was given + #[fail(display = "UnknownPaymentMethod")] + UnknownPaymentMethod = 700, + //No method were scraped from inputs/outputs or more than one were scraped + #[fail(display = "IncompatiblePaymentError")] + IncompatiblePaymentError = 701, + + // Insufficient funds on inputs + #[fail(display = "PaymentInsufficientFundsError")] + PaymentInsufficientFundsError = 702, + + // No such source on a ledger + #[fail(display = "PaymentSourceDoesNotExistError")] + PaymentSourceDoesNotExistError = 703, + + // Operation is not supported for payment method + #[fail(display = "PaymentOperationNotSupportedError")] + PaymentOperationNotSupportedError = 704, + + // Extra funds on inputs + #[fail(display = "PaymentExtraFundsError")] + PaymentExtraFundsError = 705, +} + + +impl From for ErrorCode { + fn from(i: i32) -> Self { + let conversion = num_traits::FromPrimitive::from_i32(i); + if conversion.is_some() { + conversion.unwrap() + } else { + panic!("Unable to convert from {}, unknown error code", i) + } + } +} + +impl Into for ErrorCode { + fn into(self) -> i32 { + num_traits::ToPrimitive::to_i32(&self).unwrap() + } +} \ No newline at end of file diff --git a/wrappers/rust/src/logger.rs b/wrappers/rust/src/logger.rs new file mode 100644 index 00000000..6cf3ea76 --- /dev/null +++ b/wrappers/rust/src/logger.rs @@ -0,0 +1,170 @@ +use ErrorCode; + +use std::ffi::CString; + +use ffi::{logger, CVoid, CString as IndyCString}; + +use log::{Log, Record, Metadata, Level}; + +use std::ptr::null; + +use utils::ctypes::c_str_to_string; + +static mut LOGGER: Option> = None; + +/// Set default logger implementation. +/// +/// Allows library user use `env_logger` logger as default implementation. +/// More details about `env_logger` and its customization can be found here: https://crates.io/crates/env_logger +/// +/// # Arguments +/// * `pattern` - (optional) pattern that corresponds with the log messages to show. +pub fn set_default_logger(pattern: Option<&str>) -> Result<(), ErrorCode> { + let pattern_str = opt_c_str!(pattern); + + let res = ErrorCode::from(unsafe { + logger::indy_set_default_logger(opt_c_ptr!(pattern, pattern_str)) + }); + + match res { + ErrorCode::Success => Ok(()), + err => Err(err) + } +} + +/// Set application logger implementation to Libindy. +/// +/// # Arguments +/// * `logger` - reference to logger used by application. +pub fn set_logger(logger: &'static Log) -> Result<(), ErrorCode> { + { + unsafe { + if LOGGER.is_some() { return Err(ErrorCode::CommonInvalidState); } + LOGGER = Some(Box::new(logger)); + } + } + + let res = ErrorCode::from(unsafe { + logger::indy_set_logger( + null(), + Some(IndyLogger::enabled_cb), + Some(IndyLogger::log_cb), + Some(IndyLogger::flush_cb), + ) + }); + + match res { + ErrorCode::Success => Ok(()), + err => Err(err) + } +} + +pub struct IndyLogger; + +impl IndyLogger { + pub extern fn enabled_cb(_context: *const CVoid, + level: u32, + target: IndyCString) -> bool { + unsafe { + match LOGGER { + Some(ref logger) => { + let level = Self::get_level(level); + let target = c_str_to_string(target).unwrap().unwrap(); + + let metadata: Metadata = Metadata::builder() + .level(level) + .target(&target) + .build(); + + logger.enabled(&metadata) + } + None => true + } + } + } + + extern fn log_cb(_context: *const CVoid, + level: u32, + target: IndyCString, + args: IndyCString, + module_path: IndyCString, + file: IndyCString, + line: u32) { + unsafe { + match LOGGER { + Some(ref logger) => { + let target = c_str_to_string(target).unwrap().unwrap(); + let args = c_str_to_string(args).unwrap().unwrap(); + let module_path = c_str_to_string(module_path).unwrap(); + let file = c_str_to_string(file).unwrap(); + let level = Self::get_level(level); + + logger.log( + &Record::builder() + .args(format_args!("{}", args)) + .level(level) + .target(&target) + .module_path(module_path) + .file(file) + .line(Some(line)) + .build(), + ); + } + None => {} + } + } + } + + pub extern fn flush_cb(_context: *const CVoid) { + unsafe { + match LOGGER { + Some(ref logger) => { logger.flush() } + None => {} + } + } + } + + pub fn get_level(level: u32) -> Level { + match level { + 1 => Level::Error, + 2 => Level::Warn, + 3 => Level::Info, + 4 => Level::Debug, + 5 => Level::Trace, + _ => unreachable!(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use log::{set_boxed_logger, logger}; + + #[test] + fn test_logger() { + set_boxed_logger(Box::new(SimpleLogger {})).unwrap(); + set_logger(logger()).unwrap(); + } + + struct SimpleLogger; + + impl Log for SimpleLogger { + fn enabled(&self, _metadata: &Metadata) -> bool { + true + } + + fn log(&self, record: &Record) { + println!( + "{:>5}|{:<20}|{:>25}:{:?}| {:?}", + record.level(), + record.target(), + record.file().unwrap_or(""), + record.line(), + record.args()); + } + + fn flush(&self) {} + } +} + diff --git a/wrappers/rust/src/macros/mod.rs b/wrappers/rust/src/macros/mod.rs new file mode 100644 index 00000000..3712b32f --- /dev/null +++ b/wrappers/rust/src/macros/mod.rs @@ -0,0 +1,48 @@ +macro_rules! c_str { + ($x:ident) => { + CString::new($x).unwrap() + }; + ($x:expr) => { + CString::new($x).unwrap() + } +} + +macro_rules! opt_c_str { + ($x:ident) => { + $x.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap()) + } +} + +macro_rules! opt_c_str_json { + ($x:ident) => { + $x.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("{}").unwrap()) + } +} + +macro_rules! opt_c_ptr { + ($x:ident, $y:ident) => { + if $x.is_some() { $y.as_ptr() } else { null() } + } +} + +macro_rules! rust_str { + ($x:ident) => { + unsafe { CStr::from_ptr($x).to_str().unwrap().to_string() } + } +} + +macro_rules! opt_rust_str { + ($x:ident) => { + if $x.is_null() { + None + } else { + Some(unsafe { CStr::from_ptr($x).to_str().unwrap().to_string() }) + } + }; +} + +macro_rules! rust_slice { + ($x:ident, $y:ident) => { + unsafe { ::std::slice::from_raw_parts($x, $y as usize) } + } +} diff --git a/wrappers/rust/src/pairwise.rs b/wrappers/rust/src/pairwise.rs new file mode 100644 index 00000000..4e767e36 --- /dev/null +++ b/wrappers/rust/src/pairwise.rs @@ -0,0 +1,94 @@ +use {ErrorCode, IndyHandle}; + +use futures::Future; + +use std::ffi::CString; +use std::ptr::null; + +use utils::callbacks::{ClosureHandler, ResultHandler}; + +use ffi::pairwise; +use ffi::{ResponseEmptyCB, + ResponseStringCB, + ResponseBoolCB}; + +pub fn is_pairwise_exists(wallet_handle: IndyHandle, their_did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_bool(); + + let err = _is_pairwise_exists(command_handle, wallet_handle, their_did, cb); + + ResultHandler::bool(command_handle, err, receiver) +} + +fn _is_pairwise_exists(command_handle: IndyHandle, wallet_handle: IndyHandle, their_did: &str, cb: Option) -> ErrorCode { + let their_did = c_str!(their_did); + + ErrorCode::from(unsafe { + pairwise::indy_is_pairwise_exists(command_handle, wallet_handle, their_did.as_ptr(), cb) + }) +} + +pub fn create_pairwise(wallet_handle: IndyHandle, their_did: &str, my_did: &str, metadata: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _create_pairwise(command_handle, wallet_handle, their_did, my_did, metadata, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _create_pairwise(command_handle: IndyHandle, wallet_handle: IndyHandle, their_did: &str, my_did: &str, metadata: Option<&str>, cb: Option) -> ErrorCode { + let their_did = c_str!(their_did); + let my_did = c_str!(my_did); + let metadata_str = opt_c_str!(metadata); + + ErrorCode::from(unsafe { + pairwise::indy_create_pairwise(command_handle, wallet_handle, their_did.as_ptr(), my_did.as_ptr(), opt_c_ptr!(metadata, metadata_str), cb) + }) +} + +pub fn list_pairwise(wallet_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _list_pairwise(command_handle, wallet_handle, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _list_pairwise(command_handle: IndyHandle, wallet_handle: IndyHandle, cb: Option) -> ErrorCode { + ErrorCode::from(unsafe { + pairwise::indy_list_pairwise(command_handle, wallet_handle, cb) + }) +} + +pub fn get_pairwise(wallet_handle: IndyHandle, their_did: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _get_pairwise(command_handle, wallet_handle, their_did, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _get_pairwise(command_handle: IndyHandle, wallet_handle: IndyHandle, their_did: &str, cb: Option) -> ErrorCode { + let their_did = c_str!(their_did); + + ErrorCode::from(unsafe { + pairwise::indy_get_pairwise(command_handle, wallet_handle, their_did.as_ptr(), cb) + }) +} + +pub fn set_pairwise_metadata(wallet_handle: IndyHandle, their_did: &str, metadata: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _set_pairwise_metadata(command_handle, wallet_handle, their_did, metadata, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _set_pairwise_metadata(command_handle: IndyHandle, wallet_handle: IndyHandle, their_did: &str, metadata: Option<&str>, cb: Option) -> ErrorCode { + let their_did = c_str!(their_did); + let metadata_str = opt_c_str!(metadata); + + ErrorCode::from(unsafe { + pairwise::indy_set_pairwise_metadata(command_handle, wallet_handle, their_did.as_ptr(), opt_c_ptr!(metadata, metadata_str), cb) + }) +} diff --git a/wrappers/rust/src/payments.rs b/wrappers/rust/src/payments.rs new file mode 100644 index 00000000..b56f372e --- /dev/null +++ b/wrappers/rust/src/payments.rs @@ -0,0 +1,462 @@ +use {ErrorCode, IndyHandle}; + +use std::ffi::CString; +use std::ptr::null; + +use futures::Future; + +use ffi::payments; +use ffi::{ResponseStringCB, + ResponseStringStringCB}; + +use utils::callbacks::{ClosureHandler, ResultHandler}; + +/// Create the payment address for specified payment method +/// +/// This method generates private part of payment address +/// and stores it in a secure place. Ideally it should be +/// secret in libindy wallet (see crypto module). +/// +/// Note that payment method should be able to resolve this +/// secret by fully resolvable payment address format. +/// +/// # Arguments +/// * `wallet_handle` - wallet handle where to save new address +/// * `payment_method` - payment method to use (for example, 'sov') +/// * `config` - payment address config as json +/// +/// # Example +/// config +/// { +/// seed: , // allows deterministic creation of payment address +/// } +/// +/// # Returns +/// * `payment_address` - public identifier of payment address in fully resolvable payment address format +pub fn create_payment_address(wallet_handle: IndyHandle, payment_method: &str, config: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _create_payment_address(command_handle, wallet_handle, payment_method, config, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _create_payment_address(command_handle: IndyHandle, wallet_handle: IndyHandle, payment_method: &str, config: &str, cb: Option) -> ErrorCode { + let payment_method = c_str!(payment_method); + let config = c_str!(config); + + ErrorCode::from(unsafe { payments::indy_create_payment_address(command_handle, wallet_handle, payment_method.as_ptr(), config.as_ptr(), cb) }) +} + +/// Lists all payment addresses that are stored in the wallet +/// +/// # Arguments +/// * `wallet_handle` - wallet to search for payment_addresses +/// +/// # Returns +/// * `payment_addresses_json` - json array of string with json addresses +pub fn list_payment_addresses(wallet_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _list_payment_addresses(command_handle, wallet_handle, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _list_payment_addresses(command_handle: IndyHandle, wallet_handle: IndyHandle, cb: Option) -> ErrorCode { + ErrorCode::from(unsafe { payments::indy_list_payment_addresses(command_handle, wallet_handle, cb) }) +} + +/// Modifies Indy request by adding information how to pay fees for this transaction +/// according to selected payment method. +/// +/// Payment selection is performed by looking to o +/// +/// This method consumes set of UTXO inputs and outputs. The difference between inputs balance +/// and outputs balance is the fee for this transaction. +/// +/// Not that this method also produces correct fee signatures. +/// +/// Format of inputs is specific for payment method. Usually it should reference payment transaction +/// with at least one output that corresponds to payment address that user owns. +/// +/// # Arguments +/// * `wallet_handle` - wallet handle +/// * `submitter_did` - DID of request sender +/// * `req_json` - initial transaction request as json +/// * `inputs_json` - the list of UTXO inputs as json array +/// +/// # Examples +/// inputs_json: +/// ["input1", ...] +/// Notes: +/// - each input should reference paymentAddress +/// - this param will be used to determine payment_method +/// outputs_json: The list of UTXO outputs as json array: +/// [{ +/// paymentAddress: , // payment address used as output +/// amount: , // amount of tokens to transfer to this payment address +/// extra: , // optional data +/// }] +/// +/// # Returns +/// * `req_with_fees_json` - modified Indy request with added fees info +/// * `payment_method` +pub fn add_request_fees(wallet_handle: IndyHandle, + submitter_did: Option<&str>, + req_json: &str, + inputs_json: &str, + outputs_json: &str, + extra: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _add_request_fees(command_handle, wallet_handle, submitter_did, req_json, inputs_json, outputs_json, extra, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _add_request_fees(command_handle: IndyHandle, + wallet_handle: IndyHandle, + submitter_did: Option<&str>, + req_json: &str, + inputs_json: &str, + outputs_json: &str, + extra: Option<&str>, + cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let req_json = c_str!(req_json); + let inputs_json = c_str!(inputs_json); + let outputs_json = c_str!(outputs_json); + let extra_str = opt_c_str!(extra); + + ErrorCode::from(unsafe { + payments::indy_add_request_fees(command_handle, + wallet_handle, + opt_c_ptr!(submitter_did, submitter_did_str), + req_json.as_ptr(), + inputs_json.as_ptr(), + outputs_json.as_ptr(), + opt_c_ptr!(extra, extra_str), + cb) + }) +} + +/// Parses response for Indy request with fees. +/// +/// # Arguments +/// * `payment_method` +/// * `resp_json`: response for Indy request with fees +/// Note: this param will be used to determine payment_method +/// +/// # Returns +/// * `utxo_json` - parsed (payment method and node version agnostic) utxo info as json +/// +/// # Example +/// utxo_json +/// [{ +/// input: , // UTXO input +/// amount: , // amount of tokens in this input +/// extra: , // optional data from payment transaction +/// }] +pub fn parse_response_with_fees(payment_method: &str, resp_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _parse_response_with_fees(command_handle, payment_method, resp_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _parse_response_with_fees(command_handle: IndyHandle, payment_method: &str, resp_json: &str, cb: Option) -> ErrorCode { + let payment_method = c_str!(payment_method); + let resp_json = c_str!(resp_json); + + ErrorCode::from(unsafe { payments::indy_parse_response_with_fees(command_handle, payment_method.as_ptr(), resp_json.as_ptr(), cb) }) +} + +/// Builds Indy request for getting UTXO list for payment address +/// according to this payment method. +/// +/// # Arguments +/// * `wallet_handle` - wallet handle +/// * `submitter_did` - DID of request sender +/// * `payment_address` -: target payment address +/// +/// # Returns +/// * `get_utxo_txn_json` - Indy request for getting UTXO list for payment address +/// * `payment_method` +pub fn build_get_payment_sources_request(wallet_handle: IndyHandle, submitter_did: Option<&str>, payment_address: &str) -> Box> { + let (receiver, command_handle, cb) = + ClosureHandler::cb_ec_string_string(); + + let err = _build_get_payment_sources_request(command_handle, wallet_handle, submitter_did, payment_address, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _build_get_payment_sources_request(command_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: Option<&str>, payment_address: &str, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let payment_address = c_str!(payment_address); + + ErrorCode::from(unsafe { payments::indy_build_get_payment_sources_request(command_handle, wallet_handle, opt_c_ptr!(submitter_did, submitter_did_str), payment_address.as_ptr(), cb) }) +} + +/// Parses response for Indy request for getting UTXO list. +/// +/// # Arguments +/// * `payment_method` +/// * `resp_json` - response for Indy request for getting UTXO list +/// Note: this param will be used to determine payment_method +/// +/// # Returns +/// * `utxo_json` - parsed (payment method and node version agnostic) utxo info as json: +/// # Examples: +/// [{ +/// input: , // UTXO input +/// amount: , // amount of tokens in this input +/// extra: , // optional data from payment transaction +/// }] +pub fn parse_get_payment_sources_response(payment_method: &str, resp_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _parse_get_payment_sources_response(command_handle, payment_method, resp_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _parse_get_payment_sources_response(command_handle: IndyHandle, payment_method: &str, resp_json: &str, cb: Option) -> ErrorCode { + let payment_method = c_str!(payment_method); + let resp_json = c_str!(resp_json); + + ErrorCode::from(unsafe { payments::indy_parse_get_payment_sources_response(command_handle, payment_method.as_ptr(), resp_json.as_ptr(), cb) }) +} + +/// Builds Indy request for doing tokens payment +/// according to this payment method. +/// +/// This method consumes set of UTXO inputs and outputs. +/// +/// Format of inputs is specific for payment method. Usually it should reference payment transaction +/// with at least one output that corresponds to payment address that user owns. +/// +/// # Arguments +/// * `wallet_handle` - wallet handle +/// * `submitter_did` - DID of request sender +/// * `inputs_json` - The list of UTXO inputs as json array: +/// ["input1", ...] +/// Note that each input should reference paymentAddress +/// * `outputs_json` - The list of UTXO outputs as json array: +/// [{ +/// paymentAddress: , // payment address used as output +/// amount: , // amount of tokens to transfer to this payment address +/// extra: , // optional data +/// }] +/// +/// # Returns +/// * `payment_req_json` - Indy request for doing tokens payment +/// * `payment_method` +pub fn build_payment_req(wallet_handle: IndyHandle, submitter_did: Option<&str>, inputs: &str, outputs: &str, extra: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _build_payment_req(command_handle, wallet_handle, submitter_did, inputs, outputs, extra, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _build_payment_req(command_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: Option<&str>, inputs: &str, outputs: &str, extra: Option<&str>, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let inputs = c_str!(inputs); + let outputs = c_str!(outputs); + let extra_str = opt_c_str!(extra); + + ErrorCode::from(unsafe { + payments::indy_build_payment_req(command_handle, + wallet_handle, + opt_c_ptr!(submitter_did, submitter_did_str), + inputs.as_ptr(), + outputs.as_ptr(), + opt_c_ptr!(extra, extra_str), + cb) + }) +} + +/// Parses response for Indy request for payment txn. +/// +/// # Arguments +/// * `command_handle` +/// * `payment_method` +/// * `resp_json` - response for Indy request for payment txn +/// Note: this param will be used to determine payment_method +/// +/// # Returns +/// * `utxo_json` - parsed (payment method and node version agnostic) utxo info as jso-n +/// [{ +/// input: , // UTXO input +/// amount: , // amount of tokens in this input +/// extra: , // optional data from payment transaction +/// }] +pub fn parse_payment_response(payment_method: &str, resp_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _parse_payment_response(command_handle, payment_method, resp_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _parse_payment_response(command_handle: IndyHandle, payment_method: &str, resp_json: &str, cb: Option) -> ErrorCode { + let payment_method = c_str!(payment_method); + let resp_json = c_str!(resp_json); + + ErrorCode::from(unsafe { payments::indy_parse_payment_response(command_handle, payment_method.as_ptr(), resp_json.as_ptr(), cb) }) + +} + +/// Builds Indy request for doing tokens minting +/// according to this payment method. +/// +/// # Arguments +/// * `wallet_handle` - wallet handle +/// * `submitter_did` - DID of request sender +/// * `outputs_json` - The list of UTXO outputs as json array: +/// [{ +/// paymentAddress: , // payment address used as output +/// amount: , // amount of tokens to transfer to this payment address +/// extra: , // optional data +/// }] +/// +/// # Returns +/// * `mint_req_json` - Indy request for doing tokens minting +/// * `payment_method` +pub fn build_mint_req(wallet_handle: IndyHandle, submitter_did: Option<&str>, outputs_json: &str, extra: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _build_mint_req(command_handle, wallet_handle, submitter_did, outputs_json, extra, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _build_mint_req(command_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: Option<&str>, outputs_json: &str, extra: Option<&str>, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let outputs_json = c_str!(outputs_json); + let extra_str = opt_c_str!(extra); + + ErrorCode::from(unsafe { payments::indy_build_mint_req(command_handle, wallet_handle, opt_c_ptr!(submitter_did, submitter_did_str), outputs_json.as_ptr(), opt_c_ptr!(extra, extra_str), cb) }) +} + +/// Builds Indy request for setting fees for transactions in the ledger +/// +/// # Arguments +/// * `wallet_handle` - wallet handle +/// * `submitter_did` - DID of request sender +/// * `payment_method` +/// * `fees_json` - { +/// txnType1: amount1, +/// txnType2: amount2, +/// ................. +/// txnTypeN: amountN, +/// } +/// +/// # Returns +/// * `set_txn_fees_json` - Indy request for setting fees for transactions in the ledger +pub fn build_set_txn_fees_req(wallet_handle: IndyHandle, submitter_did: Option<&str>, payment_method: &str, fees_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_set_txn_fees_req(command_handle, wallet_handle, submitter_did, payment_method, fees_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_set_txn_fees_req(command_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: Option<&str>, payment_method: &str, fees_json: &str, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let payment_method = c_str!(payment_method); + let fees_json = c_str!(fees_json); + + ErrorCode::from(unsafe { payments::indy_build_set_txn_fees_req(command_handle, wallet_handle, opt_c_ptr!(submitter_did, submitter_did_str), payment_method.as_ptr(), fees_json.as_ptr(), cb) }) +} + +/// Builds Indy get request for getting fees for transactions in the ledger +/// +/// # Arguments +/// * `command_handle` +/// * `wallet_handle` - wallet handle +/// * `submitter_did` - DID of request sender +/// * `payment_method` +/// +/// # Returns +/// * `get_txn_fees_json` - Indy request for getting fees for transactions in the ledger +pub fn build_get_txn_fees_req(wallet_handle: IndyHandle, submitter_did: Option<&str>, payment_method: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _build_get_txn_fees_req(command_handle, wallet_handle, submitter_did, payment_method, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _build_get_txn_fees_req(command_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: Option<&str>, payment_method: &str, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let payment_method = c_str!(payment_method); + + ErrorCode::from(unsafe { payments::indy_build_get_txn_fees_req(command_handle, wallet_handle, opt_c_ptr!(submitter_did, submitter_did_str), payment_method.as_ptr(), cb) }) +} + +/// Parses response for Indy request for getting fees +/// +/// # Arguments +/// * `command_handle` +/// * `payment_method` +/// * `resp_json` - response for Indy request for getting fees +/// +/// # Returns +/// * `fees_json` { +/// txnType1: amount1, +/// txnType2: amount2, +/// ................. +/// txnTypeN: amountN, +/// } +pub fn parse_get_txn_fees_response(payment_method: &str, resp_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _parse_get_txn_fees_response(command_handle, payment_method, resp_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _parse_get_txn_fees_response(command_handle: IndyHandle, payment_method: &str, resp_json: &str, cb: Option) -> ErrorCode { + let payment_method = c_str!(payment_method); + let resp_json = c_str!(resp_json); + + ErrorCode::from(unsafe { payments::indy_parse_get_txn_fees_response(command_handle, payment_method.as_ptr(), resp_json.as_ptr(), cb) }) +} + +pub fn build_verify_payment_req(wallet_handle: IndyHandle, submitter_did: Option<&str>, receipt: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_string(); + + let err = _build_verify_req(command_handle, wallet_handle, submitter_did, receipt, cb); + + ResultHandler::str_str(command_handle, err, receiver) +} + +fn _build_verify_req(command_handle: IndyHandle, wallet_handle: IndyHandle, submitter_did: Option<&str>, receipt: &str, cb: Option) -> ErrorCode { + let submitter_did_str = opt_c_str!(submitter_did); + let receipt = c_str!(receipt); + + ErrorCode::from(unsafe { + payments::indy_build_verify_payment_req(command_handle, wallet_handle, opt_c_ptr!(submitter_did, submitter_did_str), receipt.as_ptr(), cb) + }) +} + +pub fn parse_verify_payment_response(payment_method: &str, resp_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _parse_verify_response(command_handle, payment_method, resp_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _parse_verify_response(command_handle: IndyHandle, payment_method: &str, resp_json: &str, cb: Option) -> ErrorCode { + let payment_method = c_str!(payment_method); + let resp_json = c_str!(resp_json); + + ErrorCode::from(unsafe { + payments::indy_parse_verify_payment_response(command_handle, payment_method.as_ptr(), resp_json.as_ptr(), cb) + }) +} diff --git a/wrappers/rust/src/pool.rs b/wrappers/rust/src/pool.rs new file mode 100644 index 00000000..4eb9f5fe --- /dev/null +++ b/wrappers/rust/src/pool.rs @@ -0,0 +1,161 @@ +use {ErrorCode, IndyHandle}; + +use std::ffi::CString; +use std::ptr::null; + +use utils::callbacks::{ClosureHandler, ResultHandler}; + +use ffi::pool; +use ffi::{ResponseEmptyCB, + ResponseStringCB, + ResponseI32CB}; + +use futures::Future; + +/// Creates a new local pool ledger configuration that can be used later to connect pool nodes. +/// +/// # Arguments +/// * `config_name` - Name of the pool ledger configuration. +/// * `config` (required)- Pool configuration json. Example: +/// { +/// "genesis_txn": string (required), A path to genesis transaction file. +/// } +pub fn create_pool_ledger_config(pool_name: &str, pool_config: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _create_pool_ledger_config(command_handle, pool_name, pool_config, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _create_pool_ledger_config(command_handle: IndyHandle, pool_name: &str, pool_config: Option<&str>, cb: Option) -> ErrorCode { + let pool_name = c_str!(pool_name); + let pool_config_str = opt_c_str!(pool_config); + + ErrorCode::from(unsafe { pool::indy_create_pool_ledger_config(command_handle, pool_name.as_ptr(), opt_c_ptr!(pool_config, pool_config_str), cb) }) +} + +/// Opens pool ledger and performs connecting to pool nodes. +/// +/// Pool ledger configuration with corresponded name must be previously created +/// with indy_create_pool_ledger_config method. +/// It is impossible to open pool with the same name more than once. +/// +/// # Arguments +/// * `config_name` - Name of the pool ledger configuration. +/// * `config` (optional)- Runtime pool configuration json. +/// if NULL, then default config will be used. Example: +/// { +/// "refresh_on_open": bool (optional), Forces pool ledger to be refreshed immediately after opening. +/// Defaults to true. +/// "auto_refresh_time": int (optional), After this time in minutes pool ledger will be automatically refreshed. +/// Use 0 to disable automatic refresh. Defaults to 24*60. +/// "network_timeout": int (optional), Network timeout for communication with nodes in milliseconds. +/// Defaults to 20000. +/// } +/// +/// # Returns +/// Handle to opened pool to use in methods that require pool connection. +pub fn open_pool_ledger(pool_name: &str, config: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_handle(); + + let err = _open_pool_ledger(command_handle, pool_name, config, cb); + + ResultHandler::handle(command_handle, err, receiver) +} + +fn _open_pool_ledger(command_handle: IndyHandle, pool_name: &str, config: Option<&str>, cb: Option) -> ErrorCode { + let pool_name = c_str!(pool_name); + let config_str = opt_c_str!(config); + + ErrorCode::from(unsafe { pool::indy_open_pool_ledger(command_handle, pool_name.as_ptr(), opt_c_ptr!(config, config_str), cb) }) +} + +/// Refreshes a local copy of a pool ledger and updates pool nodes connections. +/// +/// # Arguments +/// * `handle` - pool handle returned by open_ledger +pub fn refresh_pool_ledger(pool_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _refresh_pool_ledger(command_handle, pool_handle, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _refresh_pool_ledger(command_handle: IndyHandle, pool_handle: IndyHandle, cb: Option) -> ErrorCode { + ErrorCode::from(unsafe { pool::indy_refresh_pool_ledger(command_handle, pool_handle, cb) }) +} + +/// Lists names of created pool ledgers +pub fn list_pools() -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _list_pools(command_handle, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _list_pools(command_handle: IndyHandle, cb: Option) -> ErrorCode { + ErrorCode::from(unsafe { pool::indy_list_pools(command_handle, cb) }) +} + +/// Closes opened pool ledger, opened nodes connections and frees allocated resources. +/// +/// # Arguments +/// * `handle` - pool handle returned by open_ledger. +pub fn close_pool_ledger(pool_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _close_pool_ledger(command_handle, pool_handle, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _close_pool_ledger(command_handle: IndyHandle, pool_handle: IndyHandle, cb: Option) -> ErrorCode { + ErrorCode::from(unsafe { pool::indy_close_pool_ledger(command_handle, pool_handle, cb) }) +} + +/// Deletes created pool ledger configuration. +/// +/// # Arguments +/// * `config_name` - Name of the pool ledger configuration to delete. +pub fn delete_pool_ledger(pool_name: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _delete_pool_ledger(command_handle, pool_name, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _delete_pool_ledger(command_handle: IndyHandle, pool_name: &str, cb: Option) -> ErrorCode { + let pool_name = c_str!(pool_name); + + ErrorCode::from(unsafe { pool::indy_delete_pool_ledger_config(command_handle, pool_name.as_ptr(), cb) }) +} + +/// Set PROTOCOL_VERSION to specific version. +/// +/// There is a global property PROTOCOL_VERSION that used in every request to the pool and +/// specified version of Indy Node which Libindy works. +/// +/// By default PROTOCOL_VERSION=1. +/// +/// # Arguments +/// * `protocol_version` - Protocol version will be used: +/// 1 - for Indy Node 1.3 +/// 2 - for Indy Node 1.4 +pub fn set_protocol_version(protocol_version: usize) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _set_protocol_version(command_handle, protocol_version, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _set_protocol_version(command_handle: IndyHandle, protocol_version: usize, cb: Option) -> ErrorCode { + + ErrorCode::from(unsafe { + pool::indy_set_protocol_version(command_handle, protocol_version, cb) + }) +} diff --git a/wrappers/rust/src/utils/callbacks.rs b/wrappers/rust/src/utils/callbacks.rs new file mode 100644 index 00000000..7d463ce4 --- /dev/null +++ b/wrappers/rust/src/utils/callbacks.rs @@ -0,0 +1,179 @@ +#![warn(dead_code)] +use {ErrorCode, IndyHandle}; + +use libc::c_char; + +use std::collections::HashMap; +use std::ffi::CStr; +use std::sync::Mutex; + +use futures::*; +use futures::sync::oneshot; + +lazy_static! { + static ref CALLBACKS_EMPTY: Mutex>>> = Default::default(); + static ref CALLBACKS_SLICE: Mutex, ErrorCode>>>> = Default::default(); + static ref CALLBACKS_HANDLE: Mutex>>> = Default::default(); + static ref CALLBACKS_BOOL: Mutex>>> = Default::default(); + static ref CALLBACKS_STR_SLICE: Mutex), ErrorCode>>>> = Default::default(); + static ref CALLBACKS_HANDLE_USIZE: Mutex>>> = Default::default(); + static ref CALLBACKS_STR_STR_U64: Mutex>>> = Default::default(); + static ref CALLBACKS_STR: Mutex>>> = Default::default(); + static ref CALLBACKS_STR_STR: Mutex>>> = Default::default(); + static ref CALLBACKS_STR_OPTSTR: Mutex), ErrorCode>>>> = Default::default(); + static ref CALLBACKS_STR_STR_STR: Mutex>>> = Default::default(); + static ref CALLBACKS_STR_OPTSTR_OPTSTR: Mutex, Option), ErrorCode>>>> = Default::default(); +} + +macro_rules! cb_ec { + ($name:ident($($cr:ident:$crt:ty),*)->$rrt:ty, $cbs:ident, $res:expr) => ( + pub fn $name() -> (sync::oneshot::Receiver>, + IndyHandle, + Option) { + extern fn callback(command_handle: IndyHandle, err: i32, $($cr:$crt),*) { + let tx = { + let mut callbacks = $cbs.lock().unwrap(); + callbacks.remove(&command_handle).unwrap() + }; + + let res = if err != 0 { + Err(ErrorCode::from(err)) + } else { + Ok($res) + }; + + tx.send(res).unwrap(); + } + + let (rx, command_handle) = { + let (tx, rx) = oneshot::channel(); + let command_handle = ::utils::sequence::SequenceUtils::get_next_id(); + let mut callbacks = $cbs.lock().unwrap(); + callbacks.insert(command_handle, tx); + (rx, command_handle) + }; + (rx, command_handle, Some(callback)) + } + ) +} + +pub struct ClosureHandler {} + +impl ClosureHandler { + cb_ec!(cb_ec()->(), CALLBACKS_EMPTY, ()); + + cb_ec!(cb_ec_handle(handle:IndyHandle)->IndyHandle, CALLBACKS_HANDLE, handle); + + cb_ec!(cb_ec_handle_usize(handle:IndyHandle, u: usize)->(IndyHandle, usize), CALLBACKS_HANDLE_USIZE, (handle, u)); + + cb_ec!(cb_ec_string(str1:*const c_char)->String, + CALLBACKS_STR, + rust_str!(str1)); + + cb_ec!(cb_ec_string_string(str1:*const c_char, str2:*const c_char)->(String, String), + CALLBACKS_STR_STR, + (rust_str!(str1), rust_str!(str2))); + + cb_ec!(cb_ec_string_opt_string(str1:*const c_char, str2:*const c_char)->(String, Option), + CALLBACKS_STR_OPTSTR, + (rust_str!(str1), opt_rust_str!(str2))); + + cb_ec!(cb_ec_string_string_string(str1: *const c_char, str2: *const c_char, str3: *const c_char)->(String, String, String), + CALLBACKS_STR_STR_STR, + (rust_str!(str1), rust_str!(str2), rust_str!(str3))); + + cb_ec!(cb_ec_string_opt_string_opt_string(str1: *const c_char, str2: *const c_char, str3: *const c_char)->(String, Option, Option), + CALLBACKS_STR_OPTSTR_OPTSTR, + (rust_str!(str1), opt_rust_str!(str2), opt_rust_str!(str3))); + + cb_ec!(cb_ec_string_string_u64(str1:*const c_char, str2:*const c_char, u: u64)->(String, String, u64), + CALLBACKS_STR_STR_U64, + (rust_str!(str1), rust_str!(str2), u)); + + cb_ec!(cb_ec_slice(data:*const u8, len:u32)->Vec, CALLBACKS_SLICE, rust_slice!(data, len).to_owned()); + + cb_ec!(cb_ec_string_slice(str: *const c_char, data:*const u8, len:u32)->(String, Vec), + CALLBACKS_STR_SLICE, + (rust_str!(str), rust_slice!(data, len).to_owned())); + + cb_ec!(cb_ec_bool(b: u8)->bool, CALLBACKS_BOOL, b > 0); +} + +macro_rules! result_handler { + ($name:ident($res_type:ty), $map:ident) => ( + pub fn $name(command_handle: IndyHandle, + err: ErrorCode, + rx: sync::oneshot::Receiver>) -> Box> { + if err != ErrorCode::Success { + let mut callbacks = $map.lock().unwrap(); + callbacks.remove(&command_handle).unwrap(); + Box::new(future::err(ErrorCode::from(err))) + } else { + Box::new(rx + .map_err(|_| panic!("channel error!")) + .and_then(|res| res)) + } + } + ) +} + +pub struct ResultHandler {} + +impl ResultHandler { + result_handler!(empty(()), CALLBACKS_EMPTY); + result_handler!(handle(IndyHandle), CALLBACKS_HANDLE); + result_handler!(slice(Vec), CALLBACKS_SLICE); + result_handler!(bool(bool), CALLBACKS_BOOL); + result_handler!(str(String), CALLBACKS_STR); + result_handler!(handle_usize((IndyHandle, usize)), CALLBACKS_HANDLE_USIZE); + result_handler!(str_slice((String, Vec)), CALLBACKS_STR_SLICE); + result_handler!(str_str((String, String)), CALLBACKS_STR_STR); + result_handler!(str_optstr((String, Option)), CALLBACKS_STR_OPTSTR); + result_handler!(str_optstr_optstr((String, Option, Option)), CALLBACKS_STR_OPTSTR_OPTSTR); + result_handler!(str_str_str((String, String, String)), CALLBACKS_STR_STR_STR); + result_handler!(str_str_u64((String, String, u64)), CALLBACKS_STR_STR_U64); +} + +#[cfg(test)] +mod test { + use super::*; + + use std::ffi::CString; + use std::ptr::null; + + #[test] + fn cb_ec_slice() { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_slice(); + + let test_vec: Vec = vec![250, 251, 252, 253, 254, 255]; + let callback = cb.unwrap(); + callback(command_handle, 0, test_vec.as_ptr(), test_vec.len() as u32); + + let slice1 = receiver.wait().unwrap().unwrap(); + assert_eq!(test_vec, slice1); + } + + #[test] + fn ec_string_opt_string_null() { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_opt_string(); + + let callback = cb.unwrap(); + callback(command_handle, 0, CString::new("This is a test").unwrap().as_ptr(), null()); + + let (str1, str2) = receiver.wait().unwrap().unwrap(); + assert_eq!(str1, "This is a test".to_string()); + assert_eq!(str2, None); + } + + #[test] + fn ec_string_opt_string_some() { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_opt_string(); + + let callback = cb.unwrap(); + callback(command_handle, 0, CString::new("This is a test").unwrap().as_ptr(), CString::new("The second string has something").unwrap().as_ptr()); + + let (str1, str2) = receiver.wait().unwrap().unwrap(); + assert_eq!(str1, "This is a test".to_string()); + assert_eq!(str2, Some("The second string has something".to_string())); + } +} diff --git a/wrappers/rust/src/utils/ctypes.rs b/wrappers/rust/src/utils/ctypes.rs new file mode 100644 index 00000000..a92276c8 --- /dev/null +++ b/wrappers/rust/src/utils/ctypes.rs @@ -0,0 +1,20 @@ +extern crate libc; + +use self::libc::c_char; + +use std::ffi::CStr; +use std::str::Utf8Error; + +/// String helpers +pub fn c_str_to_string<'a>(cstr: *const c_char) -> Result, Utf8Error> { + if cstr.is_null() { + return Ok(None); + } + + unsafe { + match CStr::from_ptr(cstr).to_str() { + Ok(str) => Ok(Some(str)), + Err(err) => Err(err) + } + } +} \ No newline at end of file diff --git a/wrappers/rust/src/utils/mod.rs b/wrappers/rust/src/utils/mod.rs new file mode 100644 index 00000000..9143a159 --- /dev/null +++ b/wrappers/rust/src/utils/mod.rs @@ -0,0 +1,3 @@ +pub mod callbacks; +pub mod ctypes; +pub mod sequence; diff --git a/wrappers/rust/src/utils/sequence.rs b/wrappers/rust/src/utils/sequence.rs new file mode 100644 index 00000000..16d59e09 --- /dev/null +++ b/wrappers/rust/src/utils/sequence.rs @@ -0,0 +1,13 @@ +use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + +pub struct SequenceUtils {} + +lazy_static! { + static ref IDS_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; //TODO use AtomicI32 +} + +impl SequenceUtils { + pub fn get_next_id() -> i32 { + (IDS_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32 + } +} diff --git a/wrappers/rust/src/wallet.rs b/wrappers/rust/src/wallet.rs new file mode 100644 index 00000000..bd10df3c --- /dev/null +++ b/wrappers/rust/src/wallet.rs @@ -0,0 +1,668 @@ +use futures::Future; + +use {ErrorCode, IndyHandle}; + +use std::ffi::CString; +use std::ptr::null; + +use utils::callbacks::{ClosureHandler, ResultHandler}; + +use ffi::{wallet, non_secrets}; +use ffi::{ResponseEmptyCB, + ResponseStringCB, + ResponseI32CB}; + +/// Registers custom wallet implementation. +/// +/// It allows library user to provide custom wallet implementation. +/// +/// # Arguments +/// * `command_handle` - Command handle to map callback to caller context. +/// * `xtype` - Wallet type name. +/// * `create` - WalletType create operation handler +/// * `open` - WalletType open operation handler +/// * `set` - Wallet set operation handler +/// * `get` - Wallet get operation handler +/// * `get_not_expired` - Wallet get_not_expired operation handler +/// * `list` - Wallet list operation handler(must to return data in the following format: {"values":[{"key":"", "value":""}, {"key":"", "value":""}]} +/// * `close` - Wallet close operation handler +/// * `delete` - WalletType delete operation handler +/// * `free` - Handler that allows to de-allocate strings allocated in caller code +pub fn register_wallet_storage(xtype: &str, + create: Option, + open: Option, + close: Option, + delete: Option, + add_record: Option, + update_record_value: Option, + update_record_tags: Option, + add_record_tags: Option, + delete_record_tags: Option, + delete_record: Option, + get_record: Option, + get_record_id: Option, + get_record_type: Option, + get_record_value: Option, + get_record_tags: Option, + free_record: Option, + get_storage_metadata: Option, + set_storage_metadata: Option, + free_storage_metadata: Option, + search_records: Option, + search_all_records: Option, + get_search_total_count: Option, + fetch_search_next_record: Option, + free_search: Option) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _register_storage(command_handle, + xtype, + create, + open, + close, + delete, + add_record, + update_record_value, + update_record_tags, + add_record_tags, + delete_record_tags, + delete_record, + get_record, + get_record_id, + get_record_type, + get_record_value, + get_record_tags, + free_record, + get_storage_metadata, + set_storage_metadata, + free_storage_metadata, + search_records, + search_all_records, + get_search_total_count, + fetch_search_next_record, + free_search, + cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _register_storage(command_handle: IndyHandle, + xtype: &str, + create: Option, + open: Option, + close: Option, + delete: Option, + add_record: Option, + update_record_value: Option, + update_record_tags: Option, + add_record_tags: Option, + delete_record_tags: Option, + delete_record: Option, + get_record: Option, + get_record_id: Option, + get_record_type: Option, + get_record_value: Option, + get_record_tags: Option, + free_record: Option, + get_storage_metadata: Option, + set_storage_metadata: Option, + free_storage_metadata: Option, + search_records: Option, + search_all_records: Option, + get_search_total_count: Option, + fetch_search_next_record: Option, + free_search: Option, + cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + + ErrorCode::from(unsafe { + wallet::indy_register_wallet_storage(command_handle, + xtype.as_ptr(), + create, + open, + close, + delete, + add_record, + update_record_value, + update_record_tags, + add_record_tags, + delete_record_tags, + delete_record, + get_record, + get_record_id, + get_record_type, + get_record_value, + get_record_tags, + free_record, + get_storage_metadata, + set_storage_metadata, + free_storage_metadata, + search_records, + search_all_records, + get_search_total_count, + fetch_search_next_record, + free_search, + cb) + }) +} + +/// Creates a new secure wallet with the given unique name. +/// +/// # Arguments +/// * `config` - Wallet configuration json. List of supported keys are defined by wallet type. +/// if NULL, then default config will be used. +/// * `credentials` - Wallet credentials json. List of supported keys are defined by wallet type. +/// if NULL, then default config will be used. +pub fn create_wallet(config: &str, credentials: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _create_wallet(command_handle, config, credentials, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _create_wallet(command_handle: IndyHandle, config: &str, credentials: &str, cb: Option) -> ErrorCode { + let config = c_str!(config); + let credentials = c_str!(credentials); + + ErrorCode::from(unsafe { + wallet::indy_create_wallet(command_handle, config.as_ptr(), credentials.as_ptr(), cb) + }) +} + +/// Opens the wallet with specific name. +/// +/// Wallet with corresponded name must be previously created with indy_create_wallet method. +/// It is impossible to open wallet with the same name more than once. +/// +/// # Arguments +/// * `runtime_config` (optional)- Runtime wallet configuration json. if NULL, then default runtime_config will be used. Example: +/// { +/// "freshness_time": string (optional), Amount of minutes to consider wallet value as fresh. Defaults to 24*60. +/// ... List of additional supported keys are defined by wallet type. +/// } +/// * `credentials` (optional) - Wallet credentials json. List of supported keys are defined by wallet type. +/// if NULL, then default credentials will be used. +/// +/// # Returns +/// Handle to opened wallet to use in methods that require wallet access. +pub fn open_wallet(config: &str, credentials: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_handle(); + + let err = _open_wallet(command_handle, config, credentials, cb); + + ResultHandler::handle(command_handle, err, receiver) +} + +fn _open_wallet(command_handle: IndyHandle, config: &str, credentials: &str, cb: Option) -> ErrorCode { + let config = c_str!(config); + let credentials = c_str!(credentials); + + ErrorCode::from(unsafe { + wallet::indy_open_wallet(command_handle, config.as_ptr(), credentials.as_ptr(), cb) + }) +} + +/// Exports opened wallet +/// +/// Note this endpoint is EXPERIMENTAL. Function signature and behaviour may change +/// in the future releases. +/// +/// # Arguments: +/// * `wallet_handle` - wallet handle returned by indy_open_wallet +/// * `export_config` - JSON containing settings for input operation. +/// { +/// "path": path of the file that contains exported wallet content +/// "key": passphrase used to derive export key +/// } +pub fn export_wallet(wallet_handle: IndyHandle, export_config: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _export_wallet(command_handle, wallet_handle, export_config, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _export_wallet(command_handle: IndyHandle, wallet_handle: IndyHandle, export_config: &str, cb: Option) -> ErrorCode { + let export_config = c_str!(export_config); + + ErrorCode::from(unsafe { + wallet::indy_export_wallet(command_handle, wallet_handle, export_config.as_ptr(), cb) + }) +} + +/// Creates a new secure wallet with the given unique name and then imports its content +/// according to fields provided in import_config +/// This can be seen as an create call with additional content import +/// +/// Note this endpoint is EXPERIMENTAL. Function signature and behaviour may change +/// in the future releases. +/// +/// # Arguments +/// * `config` - Wallet configuration json. +/// { +/// "storage": List of supported keys are defined by wallet type. +/// } +/// * `credentials` - Wallet credentials json (if NULL, then default config will be used). +/// { +/// "key": string, +/// "storage": Optional List of supported keys are defined by wallet type. +/// +/// } +/// * `import_config` - JSON containing settings for input operation. +/// { +/// "path": path of the file that contains exported wallet content +/// "key": passphrase used to derive export key +/// } +pub fn import_wallet(config: &str, credentials: &str, import_config: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _import_wallet(command_handle, config, credentials, import_config, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _import_wallet(command_handle: IndyHandle, config: &str, credentials: &str, import_config: &str, cb: Option) -> ErrorCode { + let config = c_str!(config); + let credentials = c_str!(credentials); + let import_config = c_str!(import_config); + + ErrorCode::from(unsafe { + wallet::indy_import_wallet(command_handle, config.as_ptr(), credentials.as_ptr(), import_config.as_ptr(), cb) + }) +} + +/// Deletes created wallet. +pub fn delete_wallet(config: &str, credentials: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _delete_wallet(command_handle, config, credentials, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _delete_wallet(command_handle: IndyHandle, config: &str, credentials: &str, cb: Option) -> ErrorCode { + let config = c_str!(config); + let credentials = c_str!(credentials); + + ErrorCode::from(unsafe { + wallet::indy_delete_wallet(command_handle, config.as_ptr(), credentials.as_ptr(), cb) + }) +} + +/// Closes opened wallet and frees allocated resources. +/// +/// # Arguments +/// * `handle` - wallet handle returned by open. +pub fn close_wallet(wallet_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _close_wallet(command_handle, wallet_handle, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _close_wallet(command_handle: IndyHandle, wallet_handle: IndyHandle, cb: Option) -> ErrorCode { + ErrorCode::from(unsafe { wallet::indy_close_wallet(command_handle, wallet_handle, cb) }) +} + +/// Create a new non-secret record in the wallet +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by open_wallet) +/// * `xtype` - allows to separate different record types collections +/// * `id` - the id of record +/// * `value` - the value of record +/// * `tags_json` - the record tags used for search and storing meta information as json: +/// { +/// "tagName1": , // string tag (will be stored encrypted) +/// "tagName2": , // string tag (will be stored encrypted) +/// "~tagName3": , // string tag (will be stored un-encrypted) +/// "~tagName4": , // string tag (will be stored un-encrypted) +/// } +/// Note that null means no tags +/// If tag name starts with "~" the tag will be stored un-encrypted that will allow +/// usage of this tag in complex search queries (comparison, predicates) +/// Encrypted tags can be searched only for exact matching +pub fn add_wallet_record(wallet_handle: IndyHandle, xtype: &str, id: &str, value: &str, tags_json: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _add_wallet_record(command_handle, wallet_handle, xtype, id, value, tags_json, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _add_wallet_record(command_handle: IndyHandle, wallet_handle: IndyHandle, xtype: &str, id: &str, value: &str, tags_json: Option<&str>, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let id = c_str!(id); + let value = c_str!(value); + let tags_json_str = opt_c_str!(tags_json); + ErrorCode::from(unsafe { + non_secrets::indy_add_wallet_record(command_handle, + wallet_handle, + xtype.as_ptr(), + id.as_ptr(), + value.as_ptr(), + opt_c_ptr!(tags_json, tags_json_str), + cb) + }) +} + +/// Update a non-secret wallet record value +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by open_wallet) +/// * `xtype` - allows to separate different record types collections +/// * `id` - the id of record +/// * `value` - the new value of record +pub fn update_wallet_record_value(wallet_handle: IndyHandle, xtype: &str, id: &str, value: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _update_wallet_record_value(command_handle, wallet_handle, xtype, id, value, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _update_wallet_record_value(command_handle: IndyHandle, wallet_handle: IndyHandle, xtype: &str, id: &str, value: &str, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let id = c_str!(id); + let value = c_str!(value); + + ErrorCode::from(unsafe{ + non_secrets::indy_update_wallet_record_value(command_handle, + wallet_handle, + xtype.as_ptr(), + id.as_ptr(), + value.as_ptr(), + cb) + }) +} + +/// Update a non-secret wallet record tags +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by open_wallet) +/// * `xtype` - allows to separate different record types collections +/// * `id` - the id of record +/// * `tags_json` - the record tags used for search and storing meta information as json: +/// { +/// "tagName1": , // string tag (will be stored encrypted) +/// "tagName2": , // string tag (will be stored encrypted) +/// "~tagName3": , // string tag (will be stored un-encrypted) +/// "~tagName4": , // string tag (will be stored un-encrypted) +/// } +/// If tag name starts with "~" the tag will be stored un-encrypted that will allow +/// usage of this tag in complex search queries (comparison, predicates) +/// Encrypted tags can be searched only for exact matching +pub fn update_wallet_record_tags(wallet_handle: IndyHandle, xtype: &str, id: &str, tags_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _update_wallet_record_tags(command_handle, wallet_handle, xtype, id, tags_json, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _update_wallet_record_tags(command_handle: IndyHandle, wallet_handle: IndyHandle, xtype: &str, id: &str, tags_json: &str, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let id = c_str!(id); + let tags_json = c_str!(tags_json); + + ErrorCode::from(unsafe { + non_secrets::indy_update_wallet_record_tags(command_handle, wallet_handle, xtype.as_ptr(), id.as_ptr(), tags_json.as_ptr(), cb) + }) +} + +/// Add new tags to the wallet record +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by open_wallet) +/// * `xtype` - allows to separate different record types collections +/// * `id` - the id of record +/// * `tags_json` - the record tags used for search and storing meta information as json: +/// { +/// "tagName1": , // string tag (will be stored encrypted) +/// "tagName2": , // string tag (will be stored encrypted) +/// "~tagName3": , // string tag (will be stored un-encrypted) +/// "~tagName4": , // string tag (will be stored un-encrypted) +/// } +/// If tag name starts with "~" the tag will be stored un-encrypted that will allow +/// usage of this tag in complex search queries (comparison, predicates) +/// Encrypted tags can be searched only for exact matching +/// Note if some from provided tags already assigned to the record than +/// corresponding tags values will be replaced +pub fn add_wallet_record_tags(wallet_handle: IndyHandle, xtype: &str, id: &str, tags_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _add_wallet_record_tags(command_handle, wallet_handle, xtype, id, tags_json, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _add_wallet_record_tags(command_handle: IndyHandle, wallet_handle: IndyHandle, xtype: &str, id: &str, tags_json: &str, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let id = c_str!(id); + let tags_json = c_str!(tags_json); + + ErrorCode::from(unsafe { + non_secrets::indy_add_wallet_record_tags(command_handle, wallet_handle, xtype.as_ptr(), id.as_ptr(), tags_json.as_ptr(), cb) + }) +} + +/// Delete tags from the wallet record +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by open_wallet) +/// * `xtype` - allows to separate different record types collections +/// * `id` - the id of record +/// * `tag_names_json` - the list of tag names to remove from the record as json array: +/// ["tagName1", "tagName2", ...] +pub fn delete_wallet_record_tags(wallet_handle: IndyHandle, xtype: &str, id: &str, tag_names_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _delete_wallet_record_tags(command_handle, wallet_handle, xtype, id, tag_names_json, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _delete_wallet_record_tags(command_handle: IndyHandle, wallet_handle: IndyHandle, xtype: &str, id: &str, tag_names_json: &str, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let id = c_str!(id); + let tag_names_json = c_str!(tag_names_json); + + ErrorCode::from(unsafe { + non_secrets::indy_delete_wallet_record_tags(command_handle, wallet_handle, xtype.as_ptr(), id.as_ptr(), tag_names_json.as_ptr(), cb) + }) +} + +/// Delete an existing wallet record in the wallet +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by open_wallet) +/// * `xtype` - record type +/// * `id` - the id of record +pub fn delete_wallet_record(wallet_handle: IndyHandle, xtype: &str, id: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _delete_wallet_record(command_handle, wallet_handle, xtype, id, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _delete_wallet_record(command_handle: IndyHandle, wallet_handle: IndyHandle, xtype: &str, id: &str, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let id = c_str!(id); + + ErrorCode::from(unsafe { + non_secrets::indy_delete_wallet_record(command_handle, wallet_handle, xtype.as_ptr(), id.as_ptr(), cb) + }) +} + +/// Get an wallet record by id +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by open_wallet) +/// * `xtype` - allows to separate different record types collections +/// * `id` - the id of record +/// * `options_json` - //TODO: FIXME: Think about replacing by bitmaks +/// { +/// retrieveType: (optional, false by default) Retrieve record type, +/// retrieveValue: (optional, true by default) Retrieve record value, +/// retrieveTags: (optional, false by default) Retrieve record tags +/// } +/// # Returns +/// * `wallet record json` - +/// { +/// id: "Some id", +/// type: "Some type", // present only if retrieveType set to true +/// value: "Some value", // present only if retrieveValue set to true +/// tags: , // present only if retrieveTags set to true +/// } +pub fn get_wallet_record(wallet_handle: IndyHandle, xtype: &str, id: &str, options_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _get_wallet_record(command_handle, wallet_handle, xtype, id, options_json, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _get_wallet_record(command_handle: IndyHandle, wallet_handle: IndyHandle, xtype: &str, id: &str, options_json: &str, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let id = c_str!(id); + let options_json = c_str!(options_json); + + ErrorCode::from(unsafe { + non_secrets::indy_get_wallet_record(command_handle, wallet_handle, xtype.as_ptr(), id.as_ptr(), options_json.as_ptr(), cb) + }) +} + +/// Search for wallet records. +/// +/// Note instead of immediately returning of fetched records +/// this call returns wallet_search_handle that can be used later +/// to fetch records by small batches (with indy_fetch_wallet_search_next_records). +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by open_wallet) +/// * `xtype` - allows to separate different record types collections +/// * `query_json` - MongoDB style query to wallet record tags: +/// { +/// "tagName": "tagValue", +/// $or: { +/// "tagName2": { $regex: 'pattern' }, +/// "tagName3": { $gte: '123' }, +/// }, +/// } +/// * `options_json` - //TODO: FIXME: Think about replacing by bitmaks +/// { +/// retrieveRecords: (optional, true by default) If false only "counts" will be calculated, +/// retrieveTotalCount: (optional, false by default) Calculate total count, +/// retrieveType: (optional, false by default) Retrieve record type, +/// retrieveValue: (optional, true by default) Retrieve record value, +/// retrieveTags: (optional, false by default) Retrieve record tags, +/// } +/// # Returns +/// * `search_handle` - Wallet search handle that can be used later +/// to fetch records by small batches (with indy_fetch_wallet_search_next_records) +pub fn open_wallet_search(wallet_handle: IndyHandle, xtype: &str, query_json: &str, options_json: &str) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_handle(); + + let err = _open_wallet_search(command_handle, wallet_handle, xtype, query_json, options_json, cb); + + ResultHandler::handle(command_handle, err, receiver) +} + +fn _open_wallet_search(command_handle: IndyHandle, wallet_handle: IndyHandle, xtype: &str, query_json: &str, options_json: &str, cb: Option) -> ErrorCode { + let xtype = c_str!(xtype); + let query_json = c_str!(query_json); + let options_json = c_str!(options_json); + + ErrorCode::from(unsafe { + non_secrets::indy_open_wallet_search(command_handle, wallet_handle, xtype.as_ptr(), query_json.as_ptr(), options_json.as_ptr(), cb) + }) +} + +/// Fetch next records for wallet search. +/// +/// Not if there are no records this call returns WalletNoRecords error. +/// +/// # Arguments +/// * `wallet_handle` - wallet handle (created by open_wallet) +/// * `wallet_search_handle` - wallet search handle (created by indy_open_wallet_search) +/// * `count` - Count of records to fetch +/// +/// # Returns +/// * `wallet records json` - +/// { +/// totalCount: , // present only if retrieveTotalCount set to true +/// records: [{ // present only if retrieveRecords set to true +/// id: "Some id", +/// type: "Some type", // present only if retrieveType set to true +/// value: "Some value", // present only if retrieveValue set to true +/// tags: , // present only if retrieveTags set to true +/// }], +/// } +pub fn fetch_wallet_search_next_records(wallet_handle: IndyHandle, wallet_search_handle: IndyHandle, count: usize) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _fetch_wallet_search_next_records(command_handle, wallet_handle, wallet_search_handle, count, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _fetch_wallet_search_next_records(command_handle: IndyHandle, wallet_handle: IndyHandle, wallet_search_handle: IndyHandle, count: usize, cb: Option) -> ErrorCode { + ErrorCode::from(unsafe { + non_secrets::indy_fetch_wallet_search_next_records(command_handle, wallet_handle, wallet_search_handle, count, cb) + }) +} + +/// Close wallet search (make search handle invalid) +/// +/// # Arguments +/// * `wallet_search_handle` - wallet search handle +pub fn close_wallet_search(wallet_search_handle: IndyHandle) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec(); + + let err = _close_wallet_search(command_handle, wallet_search_handle, cb); + + ResultHandler::empty(command_handle, err, receiver) +} + +fn _close_wallet_search(command_handle: IndyHandle, wallet_search_handle: IndyHandle, cb: Option) -> ErrorCode { + ErrorCode::from(unsafe { + non_secrets::indy_close_wallet_search(command_handle, wallet_search_handle, cb) + }) +} + +fn _default_credentials(credentials: Option<&str>) -> CString { + match credentials { + Some(s) => c_str!(s), + None => c_str!(r#"{"key":""}"#) + } +} + +/// Generate wallet master key. +/// Returned key is compatible with "RAW" key derivation method. +/// It allows to avoid expensive key derivation for use cases when wallet keys can be stored in a secure enclave. +/// +/// # Arguments +/// * `config` - (optional) key configuration json. +/// { +/// "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created). +/// Can be UTF-8, base64 or hex string. +/// } +/// +/// # Returns +/// wallet key can be used with RAW derivation type +pub fn generate_wallet_key(config: Option<&str>) -> Box> { + let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string(); + + let err = _generate_wallet_key(command_handle, config, cb); + + ResultHandler::str(command_handle, err, receiver) +} + +fn _generate_wallet_key(command_handle: IndyHandle, config: Option<&str>, cb: Option) -> ErrorCode { + let config = opt_c_str_json!(config); + + ErrorCode::from(unsafe { wallet::indy_generate_wallet_key(command_handle, config.as_ptr(), cb) }) +} diff --git a/wrappers/rust/tests/config.rs b/wrappers/rust/tests/config.rs new file mode 100644 index 00000000..f21df079 --- /dev/null +++ b/wrappers/rust/tests/config.rs @@ -0,0 +1,10 @@ +extern crate indyrs as indy; + +mod tests { + use super::*; + + #[test] + fn set_runtime_config_works () { + indy::set_runtime_config(r#"{"crypto_thread_pool_size": 2}"#); + } +} diff --git a/wrappers/rust/tests/crypto.rs b/wrappers/rust/tests/crypto.rs new file mode 100644 index 00000000..283579ea --- /dev/null +++ b/wrappers/rust/tests/crypto.rs @@ -0,0 +1,236 @@ +extern crate indyrs as indy; +#[macro_use] extern crate serde_json; +#[macro_use] extern crate serde_derive; +extern crate rmp_serde; +extern crate byteorder; +extern crate futures; +#[macro_use] +mod utils; + +use indy::crypto; +use indy::wallet; + +#[allow(unused_imports)] +use futures::Future; + +use utils::constants::DEFAULT_CREDENTIALS; + +macro_rules! safe_wallet_create { + ($x:ident) => { + match wallet::delete_wallet($x, DEFAULT_CREDENTIALS).wait() { + Ok(..) => {}, + Err(..) => {} + }; + wallet::create_wallet($x, DEFAULT_CREDENTIALS).wait().unwrap(); + } +} + +macro_rules! wallet_cleanup { + ($x:ident, $y:ident) => { + wallet::close_wallet($x).wait().unwrap(); + wallet::delete_wallet($y, DEFAULT_CREDENTIALS).wait().unwrap(); + } +} + +pub fn time_it_out(msg: &str, test: F) -> bool where F: Fn() -> bool { + for _ in 1..250 { + if test() { + return true; + } + } + // It tried to do a timeout test 250 times and the system was too fast, so just succeed + println!("{} - system too fast for timeout test", msg); + true +} + +mod high_cases { + use super::*; + + mod key_tests { + use super::*; + + #[test] + fn all_async_works() { + let wallet_name = r#"{"id":"all_async_works"}"#; + safe_wallet_create!(wallet_name); + let handle = wallet::open_wallet(wallet_name, DEFAULT_CREDENTIALS).wait().unwrap(); + + let vkey = crypto::create_key(handle, None).wait().unwrap(); + + let metadata = r#"{"name": "dummy"}"#; + crypto::set_key_metadata(handle, &vkey, metadata).wait().unwrap(); + + let meta= crypto::get_key_metadata(handle, &vkey).wait().unwrap(); + assert_eq!(metadata.to_string(),meta); + + wallet_cleanup!(handle, wallet_name); + } + } + + mod crypto_tests { + use super::*; + + #[test] + fn sign_verify_async_works() { + let wallet_name = r#"{"id":"sign_verify_async_works"}"#; + safe_wallet_create!(wallet_name); + let handle = wallet::open_wallet(wallet_name, DEFAULT_CREDENTIALS).wait().unwrap(); + + let vkey = crypto::create_key(handle, None).wait().unwrap(); + + let message = r#"Hello World"#.as_bytes(); + let sig = crypto::sign(handle, &vkey, message).wait().unwrap(); + assert_eq!(sig.len(), 64); + + wallet_cleanup!(handle, wallet_name); + } + } +} + +mod low_cases { + use super::*; + + mod key_tests { + use super::*; + + #[test] + fn create_key_works() { + let wallet_name = r#"{"id":"create_key_works"}"#; + safe_wallet_create!(wallet_name); + let handle = wallet::open_wallet(wallet_name, DEFAULT_CREDENTIALS).wait().unwrap(); + + let res = crypto::create_key(handle, None).wait(); + assert!(res.is_ok()); + + wallet_cleanup!(handle, wallet_name); + } + #[test] + fn set_metadata_works() { + let wallet_name = r#"{"id":"set_metadata_works"}"#; + safe_wallet_create!(wallet_name); + let handle = wallet::open_wallet(wallet_name, DEFAULT_CREDENTIALS).wait().unwrap(); + let verkey = crypto::create_key(handle, None).wait().unwrap(); + + assert!(crypto::set_key_metadata(handle, &verkey, r#"{"name": "dummy key"}"#).wait().is_ok()); + wallet_cleanup!(handle, wallet_name); + } + + #[test] + fn get_metadata_works() { + let wallet_name = r#"{"id":"get_metadata_works"}"#; + safe_wallet_create!(wallet_name); + let handle = wallet::open_wallet(wallet_name, DEFAULT_CREDENTIALS).wait().unwrap(); + let verkey = crypto::create_key(handle, None).wait().unwrap(); + + assert!(crypto::set_key_metadata(handle, &verkey, r#"{"name": "dummy key"}"#).wait().is_ok()); + assert_eq!(crypto::get_key_metadata(handle, &verkey).wait().unwrap(), r#"{"name": "dummy key"}"#); + wallet_cleanup!(handle, wallet_name); + } + } + + mod crypto_tests { + use super::*; + + #[test] + fn sign_works() { + let wallet_name = r#"{"id":"sign_works"}"#; + safe_wallet_create!(wallet_name); + let handle = wallet::open_wallet(wallet_name, DEFAULT_CREDENTIALS).wait().unwrap(); + let vkey = crypto::create_key(handle, None).wait().unwrap(); + + let res = crypto::sign(handle, &vkey, r#"Hello World"#.as_bytes()).wait(); + assert!(res.is_ok()); + let sig = res.unwrap(); + assert_eq!(sig.len(), 64); + + wallet_cleanup!(handle, wallet_name); + } + + #[test] + fn verify_works() { + let wallet_name = r#"{"id":"verify_works"}"#; + let message = r#"Hello World"#; + safe_wallet_create!(wallet_name); + let handle = wallet::open_wallet(wallet_name, DEFAULT_CREDENTIALS).wait().unwrap(); + let vkey = crypto::create_key(handle, None).wait().unwrap(); + let res = crypto::sign(handle, &vkey, message.as_bytes()).wait(); + assert!(res.is_ok()); + let sig = res.unwrap(); + + let res = crypto::verify(&vkey, message.as_bytes(), sig.as_slice()).wait(); + assert!(res.is_ok()); + assert!(res.unwrap()); + + let mut fake_sig = Vec::new(); + for i in 1..65 { + fake_sig.push(i as u8); + } + + let res = crypto::verify(&vkey, message.as_bytes(), fake_sig.as_slice()).wait(); + assert!(res.is_ok()); + assert!(!res.unwrap()); + wallet_cleanup!(handle, wallet_name); + } + + #[test] + fn auth_crypt_decrypt_works() { + let wallet_name = r#"{"id":"auth_crypt_decrypt_works"}"#; + let message = r#"Hello World"#; + safe_wallet_create!(wallet_name); + let handle = wallet::open_wallet(wallet_name, DEFAULT_CREDENTIALS).wait().unwrap(); + let vkey1 = crypto::create_key(handle, None).wait().unwrap(); + let vkey2 = crypto::create_key(handle, None).wait().unwrap(); + + let res = crypto::auth_crypt(handle, &vkey1, &vkey2, message.as_bytes()).wait(); + assert!(res.is_ok()); + let ciphertext = res.unwrap(); + + let res = crypto::auth_decrypt(handle, &vkey2, ciphertext.as_slice()).wait(); + + assert!(res.is_ok()); + let (actual_vkey, plaintext) = res.unwrap(); + assert_eq!(actual_vkey, vkey1); + assert_eq!(plaintext, message.as_bytes()); + + let mut fake_msg = Vec::new(); + for i in 1..ciphertext.len() { + fake_msg.push(i as u8); + } + + let res = crypto::auth_decrypt(handle, &vkey2, fake_msg.as_slice()).wait(); + assert!(res.is_err()); + + wallet_cleanup!(handle, wallet_name); + } + + #[test] + fn anon_crypt_decrypt_works() { + let wallet_name = r#"{"id":"anon_crypt_decrypt_works"}"#; + let message = r#"Hello World"#; + safe_wallet_create!(wallet_name); + let handle = wallet::open_wallet(wallet_name, DEFAULT_CREDENTIALS).wait().unwrap(); + let vkey1 = crypto::create_key(handle, None).wait().unwrap(); + + let res = crypto::anon_crypt(&vkey1, message.as_bytes()).wait(); + assert!(res.is_ok()); + let ciphertext = res.unwrap(); + + let res = crypto::anon_decrypt(handle, &vkey1, ciphertext.as_slice()).wait(); + + assert!(res.is_ok()); + let plaintext = res.unwrap(); + assert_eq!(plaintext, message.as_bytes()); + + let mut fake_msg = Vec::new(); + for i in 1..ciphertext.len() { + fake_msg.push(i as u8); + } + + let res = crypto::anon_decrypt(handle, &vkey1, fake_msg.as_slice()).wait(); + assert!(res.is_err()); + + wallet_cleanup!(handle, wallet_name); + } + + } +} diff --git a/wrappers/rust/tests/did.rs b/wrappers/rust/tests/did.rs new file mode 100644 index 00000000..b5a2b520 --- /dev/null +++ b/wrappers/rust/tests/did.rs @@ -0,0 +1,962 @@ +#[macro_use] extern crate serde_json; +#[macro_use] extern crate serde_derive; +extern crate rmp_serde; +extern crate byteorder; +extern crate indyrs as indy; +extern crate futures; +#[macro_use] +mod utils; + +use indy::did; +use indy::ErrorCode; +use utils::b58::{FromBase58}; +use utils::constants::{ + DID_1, + SEED_1, + VERKEY_1, + METADATA, + VERKEY_ABV_1, + INVALID_HANDLE +}; +use utils::setup::{Setup, SetupConfig}; +use utils::wallet::Wallet; + +#[allow(unused_imports)] +use futures::Future; + +#[inline] +fn assert_verkey_len(verkey: &str) { + assert_eq!(32, verkey.from_base58().unwrap().len()); +} + +#[cfg(test)] +mod create_new_did { + use super::*; + + #[inline] + fn assert_did_length(did: &str) { + assert_eq!(16, did.from_base58().unwrap().len()); + } + + #[test] + fn create_did_with_empty_json() { + let wallet = Wallet::new(); + + let (did, verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + assert_did_length(&did); + assert_verkey_len(&verkey); + } + + #[test] + fn create_did_with_seed() { + let wallet = Wallet::new(); + + let config = json!({ + "seed": SEED_1 + }).to_string(); + + let (did, verkey) = did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + + assert_eq!(DID_1, did); + assert_eq!(VERKEY_1, verkey); + } + + #[test] + fn create_did_with_cid() { + let wallet = Wallet::new(); + + let config = json!({ + "seed": SEED_1, + "cid": true, + }).to_string(); + + let (did, verkey) = did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + + assert_eq!(VERKEY_1, did); + assert_eq!(VERKEY_1, verkey); + } + + #[test] + fn create_did_with_did() { + let wallet = Wallet::new(); + + let config = json!({ + "did": DID_1 + }).to_string(); + + let (did, verkey) = did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + + assert_eq!(DID_1, did); + assert_ne!(VERKEY_1, verkey); + } + + #[test] + fn create_did_with_crypto_type() { + let wallet = Wallet::new(); + + let config = json!({ + "crypto_type": "ed25519" + }).to_string(); + + let result = did::create_and_store_my_did(wallet.handle, &config).wait(); + + assert!(result.is_ok()); + + } + + #[test] + fn create_did_with_invalid_wallet_handle() { + let result = did::create_and_store_my_did(INVALID_HANDLE, "{}").wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } + + #[test] + fn create_wallet_empty_config() { + let wallet = Wallet::new(); + + let result = did::create_and_store_my_did(wallet.handle, "").wait(); + + assert!(result.is_err()); + } + +} + +#[cfg(test)] +mod replace_keys_start { + use super::*; + + #[test] + fn replace_keys_start() { + let wallet = Wallet::new(); + let (did, verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let new_verkey = did::replace_keys_start(wallet.handle, &did, "{}").wait().unwrap(); + + assert_verkey_len(&new_verkey); + assert_ne!(verkey, new_verkey); + } + + #[test] + fn replace_keys_start_invalid_wallet() { + let result = did::replace_keys_start(INVALID_HANDLE, DID_1, "{}").wait(); + + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } + + #[test] + fn replace_keys_start_with_seed() { + let wallet = Wallet::new(); + let (did, verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let config = json!({"seed": SEED_1}).to_string(); + + let new_verkey = did::replace_keys_start(wallet.handle, &did, &config).wait().unwrap(); + + assert_eq!(VERKEY_1, new_verkey); + assert_ne!(verkey, new_verkey); + } + + #[test] + fn replace_keys_start_valid_crypto_type() { + let wallet = Wallet::new(); + let (did, verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let config = json!({"crypto_type": "ed25519"}).to_string(); + + let new_verkey = did::replace_keys_start(wallet.handle, &did, &config).wait().unwrap(); + + assert_verkey_len(&new_verkey); + assert_ne!(verkey, new_verkey); + } + + #[test] + fn replace_keys_start_invalid_crypto_type() { + let wallet = Wallet::new(); + let (did, _verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let config = json!({"crypto_type": "ed25518"}).to_string(); + + let result = did::replace_keys_start(wallet.handle, &did, &config).wait(); + + assert_eq!(ErrorCode::UnknownCryptoTypeError, result.unwrap_err()); + } + + #[test] + fn replace_keys_start_invalid_did() { + let wallet = Wallet::new(); + let result = did::replace_keys_start(wallet.handle, DID_1, "{}").wait(); + + assert_eq!(ErrorCode::WalletItemNotFound, result.unwrap_err()); + } +} + +#[cfg(test)] +mod replace_keys_apply { + use super::*; + + fn setup() -> (Wallet, String, String) { + let wallet = Wallet::new(); + let (did, verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + (wallet, did, verkey) + } + + #[inline] + fn start_key_replacement(wallet: &Wallet, did: &str) { + let config = json!({"seed": SEED_1}).to_string(); + did::replace_keys_start(wallet.handle, did, &config).wait().unwrap(); + } + + #[test] + fn replace_keys_apply() { + let (wallet, did, verkey) = setup(); + start_key_replacement(&wallet, &did); + + let result = did::replace_keys_apply(wallet.handle, &did).wait(); + + assert_eq!((), result.unwrap()); + + let new_verkey = did::key_for_local_did(wallet.handle, &did).wait().unwrap(); + + assert_eq!(VERKEY_1, new_verkey); + assert_ne!(verkey, new_verkey); + } + + #[test] + fn replace_keys_apply_without_replace_keys_start() { + let (wallet, did, _) = setup(); + + let result = did::replace_keys_apply(wallet.handle, &did).wait(); + + assert_eq!(ErrorCode::WalletItemNotFound, result.unwrap_err()); + } + + #[test] + fn replace_keys_apply_invalid_did() { + let wallet = Wallet::new(); + + let result = did::replace_keys_apply(wallet.handle, DID_1).wait(); + + assert_eq!(ErrorCode::WalletItemNotFound, result.unwrap_err()); + } + + #[test] + fn replace_keys_apply_invalid_wallet() { + let result = did::replace_keys_apply(INVALID_HANDLE, DID_1).wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } +} + +#[cfg(test)] +mod test_store_their_did { + use super::*; + + #[test] + fn store_their_did() { + let wallet = Wallet::new(); + let config = json!({"did": VERKEY_1}).to_string(); + + let result = did::store_their_did(wallet.handle, &config).wait(); + + assert_eq!((), result.unwrap()); + + let verkey = did::key_for_local_did(wallet.handle, VERKEY_1).wait().unwrap(); + + assert_eq!(VERKEY_1, verkey); + } + + #[test] + fn store_their_did_with_verkey() { + let wallet = Wallet::new(); + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + + let result = did::store_their_did(wallet.handle, &config).wait(); + + assert_eq!((), result.unwrap()); + + let verkey = did::key_for_local_did(wallet.handle, DID_1).wait().unwrap(); + + assert_eq!(VERKEY_1, verkey); + } + + #[test] + fn store_their_did_with_crypto_verkey() { + let wallet = Wallet::new(); + let config = json!({ + "did": DID_1, + "verkey": format!("{}:ed25519", VERKEY_1) + }).to_string(); + + let result = did::store_their_did(wallet.handle, &config).wait(); + + assert_eq!((), result.unwrap()); + + let verkey = did::key_for_local_did(wallet.handle, DID_1).wait().unwrap(); + + assert_eq!(format!("{}:ed25519", VERKEY_1), verkey); + } + + #[test] + fn store_their_did_empty_identify_json() { + let wallet = Wallet::new(); + + let result = did::store_their_did(wallet.handle, "{}").wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + } + + #[test] + fn store_their_did_invalid_handle() { + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + let result = did::store_their_did(INVALID_HANDLE, &config).wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } + + #[test] + fn store_their_did_abbreviated_verkey() { + let wallet = Wallet::new(); + let config = json!({ + "did": "8wZcEriaNLNKtteJvx7f8i", + "verkey": "~NcYxiDXkpYi6ov5FcYDi1e" + }).to_string(); + + let result = did::store_their_did(wallet.handle, &config).wait(); + + assert_eq!((), result.unwrap()); + } + + #[test] + fn store_their_did_invalid_did() { + let wallet = Wallet::new(); + let config = json!({"did": "InvalidDid"}).to_string(); + + let result = did::store_their_did(wallet.handle, &config).wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + } + + #[test] + fn store_their_did_with_invalid_verkey() { + let wallet = Wallet::new(); + let config = json!({ + "did": DID_1, + "verkey": "InvalidVerkey" + }).to_string(); + + let result = did::store_their_did(wallet.handle, &config).wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + } + + #[test] + fn store_their_did_with_invalid_crypto_verkey() { + let wallet = Wallet::new(); + let config = json!({ + "did": DID_1, + "verkey": format!("{}:bad_crypto_type", VERKEY_1) + }).to_string(); + + let result = did::store_their_did(wallet.handle, &config).wait(); + + assert_eq!(ErrorCode::UnknownCryptoTypeError, result.unwrap_err()); + } + + #[test] + fn store_their_did_duplicate() { + let wallet = Wallet::new(); + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + + did::store_their_did(wallet.handle, &config).wait().unwrap(); + + let result = did::store_their_did(wallet.handle, &config).wait(); + + assert_eq!(ErrorCode::WalletItemAlreadyExists, result.unwrap_err()); + } + + #[test] + /* + This test resulted from the ticket https://jira.hyperledger.org/browse/IS-802 + Previously, an error was being thrown because rollback wasn't happening. + This test ensures the error is no longer occuring. + */ + fn store_their_did_multiple_error_fixed() { + let wallet = Wallet::new(); + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + + did::store_their_did(wallet.handle, &config).wait().unwrap(); + + let result = did::store_their_did(wallet.handle, &config).wait(); + assert_eq!(ErrorCode::WalletItemAlreadyExists, result.unwrap_err()); + + let result = did::store_their_did(wallet.handle, &config).wait(); + assert_eq!(ErrorCode::WalletItemAlreadyExists, result.unwrap_err()); + } +} + +#[cfg(test)] +mod test_get_verkey_local { + use super::*; + + #[test] + fn get_verkey_local_my_did() { + let wallet = Wallet::new(); + let config = json!({"seed": SEED_1}).to_string(); + let (did, verkey) = did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + + let stored_verkey = did::key_for_local_did(wallet.handle, &did).wait().unwrap(); + + assert_eq!(verkey, stored_verkey); + } + + #[test] + fn get_verkey_local_their_did() { + let wallet = Wallet::new(); + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + did::store_their_did(wallet.handle, &config).wait().unwrap(); + + let stored_verkey = did::key_for_local_did(wallet.handle, DID_1).wait().unwrap(); + + assert_eq!(VERKEY_1, stored_verkey); + } + + #[test] + fn get_verkey_local_invalid_did() { + let wallet = Wallet::new(); + let result = did::key_for_local_did(wallet.handle, DID_1).wait(); + + assert_eq!(ErrorCode::WalletItemNotFound, result.unwrap_err()); + } + + #[test] + fn get_verkey_local_invalid_wallet() { + let result = did::key_for_local_did(INVALID_HANDLE, DID_1).wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } +} + +#[cfg(test)] +mod test_get_verkey_ledger { + use super::*; + + #[test] + fn get_verkey_my_did() { + let wallet = Wallet::new(); + let (did, verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let stored_verkey = did::key_for_did( + -1, + wallet.handle, + &did + ).wait().unwrap(); + + assert_eq!(verkey, stored_verkey); + } + + #[test] + fn get_verkey_their_did() { + let wallet = Wallet::new(); + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + did::store_their_did(wallet.handle, &config).wait().unwrap(); + + let stored_verkey = did::key_for_did( + -1, + wallet.handle, + DID_1, + ).wait().unwrap(); + + assert_eq!(VERKEY_1, stored_verkey); + } + + #[test] + fn get_verkey_not_on_ledger() { + let wallet = Wallet::new(); + let wallet2 = Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: true, + num_trustees: 0, + num_users: 0, + num_nodes: 4 + }); + let pool_handle = setup.pool_handle.unwrap(); + + let (did, _verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let result = did::key_for_did( + pool_handle, + wallet2.handle, + &did + ).wait(); + + assert_eq!(ErrorCode::WalletItemNotFound, result.unwrap_err()); + } + + #[test] + fn get_verkey_on_ledger() { + let wallet = Wallet::new(); + let wallet2 = Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: true, + num_trustees: 1, + num_users: 1, + num_nodes: 4 + }); + let pool_handle = setup.pool_handle.unwrap(); + let user = &setup.users.as_ref().unwrap()[0]; + + let ledger_verkey = did::key_for_did( + pool_handle, + wallet2.handle, + &user.did + ).wait().unwrap(); + + assert_eq!(ledger_verkey, user.verkey); + } + + #[test] + fn get_verkey_invalid_pool() { + let wallet = Wallet::new(); + + let result = did::key_for_did(-1, wallet.handle, DID_1).wait(); + + assert_eq!(ErrorCode::PoolLedgerInvalidPoolHandle, result.unwrap_err()); + } + + #[test] + fn get_verkey_invalid_wallet() { + let result = did::key_for_did(-1, INVALID_HANDLE, DID_1).wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } +} + +#[cfg(test)] +mod test_set_metadata { + use super::*; + + #[inline] + fn setup() -> (Wallet, String) { + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + (wallet, did) + } + + #[test] + fn set_metadata_my_did() { + let (wallet, did) = setup(); + + let result = did::set_did_metadata(wallet.handle, &did, METADATA).wait(); + let metadata = did::get_did_metadata(wallet.handle, &did).wait().unwrap(); + + assert_eq!((), result.unwrap()); + assert_eq!(METADATA, metadata); + } + + #[test] + fn set_metadata_their_did() { + let wallet = Wallet::new(); + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + did::store_their_did(wallet.handle, &config).wait().unwrap(); + + let result = did::set_did_metadata(wallet.handle, DID_1, METADATA).wait(); + let metadata = did::get_did_metadata(wallet.handle, DID_1).wait().unwrap(); + + assert_eq!((), result.unwrap()); + assert_eq!(METADATA, metadata); + } + + #[test] + fn set_metadata_replace_metadata() { + let (wallet, did) = setup(); + + did::set_did_metadata(wallet.handle, &did, METADATA).wait().unwrap(); + let metadata = did::get_did_metadata(wallet.handle, &did).wait().unwrap(); + + assert_eq!(METADATA, metadata); + + let next_metadata = "replacement metadata"; + did::set_did_metadata(wallet.handle, &did, next_metadata).wait().unwrap(); + let metadata = did::get_did_metadata(wallet.handle, &did).wait().unwrap(); + + assert_eq!(next_metadata, metadata); + } + + #[test] + fn set_metadata_empty_string() { + let (wallet, did) = setup(); + + let result = did::set_did_metadata(wallet.handle, &did, "").wait(); + let metadata = did::get_did_metadata(wallet.handle, &did).wait().unwrap(); + + assert_eq!((), result.unwrap()); + assert_eq!("", metadata); + } + + #[test] + fn set_metadata_invalid_did() { + let wallet = Wallet::new(); + + let result = did::set_did_metadata(wallet.handle, "InvalidDid", METADATA).wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + } + + #[test] + fn set_metadata_unknown_did() { + let wallet = Wallet::new(); + + let result = did::set_did_metadata(wallet.handle, DID_1, METADATA).wait(); + let metadata = did::get_did_metadata(wallet.handle, DID_1).wait().unwrap(); + + assert_eq!((), result.unwrap()); + assert_eq!(METADATA, metadata); + } + + #[test] + fn set_metadata_invalid_wallet() { + let result = did::set_did_metadata(INVALID_HANDLE, DID_1, METADATA).wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } +} + +#[cfg(test)] +mod test_get_metadata { + use super::*; + + #[inline] + fn setup() -> (Wallet, String) { + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + (wallet, did) + } + + #[test] + fn get_metadata_my_did() { + let (wallet, did) = setup(); + did::set_did_metadata(wallet.handle, &did, METADATA).wait().unwrap(); + + let result = did::get_did_metadata(wallet.handle, &did).wait(); + + assert_eq!(METADATA, result.unwrap()); + } + + #[test] + fn get_metadata_their_did() { + let wallet = Wallet::new(); + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + did::store_their_did(wallet.handle, &config).wait().unwrap(); + did::set_did_metadata(wallet.handle, DID_1, METADATA).wait().unwrap(); + + let result = did::get_did_metadata(wallet.handle, DID_1).wait(); + + assert_eq!(METADATA, result.unwrap()); + } + + #[test] + fn get_metadata_empty_string() { + let (wallet, did) = setup(); + did::set_did_metadata(wallet.handle, &did, "").wait().unwrap(); + + let result = did::get_did_metadata(wallet.handle, &did).wait(); + + assert_eq!(String::from(""), result.unwrap()); + } + + #[test] + fn get_metadata_no_metadata_set() { + let (wallet, did) = setup(); + + let result = did::get_did_metadata(wallet.handle, &did).wait(); + + assert_eq!(ErrorCode::WalletItemNotFound, result.unwrap_err()); + } + + #[test] + fn get_metadata_unknown_did() { + let wallet = Wallet::new(); + + let result = did::get_did_metadata(wallet.handle, DID_1).wait(); + + assert_eq!(ErrorCode::WalletItemNotFound, result.unwrap_err()); + } + + #[test] + fn get_metadata_invalid_wallet() { + let result = did::get_did_metadata(INVALID_HANDLE, DID_1).wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } +} + +#[cfg(test)] +mod test_set_endpoint { + use super::*; + + #[test] + pub fn set_endpoint_succeeds() { + let wallet = Wallet::new(); + + let config = json!({ + "seed": SEED_1 + }).to_string(); + + let (did, verkey) = did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + + indy::did::set_endpoint_for_did(wallet.handle, &did, "192.168.1.10", &verkey).wait().unwrap(); + + } +} + +#[cfg(test)] +mod test_get_endpoint { + use super::*; + + #[test] + pub fn get_endpoint_succeeds() { + let end_point_address = "192.168.1.10"; + let wallet = Wallet::new(); + + let config = json!({ + "seed": SEED_1 + }).to_string(); + + let (did, verkey) = did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + + let pool_setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + indy::did::set_endpoint_for_did(wallet.handle, &did, end_point_address, &verkey).wait().unwrap(); + + let pool_handle = indy::pool::open_pool_ledger(&pool_setup.pool_name, None).wait().unwrap(); + let mut test_succeeded : bool = false; + let mut error_code: indy::ErrorCode = indy::ErrorCode::Success; + + match indy::did::get_endpoint_for_did(wallet.handle, pool_handle, &did).wait() { + Ok(ret_address) => { + + let (address, _) = Some(ret_address).unwrap(); + + if end_point_address.to_string() == address { + test_succeeded = true; + } + }, + Err(ec) => { + error_code = ec; + } + } + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + + if indy::ErrorCode::Success != error_code { + assert!(false, "get_endpoint_works failed error code {:?}", error_code); + } + + if false == test_succeeded { + assert!(false, "get_endpoint_works failed to successfully compare end_point address"); + } + } + + /// ---------------------------------------------------------------------------------------- + /// get_endpoint_fails_no_set doesnt call set_endpoint before calling get_endpoint. + /// get_endpoint should return error code since the endpoint has not been set + /// ---------------------------------------------------------------------------------------- + #[test] + pub fn get_endpoint_fails_no_set() { + let wallet = Wallet::new(); + + let config = json!({}).to_string(); + + let (did, _verkey) = did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + + let pool_setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = indy::pool::open_pool_ledger(&pool_setup.pool_name, None).wait().unwrap(); + let mut error_code: indy::ErrorCode = indy::ErrorCode::Success; + + match indy::did::get_endpoint_for_did(wallet.handle, pool_handle, &did).wait() { + Ok(_) => { }, + Err(ec) => { + error_code = ec; + } + } + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + + assert_eq!(error_code, indy::ErrorCode::CommonInvalidState); + } +} + +#[cfg(test)] +mod test_abbreviate_verkey { + use super::*; + + #[test] + fn abbreviate_verkey_abbreviated() { + let result = did::abbreviate_verkey(DID_1, VERKEY_1).wait(); + assert_eq!(VERKEY_ABV_1, result.unwrap()); + } + + #[test] + fn abbreviate_verkey_full_verkey() { + let wallet = Wallet::new(); + let config = json!({"did": DID_1}).to_string(); + + let (did, verkey) = did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + + let result = did::abbreviate_verkey(&did, &verkey).wait(); + + assert_eq!(verkey, result.unwrap()); + } + + #[test] + fn abbreviate_verkey_invalid_did() { + let result = did::abbreviate_verkey("InvalidDid", VERKEY_1).wait(); + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + } + + #[test] + fn abbreviate_verkey_invalid_verkey() { + let result = did::abbreviate_verkey(DID_1, "InvalidVerkey").wait(); + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + } +} + +#[cfg(test)] +mod test_list_with_metadata { + use super::*; + + fn setup_multiple(wallet: &Wallet) -> Vec { + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + did::store_their_did(wallet.handle, &config).wait().unwrap(); + let (did1, verkey1) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let (did2, verkey2) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + did::set_did_metadata(wallet.handle, &did1, METADATA).wait().unwrap(); + + let expected = vec![ + json!({ + "did": did1, + "verkey": verkey1, + "tempVerkey": null, + "metadata": Some(METADATA.to_string()), + }), + json!({ + "did": did2, + "verkey": verkey2, + "tempVerkey": null, + "metadata": null + }) + ]; + + expected + } + + fn assert_multiple(json: String, expected: Vec) { + let dids: Vec = serde_json::from_str(&json).unwrap(); + + assert_eq!(expected.len(), dids.len()); + + for did in expected { + assert!(dids.contains(&did)); + } + } + + #[test] + fn list_with_metadata_no_dids() { + let wallet = Wallet::new(); + + let result = did::list_my_dids_with_metadata(wallet.handle).wait(); + + assert_eq!("[]", result.unwrap()); + } + + #[test] + fn list_with_metadata_their_did() { + let wallet = Wallet::new(); + let config = json!({"did": DID_1, "verkey": VERKEY_1}).to_string(); + did::store_their_did(wallet.handle, &config).wait().unwrap(); + + let result = did::list_my_dids_with_metadata(wallet.handle).wait(); + + assert_eq!("[]", result.unwrap()); + } + + #[test] + fn list_with_metadata_cryptonym() { + let wallet = Wallet::new(); + let config = json!({"seed": SEED_1, "cid": true}).to_string(); + did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + + let json = did::list_my_dids_with_metadata(wallet.handle).wait().unwrap(); + let dids: serde_json::Value = serde_json::from_str(&json).unwrap(); + + let expected = json!([{ + "did": VERKEY_1, + "verkey": VERKEY_1, + "tempVerkey": null, + "metadata": null + }]); + + assert_eq!(expected, dids); + } + + #[test] + fn list_with_metadata_did_with_metadata() { + let wallet = Wallet::new(); + let config = json!({"seed": SEED_1}).to_string(); + did::create_and_store_my_did(wallet.handle, &config).wait().unwrap(); + did::set_did_metadata(wallet.handle, DID_1, METADATA).wait().unwrap(); + + let json = did::list_my_dids_with_metadata(wallet.handle).wait().unwrap(); + let dids: serde_json::Value = serde_json::from_str(&json).unwrap(); + + let expected = json!([{ + "did": DID_1, + "verkey": VERKEY_1, + "tempVerkey": null, + "metadata": METADATA + }]); + + assert_eq!(expected, dids); + } + + #[test] + fn list_with_metadata_multiple_dids() { + let wallet = Wallet::new(); + let expected = setup_multiple(&wallet); + + let dids = did::list_my_dids_with_metadata(wallet.handle).wait().unwrap(); + + assert_multiple(dids, expected); + } + + #[test] + fn list_with_metadata_invalid_wallet() { + let result = did::list_my_dids_with_metadata(INVALID_HANDLE).wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } +} + +#[cfg(test)] +mod test_get_my_metadata { + use super::*; + + #[test] + pub fn get_my_metadata_success() { + let wallet = Wallet::new(); + + let (did, _verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + match did::get_my_did_with_metadata(wallet.handle, &did).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "get_my_metadata_success failed with error code {:?}", ec); + } + } + } +} diff --git a/wrappers/rust/tests/ledger.rs b/wrappers/rust/tests/ledger.rs new file mode 100644 index 00000000..52c2115f --- /dev/null +++ b/wrappers/rust/tests/ledger.rs @@ -0,0 +1,634 @@ +#[macro_use] extern crate serde_json; +#[macro_use] extern crate serde_derive; +extern crate rmp_serde; +extern crate byteorder; +extern crate indyrs as indy; +extern crate futures; +#[allow(unused_variables)] +#[allow(unused_macros)] +#[allow(dead_code)] +#[macro_use] +pub mod utils; + +use indy::did; +use indy::ledger; +use indy::pool; +use utils::constants::PROTOCOL_VERSION; +use utils::setup::{Setup, SetupConfig}; +use utils::wallet::Wallet; +#[allow(unused_imports)] +use futures::Future; + +const REQUEST_JSON: &str = r#"{ + "reqId":1496822211362017764, + "identifier":"GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL", + "operation":{ + "type":"1", + "dest":"VsKV7grR1BUE29mG2Fm2kX", + "verkey":"GjZWsBLgZCR18aL468JAT7w9CZRiBnpxUPPgyQxh4voa" + }, + "protocolVersion":2 + }"#; +#[cfg(test)] +mod test_sign_and_submit_request { + + use super::*; + + #[test] + pub fn sign_and_submit_request_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let result = ledger::sign_and_submit_request(pool_handle, wallet.handle, &did, REQUEST_JSON).wait(); + + pool::close_pool_ledger(pool_handle).wait().unwrap(); + + match result { + Ok(_) => { }, + Err(ec) => { assert!(false, "sign_and_submit_request_success got error code {:?}", ec); }, + } + + + /* + * The format of SignAndSubmitRequestAsync response is like this. + * + {"result":{ + "reqSignature":{ + "type":"ED25519", + "values":[{"value":"7kDrVBrmrKAvSs1QoQWYq6F774ZN3bRXx5e3aaUFiNvmh4F1yNqQw1951Az35nfrnGjZ99vtCmSFXZ5GqS1zLiG","from":"V4SGRU86Z58d6TV7PBUe6f"}] + }, + "txnMetadata":{ + "txnTime":1536876204, + "seqNo":36, + "txnId":"5d38ac6a242239c97ee28884c2b5cadec62248b2256bce51afd814c7847a853e" + }, + "ver":"1", + "auditPath":["DATtzSu9AMrArv8C2oribQh4wJ6TaD2K9o76t7EL2N7G","AbGuM7s9MudnT8M2eZe1yaG2EGUGxggMXSSbXCm4DFDx","3fjMoUdsbNrRfG5ZneHaQuX994oA4Z2pYPZtRRPmkngw"], + "rootHash":"A9LirjLuoBT59JJTJYvUgfQyEJA32Wb7njrbD9XqT2wc", + "txn":{ + "data":{ + "dest":"KQRpY4EmSG4MwH7md8gMoN","verkey":"B2nW4JfqZ2omHksoCmwD8zXXmtBsvbQk6WVSboazd8QB" + }, + "protocolVersion":2, + "type":"1", + "metadata":{ + "digest":"14594e0b31f751faf72d4bf4abdc6f54af34dab855fe1a0c67fe651b47bb93b5","reqId":1536876205519496000,"from":"V4SGRU86Z58d6TV7PBUe6f" + } + } + }, + "op":"REPLY"} + */ + } +} + +#[cfg(test)] +mod test_submit_request { + use super::*; + + #[test] + pub fn submit_request_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + let (_, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let submit_request_result = ledger::submit_request(pool_handle, REQUEST_JSON).wait(); + + pool::close_pool_ledger(pool_handle).wait().unwrap(); + + match submit_request_result { + Ok(submit_request_response) => { + // return is REQNACK client request invalid: MissingSignature()....this is ok. we wanted to make sure the function works + // and getting that response back indicates success + assert!(submit_request_response.contains("REQNACK"), "submit_request did not return REQNACK => {:?}", submit_request_response); + assert!(submit_request_response.contains("MissingSignature"), "submit_request did not return MissingSignature => {:?}", submit_request_response); + }, + Err(ec) => { + assert!(false, "submit_request failed with {:?}", ec); + } + } + + } +} + +#[cfg(test)] +mod test_submit_action { + use super::*; + + const NODES : &str = "[\"Node1\", \"Node2\"]"; + + #[test] + #[ignore] // TODO: restore after IS-1027 will be fixed + pub fn submit_action_this_hangs_indefinitely() { + + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let validator_request = ledger::build_get_validator_info_request(&did).wait().unwrap(); + let signed_request = ledger::sign_request(wallet.handle, &did, &validator_request).wait().unwrap(); + + ledger::submit_action(pool_handle, &signed_request, Some("[]"), Some(5)).wait().unwrap_err(); + + pool::close_pool_ledger(pool_handle).wait().unwrap(); + } + + #[test] + pub fn submit_action_success() { + + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let validator_request = ledger::build_get_validator_info_request(&did).wait().unwrap(); + let signed_request = ledger::sign_request(wallet.handle, &did, &validator_request).wait().unwrap(); + + let result = ledger::submit_action(pool_handle, &signed_request, Some(NODES), Some(5)).wait(); + + pool::close_pool_ledger(pool_handle).wait().unwrap(); + + match result { + Ok(_) => {}, + Err(ec) => { + assert!(false, "submit_action_success failed with {:?} extra {:?}", ec, signed_request); + } + } + } +} + +#[cfg(test)] +mod test_sign_request { + use super::*; + + #[test] + pub fn sign_request_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let validator_request = ledger::build_get_validator_info_request(&did).wait().unwrap(); + let signed_request_result = ledger::sign_request(wallet.handle, &did, &validator_request).wait(); + + pool::close_pool_ledger(pool_handle).wait().unwrap(); + + match signed_request_result { + Ok(_) => {}, + Err(ec) => { + assert!(false, "sign_request returned error {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_multi_sign_request { + use super::*; + + #[test] + pub fn multi_sign_request_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let validator_request = ledger::build_get_validator_info_request(&did).wait().unwrap(); + let signed_request_result = ledger::multi_sign_request(wallet.handle, &did, &validator_request).wait(); + + pool::close_pool_ledger(pool_handle).wait().unwrap(); + + match signed_request_result { + Ok(_) => {}, + Err(ec) => { + assert!(false, "multi_sign_request returned error {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_nym_request { + use super::*; + + use utils::did::NymRole; + + #[test] + pub fn build_nym_request_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let (did, verkey) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let (trustee_did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let nym_result = ledger::build_nym_request(&trustee_did, &did, Some(&verkey), None, NymRole::Trustee.prepare()).wait(); + + match nym_result { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_nym_request returned error_code {:?}", ec); + } + } + + } + + #[test] + pub fn build_nym_request_with_no_verkey_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let (trustee_did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let nym_result = ledger::build_nym_request(&trustee_did, &did, None, None, NymRole::Trustee.prepare()).wait(); + + match nym_result { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_nym_request returned error_code {:?}", ec); + } + } + + } + + #[test] + pub fn build_nym_request_with_data_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let (trustee_did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let nym_result = ledger::build_nym_request(&trustee_did, &did, None, Some("some_data"), NymRole::Trustee.prepare()).wait(); + + match nym_result { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_nym_request returned error_code {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_get_nym_request { + use super::*; + + #[test] + pub fn build_get_nym_request_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let submitter_wallet = Wallet::new(); + let wallet = Wallet::new(); + let (submitter_did, _) = did::create_and_store_my_did(submitter_wallet.handle, "{}").wait().unwrap(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let get_result = ledger::build_get_nym_request(Some(&submitter_did), &did).wait(); + + match get_result { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_get_nym_request returned error_code {:?}", ec); + } + } + } + + #[test] + pub fn build_get_nym_request_no_submitter_did_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + let get_result = ledger::build_get_nym_request(None, &did).wait(); + + match get_result { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_get_nym_request returned error_code {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_attrib_request { + use super::*; + + #[test] + pub fn build_attrib_request_success() { + + let submitter_wallet = Wallet::new(); + let wallet = Wallet::new(); + let (submitter_did, _) = did::create_and_store_my_did(submitter_wallet.handle, "{}").wait().unwrap(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + match ledger::build_attrib_request(&submitter_did, &did, None, Some("{}"), None).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_attrib_request failed with error {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_get_attrib_request { + + use super::*; + + #[test] + pub fn build_get_attrib_request_success() { + + let submitter_wallet = Wallet::new(); + let wallet = Wallet::new(); + let (submitter_did, _) = did::create_and_store_my_did(submitter_wallet.handle, "{}").wait().unwrap(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + match ledger::build_get_attrib_request(Some(&submitter_did), &did, Some("{}"), None, None).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_attrib_request failed with error {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_schema_request { + use super::*; + + const SCHEMA_DATA : &str = r#"{"id":"id","attrNames": ["name", "male"],"name":"gvt2","version":"3.1","ver":"1.0"}"#; + + #[test] + pub fn build_schema_request_success() { + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + match ledger::build_schema_request(&did, SCHEMA_DATA).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_schema_request failed with error {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_get_schema_request { +use super::*; + + const SCHEMA_REQUEST : &str = "5LEV4bTAXntXqmtLFm7yCS:2:bob:1.0"; + + #[test] + pub fn build_get_schema_request_success() { + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + + match ledger::build_get_schema_request(Some(&did), SCHEMA_REQUEST).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_get_schema_request failed with error {:?}", ec); + } + } + } +} + +#[cfg(test)] +#[cfg(feature = "tests_to_fix")] +mod test_parse_get_schema_response { + + use super::*; + + const SCHEMA_NAME : &str = "schema_1234"; + const SCHEMA_DATA : &str = r#"{"id":"schema_id1234","attrNames": ["name", "male"],"name":"schema_1234","version":"1.0","ver":"1.0"}"#; + + + fn create_build_schema_request(did : &String) -> String { + format!("{}:2:{}:1.0", did, SCHEMA_NAME) + } + + fn build_schema(did: &String, pool_handle: i32) { + let build_schema = ledger::build_schema_request(&did, SCHEMA_DATA).wait().unwrap(); + let _submit_response = ledger::submit_request(pool_handle, &build_schema).wait().unwrap(); + } + + #[test] + #[ignore] + pub fn parse_get_schema_response_success() { + pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + build_schema(&did, pool_handle); + let schema_request = create_build_schema_request(&did); + + let schema_response = ledger::build_get_schema_request(Some(&did), &schema_request).wait().unwrap(); + let signed_response = ledger::sign_request(wallet.handle, &did,&schema_response).wait().unwrap(); + let submit_response = ledger::submit_request(pool_handle, &signed_response).wait().unwrap(); + + let parse_response = ledger::parse_get_schema_response(&submit_response).wait(); + + pool::close_pool_ledger(pool_handle).wait().unwrap(); + + match parse_response { + Ok(_) => {}, + Err(ec) => { + assert!(false, "parse_get_schema_response failed error_code {:?} \n\n using submit_response {:?} \n\n with signed_response {:?} \n\n from schema_response {:?} \n\n schema {:?}", ec, submit_response, signed_response, schema_response, schema_request); + } + } + } +} + +#[cfg(test)] +mod test_build_get_ddo_request { + + use super::*; + + #[test] + pub fn build_get_ddo_request_success() { + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + match ledger::build_get_ddo_request(Some(&did), &did).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_get_ddo_request failed error_code {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_get_txn_request { + use super::*; + + const LEDGER_TYPE : &str = "DOMAIN"; + + #[test] + pub fn build_get_txn_request_success() { + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + match ledger::build_get_txn_request(Some(&did), Some(LEDGER_TYPE), 1).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_get_txn_request failed error_code {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_cred_def_request { + use super::*; + + const CRED_DATA : &str = r#"{"ver":"1.0","id":"V4SGRU86Z58d6TV7PBUe6f:3:CL:17:oI6Iokv","schemaId":"17","type":"CL","tag":"oI6Iokv","value":{"primary":{"n":"87178281071734731437690387382922138711010162107879888888538848407132327215161696479014638246148780516059076502007170233816521638866237445955186196199106181664196333035350522256775772678749757516076687671733088043974750225859037634391059057871128952528114293385763258675546471992534732373945591487042489023109902330242980705545998552851661474245748466697559479508930710234503328250288511766352977719334252928597855882930620741923986586828547412389638821815758450532251881301327049927072714545264108360496728434366393519356711418047944068773770531352206244052618670493983767902201878934735288733850555036281883721724473","s":"66794590351311400173440340223561508784777853797981871904981559245334503567545616382611784848902543717386870008558289905316601662574754089209687052710438230437549560386636286514822680768065835610624750399055088116166226098175424830519537908801592274839622946402090491946787040058370552124732885892610142242847158959492000732292603755213902976259446731410240912872744210451254301242220759673686769861789834996124153811460984114732824978048021325148492655982695079333718710090836034672739682282204904856516947015563681443657793597047393731812247221167838278986153621564706820976058621996938916226023920421313258317181056","r":{"height":"37686658568948037814775431903843597441856100114754323955796133079330648476309192012260294209465266635551131504125646637359931844595436529982289207908218765877672222632310887737940054188921134584912244256324727048869497937750475441196124576035922245172355820888415660512858847440533214955712359488689065763607483137995713620001810321655685884305156101062519673602853819411046367019986397235673847881046529391589711229735614071805410066894389088951657447726215788267372471488185033424222037788505918934857840957649277458736101301203881379280675945440723899652144116975079241713669490809165909240425120649887001447597783","sex":"48901017446440182649799731593114947230876351500273905015595989118217119375071111218399500737051508041416910144890371937193478691958771514378058820388069120931504416289663010431000145369715463131882383259114210820041731832960312557792681552574471886139487662967612807830334835729846093444859302732007584479807271091676491277902271511164922767210557187133481955551837663018165430244652992048757580783775433571336475692686259720997931194126203237043117966211161878071070916577025579669942228991696500136399569383974985399786080235342264485395522119939857486145401501612186163491615961653478438596959371113747671419654818","master_secret":"25754344723836699563584283879786692153622691083042382144160949511089528018631287834606498465418239311334501386316618629687258527283908520406207259178795217648481719864528515688115872808761112818709464686844054961387398147908732686218740513751960844653382166618983380191016571483892249629309506399346596975262589381752411984820505602091163687287542251803844421163362364666975191601496467090517324300542321861313152630025880504086070664031524805153571288074723002683472372414034607393588926109015678216745625826790077479058525170476570603845174669212586627449339894597259739762350550126584394404404482135882343197379054","name":"64945144723199018124037264140277156942131666148001245998219662472757345342279533884405888431954009830746588251472121029944168008438815350643138701794229741155411122621890661138856631059298571458398258239896113210276837384872922411226059610000961503919325158321529528085516642820682380678880886510720705463915144189095545183388444662260696183777535832602518582169729325489244691039221691384084009024188000745680035168934609700642727769603625029893488551202843527601643121220149122355960460523112480070939364242895718918315978456710031746858656148388609050488969420517950113219916527876709626082332309036117494497571230","age":"32059832863983999153613274260157019698296212529496396734792926477728751870868732126531732944880026440901943732956875433636855727848522486073745001899386738358016223503298068118020520201025961660332519845724521320552467451946852925824035412812595344753770029091958417300642692814810865758776286263929051571009155820474717897179825570107678882180230319004359558595714472285100325554837250772201405847343231203624749918461130474867722155978675551762505078508248381791048831193422832357874770535478244636601382323151375446307087219224928662366021820679699538198192887109930714869161019271417169222414370495648047714662103"},"rctxt":"38527464755916130963069611882293312815641859720607042775748742527688895624917359948168832828223678535804570958646474457323858571801037955359525462917173252086033591899208879285429574561167189107147758287137082689831331351781369164690717667586513821072095969666206581907243540078811132148136508600170388059098530570400824663936962403223100603326027117401899329035603739144303108339956544437073624926208818126402005595194344120188160525632489014089138283290414616529527375527577666875823786710497945303252443476610222721607664991987281949777517734685590949741562190122640202895612444667451959072089271004850428610427341","z":"31160349078984317779569363785252606468286101126154161634595102825752576352018565401209247600497171866986884547654707390053445672860929599916189762737605262398652714436350679825010487409345252016639698884761154432723648619393558760904141612222413004613912305317054390982133492273484244661652402423836430130022761985374095739624351663212686292616011934960947889676162946869205272435766196882679460333258355511812361345778943009086137697548566706243827603133668933678120765799991107515465495261132740007129958253450651703438567276912235691326876396719017894799034243480316169679472944643292666194979984921170821328746189"}}}"#; + + #[test] + pub fn test_build_cred_def_request_success(){ + + let wallet = Wallet::new(); + let (did, _) = did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + + match ledger::build_cred_def_request(&did, &CRED_DATA).wait() { + Ok(_) => {}, + Err(ec) => { + assert!(false, "build_cred_def_request returned error_code {:?}", ec); + } + } + } +} + +#[cfg(test)] +mod test_build_get_cred_def_request { + +} + +#[cfg(test)] +mod test_build_node_request { + +} + +#[cfg(test)] +mod test_build_get_validator_info_request { + +} + +#[cfg(test)] +mod test_build_pool_config_request { + +} + +#[cfg(test)] +mod test_build_pool_restart_request { + +} + +#[cfg(test)] +mod test_build_pool_upgrade_request { + +} + +#[cfg(test)] +mod test_build_revoc_reg_def_request { + +} + +#[cfg(test)] +mod test_build_get_revoc_reg_def_request { + +} + +#[cfg(test)] +mod test_parse_get_revoc_reg_def_response { + +} + +#[cfg(test)] +mod test_build_revoc_reg_entry_request { +} + +#[cfg(test)] +mod test_build_get_revoc_reg_request { + +} + +#[cfg(test)] +mod test_parse_get_revoc_reg_response { + +} + +#[cfg(test)] +mod test_build_get_revoc_reg_delta_request { + +} + +#[cfg(test)] +mod test_parse_get_revoc_reg_delta_response { + +} + +#[cfg(test)] +mod test_register_transaction_parser_for_sp { + +} diff --git a/wrappers/rust/tests/pairwise.rs b/wrappers/rust/tests/pairwise.rs new file mode 100644 index 00000000..bb39c0c2 --- /dev/null +++ b/wrappers/rust/tests/pairwise.rs @@ -0,0 +1,269 @@ +#[macro_use] extern crate serde_json; +#[macro_use] extern crate serde_derive; +extern crate rmp_serde; +extern crate byteorder; +extern crate indyrs as indy; +extern crate futures; +#[macro_use] +mod utils; + +#[allow(unused_imports)] +use futures::Future; + +use utils::wallet::Wallet; +use utils::constants::{DID_TRUSTEE, VERKEY_TRUSTEE, METADATA, DID}; + +use indy::ErrorCode; + +mod create_pairwise { + use super::*; + + #[test] + pub fn create_pairwise_works() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, Some(METADATA)).wait().unwrap(); + } + #[test] + pub fn create_pairwise_works_for_empty_metadata() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, None).wait().unwrap(); + } + #[test] + pub fn create_pairwise_works_for_not_found_my_did() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let ec = indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, DID, Some(METADATA)).wait().unwrap_err(); + assert_eq!(ec, ErrorCode::WalletItemNotFound); + } + + #[test] + pub fn create_pairwise_works_for_not_found_their_did() { + let wallet = Wallet::new(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let ec = indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, Some(METADATA)).wait().unwrap_err(); + assert_eq!(ec, ErrorCode::WalletItemNotFound); + } + + #[test] + pub fn create_pairwise_works_for_invalid_handle() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + let ec = indy::pairwise::create_pairwise(wallet.handle + 1, DID_TRUSTEE, &did, Some(METADATA)).wait().unwrap_err(); + assert_eq!(ec, ErrorCode::WalletInvalidHandle); + } + + #[test] + pub fn create_pairwise_works_for_twice() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, Some(METADATA)).wait().unwrap(); + + let ec = indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, None).wait().unwrap_err(); + assert_eq!(ec, ErrorCode::WalletItemAlreadyExists); + } +} + +mod list_pairwise { + use super::*; + + #[test] + pub fn list_pairwise_works() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, None).wait().unwrap(); + + let res = indy::pairwise::list_pairwise(wallet.handle).wait().unwrap(); + let vec_res: Vec = serde_json::from_str(&res).unwrap(); + + assert_eq!(vec_res.len(), 1); + assert!(vec_res.contains(&format!(r#"{{"my_did":"{}","their_did":"{}"}}"#, did, DID_TRUSTEE))); + } + + #[test] + pub fn list_pairwise_works_for_empty_result() { + let wallet = Wallet::new(); + + let res = indy::pairwise::list_pairwise(wallet.handle).wait().unwrap(); + let vec_res: Vec = serde_json::from_str(&res).unwrap(); + + assert_eq!(vec_res.len(), 0); + } + + #[test] + pub fn list_pairwise_works_for_invalid_wallet_handle() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, None).wait().unwrap(); + + let ec = indy::pairwise::list_pairwise(wallet.handle + 1).wait().unwrap_err(); + assert_eq!(ec, ErrorCode::WalletInvalidHandle); + } +} + +mod pairwise_exists { + use super::*; + + #[test] + pub fn pairwise_exists_works() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, Some(METADATA)).wait().unwrap(); + + assert!(indy::pairwise::is_pairwise_exists(wallet.handle, DID_TRUSTEE).wait().unwrap()); + } + + #[test] + pub fn pairwise_exists_works_for_not_created() { + let wallet = Wallet::new(); + + assert!(!indy::pairwise::is_pairwise_exists(wallet.handle, DID_TRUSTEE).wait().unwrap()); + } + + #[test] + pub fn pairwise_exists_works_for_invalid_handle() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, Some(METADATA)).wait().unwrap(); + + assert_eq!(ErrorCode::WalletInvalidHandle, indy::pairwise::is_pairwise_exists(wallet.handle + 1, DID_TRUSTEE).wait().unwrap_err()); + } +} + +mod get_pairwise { + use super::*; + + #[test] + pub fn get_pairwise_works() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, Some(METADATA)).wait().unwrap(); + + let pairwise_info_json = indy::pairwise::get_pairwise(wallet.handle, DID_TRUSTEE).wait().unwrap(); + + assert_eq!(format!(r#"{{"my_did":"{}","metadata":"{}"}}"#, did, METADATA), pairwise_info_json); + } + + #[test] + pub fn get_pairwise_works_for_not_created_pairwise() { + let wallet = Wallet::new(); + + let ec = indy::pairwise::get_pairwise(wallet.handle, DID_TRUSTEE).wait().unwrap_err(); + + assert_eq!(ec, ErrorCode::WalletItemNotFound); + } + + #[test] + pub fn get_pairwise_works_for_invalid_wallet_handle() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, Some(METADATA)).wait().unwrap(); + + let ec = indy::pairwise::get_pairwise(wallet.handle + 1, DID_TRUSTEE).wait().unwrap_err(); + + assert_eq!(ec, ErrorCode::WalletInvalidHandle); + } +} + +mod set_pairwise_metadata { + use super::*; + + #[test] + pub fn set_pairwise_metadata_works() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, None).wait().unwrap(); + + let pairwise_info_without_metadata = indy::pairwise::get_pairwise(wallet.handle, DID_TRUSTEE).wait().unwrap(); + + assert_eq!(format!(r#"{{"my_did":"{}"}}"#, did), pairwise_info_without_metadata); + + indy::pairwise::set_pairwise_metadata(wallet.handle, DID_TRUSTEE, Some(METADATA)).wait().unwrap(); + + let pairwise_info_with_metadata = indy::pairwise::get_pairwise(wallet.handle, DID_TRUSTEE).wait().unwrap(); + + assert_ne!(pairwise_info_with_metadata, pairwise_info_without_metadata); + assert_eq!(format!(r#"{{"my_did":"{}","metadata":"{}"}}"#, did, METADATA), pairwise_info_with_metadata); + } + + #[test] + pub fn set_pairwise_metadata_works_for_reset() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, Some(METADATA)).wait().unwrap(); + + let pairwise_info_without_metadata = indy::pairwise::get_pairwise(wallet.handle, DID_TRUSTEE).wait().unwrap(); + + assert_eq!(format!(r#"{{"my_did":"{}","metadata":"{}"}}"#, did, METADATA), pairwise_info_without_metadata); + + indy::pairwise::set_pairwise_metadata(wallet.handle, DID_TRUSTEE, None).wait().unwrap(); + + let pairwise_info_with_metadata = indy::pairwise::get_pairwise(wallet.handle, DID_TRUSTEE).wait().unwrap(); + + assert_ne!(pairwise_info_with_metadata, pairwise_info_without_metadata); + assert_eq!(format!(r#"{{"my_did":"{}"}}"#, did), pairwise_info_with_metadata); + } + + #[test] + pub fn set_pairwise_metadata_works_for_not_created_pairwise() { + let wallet = Wallet::new(); + + let ec = indy::pairwise::set_pairwise_metadata(wallet.handle, DID_TRUSTEE, Some(METADATA)).wait().unwrap_err(); + + assert_eq!(ec, ErrorCode::WalletItemNotFound); + } + + #[test] + pub fn set_pairwise_metadata_works_for_invalid_wallet_handle() { + let wallet = Wallet::new(); + let their_identity_json = json!({"did": DID_TRUSTEE, "verkey": VERKEY_TRUSTEE}).to_string(); + indy::did::store_their_did(wallet.handle, &their_identity_json).wait().unwrap(); + + let (did, _) = indy::did::create_and_store_my_did(wallet.handle, "{}").wait().unwrap(); + indy::pairwise::create_pairwise(wallet.handle, DID_TRUSTEE, &did, None).wait().unwrap(); + + let ec = indy::pairwise::set_pairwise_metadata(wallet.handle + 1, DID_TRUSTEE, Some(METADATA)).wait().unwrap_err(); + + assert_eq!(ec, ErrorCode::WalletInvalidHandle); + } +} diff --git a/wrappers/rust/tests/payment.rs b/wrappers/rust/tests/payment.rs new file mode 100644 index 00000000..4d7c279a --- /dev/null +++ b/wrappers/rust/tests/payment.rs @@ -0,0 +1,18 @@ +extern crate indyrs as indy; +#[macro_use] extern crate serde_json; +#[macro_use] extern crate serde_derive; +extern crate rmp_serde; +extern crate byteorder; + +#[macro_use] +mod utils; +use utils::wallet::Wallet; + +mod low_tests { + use super::*; + + #[test] + fn create_payment_address_works () { + let _handle = Wallet::new(); + } +} diff --git a/wrappers/rust/tests/pool.rs b/wrappers/rust/tests/pool.rs new file mode 100644 index 00000000..a2c5f276 --- /dev/null +++ b/wrappers/rust/tests/pool.rs @@ -0,0 +1,461 @@ +#[macro_use] extern crate serde_json; +#[macro_use] extern crate serde_derive; +extern crate rmp_serde; +extern crate byteorder; +extern crate futures; +extern crate indyrs as indy; +#[macro_use] +pub mod utils; + +use utils::constants::{DID_1}; +use utils::setup::{Setup, SetupConfig}; +use indy::ErrorCode; +use indy::pool; +#[allow(unused_imports)] +use futures::Future; + +#[cfg(test)] +mod open_pool { + use super::*; + use futures::future::Future; + + #[test] + pub fn open_pool_works() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + } + + #[test] + pub fn open_pool_works_for_config() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let config = Some(r#"{"timeout": 20}"#); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, config).wait().unwrap(); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + } + + #[test] + pub fn open_pool_works_for_twice() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + let ec = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap_err(); + assert_eq!(ec, ErrorCode::PoolLedgerInvalidPoolHandle); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + } + + #[test] + pub fn open_pool_works_for_two_nodes() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 2, + num_users: 0, + }); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + } + + #[test] + pub fn open_pool_works_for_three_nodes() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 3, + num_users: 0, + }); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + } + + #[test] + pub fn open_pool_works_for_cached_txns() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + utils::pool::dump_correct_genesis_txns_to_cache(&setup.pool_name).unwrap(); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + } + + #[test] + pub fn open_pool_works_for_corrupted_cached_txns() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + utils::pool::dump_incorrect_genesis_txns_to_cache(&setup.pool_name).unwrap(); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + } +} + +#[cfg(test)] +mod close_pool { + use super::*; + use futures::future::Future; + + #[test] + pub fn close_pool_works() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + } + + #[test] + pub fn close_pool_works_for_twice() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + let ec = indy::pool::close_pool_ledger(pool_handle).wait().unwrap_err(); + assert_eq!(ec, ErrorCode::PoolLedgerInvalidPoolHandle); + } + + #[test] + pub fn close_pool_works_for_reopen_after_close() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + } + + #[test] + pub fn close_pool_works_for_pending_request() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: false, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + let pool_handle = indy::pool::open_pool_ledger(&setup.pool_name, None).wait().unwrap(); + + let get_nym_req = indy::ledger::build_get_nym_request(Some(DID_1), DID_1).wait().unwrap(); + + let _request_future = indy::ledger::submit_request(pool_handle, &get_nym_req); + + indy::pool::close_pool_ledger(pool_handle).wait().unwrap(); + + let res = _request_future.wait(); + assert_eq!(res.unwrap_err(), ErrorCode::PoolLedgerTerminated); + } + +} + +#[cfg(test)] +mod test_pool_create_config { + use super::*; + + use std::fs; + use utils::file::TempFile; + use utils::pool::{PoolList, test_pool_name, test_genesis_config}; + + #[inline] + pub fn assert_pool_exists(name: &str) { + assert!(PoolList::new().pool_exists(name)); + } + + #[inline] + pub fn assert_pool_not_exists(name: &str) { + assert!(! PoolList::new().pool_exists(name)); + } + + /* + Returns the file, otherwise the file would be deleted + when it goes out of scope.rustc_lsan + */ + fn invalid_temporary_genesis_config() -> (String, TempFile) { + let file = TempFile::new(None).unwrap(); + fs::write(&file, b"Some nonsensical data").unwrap(); + let config = json!({"genesis_txn": file.as_ref()}).to_string(); + + (config, file) + } + + #[test] + /* Create a valid config with custom genesis txn. */ + fn config_with_genesis_txn() { + let name = test_pool_name(); + let (config, _file) = test_genesis_config(); + let result = pool::create_pool_ledger_config(&name, Some(&config)).wait(); + + assert_eq!((), result.unwrap()); + assert_pool_exists(&name); + pool::delete_pool_ledger(&name).wait().unwrap(); + } + + #[test] + /* Config options missing genesis_txn */ + fn config_missing_genesis_txn() { + let name = test_pool_name(); + let result = pool::create_pool_ledger_config(&name, Some("{}")).wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + assert_pool_not_exists(&name); + } + + #[test] + /* A path which doesn't exists results in error. */ + fn config_with_unknown_path_genesis_txn() { + let name = test_pool_name(); + let config = json!({"genesis_txn": "/nonexist15794345"}).to_string(); + let result = pool::create_pool_ledger_config(&name, Some(&config)).wait(); + + assert_eq!(ErrorCode::CommonIOError, result.unwrap_err()); + assert_pool_not_exists(&name); + } + + #[test] + /* Error with an incorrectly formed gensis txn. */ + fn config_with_bad_genesis_txn() { + let name = test_pool_name(); + let (config, _file) = invalid_temporary_genesis_config(); + + let result = pool::create_pool_ledger_config(&name, Some(&config)).wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + assert_pool_not_exists(&name); + } + + #[test] + /* Must specify pool name when config is created. */ + fn config_with_empty_pool_name() { + let name = test_pool_name(); + let (config, _file) = test_genesis_config(); + let result = pool::create_pool_ledger_config("", Some(&config)).wait(); + + assert_eq!(ErrorCode::CommonInvalidParam2, result.unwrap_err()); + assert_pool_not_exists(&name); + } + + #[test] + /* Error when creating a pool that already exists */ + fn config_already_exists() { + let name = test_pool_name(); + let (config, _file) = test_genesis_config(); + + let result = pool::create_pool_ledger_config(&name, Some(&config)).wait(); + assert_eq!((), result.unwrap()); + + let result = pool::create_pool_ledger_config(&name, Some(&config)).wait(); + assert_eq!(ErrorCode::PoolLedgerConfigAlreadyExistsError, result.unwrap_err()); + + assert_pool_exists(&name); + pool::delete_pool_ledger(&name).wait().unwrap(); + } + +} + +#[cfg(test)] +mod test_delete_config { + use super::*; + + use futures::future::Future; + + use utils::pool::{PoolList, create_default_pool}; + + const NON_EXISTENT_NAME: &str = "a_pool_name_which_does_not_exist"; + + #[inline] + pub fn assert_pool_exists(name: &str) { + assert!(PoolList::new().pool_exists(name)); + } + + #[inline] + pub fn assert_pool_not_exists(name: &str) { + assert!(! PoolList::new().pool_exists(name)); + } + + #[test] + /* Delete a pool_config. */ + fn delete_pool() { + let pool_name = create_default_pool(); + assert_pool_exists(&pool_name); + + let result = pool::delete_pool_ledger(&pool_name).wait(); + assert_eq!((), result.unwrap()); + + assert_pool_not_exists(&pool_name); + } + + #[test] + /* Error deleting non existent pool_config. */ + fn delete_pool_not_exist() { + let result = pool::delete_pool_ledger(NON_EXISTENT_NAME).wait(); + assert_eq!(ErrorCode::CommonIOError, result.unwrap_err()); + } + + #[test] + /* Error deleting an open pool_config. */ + fn delete_pool_open() { + let pool_name = create_default_pool(); + let config = json!({ + "refresh_on_open": false, + "auto_refresh_time": 0, + }).to_string(); + + pool::set_protocol_version(2).wait().unwrap(); + let pool_handle = pool::open_pool_ledger(&pool_name, Some(&config)).wait().unwrap(); + + let result = pool::delete_pool_ledger(&pool_name).wait(); + assert_eq!(ErrorCode::CommonInvalidState, result.unwrap_err()); + assert_pool_exists(&pool_name); + + pool::close_pool_ledger(pool_handle).wait().unwrap(); + pool::delete_pool_ledger(&pool_name).wait().unwrap(); + pool::set_protocol_version(1).wait().unwrap(); + } + +} + +#[cfg(test)] +mod test_set_protocol_version { + use super::*; + + use indy::ledger; + use serde_json; + + const VALID_VERSIONS: [usize; 2] = [1, 2]; + + fn assert_protocol_version_set(version: usize) { + let did = "5UBVMdSADMjGzuJMQwJ6yyzYV1krTcKRp6EqRAz8tiDP"; + let request = ledger::build_get_nym_request(Some(did), did).wait().unwrap(); + let request: serde_json::Value = serde_json::from_str(&request).unwrap(); + assert_eq!(json!(version), *request.get("protocolVersion").unwrap()); + } + + #[test] + /* Set all available protocol versions. */ + fn set_all_valid_versions() { + for &version in VALID_VERSIONS.into_iter() { + let result = pool::set_protocol_version(version).wait(); + assert_eq!((), result.unwrap()); + assert_protocol_version_set(version); + } + + pool::set_protocol_version(1).wait().unwrap(); + } + + #[test] + /* Error setting invalid protocol version. */ + fn set_invalid_versions() { + let result = pool::set_protocol_version(0).wait(); + assert_eq!(ErrorCode::PoolIncompatibleProtocolVersion, result.unwrap_err()); + assert_protocol_version_set(1); + + let next_protocol_version = *VALID_VERSIONS.last().unwrap() + 1; + let result = pool::set_protocol_version(next_protocol_version).wait(); + assert_eq!(ErrorCode::PoolIncompatibleProtocolVersion, result.unwrap_err()); + assert_protocol_version_set(1); + } + +} + +#[cfg(test)] +/* +The sync pool::list is already tested by the create tests. +There aren't tests for failure because I'm not sure how it would fail. +*/ +mod test_pool_list { + use super::*; + + use utils::pool::{PoolList, create_default_pool}; + + #[test] + fn list_pool() { + let name = create_default_pool(); + + let pool_json = pool::list_pools().wait().unwrap(); + assert!(PoolList::from_json(&pool_json).pool_exists(&name)); + + pool::delete_pool_ledger(&name).wait().unwrap(); + } + +} + +#[cfg(test)] +mod test_refresh_works { + use super::*; + + #[test] + pub fn refresh_pool_works() { + let wallet = utils::wallet::Wallet::new(); + let setup = Setup::new(&wallet, SetupConfig { + connect_to_pool: true, + num_trustees: 0, + num_nodes: 4, + num_users: 0, + }); + + indy::pool::refresh_pool_ledger(setup.pool_handle.unwrap()).wait().unwrap(); + } + +} diff --git a/wrappers/rust/tests/utils/b58.rs b/wrappers/rust/tests/utils/b58.rs new file mode 100644 index 00000000..7ec18238 --- /dev/null +++ b/wrappers/rust/tests/utils/b58.rs @@ -0,0 +1,35 @@ +extern crate bs58; + +use self::bs58::decode::{DecodeError}; + +pub trait FromBase58 { + fn from_base58(&self) -> Result, DecodeError>; + fn from_base58_check(&self) -> Result, DecodeError>; +} + +impl> FromBase58 for I { + fn from_base58(&self) -> Result, DecodeError> { + bs58::decode(self).into_vec() + } + + fn from_base58_check(&self) -> Result, DecodeError> { + bs58::decode(self).with_check(None).into_vec() + } +} + + +pub trait IntoBase58 { + fn into_base58(&self) -> String; + fn into_base58_check(&self) -> String; +} + + +impl> IntoBase58 for I { + fn into_base58(&self) -> String { + bs58::encode(self).into_string() + } + + fn into_base58_check(&self) -> String { + bs58::encode(self).with_check().into_string() + } +} \ No newline at end of file diff --git a/wrappers/rust/tests/utils/constants.rs b/wrappers/rust/tests/utils/constants.rs new file mode 100644 index 00000000..91323d6f --- /dev/null +++ b/wrappers/rust/tests/utils/constants.rs @@ -0,0 +1,18 @@ +use std::time::Duration; + +pub const DEFAULT_CREDENTIALS: &str = r#"{"key":"8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY", "key_derivation_method":"RAW"}"#; +pub const DID: &str = "8wZcEriaNLNKtteJvx7f8i"; +pub const DID_1: &str = "VsKV7grR1BUE29mG2Fm2kX"; +pub const DID_TRUSTEE: &str = "V4SGRU86Z58d6TV7PBUe6f"; +pub const EXPORT_KEY: &str = "export_key"; +pub const INVALID_HANDLE: i32 = 583741; +pub const METADATA: &str = "some_metadata"; +pub const MY1_SEED: &str = "00000000000000000000000000000My1"; +pub const PROTOCOL_VERSION: i32 = 2; +pub const SEED_1: &str = "00000000000000000000000000000My1"; +pub const TRUSTEE_SEED: &str = "000000000000000000000000Trustee1"; +pub const VERKEY_1: &str = "GjZWsBLgZCR18aL468JAT7w9CZRiBnpxUPPgyQxh4voa"; +pub const VERKEY_ABV_1: &str = "~HYwqs2vrTc8Tn4uBV7NBTe"; +pub const VERKEY_TRUSTEE: &str = "GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL"; +pub const VALID_TIMEOUT: Duration = Duration::from_secs(5); +pub const INVALID_TIMEOUT: Duration = Duration::from_micros(1); diff --git a/wrappers/rust/tests/utils/did.rs b/wrappers/rust/tests/utils/did.rs new file mode 100644 index 00000000..13b52e11 --- /dev/null +++ b/wrappers/rust/tests/utils/did.rs @@ -0,0 +1,111 @@ +extern crate futures; + +use self::futures::Future; + +use super::indy; + +use indy::ErrorCode; + +type DidAndVerKey = (String, String); + +#[derive(Clone, Copy)] +pub enum NymRole +{ + Trustee, + User, +} + +impl NymRole +{ + pub fn prepare(&self) -> Option<&str> + { + match self { + NymRole::Trustee => Some("TRUSTEE"), + NymRole::User => None, + } + } +} + +/** +Generate a did and send a nym request for it. +*/ +pub fn create_nym( + wallet_handle: i32, + pool_handle: i32, + did_trustee: &str, + role: NymRole +) -> Result { + let (did, verkey) = indy::did::create_and_store_my_did(wallet_handle, "{}").wait().unwrap(); + + let req_nym = indy::ledger::build_nym_request( + did_trustee, + &did, + Some(&verkey), + None, + role.prepare() + ).wait()?; + + indy::ledger::sign_and_submit_request(pool_handle, wallet_handle, &did_trustee, &req_nym).wait()?; + + Ok((did, verkey)) +} + +/** +Creates multiple dids and corresponding nym requests. +*/ +pub fn create_multiple_nym( + wallet_handle: i32, + pool_handle: i32, + did_trustee: &str, + n: u8, + role: NymRole +) -> Result, ErrorCode> { + let mut v: Vec<(String, String)> = Vec::new(); + for _ in 0..n { + let new_did = create_nym(wallet_handle, pool_handle, did_trustee, role)?; + v.push(new_did); + } + + Ok(v) +} + +/** +Create and store the initial dids of trustees. + +Includes the initial trustee. +*/ +pub fn initial_trustees(num_trustees: u8, wallet_handle: i32, pool_handle: i32) -> Result, ErrorCode> { + let first = initial_trustee(wallet_handle); + + let mut trustees = create_multiple_nym( + wallet_handle, + pool_handle, + &first.0, + num_trustees - 1, + NymRole::Trustee + )?; + trustees.insert(0, first); + + Ok(trustees) +} + +/** +Store the did of the intial trustee +*/ +pub fn initial_trustee(wallet_handle: i32) -> DidAndVerKey { + let first_json_seed = json!({ + "seed":"000000000000000000000000Trustee1" + }).to_string(); + + indy::did::create_and_store_my_did(wallet_handle, &first_json_seed).wait().unwrap() +} + +/** +Discard the verkey and return the did from a `Vec(trustees: &'a Vec) -> Vec<&'a str> { + trustees + .iter() + .map(|(ref did, _)| did.as_str()) + .collect() +} diff --git a/wrappers/rust/tests/utils/environment.rs b/wrappers/rust/tests/utils/environment.rs new file mode 100644 index 00000000..b8bc9d5e --- /dev/null +++ b/wrappers/rust/tests/utils/environment.rs @@ -0,0 +1,58 @@ +extern crate dirs; + +use std::env; +use std::path::PathBuf; + +#[cfg(test)] +pub fn test_pool_ip() -> String { + env::var("TEST_POOL_IP").unwrap_or("127.0.0.1".to_string()) +} + +pub fn pool_path(pool_name: &str) -> PathBuf { + let mut path = indy_home_path(); + path.push("pool"); + path.push(pool_name); + path +} + +#[cfg(not(any(target_os = "android", target_os = "ios")))] +pub fn indy_home_path() -> PathBuf { + let mut path = dirs::home_dir().unwrap(); + path.push(".indy_client"); + path +} + +#[cfg(target_os = "ios")] +pub fn indy_home_path() -> PathBuf { + let mut path = dirs::home_dir().unwrap(); + path.push("Documents/.indy_client"); + path +} + +#[cfg(target_os = "android")] +pub fn indy_home_path() -> PathBuf { + android_create_indy_client_dir(); + android_indy_client_dir_path() +} + +#[cfg(target_os = "android")] +pub mod android { + use std::fs; + + pub fn indy_client_dir_path() -> PathBuf { + let external_storage = env::var("EXTERNAL_STORAGE"); + let android_dir = match external_storage { + Ok (val) => val + "/.indy_client", + Err(err) => { + panic!("Failed to find external storage path {:?}", err) + } + }; + + PathBuf::from(android_dir) + } + + pub fn create_indy_client_dir() { + //Creates directory only if it is not present. + fs::create_dir_all(indy_client_dir_path().as_path()).unwrap(); + } +} diff --git a/wrappers/rust/tests/utils/file.rs b/wrappers/rust/tests/utils/file.rs new file mode 100644 index 00000000..5705506c --- /dev/null +++ b/wrappers/rust/tests/utils/file.rs @@ -0,0 +1,123 @@ +use std::env; +use std::fs; +use std::fs::{File}; +use std::io; +use std::path::{Path, PathBuf}; +use utils::rand; + +pub struct TempFile { + path: PathBuf, +} + +impl TempFile { + pub fn new(file_name: Option<&str>) -> io::Result { + let path = generate_temp_path(file_name, "TempFile_"); + + let _file = File::create(&path)?; + + Ok(TempFile { + path: path + }) + } +} + +impl AsRef for TempFile { + fn as_ref(&self) -> &Path { + self.path.as_ref() + } +} + +impl Drop for TempFile { + fn drop(&mut self) { + let _ = fs::remove_file(&self.path); + } +} + +pub struct TempDir { + path: PathBuf +} + +impl TempDir { + pub fn new(dir_name: Option<&str>) -> io::Result { + let path = generate_temp_path(dir_name, "TempDir_"); + + fs::create_dir(&path)?; + + Ok(TempDir { + path: path + }) + } +} + +impl AsRef for TempDir { + fn as_ref(&self) -> &Path { + self.path.as_ref() + } +} + +impl Drop for TempDir { + fn drop(&mut self) { + fs::remove_dir_all(&self.path).unwrap(); + } +} + +fn generate_temp_path(name: Option<&str>, prefix: &str) -> PathBuf { + let mut path = env::temp_dir(); + + if let Some(name) = name { + path.push(name); + } else { + let name = format!("{}{}", prefix, rand::random_string(12)); + path.push(name); + } + + path +} + + +#[cfg(test)] +mod test_temp_file { + use super::*; + + #[test] + fn temp_file() { + let name = "test_file.txt"; + let mut path = env::temp_dir(); + path.push(name); + + { + let _file = TempFile::new(Some(name)).unwrap(); + assert!(path.exists()); + } + + assert!(! path.exists()); + } + + #[test] + fn write_read_temp_file() { + const CONTENT: &str = "Writing to a temp file"; + + let file: TempFile = TempFile::new(None).unwrap(); + + fs::write(&file, CONTENT).unwrap(); + + let contents = fs::read(&file).unwrap(); + + assert_eq!(CONTENT.as_bytes(), contents.as_slice()); + } + + #[test] + fn temp_dir() { + let name = "test_dir"; + let mut path = env::temp_dir(); + path.push(name); + + { + let _dir = TempDir::new(Some(name)).unwrap(); + assert!(path.exists()); + } + + assert!(! path.exists()); + } + +} diff --git a/wrappers/rust/tests/utils/mod.rs b/wrappers/rust/tests/utils/mod.rs new file mode 100644 index 00000000..6503d6f4 --- /dev/null +++ b/wrappers/rust/tests/utils/mod.rs @@ -0,0 +1,31 @@ +#![allow(dead_code)] +/* +We allow dead code because this module is imported for every integration test. +It expects all code to be used in each integration test. +Without this, we are warned of all unused code in each integration test. +*/ + +extern crate indyrs as indy; + +pub mod b58; +pub mod constants; +pub mod did; +pub mod environment; +pub mod file; +pub mod pool; +pub mod rand; +pub mod setup; +pub mod wallet; + +#[allow(unused_macros)] +macro_rules! hashmap { + ($( $key: expr => $val: expr ),*) => { + { + let mut map = ::std::collections::HashMap::new(); + $( + map.insert($key, $val); + )* + map + } + } +} diff --git a/wrappers/rust/tests/utils/pool.rs b/wrappers/rust/tests/utils/pool.rs new file mode 100644 index 00000000..2e522196 --- /dev/null +++ b/wrappers/rust/tests/utils/pool.rs @@ -0,0 +1,137 @@ +extern crate futures; + +use super::environment; +use self::futures::Future; + +use byteorder::{LittleEndian, WriteBytesExt}; +use indy::ErrorCode; +use indy::pool; +use rmp_serde; +use serde_json; +use std::fs; +use std::io::Write; +use utils::rand::random_string; +use utils::file::TempFile; + + +pub fn create_genesis_txn_file_for_test_pool(nodes_count: Option) -> TempFile { + let nodes_count = nodes_count.unwrap_or(4); + let test_pool_ip = environment::test_pool_ip(); + + let node_txns = vec![ + format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip) + ]; + + + let txn_file_data = node_txns[0..(nodes_count as usize)].join("\n"); + + create_genesis_txn_file(&txn_file_data) +} + +pub fn create_genesis_txn_file(txn_file_data: &str) -> TempFile { + let txn_file = TempFile::new(None).unwrap(); + fs::write(&txn_file, txn_file_data).unwrap(); + txn_file +} + +pub fn test_genesis_config() -> (String, TempFile) { + let genesis_file = create_genesis_txn_file_for_test_pool(None); + let config = json!({"genesis_txn": genesis_file.as_ref()}).to_string(); + + (config, genesis_file) +} + +#[inline] +pub fn test_pool_name() -> String { + format!("TestPool{}", random_string(10)) +} + +pub fn create_default_pool() -> String { + let name = test_pool_name(); + let (config, _genesis_file) = test_genesis_config(); + + pool::create_pool_ledger_config(&name, Some(&config)).wait().unwrap(); + + name +} + +pub fn dump_correct_genesis_txns_to_cache(pool_name: &str) -> Result<(), ErrorCode> { + let test_pool_ip = environment::test_pool_ip(); + _dump_genesis_txns_to_cache(pool_name, &vec![ + format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"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"}}"#, test_pool_ip, test_pool_ip) + ] + ) +} + +pub fn dump_incorrect_genesis_txns_to_cache(pool_name: &str) -> Result<(), ErrorCode> { + let test_pool_ip = environment::test_pool_ip(); + _dump_genesis_txns_to_cache(pool_name, &vec![ + format!(r#"{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","client_ip":"{}","client_port":9702,"node_ip":"{}","node_port":9701,"services":["VALIDAT"]}},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"}},"metadata":{{"from":"Th7MpTaRZVRYnPiabds81Y"}},"type":"0"}},"txnMetadata":{{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"}},"ver":"1"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","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"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","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"}}"#, test_pool_ip, test_pool_ip), + format!(r#"{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","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"}}"#, test_pool_ip, test_pool_ip)] + ) +} + +fn _dump_genesis_txns_to_cache(pool_name: &str, node_txns: &Vec) -> Result<(), ErrorCode> { + let mut txn_file_path = environment::pool_path(pool_name); + txn_file_path.push("stored"); + txn_file_path.set_extension("btxn"); + + if !txn_file_path.parent().unwrap().exists() { + fs::DirBuilder::new() + .recursive(true) + .create(txn_file_path.parent().unwrap()).unwrap(); + } + + let txns = node_txns.iter().map(|txn| { + let txn_json = serde_json::from_str::(txn).map_err(|_| ErrorCode::CommonInvalidStructure)?; + rmp_serde::to_vec_named(&txn_json).map_err(|_| ErrorCode::CommonInvalidStructure) + }).fold(Ok(vec![]), |acc, next| { + match (acc, next) { + (Err(e), _) | (_, Err(e)) => Err(e), + (Ok(mut acc), Ok(next)) => { + acc.push(next); + Ok(acc) + } + } + })?; + + let mut f = fs::File::create(&txn_file_path).map_err(|_| ErrorCode::CommonIOError)?; + txns.iter().for_each(|vec| { + f.write_u64::(vec.len() as u64).unwrap(); + f.write_all(vec).unwrap(); + }); + + Ok(()) +} + + +#[derive(Deserialize)] +struct PoolItem { + pool: String +} + +#[derive(Deserialize)] +pub struct PoolList(Vec); + +impl PoolList { + pub fn new() -> Self { + let json_pools = pool::list_pools().wait().unwrap(); + Self::from_json(&json_pools) + } + + pub fn from_json(json: &str) -> Self { + serde_json::from_str(&json).unwrap() + } + + pub fn pool_exists(&self, name: &str) -> bool { + self.0.iter().find(|p| &p.pool == name).is_some() + } +} \ No newline at end of file diff --git a/wrappers/rust/tests/utils/rand.rs b/wrappers/rust/tests/utils/rand.rs new file mode 100644 index 00000000..ed770041 --- /dev/null +++ b/wrappers/rust/tests/utils/rand.rs @@ -0,0 +1,15 @@ +//! Contains functions for random data generation + +extern crate rand; +use self::rand::distributions::{Distribution, Alphanumeric}; + +/** + Builds a string of random numbers of the inputted length +*/ +pub fn random_string(n: usize) -> String { + let mut range = rand::thread_rng(); + Alphanumeric + .sample_iter(&mut range) + .take(n) + .collect() +} \ No newline at end of file diff --git a/wrappers/rust/tests/utils/setup.rs b/wrappers/rust/tests/utils/setup.rs new file mode 100644 index 00000000..5edcbab6 --- /dev/null +++ b/wrappers/rust/tests/utils/setup.rs @@ -0,0 +1,195 @@ +extern crate futures; + +use self::futures::future::Future; + +use super::indy; + +use std::ops::{Index, IndexMut}; +use std::iter::FromIterator; +use utils::constants::PROTOCOL_VERSION; +use utils::wallet::Wallet; +use utils::pool; +use utils::did; + + +pub struct SetupConfig +{ + pub connect_to_pool: bool, + pub num_trustees: u8, + pub num_users: u8, + pub num_nodes: u8, +} + + +pub struct Setup<'a> +{ + pub node_count: u8, + pub pool_handle: Option, + pub pool_name: String, + pub trustees: Option, + pub users: Option, + wallet: &'a Wallet, +} + +impl<'a> Setup<'a> +{ + + /** + Create a new Setup. + + Configures the pool, generates trustees and users, abd generate addresses + according to the [`SetupConfig`]. + + [`SetupConfig`]: SetupConfig + */ + pub fn new(wallet: &Wallet, config: SetupConfig) -> Setup + { + let (pool_name, pool_handle) = Setup::setup_pool(config.connect_to_pool); + let mut trustees = None; + let mut users = None; + + match pool_handle { + Some(pool_handle) => { + if config.num_trustees > 0 { + trustees = Some(Setup::create_trustees(wallet, pool_handle, config.num_trustees)); + + { + let trustee_dids = trustees.as_ref().unwrap().dids(); + users = Some(Setup::create_users(wallet, pool_handle, trustee_dids[0], config.num_users)); + }; + } + } + _ => () + } + + Setup { + node_count: config.num_nodes, + pool_handle, + pool_name, + trustees, + users, + wallet, + } + } + + fn setup_pool(connect_to_pool: bool) -> (String, Option) + { + indy::pool::set_protocol_version(PROTOCOL_VERSION as usize).wait().unwrap(); + + let pool_name = pool::create_default_pool(); + + if connect_to_pool { + let pool_handle = indy::pool::open_pool_ledger(&pool_name, None).wait().unwrap(); + (pool_name, Some(pool_handle)) + } else { + (pool_name, None) + } + } + + fn create_users(wallet: &Wallet, pool_handle: i32, did_trustee: &str, num_users: u8) -> Entities + { + did::create_multiple_nym(wallet.handle, pool_handle, did_trustee, num_users, did::NymRole::User) + .unwrap() + .into_iter() + .map(Entity::new) + .collect() + } + + fn create_trustees(wallet: &Wallet, pool_handle: i32, num_trustees: u8) -> Entities + { + did::initial_trustees(num_trustees, wallet.handle, pool_handle) + .unwrap() + .into_iter() + .map(Entity::new) + .collect() + } +} + +impl<'a> Drop for Setup<'a> { + fn drop(&mut self) { + self.pool_handle.map(|handle| { + indy::pool::close_pool_ledger(handle).wait().unwrap() + }); + indy::pool::delete_pool_ledger(self.pool_name.as_str()).wait().unwrap(); + } +} + +/** +An entity with a did and a verkey. +*/ +pub struct Entity +{ + pub did: String, + pub verkey: String, +} + +impl Entity { + fn new((did, verkey): (String, String)) -> Self + { + Entity { + did, + verkey + } + } +} + + +/** +Contain a vector of [`Entity`]. + +You can access elements like an array. +``` +use utils::setup::{Entities, Entity}; +let entities = Entities(vec![ + Entity::new((String::from("V4SGRU86Z58d6TV7PBUe6f"), String::from("4TFcJS5FBo42EModbbaeYXHFoQAnmZKWrWKt8yWTB6Bq"))) + Entity::new((String::from("7LQt1bEbk5zB6gaFbEPDzB"), String::from("GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL"))) + Entity::new((String::from("Ln7kZXHFxZg5689JZciJMJ"), String::from("BnDcRVr6ZUkrNmxB2pmUbKVeZSuSnBecLFJNteS9iiM4"))) +]); + +assert_eq!(entities[1].did, "7LQt1bEbk5zB6gaFbEPDzB") +``` + +[`Entity`]: Entity +*/ +pub struct Entities(Vec); + +impl Entities { + + /** + The dids of the entities without the verkey. + */ + pub fn dids(&self) -> Vec<&str> { + self.0 + .iter() + .map(|trust| trust.did.as_str()) + .collect() + } +} + +impl Index for Entities +{ + type Output = Entity; + + fn index(&self, i: usize) -> &Entity { + &self.0[i] + } +} + +impl IndexMut for Entities +{ + fn index_mut(&mut self, i: usize) -> & mut Entity { + &mut self.0[i] + } +} + +impl FromIterator for Entities +{ + fn from_iter>(iter: I) -> Entities { + let mut v = Vec::new(); + for entity in iter { + v.push(entity); + } + + Entities(v) + } +} diff --git a/wrappers/rust/tests/utils/wallet.rs b/wrappers/rust/tests/utils/wallet.rs new file mode 100644 index 00000000..66dcfc98 --- /dev/null +++ b/wrappers/rust/tests/utils/wallet.rs @@ -0,0 +1,88 @@ +extern crate futures; + +use self::futures::Future; +use super::indy; +use indy::ErrorCode; +use utils::rand::random_string; + +static USEFUL_CREDENTIALS : &'static str = r#"{"key":"8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY", "key_derivation_method":"RAW"}"#; + +/** +A test wallet that deletees itself when it leaves scope. + +Use by calling `let wallet = Wallet::new();` and pass the `wallet.handle`. + +``` +use utils::wallet; +// The wallet is opened and created. +let wallet_1 = Wallet::new(); +{ + let wallet_2 = Wallet::new(); + // we have the wallet and wallet handle. + assert!(wallet.handle > 0); +} +// Now wallet_2 is out of scope, it closes and deletes itself. +assert!(wallet.handle > 0); +``` + +*/ +pub struct Wallet { + name: String, + pub handle: i32, +} + +impl Wallet { + /* constructors */ + pub fn new() -> Wallet { + let wallet_name : String = random_string(20); + let mut wallet = Wallet { name : wallet_name , handle: -1 }; + wallet.create().unwrap(); + wallet.open().unwrap(); + + return wallet; + } + + pub fn from_name(name: &str) -> Wallet { + let mut wallet = Wallet { name: name.to_string(), handle: -1 }; + wallet.create().unwrap(); + wallet.open().unwrap(); + + return wallet; + } + + /* private static method to help create config that is passed to wallet functions */ + fn create_wallet_config(wallet_name: &str) -> String { + let config = json!({ "id" : wallet_name.to_string() }).to_string(); + return config.to_string(); + } + + /* private instance methods for open/create/etc...*/ + + fn open(&mut self) -> Result { + let config : String = Wallet::create_wallet_config(&self.name); + let handle = indy::wallet::open_wallet(&config, USEFUL_CREDENTIALS).wait()?; + self.handle = handle; + return Ok(handle); + } + + fn create(&self) -> Result<(), ErrorCode> { + let config = Wallet::create_wallet_config(&self.name); + return indy::wallet::create_wallet(&config, USEFUL_CREDENTIALS).wait() + } + + fn close(&self) -> Result<(), ErrorCode> { + indy::wallet::close_wallet(self.handle).wait() + } + + fn delete(&self) -> Result<(), ErrorCode> { + let config : String = Wallet::create_wallet_config(&self.name); + return indy::wallet::delete_wallet(&config, USEFUL_CREDENTIALS).wait() + } +} + +impl Drop for Wallet { + fn drop(&mut self) { + self.close().unwrap(); + self.delete().unwrap(); + } +} diff --git a/wrappers/rust/tests/wallet.rs b/wrappers/rust/tests/wallet.rs new file mode 100644 index 00000000..5742e626 --- /dev/null +++ b/wrappers/rust/tests/wallet.rs @@ -0,0 +1,616 @@ +extern crate indyrs as indy; +#[macro_use] extern crate serde_json; +#[macro_use] extern crate serde_derive; +extern crate rmp_serde; +extern crate byteorder; +extern crate futures; + +use indy::did; +use indy::wallet; + +use indy::ErrorCode; + +use std::path::{Path, PathBuf}; + +mod utils; + +use utils::constants::{DEFAULT_CREDENTIALS, INVALID_HANDLE, METADATA}; +use utils::file::{TempDir, TempFile}; +use utils::rand; +#[allow(unused_imports)] +use futures::Future; + +const EXPORT_KEY: &str = "TheScythesHangInTheAppleTrees"; + + +mod wallet_config { + use super::*; + + #[inline] + pub fn new() -> String { + json!({ + "id": rand::random_string(20) + }).to_string() + } + + #[inline] + pub fn with_storage(storage: &str) -> String { + json!({ + "id": rand::random_string(20), + "storage_type": storage, + }).to_string() + } + + #[inline] + pub fn with_custom_path>(path: P) -> String { + json!({ + "id": rand::random_string(20), + "storage_type": "default", + "storage_config": { + "path": path.as_ref().to_str() + } + }).to_string() + } + + pub mod export { + use super::*; + + #[inline] + pub fn new>(path: P, key: &str) -> String { + json!({ + "path": path.as_ref(), + "key": key + }).to_string() + } + + pub fn with_defaults() -> (String, PathBuf, TempDir) { + let dir = TempDir::new(None).unwrap(); + let path = dir.as_ref().join("wallet_export"); + let config = wallet_config::export::new(&path, EXPORT_KEY); + + (config, path, dir) + } + } +} + + + +#[cfg(test)] +mod test_wallet_register { + // Future work +} + +#[cfg(test)] +mod test_wallet_create { + use super::*; + const CREDENTIALS: &str = r#"{"key":"9DXvkIMD7iSgD&RT$XYjHo0t"}"#; + use futures::Future; + + #[test] + fn create_default_wallet() { + let config = wallet_config::with_storage("default"); + + let result = wallet::create_wallet(&config, CREDENTIALS).wait(); + + assert_eq!((), result.unwrap()); + + wallet::delete_wallet(&config, CREDENTIALS).wait().unwrap(); + } + + #[test] + fn create_default_wallet_custom_path() { + let dir = TempDir::new(None).unwrap(); + let config = wallet_config::with_custom_path(&dir); + + let result = wallet::create_wallet(&config, CREDENTIALS).wait(); + + assert_eq!((), result.unwrap()); + + wallet::delete_wallet(&config, CREDENTIALS).wait().unwrap(); + } + + // #[test] + // fn create_wallet_custom_storage_type() { + // unimplemented!(); + // } + + #[test] + fn create_wallet_unknown_storage_type() { + let config = wallet_config::with_storage("unknown"); + + let result = wallet::create_wallet(&config, CREDENTIALS).wait(); + + assert_eq!(ErrorCode::WalletUnknownTypeError, result.unwrap_err()); + } + + #[test] + fn create_wallet_empty_storage_type() { + let config = wallet_config::new(); + + let result = wallet::create_wallet(&config, CREDENTIALS).wait(); + + assert_eq!((), result.unwrap()); + + wallet::delete_wallet(&config, CREDENTIALS).wait().unwrap(); + } + + #[test] + fn create_wallet_without_key() { + let config = wallet_config::new(); + let credentials = "{}"; + + let result = wallet::create_wallet(&config, credentials).wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + } + + #[test] + fn create_wallet_without_encryption() { + let config = wallet_config::new(); + let credentials = json!({"key": ""}).to_string(); + + let result = wallet::create_wallet(&config, &credentials).wait(); + + assert_eq!((), result.unwrap()); + + wallet::delete_wallet(&config, &credentials).wait().unwrap(); + } +} + + +#[cfg(test)] +mod test_wallet_delete { + use super::*; + use futures::Future; + + #[inline] + fn assert_wallet_deleted(config: &str, credentials: &str) { + let result = wallet::open_wallet(config, credentials).wait(); + assert_eq!(ErrorCode::WalletNotFoundError, result.unwrap_err()); + } + + #[test] + fn delete_wallet() { + let config = wallet_config::new(); + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait(); + + assert_eq!((), result.unwrap()); + assert_wallet_deleted(&config, DEFAULT_CREDENTIALS); + } + + #[test] + fn delete_wallet_custom_path() { + let dir = TempDir::new(None).unwrap(); + let config = wallet_config::with_custom_path(&dir); + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait(); + + assert_eq!((), result.unwrap()); + assert_wallet_deleted(&config, DEFAULT_CREDENTIALS); + } + + #[test] + fn delete_wallet_closed() { + let config = wallet_config::new(); + + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + let handle = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + wallet::close_wallet(handle).wait().unwrap(); + + let result = wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait(); + + assert_eq!((), result.unwrap()); + assert_wallet_deleted(&config, DEFAULT_CREDENTIALS); + } + + #[test] + fn delete_wallet_opened() { + let config = wallet_config::new(); + + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + let handle = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait(); + + assert_eq!(ErrorCode::CommonInvalidState, result.unwrap_err()); + + wallet::close_wallet(handle).wait().unwrap(); + wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + // #[test] + // fn delete_registered_wallet() { + // unimplemented!(); + // } + + #[test] + fn delete_wallet_repeated_command() { + let config = wallet_config::new(); + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait(); + + assert_eq!(ErrorCode::WalletNotFoundError, result.unwrap_err()); + } + + #[test] + fn delete_wallet_invalid_credentials() { + let config = wallet_config::new(); + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::delete_wallet(&config, r#"{"key": "badkey"}"#).wait(); + + assert_eq!(ErrorCode::WalletAccessFailed, result.unwrap_err()); + + wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + #[test] + fn delete_wallet_uncreated() { + let config = wallet_config::new(); + + let result = wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait(); + + assert_eq!(ErrorCode::WalletNotFoundError, result.unwrap_err()); + } + +} + +#[cfg(test)] +mod test_wallet_open { + use super::*; + + #[test] + fn open_wallet() { + let config = wallet_config::new(); + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let handle = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + wallet::close_wallet(handle).wait().unwrap(); + wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + #[test] + fn open_wallet_custom_path() { + let dir = TempDir::new(None).unwrap(); + let config = wallet_config::with_custom_path(&dir); + + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let handle = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + wallet::close_wallet(handle).wait().unwrap(); + wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + // #[test] + // fn open_wallet_registered() { + // unimplemented!(); + // } + + #[test] + fn open_wallet_not_created() { + let config = wallet_config::new(); + + let result = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait(); + + assert_eq!(ErrorCode::WalletNotFoundError, result.unwrap_err()); + } + + #[test] + fn open_wallet_repeated_command() { + let config = wallet_config::new(); + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let handle = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait(); + + assert_eq!(ErrorCode::WalletAlreadyOpenedError, result.unwrap_err()); + + wallet::close_wallet(handle).wait().unwrap(); + wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + #[test] + fn open_wallet_two_same_time() { + let config1 = wallet_config::new(); + let config2 = wallet_config::new(); + + wallet::create_wallet(&config1, DEFAULT_CREDENTIALS).wait().unwrap(); + wallet::create_wallet(&config2, DEFAULT_CREDENTIALS).wait().unwrap(); + + let handle1 = wallet::open_wallet(&config1, DEFAULT_CREDENTIALS).wait().unwrap(); + let handle2 = wallet::open_wallet(&config2, DEFAULT_CREDENTIALS).wait().unwrap(); + + wallet::close_wallet(handle1).wait().unwrap(); + wallet::close_wallet(handle2).wait().unwrap(); + wallet::delete_wallet(&config1, DEFAULT_CREDENTIALS).wait().unwrap(); + wallet::delete_wallet(&config2, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + #[test] + fn open_wallet_invalid_credentials() { + let config = wallet_config::new(); + let credentials = json!({"key": "xylophone rat"}).to_string(); + + wallet::create_wallet(&config, &credentials).wait().unwrap(); + + let result = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait(); + + assert_eq!(ErrorCode::WalletAccessFailed, result.unwrap_err()); + + wallet::delete_wallet(&config, &credentials).wait().unwrap(); + } + + #[test] + fn open_wallet_change_credentials() { + let config = wallet_config::new(); + let credentials1 = json!({"key": "key_1"}).to_string(); + let credentials2 = json!({"key": "key_2"}).to_string(); + let rekey = json!({"key": "key_1", "rekey": "key_2"}).to_string(); + + wallet::create_wallet(&config, &credentials1).wait().unwrap(); + + let handle = wallet::open_wallet(&config, &rekey).wait().unwrap(); + wallet::close_wallet(handle).wait().unwrap(); + + let result = wallet::open_wallet(&config, &credentials1).wait(); + assert_eq!(ErrorCode::WalletAccessFailed, result.unwrap_err()); + + let handle = wallet::open_wallet(&config, &credentials2).wait().unwrap(); + wallet::close_wallet(handle).wait().unwrap(); + + wallet::delete_wallet(&config, &credentials2).wait().unwrap(); + } + + #[test] + fn open_wallet_invalid_config() { + let config = wallet_config::new(); + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::open_wallet("{}", DEFAULT_CREDENTIALS).wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + + wallet::delete_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + } +} + +#[cfg(test)] +mod test_wallet_close { + use super::*; + + #[test] + fn close_wallet() { + let config = wallet_config::new(); + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + let handle = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::close_wallet(handle).wait(); + + assert_eq!((), result.unwrap()); + } + + // #[test] + // fn close_wallet_registered() { + // unimplemented!(); + // } + + #[test] + fn close_wallet_invalid_handle() { + let result = wallet::close_wallet(INVALID_HANDLE).wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } + + #[test] + fn close_wallet_duplicate_command() { + let config = wallet_config::new(); + wallet::create_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + let handle = wallet::open_wallet(&config, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::close_wallet(handle).wait(); + + assert_eq!((), result.unwrap()); + + let result = wallet::close_wallet(handle).wait(); + + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + } + +} + +#[cfg(test)] +mod test_wallet_export { + use super::*; + + #[test] + fn export_wallet() { + let config_wallet = wallet_config::new(); + let (config_export, path, _dir) = wallet_config::export::with_defaults(); + + wallet::create_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + let handle = wallet::open_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::export_wallet(handle, &config_export).wait(); + + assert_eq!((), result.unwrap()); + + assert!(path.exists()); + + wallet::close_wallet(handle).wait().unwrap(); + wallet::delete_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + #[test] + fn export_wallet_path_already_exists() { + let config_wallet = wallet_config::new(); + let file = TempFile::new(None).unwrap(); + let config_export = wallet_config::export::new(&file, EXPORT_KEY); + + wallet::create_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + let handle = wallet::open_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::export_wallet(handle, &config_export).wait(); + + assert_eq!(ErrorCode::CommonIOError, result.unwrap_err()); + + wallet::close_wallet(handle).wait().unwrap(); + wallet::delete_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + #[test] + fn export_wallet_invalid_config() { + let config_wallet = wallet_config::new(); + wallet::create_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + let handle = wallet::open_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::export_wallet(handle, "{}").wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + + wallet::close_wallet(handle).wait().unwrap(); + wallet::delete_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + #[test] + fn export_wallet_invalid_handle() { + let (config_export, path, _dir) = wallet_config::export::with_defaults(); + + let result = wallet::export_wallet(INVALID_HANDLE, &config_export).wait(); + assert_eq!(ErrorCode::WalletInvalidHandle, result.unwrap_err()); + assert!(!path.exists()); + } +} + +#[cfg(test)] +mod test_wallet_import { + use super::*; + + fn setup_exported_wallet( + config_wallet: &str, + credentials: &str, + config_export: &str + ) -> (String, String) { + wallet::create_wallet(&config_wallet, credentials).wait().unwrap(); + let handle = wallet::open_wallet(&config_wallet, credentials).wait().unwrap(); + + let (did, _) = did::create_and_store_my_did(handle, "{}").wait().unwrap(); + did::set_did_metadata(handle, &did, METADATA).wait().unwrap(); + let did_with_metadata = did::get_did_metadata(handle, &did).wait().unwrap(); + + wallet::export_wallet(handle, &config_export).wait().unwrap(); + + wallet::close_wallet(handle).wait().unwrap(); + wallet::delete_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + + (did, did_with_metadata) + } + + #[test] + fn import_wallet() { + let config_wallet = wallet_config::new(); + let (config_export, _path, _dir) = wallet_config::export::with_defaults(); + let (did, did_with_metadata) = setup_exported_wallet( + &config_wallet, + DEFAULT_CREDENTIALS, + &config_export + ); + + let result = wallet::import_wallet( + &config_wallet, + DEFAULT_CREDENTIALS, + &config_export + ).wait(); + + assert_eq!((), result.unwrap()); + + let handle = wallet::open_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + + let imported_did_with_metadata = did::get_did_metadata(handle, &did).wait().unwrap(); + + assert_eq!(did_with_metadata, imported_did_with_metadata); + + wallet::close_wallet(handle).wait().unwrap(); + wallet::delete_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + } + + #[test] + fn import_wallet_invalid_path() { + let config_wallet = wallet_config::new(); + let non_existant_path = Path::new("PlaceWithoutWindOrWords"); + let config_export = wallet_config::export::new( + &non_existant_path, + EXPORT_KEY + ); + + let result = wallet::import_wallet( + &config_wallet, + DEFAULT_CREDENTIALS, + &config_export + ).wait(); + + assert_eq!(ErrorCode::CommonIOError, result.unwrap_err()); + + let result = wallet::open_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait(); + assert_eq!(ErrorCode::WalletNotFoundError, result.unwrap_err()); + } + + #[test] + fn import_wallet_invalid_config() { + let config_wallet = wallet_config::new(); + + let result = wallet::import_wallet(&config_wallet, DEFAULT_CREDENTIALS, "{}").wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + } + + #[test] + fn import_wallet_invalid_key() { + let config_wallet = wallet_config::new(); + let (config_export, path, _dir) = wallet_config::export::with_defaults(); + setup_exported_wallet( + &config_wallet, + DEFAULT_CREDENTIALS, + &config_export + ); + + let config_import = wallet_config::export::new(path, "bad_key"); + + let result = wallet::import_wallet( + &config_wallet, + DEFAULT_CREDENTIALS, + &config_import + ).wait(); + + assert_eq!(ErrorCode::CommonInvalidStructure, result.unwrap_err()); + } + + #[test] + fn import_wallet_duplicate_name() { + let config_wallet = wallet_config::new(); + let (config_export, _path, _dir) = wallet_config::export::with_defaults(); + setup_exported_wallet( + &config_wallet, + DEFAULT_CREDENTIALS, + &config_export + ); + + wallet::create_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + + let result = wallet::import_wallet( + &config_wallet, + DEFAULT_CREDENTIALS, + &config_export + ).wait(); + + assert_eq!(ErrorCode::WalletAlreadyExistsError, result.unwrap_err()); + + wallet::delete_wallet(&config_wallet, DEFAULT_CREDENTIALS).wait().unwrap(); + } +}