├── .github └── workflows │ ├── release.yml │ └── verify.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── Specs └── DidcommSDK │ ├── 0.3.1 │ └── DidcommSDK.podspec │ ├── 0.3.2 │ └── DidcommSDK.podspec │ ├── 0.3.3 │ └── DidcommSDK.podspec │ └── 0.3.4 │ └── DidcommSDK.podspec ├── benches ├── pack_encrypted.rs └── pack_signed.rs ├── docs └── release.md ├── examples ├── advanced_params.rs ├── attachments.rs ├── basic.rs ├── rotate_did.rs └── routing.rs ├── renovate.json ├── src ├── algorithms.rs ├── did │ ├── did_doc.rs │ ├── did_resolver.rs │ ├── mod.rs │ └── resolvers │ │ ├── example.rs │ │ ├── mock.rs │ │ └── mod.rs ├── error.rs ├── jwe │ ├── decrypt.rs │ ├── encrypt.rs │ ├── envelope.rs │ ├── mod.rs │ └── parse.rs ├── jwk.rs ├── jws │ ├── envelope.rs │ ├── mod.rs │ ├── parse.rs │ ├── sign.rs │ └── verify.rs ├── lib.rs ├── message │ ├── attachment.rs │ ├── from_prior │ │ ├── mod.rs │ │ ├── pack.rs │ │ └── unpack.rs │ ├── message.rs │ ├── mod.rs │ ├── pack_encrypted │ │ ├── anoncrypt.rs │ │ ├── authcrypt.rs │ │ └── mod.rs │ ├── pack_plaintext.rs │ ├── pack_signed.rs │ └── unpack │ │ ├── anoncrypt.rs │ │ ├── authcrypt.rs │ │ ├── mod.rs │ │ ├── plaintext.rs │ │ └── sign.rs ├── protocols │ ├── mod.rs │ └── routing │ │ ├── forward.rs │ │ └── mod.rs ├── secrets │ ├── mod.rs │ └── resolvers │ │ ├── example.rs │ │ └── mod.rs ├── test_vectors │ ├── common.rs │ ├── did_doc │ │ ├── alice.rs │ │ ├── bob.rs │ │ ├── charlie.rs │ │ ├── mediator1.rs │ │ ├── mediator2.rs │ │ ├── mediator3.rs │ │ └── mod.rs │ ├── encrypted.rs │ ├── from_prior.rs │ ├── from_prior_jwt.rs │ ├── message.rs │ ├── mod.rs │ ├── plaintext.rs │ ├── secrets │ │ ├── alice.rs │ │ ├── bob.rs │ │ ├── charlie.rs │ │ ├── charlie_rotated_to_alice.rs │ │ ├── mediator1.rs │ │ ├── mediator2.rs │ │ ├── mediator3.rs │ │ └── mod.rs │ └── signed.rs └── utils │ ├── crypto.rs │ ├── did.rs │ ├── mod.rs │ └── serde.rs ├── uniffi ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs └── src │ ├── common.rs │ ├── did │ ├── did_resolver.rs │ ├── did_resolver_adapter.rs │ ├── mod.rs │ └── resolvers │ │ ├── example.rs │ │ └── mod.rs │ ├── didcomm.udl │ ├── didcomm │ ├── from_prior.rs │ ├── mod.rs │ ├── pack_encrypted.rs │ ├── pack_plaintext.rs │ ├── pack_signed.rs │ ├── protocols │ │ ├── mod.rs │ │ └── routing │ │ │ └── mod.rs │ └── unpack.rs │ ├── lib.rs │ ├── secrets │ ├── mod.rs │ ├── resolvers │ │ ├── example.rs │ │ └── mod.rs │ ├── secrets_resolver.rs │ └── secrets_resolver_adapter.rs │ └── test_helper.rs ├── wasm ├── .gitignore ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── demo │ ├── .gitignore │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── advanced-params.ts │ │ ├── attachments.ts │ │ ├── main.ts │ │ └── test-vectors.ts │ └── tslint.json ├── src │ ├── did │ │ ├── did_doc.rs │ │ ├── did_resolver.rs │ │ └── mod.rs │ ├── error.rs │ ├── lib.rs │ ├── message │ │ ├── from_prior │ │ │ ├── mod.rs │ │ │ ├── pack.rs │ │ │ └── unpack.rs │ │ ├── mod.rs │ │ ├── pack_encrypted.rs │ │ ├── pack_plaintext.rs │ │ ├── pack_signed.rs │ │ ├── protocols │ │ │ ├── mod.rs │ │ │ └── routing │ │ │ │ └── mod.rs │ │ └── unpack.rs │ ├── secrets │ │ ├── mod.rs │ │ ├── secret.rs │ │ └── secrets_resolver.rs │ └── utils.rs └── tests-js │ ├── .gitignore │ ├── .prettierrc.json │ ├── jest-puppeteer.config.js │ ├── jest.config.js │ ├── jest.config.puppeteer.js │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── forward │ │ ├── try-parse-forward.test.ts │ │ └── wrap-in-forward.test.ts │ ├── from_prior │ │ ├── new.test.ts │ │ ├── pack.test.ts │ │ └── unpack.test.ts │ ├── message │ │ ├── errors.test.ts │ │ ├── new.test.ts │ │ ├── pack-encrypted.anoncrypt.test.ts │ │ ├── pack-encrypted.authcrypt.test.ts │ │ ├── pack-plaintext.test.ts │ │ ├── pack-signed.test.ts │ │ └── unpack.test.ts │ └── test-vectors │ │ ├── common.ts │ │ ├── did_doc │ │ ├── alice.ts │ │ ├── bob.ts │ │ ├── charlie.ts │ │ └── index.ts │ │ ├── did_resolver.ts │ │ ├── from_prior.ts │ │ ├── from_prior_jwt.ts │ │ ├── index.ts │ │ ├── message.ts │ │ ├── plaintext.ts │ │ ├── secrets │ │ ├── alice.ts │ │ ├── bob.ts │ │ ├── charlie.ts │ │ ├── charlie_rotated_to_alice.ts │ │ └── index.ts │ │ └── secrets_resolver.ts │ └── tslint.json └── wrappers └── swift ├── README.md ├── didcomm.swiftdoc ├── didcomm.swiftsourceinfo ├── didcomm ├── didcomm.swift ├── didcomm.swiftmodule ├── didcommFFI.h ├── didcommFFI.modulemap └── libdidcomm.dylib └── examples ├── DidcommExampleiOS ├── DidcommExampleiOS.xcodeproj │ └── project.pbxproj ├── DidcommExampleiOS │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Constants.swift │ ├── Info.plist │ └── ViewController.swift ├── Podfile └── Podfile.lock ├── README.md └── base.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | 13 | # Added by cargo 14 | 15 | /target 16 | 17 | 18 | # Added by cargo 19 | # 20 | # already existing elements were commented out 21 | 22 | #/target 23 | #Cargo.lock 24 | # 25 | 26 | # vim 27 | *.swp 28 | 29 | .idea 30 | 31 | # Mac OS X Finder 32 | .DS_Store 33 | 34 | # Xcode 35 | xcuserdata/ 36 | project.xcworkspace/ 37 | DerivedData/ 38 | 39 | # Cocoapods 40 | Pods/ 41 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [[bench]] 2 | name = 'pack_signed' 3 | harness = false 4 | 5 | [[bench]] 6 | name = 'pack_encrypted' 7 | harness = false 8 | 9 | [[example]] 10 | name = 'attachments' 11 | 12 | [[example]] 13 | name = 'advanced_params' 14 | 15 | [[example]] 16 | name = 'basic' 17 | 18 | [[example]] 19 | name = 'rotate_did' 20 | 21 | [[example]] 22 | name = 'routing' 23 | 24 | [package] 25 | name = 'didcomm' 26 | version = '0.4.1' 27 | authors = ['Vyacheslav Gudkov '] 28 | edition = '2018' 29 | description = 'DIDComm for Rust' 30 | license = 'Apache-2.0' 31 | repository = 'https://github.com/sicpa-dlab/didcomm-rust' 32 | readme = 'README.md' 33 | 34 | [dependencies] 35 | anyhow = '1.0' 36 | base64 = '0.13' 37 | async-trait = '0.1' 38 | thiserror = '1.0' 39 | serde_json = '1.0' 40 | serde-enum-str = '0.1' 41 | sha2 = '0.9' 42 | bs58 = "0.4.0" 43 | varint = "0.9.0" 44 | lazy_static = { version = "1.4.0", optional = true } 45 | 46 | [dependencies.serde] 47 | version = '1.0' 48 | features = ['derive'] 49 | 50 | [dependencies.askar-crypto] 51 | version = '0.2' 52 | features = ['std'] 53 | git = 'https://github.com/hyperledger/aries-askar' 54 | rev = '4f29d43d584c4a1f1f982c4511824421aeccd2db' 55 | 56 | [dependencies.uuid] 57 | version = "0.8" 58 | features = ["v4"] 59 | 60 | [dev-dependencies] 61 | lazy_static = '1.4.0' 62 | 63 | [dev-dependencies.tokio] 64 | version = '1.9' 65 | features = [ 66 | 'rt', 67 | 'macros', 68 | ] 69 | 70 | [dev-dependencies.getrandom] 71 | version = '0.2' 72 | features = ['js'] 73 | 74 | [dev-dependencies.criterion] 75 | version = '0.3' 76 | features = ['async_futures'] 77 | 78 | [features] 79 | uniffi = [] 80 | testvectors = ["lazy_static"] 81 | -------------------------------------------------------------------------------- /Specs/DidcommSDK/0.3.1/DidcommSDK.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | 3 | spec.name = "DidcommSDK" 4 | spec.version = "0.3.1" 5 | spec.summary = "Didcomm v2 created from rust." 6 | 7 | spec.description = "Didcomm v2 created from rust. UNIFFI was used to convert from rust to Swift." 8 | spec.homepage = "https://github.com/sicpa-dlab/didcomm-rust" 9 | 10 | spec.license = { :type => 'Apache License 2.0', :file => 'LICENSE.txt' } 11 | 12 | spec.authors = { "Sicpa-Dlab" => "dlab@sicpa.com" } 13 | spec.platforms = { :ios => "10.0" } 14 | spec.source = { :http => 'https://github.com/sicpa-dlab/didcomm-rust/releases/download/v0.3.1/didcomm-swift-0.3.1.tar.gz'} 15 | spec.swift_version = '4.0' 16 | 17 | spec.ios.vendored_library = '*.a' 18 | spec.source_files = ['didcomm.swift', 'didcommFFI.h'] 19 | 20 | spec.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64 i386' } 21 | spec.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64 i386' } 22 | 23 | end 24 | -------------------------------------------------------------------------------- /Specs/DidcommSDK/0.3.2/DidcommSDK.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | 3 | spec.name = "DidcommSDK" 4 | spec.version = "0.3.2" 5 | spec.summary = "Didcomm v2 created from rust." 6 | 7 | spec.description = "Didcomm v2 created from rust. UNIFFI was used to convert from rust to Swift." 8 | spec.homepage = "https://github.com/sicpa-dlab/didcomm-rust" 9 | 10 | spec.license = { :type => 'Apache License 2.0', :file => 'LICENSE.txt' } 11 | 12 | spec.authors = { "Sicpa-Dlab" => "dlab@sicpa.com" } 13 | spec.platforms = { :ios => "10.0" } 14 | spec.source = { :http => 'https://github.com/sicpa-dlab/didcomm-rust/releases/download/v0.3.2/didcomm-swift-0.3.2.tar.gz'} 15 | spec.swift_version = '4.0' 16 | 17 | spec.ios.vendored_library = '*.a' 18 | spec.source_files = ['didcomm.swift', 'didcommFFI.h'] 19 | 20 | spec.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64 i386' } 21 | spec.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64 i386' } 22 | 23 | end 24 | -------------------------------------------------------------------------------- /Specs/DidcommSDK/0.3.3/DidcommSDK.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | 3 | spec.name = "DidcommSDK" 4 | spec.version = "0.3.3" 5 | spec.summary = "Didcomm v2 created from rust." 6 | 7 | spec.description = "Didcomm v2 created from rust. UNIFFI was used to convert from rust to Swift." 8 | spec.homepage = "https://github.com/sicpa-dlab/didcomm-rust" 9 | 10 | spec.license = { :type => 'Apache License 2.0', :file => 'LICENSE.txt' } 11 | 12 | spec.authors = { "Sicpa-Dlab" => "dlab@sicpa.com" } 13 | spec.platforms = { :ios => "10.0" } 14 | spec.source = { :http => 'https://github.com/sicpa-dlab/didcomm-rust/releases/download/v0.3.3/didcomm-swift-0.3.3.tar.gz'} 15 | spec.swift_version = '4.0' 16 | 17 | spec.ios.vendored_library = '*.a' 18 | spec.source_files = ['didcomm.swift', 'didcommFFI.h'] 19 | 20 | spec.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64 i386' } 21 | spec.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64 i386' } 22 | 23 | end 24 | -------------------------------------------------------------------------------- /Specs/DidcommSDK/0.3.4/DidcommSDK.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | 3 | spec.name = "DidcommSDK" 4 | spec.version = "0.3.4" 5 | spec.summary = "Didcomm v2 created from rust." 6 | 7 | spec.description = "Didcomm v2 created from rust. UNIFFI was used to convert from rust to Swift." 8 | spec.homepage = "https://github.com/sicpa-dlab/didcomm-rust" 9 | 10 | spec.license = { :type => 'Apache License 2.0', :file => 'LICENSE.txt' } 11 | 12 | spec.authors = { "Sicpa-Dlab" => "dlab@sicpa.com" } 13 | spec.platforms = { :ios => "10.0" } 14 | spec.source = { :http => 'https://github.com/sicpa-dlab/didcomm-rust/releases/download/v0.3.4/didcomm-swift-0.3.4.tar.gz'} 15 | spec.swift_version = '4.0' 16 | 17 | spec.ios.vendored_library = '*.a' 18 | spec.source_files = ['didcomm.swift', 'didcommFFI.h'] 19 | 20 | spec.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64 i386' } 21 | spec.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64 i386' } 22 | 23 | end 24 | -------------------------------------------------------------------------------- /benches/pack_signed.rs: -------------------------------------------------------------------------------- 1 | // Allows share test vectors between unit and integration tests 2 | pub(crate) use didcomm; 3 | 4 | #[allow(unused_imports, dead_code)] 5 | #[path = "../src/test_vectors/mod.rs"] 6 | mod test_vectors; 7 | 8 | use criterion::{async_executor::FuturesExecutor, criterion_group, criterion_main, Criterion}; 9 | use didcomm::{did::resolvers::ExampleDIDResolver, secrets::resolvers::ExampleSecretsResolver}; 10 | 11 | use test_vectors::{ 12 | ALICE_AUTH_METHOD_25519, ALICE_AUTH_METHOD_P256, ALICE_AUTH_METHOD_SECPP256K1, ALICE_DID_DOC, 13 | ALICE_SECRETS, MESSAGE_SIMPLE, 14 | }; 15 | 16 | // Here we have an async function to benchmark 17 | async fn pack_signed( 18 | sign_by: &str, 19 | did_resolver: &ExampleDIDResolver, 20 | secrets_resolver: &ExampleSecretsResolver, 21 | ) { 22 | MESSAGE_SIMPLE 23 | .pack_signed(sign_by, did_resolver, secrets_resolver) 24 | .await 25 | .expect("Unable pack_signed"); 26 | } 27 | 28 | fn benchmarks(c: &mut Criterion) { 29 | let sign_by = &ALICE_AUTH_METHOD_25519.id; 30 | let did_resolver = ExampleDIDResolver::new(vec![ALICE_DID_DOC.clone()]); 31 | let secrets_resolver = ExampleSecretsResolver::new(ALICE_SECRETS.clone()); 32 | 33 | c.bench_function("pack_signed_ed25519", move |b| { 34 | b.to_async(FuturesExecutor) 35 | .iter(|| pack_signed(sign_by, &did_resolver, &secrets_resolver)); 36 | }); 37 | 38 | let sign_by = &ALICE_AUTH_METHOD_P256.id; 39 | let did_resolver = ExampleDIDResolver::new(vec![ALICE_DID_DOC.clone()]); 40 | let secrets_resolver = ExampleSecretsResolver::new(ALICE_SECRETS.clone()); 41 | 42 | c.bench_function("pack_signed_p256", move |b| { 43 | b.to_async(FuturesExecutor) 44 | .iter(|| pack_signed(sign_by, &did_resolver, &secrets_resolver)); 45 | }); 46 | 47 | let sign_by = &ALICE_AUTH_METHOD_SECPP256K1.id; 48 | let did_resolver = ExampleDIDResolver::new(vec![ALICE_DID_DOC.clone()]); 49 | let secrets_resolver = ExampleSecretsResolver::new(ALICE_SECRETS.clone()); 50 | 51 | c.bench_function("pack_signed_k256", move |b| { 52 | b.to_async(FuturesExecutor) 53 | .iter(|| pack_signed(sign_by, &did_resolver, &secrets_resolver)); 54 | }); 55 | } 56 | 57 | criterion_group!(benches, benchmarks); 58 | criterion_main!(benches); 59 | -------------------------------------------------------------------------------- /docs/release.md: -------------------------------------------------------------------------------- 1 | ## Release 2 | 3 | Assumptions: 4 | 5 | * `main` branch can wait until release PR is merged 6 | 7 | The steps: 8 | 9 | 1. **release**: 10 | 1. **review and adjust if needed the release version in `main`** to match the changes from the latest release following the [SemVer rules](https://semver.org/#summary). 11 | 2. [create](https://github.com/sicpa-dlab/didcomm-rust/compare/stable...main) a **PR from `main` to `stable`** (you may likely want to name it as `release-`) 12 | 3. once merged [release pipeline](https://github.com/sicpa-dlab/didcomm-rust/actions/workflows/release.yml) will publish the release: 13 | * to [crates.io](https://crates.io/crates/didcomm) 14 | * to NPM: 15 | * as Bundler(Webpack) compatible [package](https://www.npmjs.com/package/didcomm) 16 | * as Node.js (CommonJS) compatible [package](https://www.npmjs.com/package/didcomm-node) 17 | 2. **bump next release version in `main`** 18 | * **Note** decision about the next release version should be based on the same [SemVer](https://semver.org/) rules and the expected changes. Usually it would be either a MINOR or MAJOR (if incompatible changes are planned) release. 19 | -------------------------------------------------------------------------------- /examples/advanced_params.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports, dead_code)] 2 | #[path = "../src/test_vectors/mod.rs"] 3 | mod test_vectors; 4 | 5 | // TODO: look for better solution 6 | // Allows test vectors usage inside and outside crate 7 | pub(crate) use didcomm; 8 | 9 | use didcomm::{ 10 | algorithms::{AnonCryptAlg, AuthCryptAlg}, 11 | did::resolvers::ExampleDIDResolver, 12 | protocols::routing::try_parse_forward, 13 | secrets::resolvers::ExampleSecretsResolver, 14 | Message, PackEncryptedOptions, UnpackOptions, 15 | }; 16 | use serde_json::json; 17 | use std::collections::HashMap; 18 | use std::iter::FromIterator; 19 | use test_vectors::{ 20 | ALICE_DID, ALICE_DID_DOC, ALICE_SECRETS, BOB_DID, BOB_DID_DOC, BOB_SECRETS, MEDIATOR1_DID_DOC, 21 | MEDIATOR1_SECRETS, 22 | }; 23 | 24 | #[tokio::main(flavor = "current_thread")] 25 | async fn main() { 26 | // --- Building message from ALICE to BOB --- 27 | let msg = Message::build( 28 | "example-1".to_owned(), 29 | "example/v1".to_owned(), 30 | json!("example-body"), 31 | ) 32 | .from(ALICE_DID.to_owned()) 33 | .to(BOB_DID.to_owned()) 34 | .created_time(1516269022) 35 | .expires_time(1516385931) 36 | .finalize(); 37 | 38 | // --- Packing encrypted and authenticated message --- 39 | let did_resolver = ExampleDIDResolver::new(vec![ 40 | ALICE_DID_DOC.clone(), 41 | BOB_DID_DOC.clone(), 42 | MEDIATOR1_DID_DOC.clone(), 43 | ]); 44 | 45 | let secrets_resolver = ExampleSecretsResolver::new(ALICE_SECRETS.clone()); 46 | 47 | let (msg, metadata) = msg 48 | .pack_encrypted( 49 | "did:example:bob#key-p256-1", 50 | "did:example:alice#key-p256-1".into(), 51 | "did:example:alice#key-2".into(), 52 | &did_resolver, 53 | &secrets_resolver, 54 | &PackEncryptedOptions { 55 | protect_sender: true, 56 | forward: true, 57 | forward_headers: Some(HashMap::from_iter([( 58 | "expires_time".to_string(), 59 | json!(99999), 60 | )])), 61 | messaging_service: Some("did:example:bob#didcomm-1".to_string()), 62 | enc_alg_auth: AuthCryptAlg::A256cbcHs512Ecdh1puA256kw, 63 | enc_alg_anon: AnonCryptAlg::A256gcmEcdhEsA256kw, 64 | }, 65 | ) 66 | .await 67 | .expect("Unable pack_encrypted"); 68 | 69 | println!("Encryption metadata is\n{:?}\n", metadata); 70 | 71 | // --- Sending message by Alice --- 72 | println!("Alice is sending message \n{}\n", msg); 73 | 74 | // --- Unpacking message by Mediator1 --- 75 | let did_resolver = ExampleDIDResolver::new(vec![ 76 | ALICE_DID_DOC.clone(), 77 | BOB_DID_DOC.clone(), 78 | MEDIATOR1_DID_DOC.clone(), 79 | ]); 80 | 81 | let secrets_resolver = ExampleSecretsResolver::new(MEDIATOR1_SECRETS.clone()); 82 | 83 | let (msg, metadata) = Message::unpack( 84 | &msg, 85 | &did_resolver, 86 | &secrets_resolver, 87 | &UnpackOptions::default(), 88 | ) 89 | .await 90 | .expect("Unable unpack"); 91 | 92 | println!("Mediator1 received message is \n{:?}\n", msg); 93 | 94 | println!( 95 | "Mediator1 received message unpack metadata is \n{:?}\n", 96 | metadata 97 | ); 98 | 99 | // --- Forwarding message by Mediator1 --- 100 | let msg = serde_json::to_string(&try_parse_forward(&msg).unwrap().forwarded_msg).unwrap(); 101 | 102 | println!("Mediator1 is forwarding message \n{}\n", msg); 103 | 104 | // --- Unpacking message by Bob --- 105 | let did_resolver = ExampleDIDResolver::new(vec![ 106 | ALICE_DID_DOC.clone(), 107 | BOB_DID_DOC.clone(), 108 | MEDIATOR1_DID_DOC.clone(), 109 | ]); 110 | 111 | let secrets_resolver = ExampleSecretsResolver::new(BOB_SECRETS.clone()); 112 | 113 | let (msg, metadata) = Message::unpack( 114 | &msg, 115 | &did_resolver, 116 | &secrets_resolver, 117 | &UnpackOptions::default(), 118 | ) 119 | .await 120 | .expect("Unable unpack"); 121 | 122 | println!("Bob received message is \n{:?}\n", msg); 123 | println!("Bob received message unpack metadata is \n{:?}\n", metadata); 124 | } 125 | -------------------------------------------------------------------------------- /examples/attachments.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports, dead_code)] 2 | #[path = "../src/test_vectors/mod.rs"] 3 | mod test_vectors; 4 | 5 | // TODO: look for better solution 6 | // Allows test vectors usage inside and outside crate 7 | pub(crate) use didcomm; 8 | 9 | use didcomm::{ 10 | did::resolvers::ExampleDIDResolver, protocols::routing::try_parse_forward, 11 | secrets::resolvers::ExampleSecretsResolver, Attachment, AttachmentData, JsonAttachmentData, 12 | Message, PackEncryptedOptions, UnpackOptions, 13 | }; 14 | use serde_json::json; 15 | use test_vectors::{ 16 | ALICE_DID, ALICE_DID_DOC, ALICE_SECRETS, BOB_DID, BOB_DID_DOC, BOB_SECRETS, MEDIATOR1_DID_DOC, 17 | MEDIATOR1_SECRETS, 18 | }; 19 | 20 | #[tokio::main(flavor = "current_thread")] 21 | async fn main() { 22 | // --- Building message from ALICE to BOB --- 23 | let msg = Message::build( 24 | "example-1".to_owned(), 25 | "example/v1".to_owned(), 26 | json!("example-body"), 27 | ) 28 | .to(BOB_DID.to_owned()) 29 | .from(ALICE_DID.to_owned()) 30 | .attachment(Attachment { 31 | data: AttachmentData::Json { 32 | value: JsonAttachmentData { 33 | json: json!({"foo": "bar"}), 34 | jws: None, 35 | }, 36 | }, 37 | id: Some("123".to_string()), 38 | description: Some("example attachment".to_string()), 39 | filename: None, 40 | media_type: Some("application/didcomm-encrypted+json".to_string()), 41 | format: None, 42 | lastmod_time: None, 43 | byte_count: None, 44 | }) 45 | .finalize(); 46 | 47 | // --- Packing encrypted and authenticated message --- 48 | let did_resolver = ExampleDIDResolver::new(vec![ 49 | ALICE_DID_DOC.clone(), 50 | BOB_DID_DOC.clone(), 51 | MEDIATOR1_DID_DOC.clone(), 52 | ]); 53 | 54 | let secrets_resolver = ExampleSecretsResolver::new(ALICE_SECRETS.clone()); 55 | 56 | let (msg, metadata) = msg 57 | .pack_encrypted( 58 | BOB_DID, 59 | Some(ALICE_DID), 60 | None, 61 | &did_resolver, 62 | &secrets_resolver, 63 | &PackEncryptedOptions::default(), 64 | ) 65 | .await 66 | .expect("Unable pack_encrypted"); 67 | 68 | println!("Encryption metadata is\n{:?}\n", metadata); 69 | 70 | // --- Alice is sending message --- 71 | println!("Alice is sending message \n{}\n", msg); 72 | 73 | // --- Unpacking message by Mediator1 --- 74 | let did_resolver = ExampleDIDResolver::new(vec![ 75 | ALICE_DID_DOC.clone(), 76 | BOB_DID_DOC.clone(), 77 | MEDIATOR1_DID_DOC.clone(), 78 | ]); 79 | 80 | let secrets_resolver = ExampleSecretsResolver::new(MEDIATOR1_SECRETS.clone()); 81 | 82 | let (msg, metadata) = Message::unpack( 83 | &msg, 84 | &did_resolver, 85 | &secrets_resolver, 86 | &UnpackOptions::default(), 87 | ) 88 | .await 89 | .expect("Unable unpack"); 90 | 91 | println!("Mediator1 received message is \n{:?}\n", msg); 92 | 93 | println!( 94 | "Mediator1 received message unpack metadata is \n{:?}\n", 95 | metadata 96 | ); 97 | 98 | // --- Forwarding message by Mediator1 --- 99 | let msg = serde_json::to_string(&try_parse_forward(&msg).unwrap().forwarded_msg).unwrap(); 100 | 101 | println!("Mediator1 is forwarding message \n{}\n", msg); 102 | 103 | // --- Unpacking message by Bob --- 104 | let did_resolver = ExampleDIDResolver::new(vec![ 105 | ALICE_DID_DOC.clone(), 106 | BOB_DID_DOC.clone(), 107 | MEDIATOR1_DID_DOC.clone(), 108 | ]); 109 | 110 | let secrets_resolver = ExampleSecretsResolver::new(BOB_SECRETS.clone()); 111 | 112 | let (msg, metadata) = Message::unpack( 113 | &msg, 114 | &did_resolver, 115 | &secrets_resolver, 116 | &UnpackOptions::default(), 117 | ) 118 | .await 119 | .expect("Unable unpack"); 120 | 121 | println!("Bob received message is \n{:?}\n", msg); 122 | println!("Bob received message unpack metadata is \n{:?}\n", metadata); 123 | } 124 | -------------------------------------------------------------------------------- /examples/rotate_did.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports, dead_code)] 2 | #[path = "../src/test_vectors/mod.rs"] 3 | mod test_vectors; 4 | 5 | // TODO: look for better solution 6 | // Allows test vectors usage inside and outside crate 7 | pub(crate) use didcomm; 8 | 9 | use didcomm::{ 10 | did::resolvers::ExampleDIDResolver, protocols::routing::try_parse_forward, 11 | secrets::resolvers::ExampleSecretsResolver, FromPrior, Message, PackEncryptedOptions, 12 | UnpackOptions, 13 | }; 14 | use serde_json::json; 15 | use test_vectors::{ 16 | ALICE_DID, ALICE_DID_DOC, BOB_DID, BOB_DID_DOC, BOB_SECRETS, CHARLIE_DID, CHARLIE_DID_DOC, 17 | CHARLIE_ROTATED_TO_ALICE_SECRETS, MEDIATOR1_DID_DOC, MEDIATOR1_SECRETS, 18 | }; 19 | 20 | #[tokio::main(flavor = "current_thread")] 21 | async fn main() { 22 | let did_resolver = ExampleDIDResolver::new(vec![ 23 | ALICE_DID_DOC.clone(), 24 | BOB_DID_DOC.clone(), 25 | CHARLIE_DID_DOC.clone(), 26 | MEDIATOR1_DID_DOC.clone(), 27 | ]); 28 | 29 | let secrets_resolver = ExampleSecretsResolver::new(CHARLIE_ROTATED_TO_ALICE_SECRETS.clone()); 30 | 31 | // --- Building from_prior header 32 | let from_prior = FromPrior::build(CHARLIE_DID.into(), ALICE_DID.into()) 33 | .aud("123".into()) 34 | .exp(1234) 35 | .nbf(12345) 36 | .iat(123456) 37 | .jti("dfg".into()) 38 | .finalize(); 39 | 40 | println!("Original from_prior is\n{:?}\n", from_prior); 41 | 42 | let (from_prior, issuer_kid) = from_prior 43 | .pack(None, &did_resolver, &secrets_resolver) 44 | .await 45 | .expect("Unable pack from_prior"); 46 | 47 | println!("Packed from_prior is\n{}\n", from_prior); 48 | println!("from_prior issuer kid is\n{}\n", issuer_kid); 49 | 50 | // --- Building message from ALICE (ex-CHARLIE) to BOB --- 51 | let msg = Message::build( 52 | "1234567890".to_owned(), 53 | "http://example.com/protocols/lets_do_lunch/1.0/proposal".to_owned(), 54 | json!({"messagespecificattribute": "and its value"}), 55 | ) 56 | .from(ALICE_DID.to_owned()) 57 | .to(BOB_DID.to_owned()) 58 | .created_time(1516269022) 59 | .expires_time(1516385931) 60 | .from_prior(from_prior) 61 | .finalize(); 62 | 63 | println!("Original message is\n{:?}\n", msg); 64 | 65 | // --- Packing encrypted and authenticated message --- 66 | let (msg, metadata) = msg 67 | .pack_encrypted( 68 | BOB_DID, 69 | Some(ALICE_DID), 70 | None, 71 | &did_resolver, 72 | &secrets_resolver, 73 | &PackEncryptedOptions::default(), 74 | ) 75 | .await 76 | .expect("Unable pack_encrypted"); 77 | 78 | println!("Encryption metadata is\n{:?}\n", metadata); 79 | 80 | // --- Sending message by Alice --- 81 | println!("Alice is sending message \n{}\n", msg); 82 | 83 | // --- Unpacking message by Mediator1 --- 84 | let did_resolver = ExampleDIDResolver::new(vec![ 85 | ALICE_DID_DOC.clone(), 86 | BOB_DID_DOC.clone(), 87 | CHARLIE_DID_DOC.clone(), 88 | MEDIATOR1_DID_DOC.clone(), 89 | ]); 90 | 91 | let secrets_resolver = ExampleSecretsResolver::new(MEDIATOR1_SECRETS.clone()); 92 | 93 | let (msg, metadata) = Message::unpack( 94 | &msg, 95 | &did_resolver, 96 | &secrets_resolver, 97 | &UnpackOptions::default(), 98 | ) 99 | .await 100 | .expect("Unable unpack"); 101 | 102 | println!("Mediator1 received message is \n{:?}\n", msg); 103 | 104 | println!( 105 | "Mediator1 received message unpack metadata is \n{:?}\n", 106 | metadata 107 | ); 108 | 109 | // --- Forwarding message by Mediator1 --- 110 | let msg = serde_json::to_string(&try_parse_forward(&msg).unwrap().forwarded_msg).unwrap(); 111 | 112 | println!("Mediator1 is forwarding message \n{}\n", msg); 113 | 114 | // --- Unpacking message by Bob --- 115 | let did_resolver = ExampleDIDResolver::new(vec![ 116 | ALICE_DID_DOC.clone(), 117 | BOB_DID_DOC.clone(), 118 | CHARLIE_DID_DOC.clone(), 119 | MEDIATOR1_DID_DOC.clone(), 120 | ]); 121 | 122 | let secrets_resolver = ExampleSecretsResolver::new(BOB_SECRETS.clone()); 123 | 124 | let (msg, metadata) = Message::unpack( 125 | &msg, 126 | &did_resolver, 127 | &secrets_resolver, 128 | &UnpackOptions::default(), 129 | ) 130 | .await 131 | .expect("Unable unpack"); 132 | 133 | println!("Bob received message is \n{:?}\n", msg); 134 | println!("Bob received message unpack metadata is \n{:?}\n", metadata); 135 | } 136 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/algorithms.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Algorithms for anonymous encryption 4 | #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] 5 | pub enum AnonCryptAlg { 6 | /// AES256-CBC + HMAC-SHA512 with a 512 bit key content encryption, 7 | /// ECDH-ES key agreement with A256KW key wrapping 8 | A256cbcHs512EcdhEsA256kw, 9 | 10 | /// XChaCha20Poly1305 with a 256 bit key content encryption, 11 | /// ECDH-ES key agreement with A256KW key wrapping 12 | Xc20pEcdhEsA256kw, 13 | 14 | /// A256GCM_ECDH_ES_A256KW: XChaCha20Poly1305 with a 256 bit key content encryption, 15 | /// ECDH-ES key agreement with A256KW key wrapping 16 | A256gcmEcdhEsA256kw, 17 | } 18 | 19 | impl Default for AnonCryptAlg { 20 | fn default() -> Self { 21 | AnonCryptAlg::Xc20pEcdhEsA256kw 22 | } 23 | } 24 | 25 | #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] 26 | pub enum AuthCryptAlg { 27 | /// AES256-CBC + HMAC-SHA512 with a 512 bit key content encryption, 28 | /// ECDH-1PU key agreement with A256KW key wrapping 29 | A256cbcHs512Ecdh1puA256kw, 30 | } 31 | 32 | impl Default for AuthCryptAlg { 33 | fn default() -> Self { 34 | AuthCryptAlg::A256cbcHs512Ecdh1puA256kw 35 | } 36 | } 37 | 38 | #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] 39 | pub enum SignAlg { 40 | EdDSA, 41 | ES256, 42 | ES256K, 43 | } 44 | -------------------------------------------------------------------------------- /src/did/did_doc.rs: -------------------------------------------------------------------------------- 1 | //! Set of interfaces that describe DID Document (https://www.w3.org/TR/did-core/) 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use serde_json::Value; 5 | 6 | /// Represents DID Document (https://www.w3.org/TR/did-core/) 7 | #[derive(Debug, Clone, Deserialize, Serialize)] 8 | #[serde(rename_all = "camelCase")] 9 | pub struct DIDDoc { 10 | /// DID for the given DID Doc 11 | pub id: String, 12 | 13 | /// DID URLs of verification methods used for key agreement. 14 | /// See https://www.w3.org/TR/did-core/#verification-methods. 15 | pub key_agreement: Vec, 16 | 17 | /// Returns DID URLs of verification methods used for authentication. 18 | /// See https://www.w3.org/TR/did-core/#authentication 19 | pub authentication: Vec, 20 | 21 | /// All local verification methods including embedded to 22 | /// key agreement and authentication sections. 23 | /// See https://www.w3.org/TR/did-core/#verification-methods. 24 | pub verification_method: Vec, 25 | 26 | /// All services (https://www.w3.org/TR/did-core/#services) 27 | pub service: Vec, 28 | } 29 | 30 | /// Represents verification method record in DID Document 31 | /// (https://www.w3.org/TR/did-core/#verification-methods). 32 | #[derive(Debug, Clone, Deserialize, Serialize)] 33 | pub struct VerificationMethod { 34 | pub id: String, 35 | #[serde(rename = "type")] 36 | pub type_: VerificationMethodType, 37 | pub controller: String, 38 | #[serde(flatten)] 39 | pub verification_material: VerificationMaterial, 40 | } 41 | 42 | #[derive(Debug, Clone, Deserialize, Serialize)] 43 | pub enum VerificationMethodType { 44 | JsonWebKey2020, 45 | X25519KeyAgreementKey2019, 46 | Ed25519VerificationKey2018, 47 | EcdsaSecp256k1VerificationKey2019, 48 | X25519KeyAgreementKey2020, 49 | Ed25519VerificationKey2020, 50 | Other, 51 | } 52 | 53 | /// Represents verification material (https://www.w3.org/TR/did-core/#verification-material) 54 | #[derive(Debug, Clone, Deserialize, Serialize)] 55 | #[serde(untagged)] 56 | pub enum VerificationMaterial { 57 | #[serde(rename_all = "camelCase")] 58 | JWK { public_key_jwk: Value }, 59 | 60 | #[serde(rename_all = "camelCase")] 61 | Multibase { public_key_multibase: String }, 62 | 63 | #[serde(rename_all = "camelCase")] 64 | Base58 { public_key_base58: String }, 65 | } 66 | 67 | /// Represents service record in DID Document (https://www.w3.org/TR/did-core/#services). 68 | #[derive(Debug, Clone, Deserialize, Serialize)] 69 | pub struct Service { 70 | pub id: String, 71 | 72 | #[serde(flatten)] 73 | pub service_endpoint: ServiceKind, 74 | } 75 | 76 | /// Represents additional service properties defined for specific Service type. 77 | #[derive(Debug, Clone, Deserialize, Serialize)] 78 | #[serde(tag = "type", content = "serviceEndpoint")] 79 | pub enum ServiceKind { 80 | DIDCommMessaging { 81 | #[serde(flatten)] 82 | value: DIDCommMessagingService, 83 | }, 84 | Other { 85 | #[serde(flatten)] 86 | value: Value, 87 | }, 88 | } 89 | 90 | /// Properties for DIDCommMessagingService 91 | /// (https://identity.foundation/didcomm-messaging/spec/#did-document-service-endpoint). 92 | #[derive(Debug, Clone, Deserialize, Serialize)] 93 | #[serde(rename_all = "camelCase")] 94 | pub struct DIDCommMessagingService { 95 | pub uri: String, 96 | 97 | #[serde(default)] 98 | #[serde(skip_serializing_if = "Option::is_none")] 99 | pub accept: Option>, 100 | 101 | #[serde(default)] 102 | pub routing_keys: Vec, 103 | } 104 | 105 | #[cfg(test)] 106 | mod tests { 107 | use super::*; 108 | use serde_json::json; 109 | 110 | const SERVICE_URI: &str = "https://example.com/path"; 111 | 112 | #[test] 113 | fn parsing_minimal_didcomm_messaging_service_works() { 114 | let service: DIDCommMessagingService = 115 | serde_json::from_value(json!({ "uri": SERVICE_URI })).unwrap(); 116 | 117 | assert_eq!(service.uri, SERVICE_URI); 118 | assert!(service.routing_keys.is_empty()); 119 | assert!(service.accept.is_none()); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/did/did_resolver.rs: -------------------------------------------------------------------------------- 1 | //! DID Resolver (https://www.w3.org/TR/did-core/#dfn-did-resolvers) interfaces 2 | 3 | use async_trait::async_trait; 4 | 5 | use crate::{did::did_doc::DIDDoc, error::Result}; 6 | 7 | /// Represents DID Doc resolver (https://www.w3.org/TR/did-core/#did-resolution). 8 | #[cfg(feature = "uniffi")] 9 | #[async_trait] 10 | pub trait DIDResolver: Sync { 11 | /// Resolves a DID document by the given DID. 12 | /// 13 | /// # Params 14 | /// - `did` a DID to be resolved. 15 | /// 16 | /// # Returns 17 | /// An instance of resolved DID DOC or None if DID is not found. 18 | /// 19 | /// # Errors 20 | /// - `IoError` IO error during resolving 21 | /// - `InvalidState` indicates a bug in resolver code 22 | async fn resolve(&self, did: &str) -> Result>; 23 | } 24 | 25 | /// Represents DID Doc resolver (https://www.w3.org/TR/did-core/#did-resolution). 26 | #[cfg(not(feature = "uniffi"))] 27 | #[async_trait(?Send)] 28 | pub trait DIDResolver { 29 | /// Resolves a DID document by the given DID. 30 | /// 31 | /// # Params 32 | /// - `did` a DID to be resolved. 33 | /// 34 | /// # Returns 35 | /// An instance of resolved DID DOC or None if DID is not found. 36 | /// 37 | /// # Errors 38 | /// - `IoError` IO error during resolving 39 | /// - `InvalidState` indicates a bug in resolver code 40 | async fn resolve(&self, did: &str) -> Result>; 41 | } 42 | -------------------------------------------------------------------------------- /src/did/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod resolvers; 2 | 3 | pub(crate) mod did_doc; 4 | pub(crate) mod did_resolver; 5 | 6 | pub use did_doc::{ 7 | DIDCommMessagingService, DIDDoc, Service, ServiceKind, VerificationMaterial, 8 | VerificationMethod, VerificationMethodType, 9 | }; 10 | 11 | pub use did_resolver::DIDResolver; 12 | -------------------------------------------------------------------------------- /src/did/resolvers/example.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | 3 | use crate::{ 4 | did::{DIDDoc, DIDResolver}, 5 | error::Result, 6 | }; 7 | 8 | /// Allows resolve pre-defined did's for `example` and other methods. 9 | pub struct ExampleDIDResolver { 10 | known_dids: Vec, 11 | } 12 | 13 | impl ExampleDIDResolver { 14 | pub fn new(known_dids: Vec) -> Self { 15 | ExampleDIDResolver { known_dids } 16 | } 17 | } 18 | 19 | #[cfg_attr(feature = "uniffi", async_trait)] 20 | #[cfg_attr(not(feature = "uniffi"), async_trait(?Send))] 21 | impl DIDResolver for ExampleDIDResolver { 22 | async fn resolve(&self, did: &str) -> Result> { 23 | Ok(self 24 | .known_dids 25 | .iter() 26 | .find(|ddoc| ddoc.id == did) 27 | .map(|ddoc| ddoc.clone())) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/did/resolvers/mock.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | use std::cell::RefCell; 3 | use std::sync::Mutex; 4 | 5 | use crate::did::{DIDDoc, DIDResolver}; 6 | 7 | pub struct MockDidResolver { 8 | results: Mutex>>>>, 9 | } 10 | 11 | impl MockDidResolver { 12 | pub fn new(res: Vec>>) -> Self { 13 | Self { 14 | results: Mutex::new(RefCell::new(res)), 15 | } 16 | } 17 | } 18 | 19 | #[cfg_attr(feature = "uniffi", async_trait)] 20 | #[cfg_attr(not(feature = "uniffi"), async_trait(?Send))] 21 | impl DIDResolver for MockDidResolver { 22 | async fn resolve(&self, _did: &str) -> crate::error::Result> { 23 | self.results.lock().unwrap().borrow_mut().pop().unwrap() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/did/resolvers/mod.rs: -------------------------------------------------------------------------------- 1 | mod example; 2 | 3 | #[cfg(test)] 4 | mod mock; 5 | 6 | pub use example::ExampleDIDResolver; 7 | 8 | #[cfg(test)] 9 | pub(crate) use mock::MockDidResolver; 10 | -------------------------------------------------------------------------------- /src/jwe/mod.rs: -------------------------------------------------------------------------------- 1 | // TODO: remove allow 2 | #[allow(dead_code)] 3 | mod encrypt; 4 | 5 | // TODO: remove allow 6 | #[allow(dead_code)] 7 | mod decrypt; 8 | 9 | // TODO: remove allow 10 | #[allow(dead_code)] 11 | mod parse; 12 | 13 | // TODO: remove allow 14 | #[allow(dead_code)] 15 | pub(crate) mod envelope; 16 | 17 | // TODO: remove allow 18 | #[allow(unused_imports)] 19 | pub(crate) use encrypt::encrypt; 20 | 21 | // TODO: remove allow 22 | #[allow(unused_imports)] 23 | pub(crate) use parse::{parse, ParsedJWE}; 24 | 25 | // TODO: remove allow 26 | #[allow(unused_imports)] 27 | pub(crate) use envelope::{Algorithm, EncAlgorithm}; 28 | 29 | #[cfg(test)] 30 | pub(crate) mod test_support { 31 | pub(crate) const ALICE_KID_X25519_1: &str = "did:example:alice#key-x25519-1"; 32 | 33 | pub(crate) const ALICE_KEY_X25519_1: &str = r#"{ 34 | "kty":"OKP", 35 | "d":"r-jK2cO3taR8LQnJB1_ikLBTAnOtShJOsHXRUWT-aZA", 36 | "crv":"X25519", 37 | "x":"avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs" 38 | }"#; 39 | 40 | pub(crate) const ALICE_PKEY_X25519_1: &str = r#"{ 41 | "kty":"OKP", 42 | "crv":"X25519", 43 | "x":"avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs" 44 | }"#; 45 | 46 | pub(crate) const ALICE_KID_P256_1: &str = "did:example:alice#key-p256-1"; 47 | 48 | pub(crate) const ALICE_KEY_P256_1: &str = r#"{ 49 | "kty":"EC", 50 | "d":"sB0bYtpaXyp-h17dDpMx91N3Du1AdN4z1FUq02GbmLw", 51 | "crv":"P-256", 52 | "x":"L0crjMN1g0Ih4sYAJ_nGoHUck2cloltUpUVQDhF2nHE", 53 | "y":"SxYgE7CmEJYi7IDhgK5jI4ZiajO8jPRZDldVhqFpYoo" 54 | }"#; 55 | 56 | pub(crate) const ALICE_PKEY_P256_1: &str = r#"{ 57 | "kty":"EC", 58 | "crv":"P-256", 59 | "x":"L0crjMN1g0Ih4sYAJ_nGoHUck2cloltUpUVQDhF2nHE", 60 | "y":"SxYgE7CmEJYi7IDhgK5jI4ZiajO8jPRZDldVhqFpYoo" 61 | }"#; 62 | 63 | pub(crate) const BOB_KID_X25519_1: &str = "did:example:bob#key-x25519-1"; 64 | 65 | pub(crate) const BOB_KEY_X25519_1: &str = r#"{ 66 | "kty":"OKP", 67 | "d":"b9NnuOCB0hm7YGNvaE9DMhwH_wjZA1-gWD6dA0JWdL0", 68 | "crv":"X25519", 69 | "x":"GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E" 70 | }"#; 71 | 72 | pub(crate) const BOB_PKEY_X25519_1: &str = r#"{ 73 | "kty":"OKP", 74 | "crv":"X25519", 75 | "x":"GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E" 76 | }"#; 77 | 78 | pub(crate) const BOB_KID_X25519_2: &str = "did:example:bob#key-x25519-2"; 79 | 80 | pub(crate) const BOB_KEY_X25519_2: &str = r#"{ 81 | "kty":"OKP", 82 | "d":"p-vteoF1gopny1HXywt76xz_uC83UUmrgszsI-ThBKk", 83 | "crv":"X25519", 84 | "x":"UT9S3F5ep16KSNBBShU2wh3qSfqYjlasZimn0mB8_VM" 85 | }"#; 86 | 87 | pub(crate) const BOB_PKEY_X25519_2: &str = r#"{ 88 | "kty":"OKP", 89 | "crv":"X25519", 90 | "x":"UT9S3F5ep16KSNBBShU2wh3qSfqYjlasZimn0mB8_VM" 91 | }"#; 92 | 93 | pub(crate) const BOB_KID_X25519_3: &str = "did:example:bob#key-x25519-3"; 94 | 95 | pub(crate) const BOB_KEY_X25519_3: &str = r#"{ 96 | "kty":"OKP", 97 | "d":"f9WJeuQXEItkGM8shN4dqFr5fLQLBasHnWZ-8dPaSo0", 98 | "crv":"X25519", 99 | "x":"82k2BTUiywKv49fKLZa-WwDi8RBf0tB0M8bvSAUQ3yY" 100 | }"#; 101 | 102 | pub(crate) const BOB_PKEY_X25519_3: &str = r#"{ 103 | "kty":"OKP", 104 | "crv":"X25519", 105 | "x":"82k2BTUiywKv49fKLZa-WwDi8RBf0tB0M8bvSAUQ3yY" 106 | }"#; 107 | 108 | pub(crate) const BOB_KID_P256_1: &str = "did:example:bob#key-p256-1"; 109 | 110 | pub(crate) const BOB_KEY_P256_1: &str = r#"{ 111 | "kty":"EC", 112 | "d":"PgwHnlXxt8pwR6OCTUwwWx-P51BiLkFZyqHzquKddXQ", 113 | "crv":"P-256", 114 | "x":"FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo", 115 | "y":"6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY" 116 | }"#; 117 | 118 | pub(crate) const BOB_PKEY_P256_1: &str = r#"{ 119 | "kty":"EC", 120 | "crv":"P-256", 121 | "x":"FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo", 122 | "y":"6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY" 123 | }"#; 124 | 125 | pub(crate) const BOB_KID_P256_2: &str = "did:example:bob#key-p256-2"; 126 | 127 | pub(crate) const BOB_KEY_P256_2: &str = r#"{ 128 | "kty":"EC", 129 | "d":"agKz7HS8mIwqO40Q2dwm_Zi70IdYFtonN5sZecQoxYU", 130 | "crv":"P-256", 131 | "x":"n0yBsGrwGZup9ywKhzD4KoORGicilzIUyfcXb1CSwe0", 132 | "y":"ov0buZJ8GHzV128jmCw1CaFbajZoFFmiJDbMrceCXIw" 133 | }"#; 134 | 135 | pub(crate) const BOB_PKEY_P256_2: &str = r#"{ 136 | "kty":"EC", 137 | "crv":"P-256", 138 | "x":"n0yBsGrwGZup9ywKhzD4KoORGicilzIUyfcXb1CSwe0", 139 | "y":"ov0buZJ8GHzV128jmCw1CaFbajZoFFmiJDbMrceCXIw" 140 | }"#; 141 | } 142 | -------------------------------------------------------------------------------- /src/jwk.rs: -------------------------------------------------------------------------------- 1 | use askar_crypto::{ 2 | alg::{ed25519::Ed25519KeyPair, k256::K256KeyPair, p256::P256KeyPair, x25519::X25519KeyPair}, 3 | jwk::{FromJwk, ToJwk}, 4 | }; 5 | 6 | use serde_json::Value; 7 | 8 | use crate::error::{ErrorKind, Result, ResultExt}; 9 | 10 | pub(crate) trait FromJwkValue: FromJwk { 11 | /// Import the key from a JWK string reference 12 | fn from_jwk_value(jwk: &Value) -> Result { 13 | let jwk = serde_json::to_string(jwk) 14 | .kind(ErrorKind::InvalidState, "Unable produce jwk string")?; 15 | 16 | Self::from_jwk(&jwk).kind(ErrorKind::Malformed, "Unable produce jwk") 17 | } 18 | } 19 | 20 | pub(crate) trait ToJwkValue: ToJwk { 21 | fn to_jwk_public_value(&self) -> Result { 22 | let jwk = self 23 | .to_jwk_public(None) 24 | .kind(ErrorKind::InvalidState, "Unable produce jwk string")?; 25 | 26 | let jwk: Value = 27 | serde_json::from_str(&jwk).kind(ErrorKind::InvalidState, "Unable produce jwk value")?; 28 | 29 | Ok(jwk) 30 | } 31 | } 32 | 33 | impl FromJwkValue for Ed25519KeyPair {} 34 | impl FromJwkValue for P256KeyPair {} 35 | impl FromJwkValue for X25519KeyPair {} 36 | impl FromJwkValue for K256KeyPair {} 37 | 38 | impl ToJwkValue for Ed25519KeyPair {} 39 | impl ToJwkValue for P256KeyPair {} 40 | impl ToJwkValue for X25519KeyPair {} 41 | 42 | #[cfg(test)] 43 | mod tests { 44 | use askar_crypto::alg::ed25519::Ed25519KeyPair; 45 | use serde_json::json; 46 | 47 | use super::*; 48 | 49 | #[test] 50 | fn from_to_jwk_value_works() { 51 | let jwk = json!({ 52 | "crv":"Ed25519", 53 | "d":"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A", 54 | "key_ops":["sign","verify"], 55 | "kid":"FdFYFzERwC2uCBB46pZQi4GG85LujR8obt-KWRBICVQ", 56 | "kty":"OKP", 57 | "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" 58 | }); 59 | 60 | let key = Ed25519KeyPair::from_jwk_value(&jwk).expect("unable from_jwk_value"); 61 | 62 | let pub_jwk = key 63 | .to_jwk_public_value() 64 | .expect("unable to_jwk_public_value"); 65 | 66 | assert_eq!( 67 | pub_jwk, 68 | json!({ 69 | "crv":"Ed25519", 70 | "kty":"OKP", 71 | "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" 72 | }) 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/jws/mod.rs: -------------------------------------------------------------------------------- 1 | // TODO: Remove allow 2 | #[allow(dead_code)] 3 | mod envelope; 4 | 5 | // TODO: Remove allow 6 | #[allow(dead_code)] 7 | mod parse; 8 | 9 | // TODO: Remove allow 10 | #[allow(dead_code)] 11 | mod sign; 12 | 13 | // TODO: Remove allow 14 | #[allow(dead_code)] 15 | mod verify; 16 | 17 | // TODO: Remove allow 18 | #[allow(unused_imports)] 19 | pub(crate) use envelope::{Algorithm, CompactHeader, Header, ProtectedHeader, Signature, JWS}; 20 | 21 | // TODO: Remove allow 22 | #[allow(unused_imports)] 23 | pub(crate) use sign::{sign, sign_compact}; 24 | 25 | // TODO: Remove allow 26 | #[allow(unused_imports)] 27 | pub(crate) use parse::{parse, parse_compact, ParsedCompactJWS, ParsedJWS}; 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use askar_crypto::{alg::ed25519::Ed25519KeyPair, jwk::FromJwk}; 32 | 33 | use crate::jws::{self, Algorithm}; 34 | 35 | #[test] 36 | fn demo_works() { 37 | // Identifier of Alice key 38 | let alice_kid = "did:example:alice#key-1"; 39 | 40 | // Alice private key 41 | let alice_key = Ed25519KeyPair::from_jwk( 42 | r#" 43 | { 44 | "kty":"OKP", 45 | "d":"pFRUKkyzx4kHdJtFSnlPA9WzqkDT1HWV0xZ5OYZd2SY", 46 | "crv":"Ed25519", 47 | "x":"G-boxFB6vOZBu-wXkm-9Lh79I8nf9Z50cILaOgKKGww" 48 | } 49 | "#, 50 | ) 51 | .expect("Unable from_jwk"); 52 | 53 | // Alice public key 54 | let alice_pkey = Ed25519KeyPair::from_jwk( 55 | r#" 56 | { 57 | "kty":"OKP", 58 | "crv":"Ed25519", 59 | "x":"G-boxFB6vOZBu-wXkm-9Lh79I8nf9Z50cILaOgKKGww" 60 | } 61 | "#, 62 | ) 63 | .expect("Unable from_jwk"); 64 | 65 | // Message payload 66 | let payload = "Hello World!"; 67 | 68 | // Produce signed message 69 | 70 | let msg = jws::sign( 71 | payload.as_bytes(), 72 | (alice_kid, &alice_key), 73 | Algorithm::EdDSA, 74 | ) 75 | .expect("unable sign"); 76 | 77 | // Parse message 78 | 79 | let mut buf = vec![]; 80 | let msg = jws::parse(&msg, &mut buf).expect("Unable parse"); 81 | 82 | // Verify signature 83 | 84 | let valid = msg 85 | .verify((alice_kid, &alice_pkey)) 86 | .expect("Unable verify."); 87 | 88 | assert!(valid); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod jwe; 2 | mod jwk; 3 | mod jws; 4 | mod message; 5 | mod utils; 6 | 7 | // Allows share test vectors between unit and integration tests 8 | #[cfg(test)] 9 | pub(crate) use crate as didcomm; 10 | 11 | #[cfg(test)] 12 | mod test_vectors; 13 | 14 | #[cfg(feature = "testvectors")] 15 | pub(crate) use crate as didcomm; 16 | 17 | #[cfg(feature = "testvectors")] 18 | pub mod test_vectors; 19 | 20 | pub mod algorithms; 21 | pub mod did; 22 | pub mod error; 23 | pub mod protocols; 24 | pub mod secrets; 25 | 26 | pub use message::{ 27 | Attachment, AttachmentBuilder, AttachmentData, Base64AttachmentData, FromPrior, 28 | JsonAttachmentData, LinksAttachmentData, Message, MessageBuilder, MessagingServiceMetadata, 29 | PackEncryptedMetadata, PackEncryptedOptions, PackSignedMetadata, UnpackMetadata, UnpackOptions, 30 | }; 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use serde_json::json; 35 | 36 | use crate::{ 37 | did::resolvers::ExampleDIDResolver, secrets::resolvers::ExampleSecretsResolver, Message, 38 | PackEncryptedOptions, UnpackOptions, 39 | }; 40 | 41 | #[tokio::test] 42 | #[ignore = "will be fixed after https://github.com/sicpa-dlab/didcomm-gemini/issues/71"] 43 | async fn demo_works() { 44 | // --- Build message --- 45 | 46 | let sender = "did:example:1"; 47 | let recipient = "did:example:2"; 48 | 49 | let msg = Message::build( 50 | "example-1".into(), 51 | "example/v1".into(), 52 | json!("example-body"), 53 | ) 54 | .to(recipient.into()) 55 | .from(sender.into()) 56 | .finalize(); 57 | 58 | // --- Packing message --- 59 | 60 | let sender_did_resolver = ExampleDIDResolver::new(vec![]); 61 | let sender_secrets_resolver = ExampleSecretsResolver::new(vec![]); 62 | 63 | let (packed_msg, metadata) = msg 64 | .pack_encrypted( 65 | recipient, 66 | Some(sender), 67 | None, 68 | &sender_did_resolver, 69 | &sender_secrets_resolver, 70 | &PackEncryptedOptions::default(), 71 | ) 72 | .await 73 | .expect("pack is ok."); 74 | 75 | // --- Send message using service endpoint --- 76 | 77 | let service_endpoint = metadata 78 | .messaging_service 79 | .expect("messagin service present.") 80 | .service_endpoint; 81 | 82 | println!("Sending message {} throug {}", packed_msg, service_endpoint); 83 | 84 | // --- Unpacking message --- 85 | 86 | let recipient_did_resolver = ExampleDIDResolver::new(vec![]); 87 | let recipient_secrets_resolver = ExampleSecretsResolver::new(vec![]); 88 | 89 | let (msg, metadata) = Message::unpack( 90 | &packed_msg, 91 | &recipient_did_resolver, 92 | &recipient_secrets_resolver, 93 | &UnpackOptions::default(), 94 | ) 95 | .await 96 | .expect("unpack is ok."); 97 | 98 | assert!(metadata.encrypted); 99 | assert!(metadata.authenticated); 100 | assert!(metadata.encrypted_from_kid.is_some()); 101 | assert!(metadata.encrypted_from_kid.unwrap().starts_with(&recipient)); 102 | 103 | assert_eq!(msg.from, Some(sender.into())); 104 | assert_eq!(msg.to, Some(vec![recipient.into()])); 105 | assert_eq!(msg.body, json!("example-body")); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/message/from_prior/mod.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | mod pack; 4 | mod unpack; 5 | 6 | #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] 7 | /// `from_prior` header value as a plaintext. 8 | /// https://identity.foundation/didcomm-messaging/spec/#did-rotation 9 | pub struct FromPrior { 10 | pub iss: String, 11 | 12 | pub sub: String, 13 | 14 | #[serde(skip_serializing_if = "Option::is_none")] 15 | pub aud: Option, 16 | 17 | #[serde(skip_serializing_if = "Option::is_none")] 18 | pub exp: Option, 19 | 20 | #[serde(skip_serializing_if = "Option::is_none")] 21 | pub nbf: Option, 22 | 23 | #[serde(skip_serializing_if = "Option::is_none")] 24 | pub iat: Option, 25 | 26 | #[serde(skip_serializing_if = "Option::is_none")] 27 | pub jti: Option, 28 | } 29 | 30 | const JWT_TYP: &str = "JWT"; 31 | 32 | impl FromPrior { 33 | pub fn build(iss: String, sub: String) -> FromPriorBuilder { 34 | FromPriorBuilder::new(iss, sub) 35 | } 36 | } 37 | 38 | pub struct FromPriorBuilder { 39 | iss: String, 40 | sub: String, 41 | aud: Option, 42 | exp: Option, 43 | nbf: Option, 44 | iat: Option, 45 | jti: Option, 46 | } 47 | 48 | impl FromPriorBuilder { 49 | fn new(iss: String, sub: String) -> Self { 50 | FromPriorBuilder { 51 | iss, 52 | sub, 53 | aud: None, 54 | exp: None, 55 | nbf: None, 56 | iat: None, 57 | jti: None, 58 | } 59 | } 60 | 61 | pub fn aud(mut self, aud: String) -> Self { 62 | self.aud = Some(aud); 63 | self 64 | } 65 | 66 | pub fn exp(mut self, exp: u64) -> Self { 67 | self.exp = Some(exp); 68 | self 69 | } 70 | 71 | pub fn nbf(mut self, nbf: u64) -> Self { 72 | self.nbf = Some(nbf); 73 | self 74 | } 75 | 76 | pub fn iat(mut self, iat: u64) -> Self { 77 | self.iat = Some(iat); 78 | self 79 | } 80 | 81 | pub fn jti(mut self, jti: String) -> Self { 82 | self.jti = Some(jti); 83 | self 84 | } 85 | 86 | pub fn finalize(self) -> FromPrior { 87 | FromPrior { 88 | iss: self.iss, 89 | sub: self.sub, 90 | aud: self.aud, 91 | exp: self.exp, 92 | nbf: self.nbf, 93 | iat: self.iat, 94 | jti: self.jti, 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/message/mod.rs: -------------------------------------------------------------------------------- 1 | mod attachment; 2 | mod from_prior; 3 | mod message; 4 | mod pack_encrypted; 5 | mod pack_plaintext; 6 | mod pack_signed; 7 | mod unpack; 8 | 9 | pub use attachment::{ 10 | Attachment, AttachmentBuilder, AttachmentData, Base64AttachmentData, JsonAttachmentData, 11 | LinksAttachmentData, 12 | }; 13 | 14 | pub use from_prior::FromPrior; 15 | 16 | pub use message::{Message, MessageBuilder}; 17 | pub use pack_encrypted::{MessagingServiceMetadata, PackEncryptedMetadata, PackEncryptedOptions}; 18 | pub use pack_signed::PackSignedMetadata; 19 | pub use unpack::{UnpackMetadata, UnpackOptions}; 20 | 21 | pub(crate) use pack_encrypted::anoncrypt; 22 | -------------------------------------------------------------------------------- /src/message/unpack/plaintext.rs: -------------------------------------------------------------------------------- 1 | use crate::did::DIDResolver; 2 | use crate::error::{ErrorKind, Result}; 3 | use crate::{FromPrior, Message, UnpackMetadata}; 4 | 5 | pub(crate) async fn _try_unpack_plaintext<'dr, 'sr>( 6 | msg: &str, 7 | did_resolver: &'dr (dyn DIDResolver + 'dr), 8 | metadata: &mut UnpackMetadata, 9 | ) -> Result> { 10 | let msg = match Message::from_str(msg) { 11 | Ok(m) => m, 12 | Err(e) if e.kind() == ErrorKind::Malformed => return Ok(None), 13 | Err(e) => Err(e)?, 14 | } 15 | .validate()?; 16 | 17 | if let Some(from_prior) = &msg.from_prior { 18 | let (unpacked_from_prior, from_prior_issuer_kid) = 19 | FromPrior::unpack(from_prior, did_resolver).await?; 20 | 21 | metadata.from_prior = Some(unpacked_from_prior); 22 | metadata.from_prior_issuer_kid = Some(from_prior_issuer_kid); 23 | }; 24 | 25 | Ok(Some(msg)) 26 | } 27 | -------------------------------------------------------------------------------- /src/protocols/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod routing; 2 | -------------------------------------------------------------------------------- /src/protocols/routing/forward.rs: -------------------------------------------------------------------------------- 1 | use serde::Serialize; 2 | use serde_json::Value; 3 | 4 | use crate::Message; 5 | 6 | /// Utility structure providing convinient access to Forward plaintext message fields. 7 | #[derive(Debug, PartialEq, Eq, Serialize, Clone)] 8 | pub struct ParsedForward<'a> { 9 | pub msg: &'a Message, 10 | pub next: String, 11 | pub forwarded_msg: Value, 12 | } 13 | -------------------------------------------------------------------------------- /src/secrets/mod.rs: -------------------------------------------------------------------------------- 1 | //! Set of interfaces that allow access to DID Document secrets 2 | 3 | pub mod resolvers; 4 | 5 | use async_trait::async_trait; 6 | use serde::{Deserialize, Serialize}; 7 | use serde_json::Value; 8 | 9 | use crate::error::Result; 10 | 11 | /// Interface for secrets resolver. 12 | /// Resolves secrets such as private keys to be used for signing and encryption. 13 | #[cfg(feature = "uniffi")] 14 | #[async_trait] 15 | pub trait SecretsResolver: Sync { 16 | /// Finds secret (usually private key) identified by the given key ID. 17 | /// 18 | /// # Parameters 19 | /// - `secret_id` the ID (in form of DID URL) identifying a secret 20 | /// 21 | /// # Returns 22 | /// A secret (usually private key) or None of there is no secret for the given ID 23 | /// 24 | /// # Errors 25 | /// - IOError 26 | /// - InvalidState 27 | async fn get_secret(&self, secret_id: &str) -> Result>; 28 | 29 | /// Find all secrets that have one of the given IDs. 30 | /// Return secrets only for key IDs for which a secret is present. 31 | /// 32 | /// # Parameters 33 | /// - `secret_ids` the IDs find secrets for 34 | /// 35 | /// # Returns 36 | /// possible empty list of all secrets that have one of the given IDs. 37 | async fn find_secrets<'a>(&self, secret_ids: &'a [&'a str]) -> Result>; 38 | } 39 | 40 | /// Interface for secrets resolver. 41 | /// Resolves secrets such as private keys to be used for signing and encryption. 42 | #[cfg(not(feature = "uniffi"))] 43 | #[async_trait(?Send)] 44 | pub trait SecretsResolver { 45 | /// Finds secret (usually private key) identified by the given key ID. 46 | /// 47 | /// # Parameters 48 | /// - `secret_id` the ID (in form of DID URL) identifying a secret 49 | /// 50 | /// # Returns 51 | /// A secret (usually private key) or None of there is no secret for the given ID 52 | /// 53 | /// # Errors 54 | /// - IOError 55 | /// - InvalidState 56 | async fn get_secret(&self, secret_id: &str) -> Result>; 57 | 58 | /// Find all secrets that have one of the given IDs. 59 | /// Return secrets only for key IDs for which a secret is present. 60 | /// 61 | /// # Parameters 62 | /// - `secret_ids` the IDs find secrets for 63 | /// 64 | /// # Returns 65 | /// possible empty list of all secrets that have one of the given IDs. 66 | async fn find_secrets<'a>(&self, secret_ids: &'a [&'a str]) -> Result>; 67 | } 68 | 69 | /// Represents secret. 70 | #[derive(Debug, Clone, Deserialize, Serialize)] 71 | pub struct Secret { 72 | /// A key ID identifying a secret (private key). 73 | pub id: String, 74 | 75 | /// Must have the same semantics as type ('type' field) of the corresponding method in DID Doc containing a public key. 76 | #[serde(rename = "type")] 77 | pub type_: SecretType, 78 | 79 | /// Value of the secret (private key) 80 | #[serde(flatten)] 81 | pub secret_material: SecretMaterial, 82 | } 83 | 84 | /// Must have the same semantics as type ('type' field) of the corresponding method in DID Doc containing a public key. 85 | #[derive(Debug, Clone, Deserialize, Serialize)] 86 | pub enum SecretType { 87 | JsonWebKey2020, 88 | X25519KeyAgreementKey2019, 89 | X25519KeyAgreementKey2020, 90 | Ed25519VerificationKey2018, 91 | Ed25519VerificationKey2020, 92 | EcdsaSecp256k1VerificationKey2019, 93 | Other, 94 | } 95 | 96 | /// Represents secret crypto material. 97 | #[derive(Debug, Clone, Deserialize, Serialize)] 98 | #[serde(untagged)] 99 | pub enum SecretMaterial { 100 | #[serde(rename_all = "camelCase")] 101 | JWK { private_key_jwk: Value }, 102 | 103 | #[serde(rename_all = "camelCase")] 104 | Multibase { private_key_multibase: String }, 105 | 106 | #[serde(rename_all = "camelCase")] 107 | Base58 { private_key_base58: String }, 108 | } 109 | -------------------------------------------------------------------------------- /src/secrets/resolvers/example.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | 3 | use crate::{ 4 | error::Result, 5 | secrets::{Secret, SecretsResolver}, 6 | }; 7 | 8 | pub struct ExampleSecretsResolver { 9 | known_secrets: Vec, 10 | } 11 | 12 | impl ExampleSecretsResolver { 13 | pub fn new(known_secrets: Vec) -> Self { 14 | ExampleSecretsResolver { known_secrets } 15 | } 16 | } 17 | 18 | #[cfg_attr(feature = "uniffi", async_trait)] 19 | #[cfg_attr(not(feature = "uniffi"), async_trait(?Send))] 20 | impl SecretsResolver for ExampleSecretsResolver { 21 | async fn get_secret(&self, secret_id: &str) -> Result> { 22 | Ok(self 23 | .known_secrets 24 | .iter() 25 | .find(|s| s.id == secret_id) 26 | .map(|s| s.clone())) 27 | } 28 | 29 | async fn find_secrets<'a>(&self, secret_ids: &'a [&'a str]) -> Result> { 30 | Ok(secret_ids 31 | .iter() 32 | .filter(|&&sid| self.known_secrets.iter().find(|s| s.id == sid).is_some()) 33 | .map(|sid| *sid) 34 | .collect()) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/secrets/resolvers/mod.rs: -------------------------------------------------------------------------------- 1 | mod example; 2 | 3 | pub use example::ExampleSecretsResolver; 4 | -------------------------------------------------------------------------------- /src/test_vectors/common.rs: -------------------------------------------------------------------------------- 1 | use serde_json::{Map, Value}; 2 | 3 | pub const ALICE_DID: &str = "did:example:alice"; 4 | pub const BOB_DID: &str = "did:example:bob"; 5 | pub const CHARLIE_DID: &str = "did:example:charlie"; 6 | 7 | pub fn update_field(msg: &str, field: &str, value: &str) -> String { 8 | let parsed: Value = serde_json::from_str(&msg).unwrap(); 9 | let mut msg_dict: Map = parsed.as_object().unwrap().clone(); 10 | msg_dict.insert(String::from(field), value.into()); 11 | serde_json::to_string(&msg_dict).unwrap() 12 | } 13 | 14 | pub fn remove_field(msg: &str, field: &str) -> String { 15 | let parsed: Value = serde_json::from_str(&msg).unwrap(); 16 | let mut msg_dict: Map = parsed.as_object().unwrap().clone(); 17 | msg_dict.remove(field); 18 | serde_json::to_string(&msg_dict).unwrap() 19 | } 20 | 21 | pub fn update_protected_field(msg: &str, field: &str, value: &str) -> String { 22 | let parsed: Value = serde_json::from_str(&msg).unwrap(); 23 | let mut msg_dict: Map = parsed.as_object().unwrap().clone(); 24 | 25 | let mut buffer = Vec::::new(); 26 | base64::decode_config_buf( 27 | msg_dict.get("protected").unwrap().as_str().unwrap(), 28 | base64::URL_SAFE_NO_PAD, 29 | &mut buffer, 30 | ) 31 | .unwrap(); 32 | let parsed_protected: Value = serde_json::from_slice(&buffer).unwrap(); 33 | let mut protected_dict: Map = parsed_protected.as_object().unwrap().clone(); 34 | protected_dict.insert(String::from(field), value.into()); 35 | let protected_str = serde_json::to_string(&protected_dict).unwrap(); 36 | println!("{}", &protected_str); 37 | let protected_str_base64 = base64::encode_config(protected_str, base64::URL_SAFE_NO_PAD); 38 | msg_dict.insert(String::from("protected"), protected_str_base64.into()); 39 | serde_json::to_string(&msg_dict).unwrap() 40 | } 41 | 42 | pub fn remove_protected_field(msg: &str, field: &str) -> String { 43 | let parsed: Value = serde_json::from_str(&msg).unwrap(); 44 | let mut msg_dict: Map = parsed.as_object().unwrap().clone(); 45 | 46 | let mut buffer = Vec::::new(); 47 | base64::decode_config_buf( 48 | msg_dict.get("protected").unwrap().as_str().unwrap(), 49 | base64::URL_SAFE_NO_PAD, 50 | &mut buffer, 51 | ) 52 | .unwrap(); 53 | let parsed_protected: Value = serde_json::from_slice(&buffer).unwrap(); 54 | let mut protected_dict: Map = parsed_protected.as_object().unwrap().clone(); 55 | protected_dict.remove(field); 56 | let protected_str = serde_json::to_string(&protected_dict).unwrap(); 57 | let protected_str_base64 = base64::encode_config(protected_str, base64::URL_SAFE_NO_PAD); 58 | 59 | msg_dict.insert(String::from("protected"), protected_str_base64.into()); 60 | serde_json::to_string(&msg_dict).unwrap() 61 | } 62 | -------------------------------------------------------------------------------- /src/test_vectors/did_doc/charlie.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use serde_json::json; 3 | 4 | use crate::didcomm::did::{ 5 | DIDCommMessagingService, DIDDoc, Service, ServiceKind, VerificationMaterial, 6 | VerificationMethod, VerificationMethodType, 7 | }; 8 | 9 | lazy_static! { 10 | pub static ref CHARLIE_VERIFICATION_METHOD_KEY_AGREEM_X25519: VerificationMethod = 11 | VerificationMethod { 12 | id: "did:example:charlie#key-x25519-1".into(), 13 | controller: "did:example:charlie#key-x25519-1".into(), 14 | type_: VerificationMethodType::JsonWebKey2020, 15 | verification_material: VerificationMaterial::JWK { 16 | public_key_jwk: json!( 17 | { 18 | "kty": "OKP", 19 | "crv": "X25519", 20 | "x": "nTiVFj7DChMsETDdxd5dIzLAJbSQ4j4UG6ZU1ogLNlw", 21 | }) 22 | }, 23 | }; 24 | pub static ref CHARLIE_AUTH_METHOD_25519: VerificationMethod = VerificationMethod { 25 | id: "did:example:charlie#key-1".into(), 26 | controller: "did:example:charlie#key-1".into(), 27 | type_: VerificationMethodType::JsonWebKey2020, 28 | verification_material: VerificationMaterial::JWK { 29 | public_key_jwk: json!( 30 | { 31 | "kty": "OKP", 32 | "crv": "Ed25519", 33 | "x": "VDXDwuGKVq91zxU6q7__jLDUq8_C5cuxECgd-1feFTE", 34 | }) 35 | }, 36 | }; 37 | pub static ref CHARLIE_DID_COMM_MESSAGING_SERVICE: DIDCommMessagingService = 38 | DIDCommMessagingService { 39 | uri: "did:example:mediator3".into(), 40 | accept: Some(vec!["didcomm/v2".into(), "didcomm/aip2;env=rfc587".into()]), 41 | routing_keys: vec![ 42 | "did:example:mediator2#key-x25519-1".into(), 43 | "did:example:mediator1#key-x25519-1".into(), 44 | ], 45 | }; 46 | pub static ref CHARLIE_SERVICE: Service = Service { 47 | id: "did:example:charlie#didcomm-1".into(), 48 | service_endpoint: ServiceKind::DIDCommMessaging { 49 | value: CHARLIE_DID_COMM_MESSAGING_SERVICE.clone() 50 | }, 51 | }; 52 | pub static ref CHARLIE_DID_DOC: DIDDoc = DIDDoc { 53 | id: "did:example:charlie".into(), 54 | authentication: vec!["did:example:charlie#key-1".into()], 55 | key_agreement: vec!["did:example:charlie#key-x25519-1".into()], 56 | service: vec![CHARLIE_SERVICE.clone()], 57 | verification_method: vec![ 58 | CHARLIE_VERIFICATION_METHOD_KEY_AGREEM_X25519.clone(), 59 | CHARLIE_AUTH_METHOD_25519.clone(), 60 | ], 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /src/test_vectors/did_doc/mediator1.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use serde_json::json; 3 | 4 | use crate::didcomm::did::{ 5 | DIDDoc, VerificationMaterial, VerificationMethod, VerificationMethodType, 6 | }; 7 | 8 | lazy_static! { 9 | pub static ref MEDIATOR1_VERIFICATION_METHOD_KEY_AGREEM_X25519_1: VerificationMethod = 10 | VerificationMethod { 11 | id: "did:example:mediator1#key-x25519-1".into(), 12 | controller: "did:example:mediator1#key-x25519-1".into(), 13 | type_: VerificationMethodType::JsonWebKey2020, 14 | verification_material: VerificationMaterial::JWK { 15 | public_key_jwk: json!( 16 | { 17 | "kty": "OKP", 18 | "crv": "X25519", 19 | "x": "GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E", 20 | }) 21 | }, 22 | }; 23 | pub static ref MEDIATOR1_VERIFICATION_METHOD_KEY_AGREEM_P256_1: VerificationMethod = 24 | VerificationMethod { 25 | id: "did:example:mediator1#key-p256-1".into(), 26 | controller: "did:example:mediator1#key-p256-1".into(), 27 | type_: VerificationMethodType::JsonWebKey2020, 28 | verification_material: VerificationMaterial::JWK { 29 | public_key_jwk: json!( 30 | { 31 | "kty": "EC", 32 | "crv": "P-256", 33 | "x": "FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo", 34 | "y": "6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY", 35 | }) 36 | }, 37 | }; 38 | pub static ref MEDIATOR1_VERIFICATION_METHOD_KEY_AGREEM_P384_1: VerificationMethod = 39 | VerificationMethod { 40 | id: "did:example:mediator1#key-p384-1".into(), 41 | controller: "did:example:mediator1#key-p384-1".into(), 42 | type_: VerificationMethodType::JsonWebKey2020, 43 | verification_material: VerificationMaterial::JWK { 44 | public_key_jwk: json!( 45 | { 46 | "kty": "EC", 47 | "crv": "P-384", 48 | "x": "MvnE_OwKoTcJVfHyTX-DLSRhhNwlu5LNoQ5UWD9Jmgtdxp_kpjsMuTTBnxg5RF_Y", 49 | "y": "X_3HJBcKFQEG35PZbEOBn8u9_z8V1F9V1Kv-Vh0aSzmH-y9aOuDJUE3D4Hvmi5l7", 50 | }) 51 | }, 52 | }; 53 | pub static ref MEDIATOR1_VERIFICATION_METHOD_KEY_AGREEM_P521_1: VerificationMethod = 54 | VerificationMethod { 55 | id: "did:example:mediator1#key-p521-1".into(), 56 | controller: "did:example:mediator1#key-p521-1".into(), 57 | type_: VerificationMethodType::JsonWebKey2020, 58 | verification_material: VerificationMaterial::JWK { 59 | public_key_jwk: json!( 60 | { 61 | "kty": "EC", 62 | "crv": "P-521", 63 | "x": "Af9O5THFENlqQbh2Ehipt1Yf4gAd9RCa3QzPktfcgUIFADMc4kAaYVViTaDOuvVS2vMS1KZe0D5kXedSXPQ3QbHi", 64 | "y": "ATZVigRQ7UdGsQ9j-omyff6JIeeUv3CBWYsZ0l6x3C_SYqhqVV7dEG-TafCCNiIxs8qeUiXQ8cHWVclqkH4Lo1qH", 65 | }) 66 | }, 67 | }; 68 | pub static ref MEDIATOR1_DID_DOC: DIDDoc = DIDDoc { 69 | id: "did:example:mediator1".into(), 70 | authentication: vec![], 71 | key_agreement: vec![ 72 | "did:example:mediator1#key-x25519-1".into(), 73 | "did:example:mediator1#key-p256-1".into(), 74 | "did:example:mediator1#key-p384-1".into(), 75 | "did:example:mediator1#key-p521-1".into(), 76 | ], 77 | service: vec![], 78 | verification_method: vec![ 79 | MEDIATOR1_VERIFICATION_METHOD_KEY_AGREEM_X25519_1.clone(), 80 | MEDIATOR1_VERIFICATION_METHOD_KEY_AGREEM_P256_1.clone(), 81 | MEDIATOR1_VERIFICATION_METHOD_KEY_AGREEM_P384_1.clone(), 82 | MEDIATOR1_VERIFICATION_METHOD_KEY_AGREEM_P521_1.clone(), 83 | ], 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /src/test_vectors/did_doc/mediator2.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use serde_json::json; 3 | 4 | use crate::didcomm::did::{ 5 | DIDDoc, VerificationMaterial, VerificationMethod, VerificationMethodType, 6 | }; 7 | 8 | lazy_static! { 9 | pub static ref MEDIATOR2_VERIFICATION_METHOD_KEY_AGREEM_X25519_1: VerificationMethod = 10 | VerificationMethod { 11 | id: "did:example:mediator2#key-x25519-1".into(), 12 | controller: "did:example:mediator2#key-x25519-1".into(), 13 | type_: VerificationMethodType::JsonWebKey2020, 14 | verification_material: VerificationMaterial::JWK { 15 | public_key_jwk: json!( 16 | { 17 | "kty": "OKP", 18 | "crv": "X25519", 19 | "x": "GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E", 20 | }) 21 | }, 22 | }; 23 | pub static ref MEDIATOR2_VERIFICATION_METHOD_KEY_AGREEM_P256_1: VerificationMethod = 24 | VerificationMethod { 25 | id: "did:example:mediator2#key-p256-1".into(), 26 | controller: "did:example:mediator2#key-p256-1".into(), 27 | type_: VerificationMethodType::JsonWebKey2020, 28 | verification_material: VerificationMaterial::JWK { 29 | public_key_jwk: json!( 30 | { 31 | "kty": "EC", 32 | "crv": "P-256", 33 | "x": "FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo", 34 | "y": "6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY", 35 | }) 36 | }, 37 | }; 38 | pub static ref MEDIATOR2_VERIFICATION_METHOD_KEY_AGREEM_P384_1: VerificationMethod = 39 | VerificationMethod { 40 | id: "did:example:mediator2#key-p384-1".into(), 41 | controller: "did:example:mediator2#key-p384-1".into(), 42 | type_: VerificationMethodType::JsonWebKey2020, 43 | verification_material: VerificationMaterial::JWK { 44 | public_key_jwk: json!( 45 | { 46 | "kty": "EC", 47 | "crv": "P-384", 48 | "x": "MvnE_OwKoTcJVfHyTX-DLSRhhNwlu5LNoQ5UWD9Jmgtdxp_kpjsMuTTBnxg5RF_Y", 49 | "y": "X_3HJBcKFQEG35PZbEOBn8u9_z8V1F9V1Kv-Vh0aSzmH-y9aOuDJUE3D4Hvmi5l7", 50 | }) 51 | }, 52 | }; 53 | pub static ref MEDIATOR2_VERIFICATION_METHOD_KEY_AGREEM_P521_1: VerificationMethod = 54 | VerificationMethod { 55 | id: "did:example:mediator2#key-p521-1".into(), 56 | controller: "did:example:mediator2#key-p521-1".into(), 57 | type_: VerificationMethodType::JsonWebKey2020, 58 | verification_material: VerificationMaterial::JWK { 59 | public_key_jwk: json!( 60 | { 61 | "kty": "EC", 62 | "crv": "P-521", 63 | "x": "Af9O5THFENlqQbh2Ehipt1Yf4gAd9RCa3QzPktfcgUIFADMc4kAaYVViTaDOuvVS2vMS1KZe0D5kXedSXPQ3QbHi", 64 | "y": "ATZVigRQ7UdGsQ9j-omyff6JIeeUv3CBWYsZ0l6x3C_SYqhqVV7dEG-TafCCNiIxs8qeUiXQ8cHWVclqkH4Lo1qH", 65 | }) 66 | }, 67 | }; 68 | pub static ref MEDIATOR2_DID_DOC: DIDDoc = DIDDoc { 69 | id: "did:example:mediator2".into(), 70 | authentication: vec![], 71 | key_agreement: vec![ 72 | "did:example:mediator2#key-x25519-1".into(), 73 | "did:example:mediator2#key-p256-1".into(), 74 | "did:example:mediator2#key-p384-1".into(), 75 | "did:example:mediator2#key-p521-1".into(), 76 | ], 77 | service: vec![], 78 | verification_method: vec![ 79 | MEDIATOR2_VERIFICATION_METHOD_KEY_AGREEM_X25519_1.clone(), 80 | MEDIATOR2_VERIFICATION_METHOD_KEY_AGREEM_P256_1.clone(), 81 | MEDIATOR2_VERIFICATION_METHOD_KEY_AGREEM_P384_1.clone(), 82 | MEDIATOR2_VERIFICATION_METHOD_KEY_AGREEM_P521_1.clone(), 83 | ], 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /src/test_vectors/did_doc/mediator3.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use serde_json::json; 3 | 4 | use crate::didcomm::did::{ 5 | DIDCommMessagingService, DIDDoc, Service, ServiceKind, VerificationMaterial, 6 | VerificationMethod, VerificationMethodType, 7 | }; 8 | 9 | lazy_static! { 10 | pub static ref MEDIATOR3_VERIFICATION_METHOD_KEY_AGREEM_X25519_1: VerificationMethod = 11 | VerificationMethod { 12 | id: "did:example:mediator3#key-x25519-1".into(), 13 | controller: "did:example:mediator3#key-x25519-1".into(), 14 | type_: VerificationMethodType::JsonWebKey2020, 15 | verification_material: VerificationMaterial::JWK { 16 | public_key_jwk: json!( 17 | { 18 | "kty": "OKP", 19 | "crv": "X25519", 20 | "x": "GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E", 21 | }) 22 | }, 23 | }; 24 | pub static ref MEDIATOR3_VERIFICATION_METHOD_KEY_AGREEM_P256_1: VerificationMethod = 25 | VerificationMethod { 26 | id: "did:example:mediator3#key-p256-1".into(), 27 | controller: "did:example:mediator3#key-p256-1".into(), 28 | type_: VerificationMethodType::JsonWebKey2020, 29 | verification_material: VerificationMaterial::JWK { 30 | public_key_jwk: json!( 31 | { 32 | "kty": "EC", 33 | "crv": "P-256", 34 | "x": "FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo", 35 | "y": "6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY", 36 | }) 37 | }, 38 | }; 39 | pub static ref MEDIATOR3_VERIFICATION_METHOD_KEY_AGREEM_P384_1: VerificationMethod = 40 | VerificationMethod { 41 | id: "did:example:mediator3#key-p384-1".into(), 42 | controller: "did:example:mediator3#key-p384-1".into(), 43 | type_: VerificationMethodType::JsonWebKey2020, 44 | verification_material: VerificationMaterial::JWK { 45 | public_key_jwk: json!( 46 | { 47 | "kty": "EC", 48 | "crv": "P-384", 49 | "x": "MvnE_OwKoTcJVfHyTX-DLSRhhNwlu5LNoQ5UWD9Jmgtdxp_kpjsMuTTBnxg5RF_Y", 50 | "y": "X_3HJBcKFQEG35PZbEOBn8u9_z8V1F9V1Kv-Vh0aSzmH-y9aOuDJUE3D4Hvmi5l7", 51 | }) 52 | }, 53 | }; 54 | pub static ref MEDIATOR3_VERIFICATION_METHOD_KEY_AGREEM_P521_1: VerificationMethod = 55 | VerificationMethod { 56 | id: "did:example:mediator3#key-p521-1".into(), 57 | controller: "did:example:mediator3#key-p521-1".into(), 58 | type_: VerificationMethodType::JsonWebKey2020, 59 | verification_material: VerificationMaterial::JWK { 60 | public_key_jwk: json!( 61 | { 62 | "kty": "EC", 63 | "crv": "P-521", 64 | "x": "Af9O5THFENlqQbh2Ehipt1Yf4gAd9RCa3QzPktfcgUIFADMc4kAaYVViTaDOuvVS2vMS1KZe0D5kXedSXPQ3QbHi", 65 | "y": "ATZVigRQ7UdGsQ9j-omyff6JIeeUv3CBWYsZ0l6x3C_SYqhqVV7dEG-TafCCNiIxs8qeUiXQ8cHWVclqkH4Lo1qH", 66 | }) 67 | }, 68 | }; 69 | pub static ref MEDIATOR3_DID_COMM_MESSAGING_SERVICE: DIDCommMessagingService = 70 | DIDCommMessagingService { 71 | uri: "http://example.com/path".into(), 72 | accept: Some(vec!["didcomm/v2".into(), "didcomm/aip2;env=rfc587".into()]), 73 | routing_keys: vec![], 74 | }; 75 | pub static ref MEDIATOR3_SERVICE: Service = Service { 76 | id: "did:example:mediator3#didcomm-1".into(), 77 | service_endpoint: ServiceKind::DIDCommMessaging { 78 | value: MEDIATOR3_DID_COMM_MESSAGING_SERVICE.clone() 79 | }, 80 | }; 81 | pub static ref MEDIATOR3_DID_DOC: DIDDoc = DIDDoc { 82 | id: "did:example:mediator3".into(), 83 | authentication: vec![], 84 | key_agreement: vec![ 85 | "did:example:mediator3#key-x25519-1".into(), 86 | "did:example:mediator3#key-p256-1".into(), 87 | "did:example:mediator3#key-p384-1".into(), 88 | "did:example:mediator3#key-p521-1".into(), 89 | ], 90 | service: vec![MEDIATOR3_SERVICE.clone()], 91 | verification_method: vec![ 92 | MEDIATOR3_VERIFICATION_METHOD_KEY_AGREEM_X25519_1.clone(), 93 | MEDIATOR3_VERIFICATION_METHOD_KEY_AGREEM_P256_1.clone(), 94 | MEDIATOR3_VERIFICATION_METHOD_KEY_AGREEM_P384_1.clone(), 95 | MEDIATOR3_VERIFICATION_METHOD_KEY_AGREEM_P521_1.clone(), 96 | ], 97 | }; 98 | } 99 | -------------------------------------------------------------------------------- /src/test_vectors/did_doc/mod.rs: -------------------------------------------------------------------------------- 1 | mod alice; 2 | mod bob; 3 | mod charlie; 4 | mod mediator1; 5 | mod mediator2; 6 | mod mediator3; 7 | 8 | // TODO: Remove allow 9 | #[allow(unused_imports)] 10 | pub use mediator1::*; 11 | 12 | // TODO: Remove allow 13 | #[allow(unused_imports)] 14 | pub use mediator2::*; 15 | 16 | // TODO: Remove allow 17 | #[allow(unused_imports)] 18 | pub use mediator3::*; 19 | 20 | // TODO: Remove allow 21 | #[allow(unused_imports)] 22 | pub use alice::*; 23 | 24 | // TODO: Remove allow 25 | #[allow(unused_imports)] 26 | pub use bob::*; 27 | 28 | // TODO: Remove allow 29 | #[allow(unused_imports)] 30 | pub use charlie::*; 31 | -------------------------------------------------------------------------------- /src/test_vectors/from_prior.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | 3 | use super::common::{ALICE_DID, CHARLIE_DID}; 4 | use crate::{ 5 | didcomm::FromPrior, 6 | test_vectors::{ALICE_AUTH_METHOD_25519, CHARLIE_AUTH_METHOD_25519}, 7 | }; 8 | 9 | lazy_static! { 10 | pub static ref FROM_PRIOR_MINIMAL: FromPrior = 11 | FromPrior::build(CHARLIE_DID.into(), ALICE_DID.into()).finalize(); 12 | } 13 | 14 | lazy_static! { 15 | pub static ref FROM_PRIOR_FULL: FromPrior = 16 | FromPrior::build(CHARLIE_DID.into(), ALICE_DID.into()) 17 | .aud("123".into()) 18 | .exp(1234) 19 | .nbf(12345) 20 | .iat(123456) 21 | .jti("dfg".into()) 22 | .finalize(); 23 | } 24 | 25 | lazy_static! { 26 | pub static ref FROM_PRIOR_INVALID_ISS: FromPrior = 27 | FromPrior::build("invalid".into(), ALICE_DID.into()) 28 | .aud("123".into()) 29 | .exp(1234) 30 | .nbf(12345) 31 | .iat(123456) 32 | .jti("dfg".into()) 33 | .finalize(); 34 | } 35 | 36 | lazy_static! { 37 | pub static ref FROM_PRIOR_INVALID_ISS_DID_URL: FromPrior = 38 | FromPrior::build(CHARLIE_AUTH_METHOD_25519.id.clone(), ALICE_DID.into()) 39 | .aud("123".into()) 40 | .exp(1234) 41 | .nbf(12345) 42 | .iat(123456) 43 | .jti("dfg".into()) 44 | .finalize(); 45 | } 46 | 47 | lazy_static! { 48 | pub static ref FROM_PRIOR_INVALID_SUB: FromPrior = 49 | FromPrior::build(CHARLIE_DID.into(), "invalid".into()) 50 | .aud("123".into()) 51 | .exp(1234) 52 | .nbf(12345) 53 | .iat(123456) 54 | .jti("dfg".into()) 55 | .finalize(); 56 | } 57 | 58 | lazy_static! { 59 | pub static ref FROM_PRIOR_INVALID_SUB_DID_URL: FromPrior = 60 | FromPrior::build(CHARLIE_DID.into(), ALICE_AUTH_METHOD_25519.id.clone()) 61 | .aud("123".into()) 62 | .exp(1234) 63 | .nbf(12345) 64 | .iat(123456) 65 | .jti("dfg".into()) 66 | .finalize(); 67 | } 68 | 69 | lazy_static! { 70 | pub static ref FROM_PRIOR_INVALID_EQUAL_ISS_AND_SUB: FromPrior = 71 | FromPrior::build(ALICE_DID.into(), ALICE_DID.into()) 72 | .aud("123".into()) 73 | .exp(1234) 74 | .nbf(12345) 75 | .iat(123456) 76 | .jti("dfg".into()) 77 | .finalize(); 78 | } 79 | -------------------------------------------------------------------------------- /src/test_vectors/from_prior_jwt.rs: -------------------------------------------------------------------------------- 1 | pub const FROM_PRIOR_JWT_FULL: &str = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpleGFtcGxlOmNoYXJsaWUja2V5LTEifQ.eyJpc3MiOiJkaWQ6ZXhhbXBsZTpjaGFybGllIiwic3ViIjoiZGlkOmV4YW1wbGU6YWxpY2UiLCJhdWQiOiIxMjMiLCJleHAiOjEyMzQsIm5iZiI6MTIzNDUsImlhdCI6MTIzNDU2LCJqdGkiOiJkZmcifQ.ir0tegXiGJIZIMagO5P853KwhzGTEw0OpFFAyarUV-nQrtbI_ELbxT9l7jPBoPve_-60ifGJ9v3ArmFjELFlDA"; 2 | 3 | pub const FROM_PRIOR_JWT_INVALID: &str = "invalid"; 4 | 5 | pub const FROM_PRIOR_JWT_INVALID_SIGNATURE: &str = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpleGFtcGxlOmNoYXJsaWUja2V5LTEifQ.eyJpc3MiOiJkaWQ6ZXhhbXBsZTpjaGFybGllIiwic3ViIjoiZGlkOmV4YW1wbGU6YWxpY2UiLCJhdWQiOiIxMjMiLCJleHAiOjEyMzQsIm5iZiI6MTIzNDUsImlhdCI6MTIzNDU2LCJqdGkiOiJkZmcifQ.ir0tegXiGJIZIMagO5P853KwhzGTEw0OpFFAyarUV-nQrtbI_ELbxT9l7jPBoPve_-60ifGJ9v3ArmFjELFlDB"; 6 | -------------------------------------------------------------------------------- /src/test_vectors/mod.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | mod did_doc; 3 | mod encrypted; 4 | mod from_prior; 5 | mod from_prior_jwt; 6 | mod message; 7 | mod plaintext; 8 | mod secrets; 9 | mod signed; 10 | 11 | pub use common::*; 12 | 13 | pub use did_doc::*; 14 | 15 | pub use encrypted::*; 16 | 17 | pub use from_prior::*; 18 | 19 | pub use from_prior_jwt::*; 20 | 21 | pub use message::*; 22 | pub use plaintext::*; 23 | 24 | pub use secrets::*; 25 | 26 | pub use signed::*; 27 | -------------------------------------------------------------------------------- /src/test_vectors/secrets/alice.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use serde_json::json; 3 | 4 | use crate::didcomm::secrets::{Secret, SecretMaterial, SecretType}; 5 | 6 | lazy_static! { 7 | pub static ref ALICE_SECRET_AUTH_KEY_ED25519: Secret = Secret { 8 | id: "did:example:alice#key-1".into(), 9 | type_: SecretType::JsonWebKey2020, 10 | secret_material: SecretMaterial::JWK { 11 | private_key_jwk: json!({ 12 | "kty": "OKP", 13 | "d": "pFRUKkyzx4kHdJtFSnlPA9WzqkDT1HWV0xZ5OYZd2SY", 14 | "crv": "Ed25519", 15 | "x": "G-boxFB6vOZBu-wXkm-9Lh79I8nf9Z50cILaOgKKGww", 16 | }) 17 | }, 18 | }; 19 | pub static ref ALICE_SECRET_AUTH_KEY_P256: Secret = Secret { 20 | id: "did:example:alice#key-2".into(), 21 | type_: SecretType::JsonWebKey2020.into(), 22 | secret_material: SecretMaterial::JWK { 23 | private_key_jwk: json!({ 24 | "kty": "EC", 25 | "d": "7TCIdt1rhThFtWcEiLnk_COEjh1ZfQhM4bW2wz-dp4A", 26 | "crv": "P-256", 27 | "x": "2syLh57B-dGpa0F8p1JrO6JU7UUSF6j7qL-vfk1eOoY", 28 | "y": "BgsGtI7UPsObMRjdElxLOrgAO9JggNMjOcfzEPox18w", 29 | }) 30 | }, 31 | }; 32 | pub static ref ALICE_SECRET_AUTH_KEY_SECP256K1: Secret = Secret { 33 | id: "did:example:alice#key-3".into(), 34 | type_: SecretType::JsonWebKey2020, 35 | secret_material: SecretMaterial::JWK { 36 | private_key_jwk: json!({ 37 | "kty": "EC", 38 | "d": "N3Hm1LXA210YVGGsXw_GklMwcLu_bMgnzDese6YQIyA", 39 | "crv": "secp256k1", 40 | "x": "aToW5EaTq5mlAf8C5ECYDSkqsJycrW-e1SQ6_GJcAOk", 41 | "y": "JAGX94caA21WKreXwYUaOCYTBMrqaX4KWIlsQZTHWCk", 42 | }) 43 | }, 44 | }; 45 | pub static ref ALICE_SECRET_KEY_AGREEMENT_KEY_X25519: Secret = Secret { 46 | id: "did:example:alice#key-x25519-1".into(), 47 | type_: SecretType::JsonWebKey2020, 48 | secret_material: SecretMaterial::JWK { 49 | private_key_jwk: json!({ 50 | "kty": "OKP", 51 | "d": "r-jK2cO3taR8LQnJB1_ikLBTAnOtShJOsHXRUWT-aZA", 52 | "crv": "X25519", 53 | "x": "avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs", 54 | }) 55 | }, 56 | }; 57 | pub static ref ALICE_SECRET_KEY_AGREEMENT_KEY_P256: Secret = Secret { 58 | id: "did:example:alice#key-p256-1".into(), 59 | type_: SecretType::JsonWebKey2020, 60 | secret_material: SecretMaterial::JWK { 61 | private_key_jwk: json!({ 62 | "kty": "EC", 63 | "d": "sB0bYtpaXyp-h17dDpMx91N3Du1AdN4z1FUq02GbmLw", 64 | "crv": "P-256", 65 | "x": "L0crjMN1g0Ih4sYAJ_nGoHUck2cloltUpUVQDhF2nHE", 66 | "y": "SxYgE7CmEJYi7IDhgK5jI4ZiajO8jPRZDldVhqFpYoo", 67 | }) 68 | }, 69 | }; 70 | pub static ref ALICE_SECRET_KEY_AGREEMENT_KEY_P521: Secret = Secret { 71 | id: "did:example:alice#key-p521-1".into(), 72 | type_: SecretType::JsonWebKey2020, 73 | secret_material: SecretMaterial::JWK { 74 | private_key_jwk: json!({ 75 | "kty": "EC", 76 | "d": "AQCQKE7rZpxPnX9RgjXxeywrAMp1fJsyFe4cir1gWj-8t8xWaM_E2qBkTTzyjbRBu-JPXHe_auT850iYmE34SkWi", 77 | "crv": "P-521", 78 | "x": "AHBEVPRhAv-WHDEvxVM9S0px9WxxwHL641Pemgk9sDdxvli9VpKCBdra5gg_4kupBDhz__AlaBgKOC_15J2Byptz", 79 | "y": "AciGcHJCD_yMikQvlmqpkBbVqqbg93mMVcgvXBYAQPP-u9AF7adybwZrNfHWCKAQwGF9ugd0Zhg7mLMEszIONFRk", 80 | }) 81 | }, 82 | }; 83 | pub static ref ALICE_SECRETS: Vec = vec![ 84 | ALICE_SECRET_AUTH_KEY_ED25519.clone(), 85 | ALICE_SECRET_AUTH_KEY_P256.clone(), 86 | ALICE_SECRET_AUTH_KEY_SECP256K1.clone(), 87 | ALICE_SECRET_KEY_AGREEMENT_KEY_X25519.clone(), 88 | ALICE_SECRET_KEY_AGREEMENT_KEY_P256.clone(), 89 | ALICE_SECRET_KEY_AGREEMENT_KEY_P521.clone(), 90 | ]; 91 | } 92 | -------------------------------------------------------------------------------- /src/test_vectors/secrets/charlie.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use serde_json::json; 3 | 4 | use crate::didcomm::secrets::{Secret, SecretMaterial, SecretType}; 5 | 6 | lazy_static! { 7 | pub static ref CHARLIE_SECRET_KEY_AGREEMENT_KEY_X25519: Secret = Secret { 8 | id: "did:example:charlie#key-x25519-1".into(), 9 | type_: SecretType::JsonWebKey2020, 10 | secret_material: SecretMaterial::JWK { 11 | private_key_jwk: json!({ 12 | "kty": "OKP", 13 | "crv": "X25519", 14 | "x": "nTiVFj7DChMsETDdxd5dIzLAJbSQ4j4UG6ZU1ogLNlw", 15 | "d": "Z-BsgFe-eCvhuZlCBX5BV2XiDE2M92gkaORCe68YdZI", 16 | }) 17 | }, 18 | }; 19 | pub static ref CHARLIE_SECRET_AUTH_KEY_ED25519: Secret = Secret { 20 | id: "did:example:charlie#key-1".into(), 21 | type_: SecretType::JsonWebKey2020, 22 | secret_material: SecretMaterial::JWK { 23 | private_key_jwk: json!({ 24 | "kty": "OKP", 25 | "crv": "Ed25519", 26 | "x": "VDXDwuGKVq91zxU6q7__jLDUq8_C5cuxECgd-1feFTE", 27 | "d": "T2azVap7CYD_kB8ilbnFYqwwYb5N-GcD6yjGEvquZXg", 28 | }) 29 | }, 30 | }; 31 | pub static ref CHARLIE_SECRETS: Vec = vec![ 32 | CHARLIE_SECRET_KEY_AGREEMENT_KEY_X25519.clone(), 33 | CHARLIE_SECRET_AUTH_KEY_ED25519.clone(), 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /src/test_vectors/secrets/charlie_rotated_to_alice.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | 3 | use crate::didcomm::secrets::Secret; 4 | 5 | use super::{ 6 | alice::{ 7 | ALICE_SECRET_AUTH_KEY_ED25519, ALICE_SECRET_AUTH_KEY_P256, ALICE_SECRET_AUTH_KEY_SECP256K1, 8 | ALICE_SECRET_KEY_AGREEMENT_KEY_P256, ALICE_SECRET_KEY_AGREEMENT_KEY_P521, 9 | ALICE_SECRET_KEY_AGREEMENT_KEY_X25519, 10 | }, 11 | charlie::{CHARLIE_SECRET_AUTH_KEY_ED25519, CHARLIE_SECRET_KEY_AGREEMENT_KEY_X25519}, 12 | }; 13 | 14 | lazy_static! { 15 | pub static ref CHARLIE_ROTATED_TO_ALICE_SECRETS: Vec = vec![ 16 | CHARLIE_SECRET_KEY_AGREEMENT_KEY_X25519.clone(), 17 | CHARLIE_SECRET_AUTH_KEY_ED25519.clone(), 18 | ALICE_SECRET_AUTH_KEY_ED25519.clone(), 19 | ALICE_SECRET_AUTH_KEY_P256.clone(), 20 | ALICE_SECRET_AUTH_KEY_SECP256K1.clone(), 21 | ALICE_SECRET_KEY_AGREEMENT_KEY_X25519.clone(), 22 | ALICE_SECRET_KEY_AGREEMENT_KEY_P256.clone(), 23 | ALICE_SECRET_KEY_AGREEMENT_KEY_P521.clone(), 24 | ]; 25 | } 26 | -------------------------------------------------------------------------------- /src/test_vectors/secrets/mediator1.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use serde_json::json; 3 | 4 | use crate::didcomm::secrets::{Secret, SecretMaterial, SecretType}; 5 | 6 | lazy_static! { 7 | pub static ref MEDIATOR1_SECRET_KEY_AGREEMENT_KEY_X25519_1: Secret = Secret { 8 | id: "did:example:mediator1#key-x25519-1".into(), 9 | type_: SecretType::JsonWebKey2020, 10 | secret_material: SecretMaterial::JWK { 11 | private_key_jwk: json!( 12 | { 13 | "kty": "OKP", 14 | "d": "b9NnuOCB0hm7YGNvaE9DMhwH_wjZA1-gWD6dA0JWdL0", 15 | "crv": "X25519", 16 | "x": "GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E", 17 | }) 18 | }, 19 | }; 20 | pub static ref MEDIATOR1_SECRET_KEY_AGREEMENT_KEY_P256_1: Secret = Secret { 21 | id: "did:example:mediator1#key-p256-1".into(), 22 | type_: SecretType::JsonWebKey2020, 23 | secret_material: SecretMaterial::JWK { 24 | private_key_jwk: json!( 25 | { 26 | "kty": "EC", 27 | "d": "PgwHnlXxt8pwR6OCTUwwWx-P51BiLkFZyqHzquKddXQ", 28 | "crv": "P-256", 29 | "x": "FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo", 30 | "y": "6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY", 31 | }) 32 | }, 33 | }; 34 | pub static ref MEDIATOR1_SECRET_KEY_AGREEMENT_KEY_P384_1: Secret = Secret { 35 | id: "did:example:mediator1#key-p384-1".into(), 36 | type_: SecretType::JsonWebKey2020, 37 | secret_material: SecretMaterial::JWK { 38 | private_key_jwk: json!( 39 | { 40 | "kty": "EC", 41 | "d": "ajqcWbYA0UDBKfAhkSkeiVjMMt8l-5rcknvEv9t_Os6M8s-HisdywvNCX4CGd_xY", 42 | "crv": "P-384", 43 | "x": "MvnE_OwKoTcJVfHyTX-DLSRhhNwlu5LNoQ5UWD9Jmgtdxp_kpjsMuTTBnxg5RF_Y", 44 | "y": "X_3HJBcKFQEG35PZbEOBn8u9_z8V1F9V1Kv-Vh0aSzmH-y9aOuDJUE3D4Hvmi5l7", 45 | }) 46 | }, 47 | }; 48 | pub static ref MEDIATOR1_SECRET_KEY_AGREEMENT_KEY_P521_1: Secret = Secret { 49 | id: "did:example:mediator1#key-p521-1".into(), 50 | type_: SecretType::JsonWebKey2020, 51 | secret_material: SecretMaterial::JWK { 52 | private_key_jwk: json!( 53 | { 54 | "kty": "EC", 55 | "d": "AV5ocjvy7PkPgNrSuvCxtG70NMj6iTabvvjSLbsdd8OdI9HlXYlFR7RdBbgLUTruvaIRhjEAE9gNTH6rWUIdfuj6", 56 | "crv": "P-521", 57 | "x": "Af9O5THFENlqQbh2Ehipt1Yf4gAd9RCa3QzPktfcgUIFADMc4kAaYVViTaDOuvVS2vMS1KZe0D5kXedSXPQ3QbHi", 58 | "y": "ATZVigRQ7UdGsQ9j-omyff6JIeeUv3CBWYsZ0l6x3C_SYqhqVV7dEG-TafCCNiIxs8qeUiXQ8cHWVclqkH4Lo1qH", 59 | }) 60 | }, 61 | }; 62 | pub static ref MEDIATOR1_SECRETS: Vec = vec![ 63 | MEDIATOR1_SECRET_KEY_AGREEMENT_KEY_X25519_1.clone(), 64 | MEDIATOR1_SECRET_KEY_AGREEMENT_KEY_P256_1.clone(), 65 | MEDIATOR1_SECRET_KEY_AGREEMENT_KEY_P384_1.clone(), 66 | MEDIATOR1_SECRET_KEY_AGREEMENT_KEY_P521_1.clone(), 67 | ]; 68 | } 69 | -------------------------------------------------------------------------------- /src/test_vectors/secrets/mediator2.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use serde_json::json; 3 | 4 | use crate::didcomm::secrets::{Secret, SecretMaterial, SecretType}; 5 | 6 | lazy_static! { 7 | pub static ref MEDIATOR2_SECRET_KEY_AGREEMENT_KEY_X25519_1: Secret = Secret { 8 | id: "did:example:mediator2#key-x25519-1".into(), 9 | type_: SecretType::JsonWebKey2020, 10 | secret_material: SecretMaterial::JWK { 11 | private_key_jwk: json!( 12 | { 13 | "kty": "OKP", 14 | "d": "b9NnuOCB0hm7YGNvaE9DMhwH_wjZA1-gWD6dA0JWdL0", 15 | "crv": "X25519", 16 | "x": "GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E", 17 | }) 18 | }, 19 | }; 20 | pub static ref MEDIATOR2_SECRET_KEY_AGREEMENT_KEY_P256_1: Secret = Secret { 21 | id: "did:example:mediator2#key-p256-1".into(), 22 | type_: SecretType::JsonWebKey2020, 23 | secret_material: SecretMaterial::JWK { 24 | private_key_jwk: json!( 25 | { 26 | "kty": "EC", 27 | "d": "PgwHnlXxt8pwR6OCTUwwWx-P51BiLkFZyqHzquKddXQ", 28 | "crv": "P-256", 29 | "x": "FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo", 30 | "y": "6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY", 31 | }) 32 | }, 33 | }; 34 | pub static ref MEDIATOR2_SECRET_KEY_AGREEMENT_KEY_P384_1: Secret = Secret { 35 | id: "did:example:mediator2#key-p384-1".into(), 36 | type_: SecretType::JsonWebKey2020, 37 | secret_material: SecretMaterial::JWK { 38 | private_key_jwk: json!( 39 | { 40 | "kty": "EC", 41 | "d": "ajqcWbYA0UDBKfAhkSkeiVjMMt8l-5rcknvEv9t_Os6M8s-HisdywvNCX4CGd_xY", 42 | "crv": "P-384", 43 | "x": "MvnE_OwKoTcJVfHyTX-DLSRhhNwlu5LNoQ5UWD9Jmgtdxp_kpjsMuTTBnxg5RF_Y", 44 | "y": "X_3HJBcKFQEG35PZbEOBn8u9_z8V1F9V1Kv-Vh0aSzmH-y9aOuDJUE3D4Hvmi5l7", 45 | }) 46 | }, 47 | }; 48 | pub static ref MEDIATOR2_SECRET_KEY_AGREEMENT_KEY_P521_1: Secret = Secret { 49 | id: "did:example:mediator2#key-p521-1".into(), 50 | type_: SecretType::JsonWebKey2020, 51 | secret_material: SecretMaterial::JWK { 52 | private_key_jwk: json!( 53 | { 54 | "kty": "EC", 55 | "d": "AV5ocjvy7PkPgNrSuvCxtG70NMj6iTabvvjSLbsdd8OdI9HlXYlFR7RdBbgLUTruvaIRhjEAE9gNTH6rWUIdfuj6", 56 | "crv": "P-521", 57 | "x": "Af9O5THFENlqQbh2Ehipt1Yf4gAd9RCa3QzPktfcgUIFADMc4kAaYVViTaDOuvVS2vMS1KZe0D5kXedSXPQ3QbHi", 58 | "y": "ATZVigRQ7UdGsQ9j-omyff6JIeeUv3CBWYsZ0l6x3C_SYqhqVV7dEG-TafCCNiIxs8qeUiXQ8cHWVclqkH4Lo1qH", 59 | }) 60 | }, 61 | }; 62 | pub static ref MEDIATOR2_SECRETS: Vec = vec![ 63 | MEDIATOR2_SECRET_KEY_AGREEMENT_KEY_X25519_1.clone(), 64 | MEDIATOR2_SECRET_KEY_AGREEMENT_KEY_P256_1.clone(), 65 | MEDIATOR2_SECRET_KEY_AGREEMENT_KEY_P384_1.clone(), 66 | MEDIATOR2_SECRET_KEY_AGREEMENT_KEY_P521_1.clone(), 67 | ]; 68 | } 69 | -------------------------------------------------------------------------------- /src/test_vectors/secrets/mediator3.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use serde_json::json; 3 | 4 | use crate::didcomm::secrets::{Secret, SecretMaterial, SecretType}; 5 | 6 | lazy_static! { 7 | pub static ref MEDIATOR3_SECRET_KEY_AGREEMENT_KEY_X25519_1: Secret = Secret { 8 | id: "did:example:mediator3#key-x25519-1".into(), 9 | type_: SecretType::JsonWebKey2020, 10 | secret_material: SecretMaterial::JWK { 11 | private_key_jwk: json!( 12 | { 13 | "kty": "OKP", 14 | "d": "b9NnuOCB0hm7YGNvaE9DMhwH_wjZA1-gWD6dA0JWdL0", 15 | "crv": "X25519", 16 | "x": "GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E", 17 | }) 18 | }, 19 | }; 20 | pub static ref MEDIATOR3_SECRET_KEY_AGREEMENT_KEY_P256_1: Secret = Secret { 21 | id: "did:example:mediator3#key-p256-1".into(), 22 | type_: SecretType::JsonWebKey2020, 23 | secret_material: SecretMaterial::JWK { 24 | private_key_jwk: json!( 25 | { 26 | "kty": "EC", 27 | "d": "PgwHnlXxt8pwR6OCTUwwWx-P51BiLkFZyqHzquKddXQ", 28 | "crv": "P-256", 29 | "x": "FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo", 30 | "y": "6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY", 31 | }) 32 | }, 33 | }; 34 | pub static ref MEDIATOR3_SECRET_KEY_AGREEMENT_KEY_P384_1: Secret = Secret { 35 | id: "did:example:mediator3#key-p384-1".into(), 36 | type_: SecretType::JsonWebKey2020, 37 | secret_material: SecretMaterial::JWK { 38 | private_key_jwk: json!( 39 | { 40 | "kty": "EC", 41 | "d": "ajqcWbYA0UDBKfAhkSkeiVjMMt8l-5rcknvEv9t_Os6M8s-HisdywvNCX4CGd_xY", 42 | "crv": "P-384", 43 | "x": "MvnE_OwKoTcJVfHyTX-DLSRhhNwlu5LNoQ5UWD9Jmgtdxp_kpjsMuTTBnxg5RF_Y", 44 | "y": "X_3HJBcKFQEG35PZbEOBn8u9_z8V1F9V1Kv-Vh0aSzmH-y9aOuDJUE3D4Hvmi5l7", 45 | }) 46 | }, 47 | }; 48 | pub static ref MEDIATOR3_SECRET_KEY_AGREEMENT_KEY_P521_1: Secret = Secret { 49 | id: "did:example:mediator3#key-p521-1".into(), 50 | type_: SecretType::JsonWebKey2020, 51 | secret_material: SecretMaterial::JWK { 52 | private_key_jwk: json!( 53 | { 54 | "kty": "EC", 55 | "d": "AV5ocjvy7PkPgNrSuvCxtG70NMj6iTabvvjSLbsdd8OdI9HlXYlFR7RdBbgLUTruvaIRhjEAE9gNTH6rWUIdfuj6", 56 | "crv": "P-521", 57 | "x": "Af9O5THFENlqQbh2Ehipt1Yf4gAd9RCa3QzPktfcgUIFADMc4kAaYVViTaDOuvVS2vMS1KZe0D5kXedSXPQ3QbHi", 58 | "y": "ATZVigRQ7UdGsQ9j-omyff6JIeeUv3CBWYsZ0l6x3C_SYqhqVV7dEG-TafCCNiIxs8qeUiXQ8cHWVclqkH4Lo1qH", 59 | }) 60 | }, 61 | }; 62 | pub static ref MEDIATOR3_SECRETS: Vec = vec![ 63 | MEDIATOR3_SECRET_KEY_AGREEMENT_KEY_X25519_1.clone(), 64 | MEDIATOR3_SECRET_KEY_AGREEMENT_KEY_P256_1.clone(), 65 | MEDIATOR3_SECRET_KEY_AGREEMENT_KEY_P384_1.clone(), 66 | MEDIATOR3_SECRET_KEY_AGREEMENT_KEY_P521_1.clone(), 67 | ]; 68 | } 69 | -------------------------------------------------------------------------------- /src/test_vectors/secrets/mod.rs: -------------------------------------------------------------------------------- 1 | mod alice; 2 | mod bob; 3 | mod charlie; 4 | mod charlie_rotated_to_alice; 5 | mod mediator1; 6 | mod mediator2; 7 | mod mediator3; 8 | 9 | // TODO: Remove allow 10 | #[allow(unused_imports)] 11 | pub use mediator1::*; 12 | 13 | // TODO: Remove allow 14 | #[allow(unused_imports)] 15 | pub use mediator2::*; 16 | 17 | // TODO: Remove allow 18 | #[allow(unused_imports)] 19 | pub use mediator3::*; 20 | 21 | // TODO: Remove allow 22 | #[allow(unused_imports)] 23 | pub use alice::*; 24 | 25 | // TODO: Remove allow 26 | #[allow(unused_imports)] 27 | pub use bob::*; 28 | 29 | // TODO: Remove allow 30 | #[allow(unused_imports)] 31 | pub use charlie::*; 32 | 33 | // TODO: Remove allow 34 | #[allow(unused_imports)] 35 | pub use charlie_rotated_to_alice::*; 36 | -------------------------------------------------------------------------------- /src/test_vectors/signed.rs: -------------------------------------------------------------------------------- 1 | pub const SIGNED_MSG_ALICE_KEY_1: &str = r#" 2 | { 3 | "payload": "eyJpZCI6IjEyMzQ1Njc4OTAiLCJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLXBsYWluK2pzb24iLCJ0eXBlIjoiaHR0cDovL2V4YW1wbGUuY29tL3Byb3RvY29scy9sZXRzX2RvX2x1bmNoLzEuMC9wcm9wb3NhbCIsImZyb20iOiJkaWQ6ZXhhbXBsZTphbGljZSIsInRvIjpbImRpZDpleGFtcGxlOmJvYiJdLCJjcmVhdGVkX3RpbWUiOjE1MTYyNjkwMjIsImV4cGlyZXNfdGltZSI6MTUxNjM4NTkzMSwiYm9keSI6eyJtZXNzYWdlc3BlY2lmaWNhdHRyaWJ1dGUiOiJhbmQgaXRzIHZhbHVlIn19", 4 | "signatures": [{ 5 | "protected": "eyJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLXNpZ25lZCtqc29uIiwiYWxnIjoiRWREU0EifQ", 6 | "signature": "FW33NnvOHV0Ted9-F7GZbkia-vYAfBKtH4oBxbrttWAhBZ6UFJMxcGjL3lwOl4YohI3kyyd08LHPWNMgP2EVCQ", 7 | "header": { 8 | "kid": "did:example:alice#key-1" 9 | } 10 | }] 11 | } 12 | "#; 13 | 14 | pub const SIGNED_MSG_ALICE_KEY_2: &str = r#" 15 | { 16 | "payload": "eyJpZCI6IjEyMzQ1Njc4OTAiLCJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLXBsYWluK2pzb24iLCJ0eXBlIjoiaHR0cDovL2V4YW1wbGUuY29tL3Byb3RvY29scy9sZXRzX2RvX2x1bmNoLzEuMC9wcm9wb3NhbCIsImZyb20iOiJkaWQ6ZXhhbXBsZTphbGljZSIsInRvIjpbImRpZDpleGFtcGxlOmJvYiJdLCJjcmVhdGVkX3RpbWUiOjE1MTYyNjkwMjIsImV4cGlyZXNfdGltZSI6MTUxNjM4NTkzMSwiYm9keSI6eyJtZXNzYWdlc3BlY2lmaWNhdHRyaWJ1dGUiOiJhbmQgaXRzIHZhbHVlIn19", 17 | "signatures": [{ 18 | "protected": "eyJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLXNpZ25lZCtqc29uIiwiYWxnIjoiRVMyNTYifQ", 19 | "signature": "gcW3lVifhyR48mLHbbpnGZQuziskR5-wXf6IoBlpa9SzERfSG9I7oQ9pssmHZwbvJvyMvxskpH5oudw1W3X5Qg", 20 | "header": { 21 | "kid": "did:example:alice#key-2" 22 | } 23 | }] 24 | } 25 | "#; 26 | 27 | pub const SIGNED_MSG_ALICE_KEY_3: &str = r#" 28 | { 29 | "payload": "eyJpZCI6IjEyMzQ1Njc4OTAiLCJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLXBsYWluK2pzb24iLCJ0eXBlIjoiaHR0cDovL2V4YW1wbGUuY29tL3Byb3RvY29scy9sZXRzX2RvX2x1bmNoLzEuMC9wcm9wb3NhbCIsImZyb20iOiJkaWQ6ZXhhbXBsZTphbGljZSIsInRvIjpbImRpZDpleGFtcGxlOmJvYiJdLCJjcmVhdGVkX3RpbWUiOjE1MTYyNjkwMjIsImV4cGlyZXNfdGltZSI6MTUxNjM4NTkzMSwiYm9keSI6eyJtZXNzYWdlc3BlY2lmaWNhdHRyaWJ1dGUiOiJhbmQgaXRzIHZhbHVlIn19", 30 | "signatures": [{ 31 | "protected": "eyJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLXNpZ25lZCtqc29uIiwiYWxnIjoiRVMyNTZLIn0", 32 | "signature": "EGjhIcts6tqiJgqtxaTiTY3EUvL-_rLjn9lxaZ4eRUwa1-CS1nknZoyJWbyY5NQnUafWh5nvCtQpdpMyzH3blw", 33 | "header": { 34 | "kid": "did:example:alice#key-3" 35 | } 36 | }] 37 | } 38 | "#; 39 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod crypto; 2 | pub(crate) mod did; 3 | pub(crate) mod serde; 4 | -------------------------------------------------------------------------------- /src/utils/serde.rs: -------------------------------------------------------------------------------- 1 | pub(crate) fn _true() -> bool { 2 | true 3 | } 4 | -------------------------------------------------------------------------------- /uniffi/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | bin/ 5 | pkg/ 6 | wasm-pack.log 7 | uniffi-rs 8 | uniffi-swift 9 | uniffi-kotlin 10 | -------------------------------------------------------------------------------- /uniffi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'didcomm-uniffi' 3 | version = '0.4.1' 4 | authors = ['Vyacheslav Gudkov '] 5 | edition = '2018' 6 | description = 'FFI wrapper for DIDComm' 7 | license = 'Apache-2.0' 8 | repository = 'https://github.com/sicpa-dlab/didcomm-rust' 9 | 10 | [lib] 11 | crate-type = [ 12 | 'cdylib' 13 | ] 14 | 15 | [dependencies.didcomm_core] 16 | path = '..' 17 | features = ['uniffi'] 18 | package = "didcomm" 19 | 20 | [dev-dependencies.didcomm_core] 21 | path = '..' 22 | features = ['testvectors'] 23 | package = "didcomm" 24 | 25 | [dependencies] 26 | uniffi = "0.24" 27 | lazy_static = "1.3" 28 | futures = { version = "0.3.17", features = ["thread-pool"] } 29 | num_cpus = "1.8.0" 30 | async-trait = '0.1' 31 | serde_json = '1.0' 32 | 33 | [dev-dependencies.tokio] 34 | version = '1.9' 35 | features = [ 36 | 'rt', 37 | 'macros', 38 | ] 39 | 40 | [build-dependencies] 41 | uniffi_build = { version = "0.24", features=["builtin-bindgen"] } 42 | 43 | -------------------------------------------------------------------------------- /uniffi/README.md: -------------------------------------------------------------------------------- 1 | ## DIDComm FFI 2 | DIDComm bindings based on [uniffi-rs](https://github.com/mozilla/uniffi-rs). 3 | 4 | It's used for [DIDComm Swift](../wrappers/swift) wrapper. 5 | 6 | DIDComm uniffi has the following specific comparing to the core DIDComm crate: 7 | - Callback-based versions of pack/unpack functions and DID/Secret resolver interfaces instead of async onces. 8 | These pack/unpack functions wrap the corresponding async futures and execute them in a thread pool executor. 9 | The result is passed to a callback function. 10 | - The language specific bidnings are generated for the API exposed in [didcomm.udl](src/didcomm.udl) file. 11 | 12 | ### Swift Build 13 | 1. Build: 14 | ``` 15 | cargo build --release 16 | ``` 17 | 18 | 2. Install uniffi_bindgen: 19 | ``` 20 | cargo install uniffi_bindgen --version $(cargo pkgid uniffi | cut -f 2 -d '@') 21 | ``` 22 | 23 | 3. Generate Swift binding: 24 | ``` 25 | uniffi-bindgen generate src/didcomm.udl --language swift -o ../wrappers/swift/didcomm 26 | ``` 27 | 28 | 4. Compile a Swift module: 29 | ``` 30 | swiftc -module-name didcomm -emit-library -o ../wrappers/swift/didcomm/libdidcomm.dylib -emit-module -emit-module-path ../wrappers/swift/didcomm -parse-as-library -L ./target/debug/ -ldidcomm_uniffi -Xcc -fmodule-map-file=../wrappers/swift/didcomm/didcommFFI.modulemap ../wrappers/swift/didcomm/didcomm.swift 31 | ``` -------------------------------------------------------------------------------- /uniffi/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | uniffi_build::generate_scaffolding("./src/didcomm.udl").unwrap(); 3 | } 4 | -------------------------------------------------------------------------------- /uniffi/src/common.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | cell::RefCell, 3 | cmp, 4 | sync::{Arc, Mutex}, 5 | }; 6 | 7 | use crate::UniffiCustomTypeConverter; 8 | use didcomm_core::error::{err_msg, ErrorKind, Result, ResultExt, ResultExtNoContext, ToResult}; 9 | use futures::{channel::oneshot, executor::ThreadPool}; 10 | use lazy_static::lazy_static; 11 | 12 | pub enum ErrorCode { 13 | Success = 0, 14 | Error = 1, 15 | } 16 | 17 | lazy_static! { 18 | // Global (lazy inited) instance of future executor 19 | pub(crate) static ref EXECUTOR: ThreadPool = ThreadPool::builder() 20 | .pool_size(cmp::max(8, num_cpus::get())) 21 | .create() 22 | .unwrap(); 23 | } 24 | 25 | // We use `JsonValue` in our UDL. It moves to and from Uniffi bindings via a string. 26 | pub type JsonValue = serde_json::Value; 27 | 28 | // We must implement the UniffiCustomTypeConverter trait. 29 | impl UniffiCustomTypeConverter for JsonValue { 30 | type Builtin = String; 31 | 32 | fn into_custom(val: Self::Builtin) -> uniffi::Result { 33 | Ok(serde_json::from_str(&val).to_didcomm("Invalid json value")?) 34 | } 35 | 36 | fn from_custom(obj: Self) -> Self::Builtin { 37 | serde_json::to_string(&obj).expect("unable serialize json value") 38 | } 39 | } 40 | 41 | pub(crate) struct OnResultReceiver(oneshot::Receiver>); 42 | 43 | impl OnResultReceiver { 44 | pub(crate) async fn get(self) -> Result { 45 | self.0 46 | .await 47 | .kind(ErrorKind::InvalidState, "unable receive callback result")? 48 | } 49 | } 50 | 51 | pub struct OnResult(Mutex>>>>); 52 | 53 | impl OnResult { 54 | pub(crate) fn new() -> (Arc, OnResultReceiver) { 55 | let (sender, receiver) = oneshot::channel::>(); 56 | let on_result = Arc::new(OnResult(Mutex::new(RefCell::new(Some(sender))))); 57 | (on_result, OnResultReceiver(receiver)) 58 | } 59 | 60 | pub fn success(&self, result: T) -> std::result::Result<(), ErrorKind> { 61 | let sender = self 62 | .0 63 | .lock() 64 | .to_error_kind(ErrorKind::InvalidState)? 65 | .replace(None); 66 | match sender { 67 | Some(sender) => sender 68 | .send(Ok(result)) 69 | .to_error_kind(ErrorKind::InvalidState)?, 70 | None => Err(ErrorKind::InvalidState)?, 71 | }; 72 | Ok(()) 73 | } 74 | 75 | pub fn error(&self, err: ErrorKind, msg: String) -> std::result::Result<(), ErrorKind> { 76 | let sender = self 77 | .0 78 | .lock() 79 | .to_error_kind(ErrorKind::InvalidState)? 80 | .replace(None); 81 | match sender { 82 | Some(sender) => sender 83 | .send(Err(err_msg(err, msg))) 84 | .to_error_kind(ErrorKind::InvalidState)?, 85 | None => Err(ErrorKind::InvalidState)?, 86 | }; 87 | Ok(()) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /uniffi/src/did/did_resolver.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use didcomm_core::did::DIDDoc; 4 | 5 | use crate::{common::OnResult, ErrorCode}; 6 | 7 | /// Represents DID Doc resolver (https://www.w3.org/TR/did-core/#did-resolution). 8 | pub trait DIDResolver: Sync + Send { 9 | /// Resolves a DID document by the given DID. 10 | /// 11 | /// # Params 12 | /// - `did` a DID to be resolved. 13 | /// - `cb` a callback with a result 14 | /// 15 | /// # Returns 16 | /// A result code 17 | /// 18 | fn resolve(&self, did: String, cb: Arc) -> ErrorCode; 19 | } 20 | 21 | pub type OnDIDResolverResult = OnResult>; 22 | -------------------------------------------------------------------------------- /uniffi/src/did/did_resolver_adapter.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use didcomm_core::{ 4 | did::{DIDDoc, DIDResolver as _DIDResolver}, 5 | error::{ErrorKind, Result, ResultExt}, 6 | }; 7 | 8 | use async_trait::async_trait; 9 | 10 | use crate::{DIDResolver, OnDIDResolverResult}; 11 | 12 | pub(crate) struct DIDResolverAdapter { 13 | did_resolver: Arc>, 14 | } 15 | 16 | impl DIDResolverAdapter { 17 | pub fn new(did_resolver: Arc>) -> Self { 18 | DIDResolverAdapter { did_resolver } 19 | } 20 | } 21 | 22 | #[async_trait] 23 | impl _DIDResolver for DIDResolverAdapter { 24 | async fn resolve(&self, did: &str) -> Result> { 25 | let (cb, receiver) = OnDIDResolverResult::new(); 26 | 27 | self.did_resolver.resolve(String::from(did), cb); 28 | 29 | let res = receiver 30 | .get() 31 | .await 32 | .kind(ErrorKind::InvalidState, "can not resolve DID Doc")?; 33 | Ok(res) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /uniffi/src/did/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod resolvers; 2 | 3 | pub(crate) mod did_resolver; 4 | pub(crate) mod did_resolver_adapter; 5 | 6 | pub use did_resolver::{DIDResolver, OnDIDResolverResult}; 7 | -------------------------------------------------------------------------------- /uniffi/src/did/resolvers/example.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use async_trait::async_trait; 4 | use didcomm_core::did::DIDDoc; 5 | 6 | use crate::{common::ErrorCode, did::DIDResolver, OnDIDResolverResult}; 7 | 8 | /// Allows resolve pre-defined did's for `example` and other methods. 9 | pub struct ExampleDIDResolver { 10 | known_dids: Vec, 11 | } 12 | 13 | impl ExampleDIDResolver { 14 | pub fn new(known_dids: Vec) -> Self { 15 | ExampleDIDResolver { known_dids } 16 | } 17 | } 18 | 19 | #[async_trait] 20 | impl DIDResolver for ExampleDIDResolver { 21 | fn resolve(&self, did: String, cb: Arc) -> ErrorCode { 22 | let diddoc = self 23 | .known_dids 24 | .iter() 25 | .find(|ddoc| ddoc.id == did) 26 | .map(|ddoc| ddoc.clone()); 27 | 28 | match cb.success(diddoc) { 29 | Ok(_) => ErrorCode::Success, 30 | Err(_) => ErrorCode::Error, 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /uniffi/src/did/resolvers/mod.rs: -------------------------------------------------------------------------------- 1 | mod example; 2 | 3 | pub use example::ExampleDIDResolver; 4 | -------------------------------------------------------------------------------- /uniffi/src/didcomm/from_prior.rs: -------------------------------------------------------------------------------- 1 | use didcomm_core::{error::ErrorKind, FromPrior}; 2 | 3 | use crate::DIDComm; 4 | 5 | use crate::common::{ErrorCode, EXECUTOR}; 6 | use crate::did_resolver_adapter::DIDResolverAdapter; 7 | use crate::secrets_resolver_adapter::SecretsResolverAdapter; 8 | 9 | pub trait OnFromPriorPackResult: Sync + Send { 10 | fn success(&self, from_prior_jwt: String, kid: String); 11 | fn error(&self, err: ErrorKind, err_msg: String); 12 | } 13 | 14 | pub trait OnFromPriorUnpackResult: Sync + Send { 15 | fn success(&self, from_prior: FromPrior, kid: String); 16 | fn error(&self, err: ErrorKind, err_msg: String); 17 | } 18 | 19 | impl DIDComm { 20 | pub fn pack_from_prior( 21 | &self, 22 | msg: &FromPrior, 23 | issuer_kid: Option, 24 | cb: Box, 25 | ) -> ErrorCode { 26 | let msg = msg.clone(); 27 | let did_resolver = DIDResolverAdapter::new(self.did_resolver.clone()); 28 | let secret_resolver = SecretsResolverAdapter::new(self.secret_resolver.clone()); 29 | 30 | let future = async move { 31 | msg.pack(issuer_kid.as_deref(), &did_resolver, &secret_resolver) 32 | .await 33 | }; 34 | EXECUTOR.spawn_ok(async move { 35 | match future.await { 36 | Ok((from_prior_jwt, kid)) => cb.success(from_prior_jwt, kid), 37 | Err(err) => cb.error(err.kind(), err.to_string()), 38 | } 39 | }); 40 | 41 | ErrorCode::Success 42 | } 43 | 44 | pub fn unpack_from_prior( 45 | &self, 46 | from_prior_jwt: String, 47 | cb: Box, 48 | ) -> ErrorCode { 49 | let did_resolver = DIDResolverAdapter::new(self.did_resolver.clone()); 50 | 51 | let future = async move { FromPrior::unpack(&from_prior_jwt, &did_resolver).await }; 52 | EXECUTOR.spawn_ok(async move { 53 | match future.await { 54 | Ok((from_prior_jwt, kid)) => cb.success(from_prior_jwt, kid), 55 | Err(err) => cb.error(err.kind(), err.to_string()), 56 | } 57 | }); 58 | 59 | ErrorCode::Success 60 | } 61 | } 62 | 63 | #[cfg(test)] 64 | mod tests { 65 | use didcomm_core::FromPrior; 66 | 67 | use crate::{ 68 | test_helper::{create_did_resolver, get_ok, FromPriorPackResult, FromPriorUnpackResult}, 69 | DIDComm, ExampleSecretsResolver, 70 | }; 71 | use didcomm_core::test_vectors::{ 72 | ALICE_DID, CHARLIE_DID, CHARLIE_ROTATED_TO_ALICE_SECRETS, CHARLIE_SECRET_AUTH_KEY_ED25519, 73 | }; 74 | 75 | #[tokio::test] 76 | async fn pack_from_prior_works() { 77 | let (cb, receiver) = FromPriorPackResult::new(); 78 | 79 | let from_prior = FromPrior::build(CHARLIE_DID.into(), ALICE_DID.into()).finalize(); 80 | 81 | DIDComm::new( 82 | create_did_resolver(), 83 | Box::new(ExampleSecretsResolver::new( 84 | CHARLIE_ROTATED_TO_ALICE_SECRETS.clone(), 85 | )), 86 | ) 87 | .pack_from_prior( 88 | &from_prior, 89 | Some(CHARLIE_SECRET_AUTH_KEY_ED25519.id.clone()), 90 | cb, 91 | ); 92 | 93 | let (_, kid) = get_ok(receiver).await; 94 | assert_eq!(kid, CHARLIE_SECRET_AUTH_KEY_ED25519.id.clone()); 95 | } 96 | 97 | #[tokio::test] 98 | async fn unpack_from_prior_works() { 99 | let (cb, receiver) = FromPriorPackResult::new(); 100 | let did_comm = DIDComm::new( 101 | create_did_resolver(), 102 | Box::new(ExampleSecretsResolver::new( 103 | CHARLIE_ROTATED_TO_ALICE_SECRETS.clone(), 104 | )), 105 | ); 106 | 107 | let from_prior = FromPrior::build(CHARLIE_DID.into(), ALICE_DID.into()) 108 | .exp(1234) 109 | .finalize(); 110 | did_comm.pack_from_prior( 111 | &from_prior, 112 | Some(CHARLIE_SECRET_AUTH_KEY_ED25519.id.clone()), 113 | cb, 114 | ); 115 | let (res, _) = get_ok(receiver).await; 116 | 117 | let (cb, receiver) = FromPriorUnpackResult::new(); 118 | did_comm.unpack_from_prior(res, cb); 119 | let (res, kid) = get_ok(receiver).await; 120 | 121 | assert_eq!(kid, CHARLIE_SECRET_AUTH_KEY_ED25519.id.clone()); 122 | assert_eq!(CHARLIE_DID.clone(), res.iss); 123 | assert_eq!(ALICE_DID.clone(), res.sub); 124 | assert_eq!(Some(1234), res.exp); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /uniffi/src/didcomm/mod.rs: -------------------------------------------------------------------------------- 1 | mod from_prior; 2 | mod pack_encrypted; 3 | mod pack_plaintext; 4 | mod pack_signed; 5 | mod protocols; 6 | mod unpack; 7 | 8 | pub use from_prior::{OnFromPriorPackResult, OnFromPriorUnpackResult}; 9 | pub use pack_encrypted::OnPackEncryptedResult; 10 | pub use pack_plaintext::OnPackPlaintextResult; 11 | pub use pack_signed::OnPackSignedResult; 12 | pub use protocols::routing::OnWrapInForwardResult; 13 | pub use unpack::OnUnpackResult; 14 | 15 | use std::sync::Arc; 16 | 17 | use crate::{DIDResolver, SecretsResolver}; 18 | 19 | pub struct DIDComm { 20 | did_resolver: Arc>, 21 | secret_resolver: Arc>, 22 | } 23 | 24 | impl DIDComm { 25 | pub fn new( 26 | did_resolver: Box, 27 | secret_resolver: Box, 28 | ) -> Self { 29 | DIDComm { 30 | did_resolver: Arc::new(did_resolver), 31 | secret_resolver: Arc::new(secret_resolver), 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /uniffi/src/didcomm/pack_plaintext.rs: -------------------------------------------------------------------------------- 1 | use didcomm_core::error::ErrorKind; 2 | use didcomm_core::Message; 3 | 4 | use crate::common::{ErrorCode, EXECUTOR}; 5 | use crate::did_resolver_adapter::DIDResolverAdapter; 6 | use crate::DIDComm; 7 | 8 | pub trait OnPackPlaintextResult: Sync + Send { 9 | fn success(&self, result: String); 10 | fn error(&self, err: ErrorKind, err_msg: String); 11 | } 12 | 13 | impl DIDComm { 14 | pub fn pack_plaintext(&self, msg: &Message, cb: Box) -> ErrorCode { 15 | let msg = msg.clone(); 16 | let did_resolver = DIDResolverAdapter::new(self.did_resolver.clone()); 17 | 18 | let future = async move { msg.pack_plaintext(&did_resolver).await }; 19 | 20 | EXECUTOR.spawn_ok(async move { 21 | match future.await { 22 | Ok(result) => cb.success(result), 23 | Err(err) => cb.error(err.kind(), err.to_string()), 24 | } 25 | }); 26 | 27 | ErrorCode::Success 28 | } 29 | } 30 | 31 | #[cfg(test)] 32 | mod tests { 33 | 34 | use crate::DIDComm; 35 | 36 | use crate::test_helper::{create_did_resolver, create_secrets_resolver, get_ok, PackResult}; 37 | use didcomm_core::test_vectors::MESSAGE_SIMPLE; 38 | 39 | #[tokio::test] 40 | async fn pack_plaintext_works() { 41 | let (cb, receiver) = PackResult::new(); 42 | 43 | DIDComm::new(create_did_resolver(), create_secrets_resolver()) 44 | .pack_plaintext(&MESSAGE_SIMPLE, cb); 45 | 46 | let res = get_ok(receiver).await; 47 | assert!(res.contains("body")); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /uniffi/src/didcomm/pack_signed.rs: -------------------------------------------------------------------------------- 1 | use didcomm_core::Message; 2 | use didcomm_core::{error::ErrorKind, PackSignedMetadata}; 3 | 4 | use crate::common::{ErrorCode, EXECUTOR}; 5 | use crate::did_resolver_adapter::DIDResolverAdapter; 6 | use crate::secrets::secrets_resolver_adapter::SecretsResolverAdapter; 7 | use crate::DIDComm; 8 | 9 | pub trait OnPackSignedResult: Sync + Send { 10 | fn success(&self, result: String, metadata: PackSignedMetadata); 11 | fn error(&self, err: ErrorKind, err_msg: String); 12 | } 13 | 14 | impl DIDComm { 15 | pub fn pack_signed( 16 | &self, 17 | msg: &Message, 18 | sign_by: String, 19 | cb: Box, 20 | ) -> ErrorCode { 21 | let msg = msg.clone(); 22 | let did_resolver = DIDResolverAdapter::new(self.did_resolver.clone()); 23 | let secret_resolver = SecretsResolverAdapter::new(self.secret_resolver.clone()); 24 | 25 | let future = async move { 26 | msg.pack_signed(&sign_by, &did_resolver, &secret_resolver) 27 | .await 28 | }; 29 | 30 | EXECUTOR.spawn_ok(async move { 31 | match future.await { 32 | Ok((result, metadata)) => cb.success(result, metadata), 33 | Err(err) => cb.error(err.kind(), err.to_string()), 34 | } 35 | }); 36 | 37 | ErrorCode::Success 38 | } 39 | } 40 | 41 | #[cfg(test)] 42 | mod tests { 43 | use didcomm_core::error::ErrorKind; 44 | use didcomm_core::Message; 45 | use serde_json::json; 46 | 47 | use crate::test_helper::{ 48 | create_did_resolver, create_secrets_resolver, get_error, get_ok, PackResult, 49 | }; 50 | use crate::DIDComm; 51 | 52 | use didcomm_core::test_vectors::{ALICE_DID, MESSAGE_SIMPLE}; 53 | 54 | #[tokio::test] 55 | async fn pack_signed_works() { 56 | let (cb, receiver) = PackResult::new(); 57 | 58 | DIDComm::new(create_did_resolver(), create_secrets_resolver()).pack_signed( 59 | &MESSAGE_SIMPLE, 60 | String::from(ALICE_DID), 61 | cb, 62 | ); 63 | 64 | let res = get_ok(receiver).await; 65 | assert!(res.contains("payload")); 66 | } 67 | 68 | #[tokio::test] 69 | async fn pack_signed_works_did_not_found() { 70 | let msg = Message::build( 71 | "example-1".to_owned(), 72 | "example/v1".to_owned(), 73 | json!("example-body"), 74 | ) 75 | .to(String::from("did:unknown:bob")) 76 | .from(ALICE_DID.to_owned()) 77 | .finalize(); 78 | 79 | let (cb, receiver) = PackResult::new(); 80 | 81 | DIDComm::new(create_did_resolver(), create_secrets_resolver()).pack_signed( 82 | &msg, 83 | String::from("did:unknown:alice"), 84 | cb, 85 | ); 86 | 87 | let res = get_error(receiver).await; 88 | assert_eq!(res.kind(), ErrorKind::DIDNotResolved); 89 | } 90 | 91 | #[tokio::test] 92 | async fn pack_signed_works_did_url_not_found() { 93 | let (cb, receiver) = PackResult::new(); 94 | 95 | DIDComm::new(create_did_resolver(), create_secrets_resolver()).pack_signed( 96 | &MESSAGE_SIMPLE, 97 | String::from(format!("{}#unknown-fragment", ALICE_DID)), 98 | cb, 99 | ); 100 | 101 | let res = get_error(receiver).await; 102 | assert_eq!(res.kind(), ErrorKind::DIDUrlNotFound); 103 | } 104 | 105 | #[tokio::test] 106 | async fn pack_signed_works_secret_not_found() { 107 | let (cb, receiver) = PackResult::new(); 108 | 109 | DIDComm::new(create_did_resolver(), create_secrets_resolver()).pack_signed( 110 | &MESSAGE_SIMPLE, 111 | String::from(format!("{}#key-not-in-secrets-1", ALICE_DID)), 112 | cb, 113 | ); 114 | 115 | let res = get_error(receiver).await; 116 | assert_eq!(res.kind(), ErrorKind::SecretNotFound); 117 | } 118 | 119 | #[tokio::test] 120 | async fn pack_signed_works_illegal_argument() { 121 | let (cb, receiver) = PackResult::new(); 122 | 123 | DIDComm::new(create_did_resolver(), create_secrets_resolver()).pack_signed( 124 | &MESSAGE_SIMPLE, 125 | String::from("not-a-did"), 126 | cb, 127 | ); 128 | 129 | let res = get_error(receiver).await; 130 | assert_eq!(res.kind(), ErrorKind::IllegalArgument); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /uniffi/src/didcomm/protocols/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod routing; 2 | -------------------------------------------------------------------------------- /uniffi/src/didcomm/unpack.rs: -------------------------------------------------------------------------------- 1 | use didcomm_core::{error::ErrorKind, Message, UnpackMetadata, UnpackOptions}; 2 | 3 | use crate::common::EXECUTOR; 4 | use crate::did_resolver_adapter::DIDResolverAdapter; 5 | use crate::DIDComm; 6 | use crate::{secrets_resolver_adapter::SecretsResolverAdapter, ErrorCode}; 7 | 8 | pub trait OnUnpackResult: Sync + Send { 9 | fn success(&self, result: Message, metadata: UnpackMetadata); 10 | fn error(&self, err: ErrorKind, err_msg: String); 11 | } 12 | 13 | impl DIDComm { 14 | pub fn unpack<'a>( 15 | &self, 16 | msg: String, 17 | options: &'a UnpackOptions, 18 | cb: Box, 19 | ) -> ErrorCode { 20 | let msg = msg.clone(); 21 | let options = options.clone(); 22 | let did_resolver = DIDResolverAdapter::new(self.did_resolver.clone()); 23 | let secret_resolver = SecretsResolverAdapter::new(self.secret_resolver.clone()); 24 | 25 | let future = 26 | async move { Message::unpack(&msg, &did_resolver, &secret_resolver, &options).await }; 27 | EXECUTOR.spawn_ok(async move { 28 | match future.await { 29 | Ok((result, metadata)) => cb.success(result, metadata), 30 | Err(err) => cb.error(err.kind(), err.to_string()), 31 | } 32 | }); 33 | 34 | ErrorCode::Success 35 | } 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use crate::test_helper::{ 41 | create_did_resolver, create_secrets_resolver, get_error, get_ok, PackResult, UnpackResult, 42 | }; 43 | use crate::DIDComm; 44 | use didcomm_core::error::ErrorKind; 45 | use didcomm_core::{PackEncryptedOptions, UnpackOptions}; 46 | 47 | use didcomm_core::test_vectors::{ALICE_DID, BOB_DID, MESSAGE_SIMPLE}; 48 | 49 | #[tokio::test] 50 | async fn unpack_works_plaintext() { 51 | let msg = MESSAGE_SIMPLE.clone(); 52 | let didcomm = DIDComm::new(create_did_resolver(), create_secrets_resolver()); 53 | 54 | let (cb, receiver) = PackResult::new(); 55 | didcomm.pack_plaintext(&MESSAGE_SIMPLE, cb); 56 | let res = get_ok(receiver).await; 57 | 58 | let (cb, receiver) = UnpackResult::new(); 59 | didcomm.unpack(res, &UnpackOptions::default(), cb); 60 | let res = get_ok(receiver).await; 61 | 62 | assert_eq!(res, msg); 63 | } 64 | 65 | #[tokio::test] 66 | async fn unpack_works_signed() { 67 | let msg = MESSAGE_SIMPLE.clone(); 68 | let didcomm = DIDComm::new(create_did_resolver(), create_secrets_resolver()); 69 | 70 | let (cb, receiver) = PackResult::new(); 71 | didcomm.pack_signed(&msg, String::from(ALICE_DID), cb); 72 | let res = get_ok(receiver).await; 73 | 74 | let (cb, receiver) = UnpackResult::new(); 75 | didcomm.unpack(res, &UnpackOptions::default(), cb); 76 | let res = get_ok(receiver).await; 77 | 78 | assert_eq!(res, msg); 79 | } 80 | 81 | #[tokio::test] 82 | async fn unpack_works_encrypted() { 83 | let msg = MESSAGE_SIMPLE.clone(); 84 | let didcomm = DIDComm::new(create_did_resolver(), create_secrets_resolver()); 85 | 86 | let (cb, receiver) = PackResult::new(); 87 | didcomm.pack_encrypted( 88 | &msg, 89 | String::from(BOB_DID), 90 | Some(String::from(ALICE_DID)), 91 | Some(String::from(ALICE_DID)), 92 | &PackEncryptedOptions { 93 | forward: false, 94 | ..PackEncryptedOptions::default() 95 | }, 96 | cb, 97 | ); 98 | let res = get_ok(receiver).await; 99 | 100 | let (cb, receiver) = UnpackResult::new(); 101 | didcomm.unpack(res, &UnpackOptions::default(), cb); 102 | let res = get_ok(receiver).await; 103 | 104 | assert_eq!(res, msg); 105 | } 106 | 107 | #[tokio::test] 108 | async fn unpack_works_malformed() { 109 | let (cb, receiver) = UnpackResult::new(); 110 | DIDComm::new(create_did_resolver(), create_secrets_resolver()).unpack( 111 | String::from("invalid message"), 112 | &UnpackOptions::default(), 113 | cb, 114 | ); 115 | let res = get_error(receiver).await; 116 | 117 | assert_eq!(res.kind(), ErrorKind::Malformed); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /uniffi/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | mod did; 3 | mod didcomm; 4 | mod secrets; 5 | 6 | pub use common::ErrorCode; 7 | pub use common::JsonValue; 8 | pub use did::resolvers::*; 9 | pub use did::*; 10 | pub use didcomm::*; 11 | pub use didcomm_core::algorithms::*; 12 | pub use didcomm_core::did::{ 13 | DIDCommMessagingService, DIDDoc, Service, ServiceKind, VerificationMaterial, 14 | VerificationMethod, VerificationMethodType, 15 | }; 16 | pub use didcomm_core::error::*; 17 | pub use didcomm_core::secrets::{Secret, SecretMaterial, SecretType}; 18 | pub use didcomm_core::*; 19 | pub use secrets::resolvers::*; 20 | pub use secrets::*; 21 | 22 | #[cfg(test)] 23 | mod test_helper; 24 | 25 | uniffi::include_scaffolding!("didcomm"); 26 | -------------------------------------------------------------------------------- /uniffi/src/secrets/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod resolvers; 2 | 3 | pub(crate) mod secrets_resolver; 4 | pub(crate) mod secrets_resolver_adapter; 5 | 6 | pub use secrets_resolver::{OnFindSecretsResult, OnGetSecretResult, SecretsResolver}; 7 | -------------------------------------------------------------------------------- /uniffi/src/secrets/resolvers/example.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use async_trait::async_trait; 4 | use didcomm_core::secrets::Secret; 5 | 6 | use crate::{common::ErrorCode, secrets::SecretsResolver, OnFindSecretsResult, OnGetSecretResult}; 7 | 8 | /// Allows resolve pre-defined did's for `example` and other methods. 9 | pub struct ExampleSecretsResolver { 10 | known_secrets: Vec, 11 | } 12 | 13 | impl ExampleSecretsResolver { 14 | pub fn new(known_secrets: Vec) -> Self { 15 | ExampleSecretsResolver { known_secrets } 16 | } 17 | } 18 | 19 | #[async_trait] 20 | impl SecretsResolver for ExampleSecretsResolver { 21 | fn get_secret(&self, secret_id: String, cb: Arc) -> ErrorCode { 22 | let secret = self 23 | .known_secrets 24 | .iter() 25 | .find(|s| s.id == secret_id) 26 | .map(|s| s.clone()); 27 | 28 | match cb.success(secret) { 29 | Ok(_) => ErrorCode::Success, 30 | Err(_) => ErrorCode::Error, 31 | } 32 | } 33 | 34 | fn find_secrets(&self, secret_ids: Vec, cb: Arc) -> ErrorCode { 35 | let res = secret_ids 36 | .iter() 37 | .filter(|sid| self.known_secrets.iter().find(|s| s.id == **sid).is_some()) 38 | .map(|sid| sid.clone()) 39 | .collect(); 40 | 41 | match cb.success(res) { 42 | Ok(_) => ErrorCode::Success, 43 | Err(_) => ErrorCode::Error, 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /uniffi/src/secrets/resolvers/mod.rs: -------------------------------------------------------------------------------- 1 | mod example; 2 | 3 | pub use example::ExampleSecretsResolver; 4 | -------------------------------------------------------------------------------- /uniffi/src/secrets/secrets_resolver.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use didcomm_core::secrets::Secret; 4 | 5 | use crate::common::{ErrorCode, OnResult}; 6 | 7 | /// Interface for secrets resolver. 8 | /// Resolves secrets such as private keys to be used for signing and encryption. 9 | pub trait SecretsResolver: Sync + Send { 10 | /// Finds secret (usually private key) identified by the given key ID. 11 | /// 12 | /// # Parameters 13 | /// - `secret_id` the ID (in form of DID URL) identifying a secret 14 | /// - `cb` a callback with a result 15 | /// 16 | /// # Returns 17 | /// A secret (usually private key) or None of there is no secret for the given ID 18 | /// 19 | fn get_secret(&self, secret_id: String, cb: Arc) -> ErrorCode; 20 | 21 | /// Find all secrets that have one of the given IDs. 22 | /// Return secrets only for key IDs for which a secret is present. 23 | /// 24 | /// # Parameters 25 | /// - `secret_ids` the IDs find secrets for 26 | /// - `cb` a callback with a result 27 | /// 28 | /// # Returns 29 | /// A secret (usually private key) or None of there is no secret for the given ID 30 | /// 31 | fn find_secrets(&self, secret_ids: Vec, cb: Arc) -> ErrorCode; 32 | } 33 | 34 | pub type OnGetSecretResult = OnResult>; 35 | pub type OnFindSecretsResult = OnResult>; 36 | -------------------------------------------------------------------------------- /uniffi/src/secrets/secrets_resolver_adapter.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use async_trait::async_trait; 4 | use didcomm_core::error::{ErrorKind, Result, ResultExt}; 5 | use didcomm_core::secrets::{Secret, SecretsResolver as _SecretsResolver}; 6 | 7 | use crate::secrets_resolver::{OnFindSecretsResult, OnGetSecretResult}; 8 | 9 | use super::SecretsResolver; 10 | 11 | pub struct SecretsResolverAdapter { 12 | secrets_resolver: Arc>, 13 | } 14 | 15 | impl SecretsResolverAdapter { 16 | pub fn new(secrets_resolver: Arc>) -> Self { 17 | SecretsResolverAdapter { secrets_resolver } 18 | } 19 | } 20 | 21 | #[async_trait] 22 | impl _SecretsResolver for SecretsResolverAdapter { 23 | async fn get_secret(&self, secret_id: &str) -> Result> { 24 | let (cb, receiver) = OnGetSecretResult::new(); 25 | 26 | self.secrets_resolver 27 | .get_secret(String::from(secret_id), cb); 28 | 29 | let res = receiver 30 | .get() 31 | .await 32 | .kind(ErrorKind::InvalidState, "can not get secret")?; 33 | Ok(res) 34 | } 35 | 36 | async fn find_secrets<'a>(&self, secret_ids: &'a [&'a str]) -> Result> { 37 | let (cb, receiver) = OnFindSecretsResult::new(); 38 | 39 | self.secrets_resolver 40 | .find_secrets(secret_ids.iter().map(|&s| String::from(s)).collect(), cb); 41 | 42 | let res = receiver 43 | .get() 44 | .await 45 | .kind(ErrorKind::InvalidState, "can not get secret")?; 46 | 47 | Ok(secret_ids 48 | .iter() 49 | .filter(|&&sid| res.iter().find(|&s| s == sid).is_some()) 50 | .map(|sid| *sid) 51 | .collect()) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /wasm/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | bin/ 5 | pkg/ 6 | wasm-pack.log 7 | -------------------------------------------------------------------------------- /wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'didcomm-js' 3 | version = '0.4.1' 4 | authors = ['Vyacheslav Gudkov '] 5 | edition = '2018' 6 | description = 'WASM based javascript wrapper for DIDComm' 7 | license = 'Apache-2.0' 8 | repository = 'https://github.com/sicpa-dlab/didcomm-rust/tree/main/wasm' 9 | homepage = 'https://github.com/sicpa-dlab/didcomm-rust/tree/main/wasm#readme' 10 | readme = 'README.md' 11 | 12 | [lib] 13 | crate-type = [ 14 | 'cdylib', 15 | 'rlib', 16 | ] 17 | 18 | [features] 19 | default = ['console_error_panic_hook'] 20 | 21 | [dependencies] 22 | async-trait = '0.1' 23 | wasm-bindgen-futures = '0.4' 24 | js-sys = '0.3' 25 | serde_json = '1.0' 26 | 27 | [dependencies.didcomm] 28 | path = '..' 29 | 30 | [dev-dependencies.getrandom] 31 | version = '0.2' 32 | features = ['js'] 33 | 34 | [dependencies.wasm-bindgen] 35 | version = '0.2' 36 | features = ['serde-serialize'] 37 | 38 | [dependencies.console_error_panic_hook] 39 | version = '0.1' 40 | optional = true 41 | 42 | [dependencies.serde] 43 | version = '1.0' 44 | features = ['derive'] 45 | 46 | [dependencies.wee_alloc] 47 | version = '0.4' 48 | optional = true 49 | 50 | [dependencies.uuid] 51 | version = "0.8" 52 | features = ["v4", "wasm-bindgen"] 53 | 54 | [dev-dependencies] 55 | wasm-bindgen-test = '0.3' 56 | 57 | [profile.release] 58 | opt-level = 's' 59 | lto = true 60 | -------------------------------------------------------------------------------- /wasm/Makefile: -------------------------------------------------------------------------------- 1 | PKG_NAME ?= didcomm 2 | WASM_TARGET ?= bundler 3 | WASM_OPTS_PUBLISH ?= 4 | 5 | ifndef PROJECT_DIR 6 | PROJECT_DIR := $(shell git rev-parse --show-toplevel) 7 | endif 8 | 9 | WASM_DIR_NAME := wasm 10 | WASM_DIR := $(PROJECT_DIR)/$(WASM_DIR_NAME) 11 | 12 | WASM_PKG_DIR_NAME := pkg 13 | WASM_PKG_DIR := $(WASM_DIR)/$(WASM_PKG_DIR_NAME) 14 | 15 | .PHONY: all \ 16 | pkg_clean build install publish clean 17 | 18 | all: build 19 | 20 | pkg_clean: 21 | rm -rf $(WASM_PKG_DIR) 22 | 23 | build: $(WASM_DIR) pkg_clean 24 | cd $< 25 | wasm-pack build --target $(WASM_TARGET) --out-name index 26 | sed -i -r "s~\"name\": \".+\"~\"name\": \"${PKG_NAME}\"~" $(WASM_PKG_DIR_NAME)/package.json 27 | 28 | install: $(WASM_PKG_DIR) 29 | cd $< && npm install . 30 | 31 | pack: $(WASM_PKG_DIR) 32 | cd $(WASM_DIR) 33 | wasm-pack pack 34 | 35 | publish: $(WASM_PKG_DIR) 36 | cd $(WASM_DIR) 37 | echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > $ console.log(e)); 68 | -------------------------------------------------------------------------------- /wasm/demo/src/attachments.ts: -------------------------------------------------------------------------------- 1 | import { Message } from "didcomm"; 2 | import { 3 | ALICE_DID, 4 | ALICE_DID_DOC, 5 | ALICE_SECRETS, 6 | BOB_DID, 7 | BOB_DID_DOC, 8 | BOB_SECRETS, 9 | } from "./test-vectors"; 10 | import { 11 | ExampleDIDResolver, 12 | ExampleSecretsResolver, 13 | } from "../../tests-js/src/test-vectors"; 14 | 15 | async function main() { 16 | // --- Building message from ALICE to BOB --- 17 | const msg = new Message({ 18 | id: "1234567890", 19 | typ: "application/didcomm-plain+json", 20 | type: "http://example.com/protocols/lets_do_lunch/1.0/proposal", 21 | from: "did:example:alice", 22 | to: ["did:example:bob"], 23 | created_time: 1516269022, 24 | expires_time: 1516385931, 25 | attachments: [ 26 | { 27 | data: { 28 | json: { foo: "bar" }, 29 | }, 30 | id: "123", 31 | description: "example", 32 | media_type: "application/didcomm-encrypted+json", 33 | }, 34 | ], 35 | body: { messagespecificattribute: "and its value" }, 36 | }); 37 | 38 | // --- Packing encrypted and authenticated message --- 39 | let didResolver = new ExampleDIDResolver([ALICE_DID_DOC, BOB_DID_DOC]); 40 | let secretsResolver = new ExampleSecretsResolver(ALICE_SECRETS); 41 | 42 | const [encryptedMsg, encryptMetadata] = await msg.pack_encrypted( 43 | BOB_DID, 44 | ALICE_DID, 45 | ALICE_DID, 46 | didResolver, 47 | secretsResolver, 48 | { 49 | forward: false, // TODO: should be true by default 50 | } 51 | ); 52 | 53 | console.log("Encryption metadata is\n", encryptMetadata); 54 | 55 | // --- Sending message --- 56 | console.log("Sending message\n", encryptedMsg); 57 | 58 | // --- Unpacking message --- 59 | didResolver = new ExampleDIDResolver([ALICE_DID_DOC, BOB_DID_DOC]); 60 | secretsResolver = new ExampleSecretsResolver(BOB_SECRETS); 61 | 62 | const [unpackedMsg, unpackMetadata] = await Message.unpack( 63 | encryptedMsg, 64 | didResolver, 65 | secretsResolver, 66 | {} 67 | ); 68 | 69 | console.log("Reveived message is\n", unpackedMsg.as_value()); 70 | console.log("Reveived message unpack metadata is\n", unpackMetadata); 71 | } 72 | 73 | main().catch((e) => console.log(e)); 74 | -------------------------------------------------------------------------------- /wasm/demo/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "no-console": false, 9 | "max-classes-per-file": false 10 | }, 11 | "rulesDirectory": [] 12 | } -------------------------------------------------------------------------------- /wasm/src/did/did_doc.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen(typescript_custom_section)] 4 | const DID_DOC_TS: &'static str = r#" 5 | /** 6 | * Represents DID Document (https://www.w3.org/TR/did-core/) 7 | */ 8 | type DIDDoc = { 9 | /** 10 | * DID for the given DID Doc 11 | */ 12 | id: string, 13 | 14 | /** 15 | * DID URLs of verification methods used for key agreement. 16 | * See https://www.w3.org/TR/did-core/#verification-methods. 17 | */ 18 | keyAgreement: Array, 19 | 20 | /** 21 | * Returns DID URLs of verification methods used for authentication. 22 | * See https://www.w3.org/TR/did-core/#authentication 23 | */ 24 | authentication: Array, 25 | 26 | /** 27 | * All local verification methods including embedded to 28 | * key agreement and authentication sections. 29 | * See https://www.w3.org/TR/did-core/#verification-methods. 30 | */ 31 | verificationMethod: Array, 32 | 33 | /** 34 | * All services (https://www.w3.org/TR/did-core/#services) 35 | */ 36 | service: Array, 37 | } 38 | "#; 39 | 40 | #[wasm_bindgen(typescript_custom_section)] 41 | const VERIFICATION_METHOD_TS: &'static str = r#" 42 | /** 43 | * Represents verification method record in DID Document 44 | * (https://www.w3.org/TR/did-core/#verification-methods). 45 | */ 46 | type VerificationMethod = { 47 | id: string, 48 | type: VerificationMethodType, 49 | controller: string, 50 | publicKeyJwk?: any, 51 | publicKeyMultibase?: string, 52 | publicKeyBase58?: string, 53 | } 54 | "#; 55 | 56 | #[wasm_bindgen(typescript_custom_section)] 57 | const VERIFICATION_METHOD_TYPE_TS: &'static str = r#" 58 | type VerificationMethodType = "JsonWebKey2020" | "X25519KeyAgreementKey2019" 59 | | "Ed25519VerificationKey2018" | "EcdsaSecp256k1VerificationKey2019" | string 60 | "#; 61 | 62 | #[wasm_bindgen(typescript_custom_section)] 63 | const SERVICE_TS: &'static str = r#" 64 | /** 65 | * Represents service record in DID Document (https://www.w3.org/TR/did-core/#services). 66 | */ 67 | type Service = { 68 | id: string, 69 | type: string, 70 | serviceEndpoint: ServiceKind, 71 | } 72 | "#; 73 | 74 | #[wasm_bindgen(typescript_custom_section)] 75 | const SERVICE_KIND_TS: &'static str = r#" 76 | /** 77 | * Represents additional service properties defined for specific Service type. 78 | */ 79 | type ServiceKind = DIDCommMessagingService | any 80 | "#; 81 | 82 | #[wasm_bindgen(typescript_custom_section)] 83 | const DIDCOMM_MESSAGING_SERVICE_TS: &'static str = r#" 84 | /** 85 | * Properties for DIDCommMessagingService 86 | * (https://identity.foundation/didcomm-messaging/spec/#did-document-service-endpoint). 87 | */ 88 | type DIDCommMessagingService = { 89 | uri: string, 90 | accept?: Array, 91 | routing_keys: Array, 92 | } 93 | "#; 94 | -------------------------------------------------------------------------------- /wasm/src/did/did_resolver.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | use didcomm::{ 3 | did::{DIDDoc, DIDResolver as _DIDResolver}, 4 | error::{ErrorKind, Result as _Result, ResultContext, ResultExt}, 5 | }; 6 | use wasm_bindgen::prelude::*; 7 | 8 | use crate::error::FromJsResult; 9 | 10 | #[wasm_bindgen] 11 | extern "C" { 12 | pub type DIDResolver; 13 | 14 | #[wasm_bindgen(structural, method, catch)] 15 | pub async fn resolve(this: &DIDResolver, did: &str) -> Result; 16 | } 17 | 18 | #[wasm_bindgen(typescript_custom_section)] 19 | const DID_RESOLVER_TS: &'static str = r#" 20 | /** 21 | * Represents DID Doc resolver (https://www.w3.org/TR/did-core/#did-resolution). 22 | */ 23 | interface DIDResolver { 24 | /** 25 | * Resolves a DID document by the given DID. 26 | * 27 | * @param `did` a DID to be resolved. 28 | * 29 | * @returns An instance of resolved DID DOC or null if DID is not found. 30 | * 31 | * @throws DIDCommMalformed - Resolved DID Doc looks malformed 32 | * @throws DIDCommIoError - IO error in resolving process 33 | * @throws DIDCommInvalidState - Code error or unexpected state was detected 34 | * 35 | * Note to throw compatible error use code like this 36 | * 37 | * ``` 38 | * let e = Error("Unble perform io operation"); 39 | * e.name = "DIDCommIoError" 40 | * throw e 41 | * ``` 42 | */ 43 | resolve(did: string): Promise; 44 | } 45 | "#; 46 | 47 | pub(crate) struct JsDIDResolver(pub(crate) DIDResolver); 48 | 49 | #[async_trait(?Send)] 50 | impl _DIDResolver for JsDIDResolver { 51 | async fn resolve(&self, did: &str) -> _Result> { 52 | let ddoc = self 53 | .0 54 | .resolve(did) 55 | .await 56 | .from_js() 57 | .context("Unable resolve did")?; 58 | 59 | let ddoc: Option = ddoc.into_serde().kind( 60 | ErrorKind::InvalidState, 61 | "Unable deserialize DIDDoc from JsValue", 62 | )?; 63 | 64 | Ok(ddoc) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /wasm/src/did/mod.rs: -------------------------------------------------------------------------------- 1 | mod did_doc; 2 | mod did_resolver; 3 | 4 | pub use did_resolver::DIDResolver; 5 | pub(crate) use did_resolver::JsDIDResolver; 6 | -------------------------------------------------------------------------------- /wasm/src/error.rs: -------------------------------------------------------------------------------- 1 | use didcomm::error::{err_msg as _err_msg, ErrorKind as _ErrorKind, Result as _Result}; 2 | use js_sys::{Error as JsError, JsString}; 3 | use wasm_bindgen::{prelude::*, JsCast}; 4 | 5 | // Alows convertion of didcomm error to javascript error 6 | pub(crate) trait JsResult { 7 | fn as_js(self) -> Result; 8 | } 9 | 10 | impl JsResult for _Result { 11 | fn as_js(self) -> Result { 12 | self.map_err(|e| { 13 | let name = match e.kind() { 14 | _ErrorKind::DIDNotResolved => "DIDCommDIDNotResolved", 15 | _ErrorKind::DIDUrlNotFound => "DIDCommDIDUrlNotFound", 16 | _ErrorKind::Malformed => "DIDCommMalformed", 17 | _ErrorKind::IoError => "DIDCommIoError", 18 | _ErrorKind::InvalidState => "DIDCommInvalidState", 19 | _ErrorKind::NoCompatibleCrypto => "DIDCommNoCompatibleCrypto", 20 | _ErrorKind::Unsupported => "DIDCommUnsupported", 21 | _ErrorKind::IllegalArgument => "DIDCommIllegalArgument", 22 | _ErrorKind::SecretNotFound => "DIDCommSecretNotFound", 23 | }; 24 | 25 | let e = JsError::new(&format!("{}", e)); 26 | e.set_name(name); 27 | e 28 | }) 29 | } 30 | } 31 | 32 | // Alows convertion of javascript error to didcomm error 33 | pub(crate) trait FromJsResult { 34 | fn from_js(self) -> _Result; 35 | } 36 | 37 | impl FromJsResult for Result { 38 | fn from_js(self) -> _Result { 39 | self.map_err(|e| { 40 | // String was thrown 41 | if let Some(e) = e.dyn_ref::() { 42 | return _err_msg( 43 | _ErrorKind::InvalidState, 44 | e.as_string().unwrap_or(format!("{:?}", e)), 45 | ); 46 | } 47 | 48 | // Error instance was thrown 49 | if let Some(e) = e.dyn_ref::() { 50 | let kind = match e.name().as_string().as_deref() { 51 | Some("DIDCommDIDNotResolved") => _ErrorKind::DIDNotResolved, 52 | Some("DIDCommDIDUrlNotFound") => _ErrorKind::DIDUrlNotFound, 53 | Some("DIDCommMalformed") => _ErrorKind::Malformed, 54 | Some("DIDCommIoError") => _ErrorKind::IoError, 55 | Some("DIDCommInvalidState") => _ErrorKind::InvalidState, 56 | Some("DIDCommNoCompatibleCrypto") => _ErrorKind::NoCompatibleCrypto, 57 | Some("DIDCommUnsupported") => _ErrorKind::Unsupported, 58 | Some("DIDCommIllegalArgument") => _ErrorKind::IllegalArgument, 59 | _ => _ErrorKind::InvalidState, 60 | }; 61 | 62 | let message = e.message().as_string().unwrap_or(format!("{:?}", e)); 63 | 64 | return _err_msg(kind, message); 65 | } 66 | 67 | // Something unusual was thrown 68 | _err_msg(_ErrorKind::InvalidState, format!("{:?}", e)) 69 | }) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod did; 2 | mod error; 3 | mod message; 4 | mod secrets; 5 | mod utils; 6 | 7 | pub use crate::{ 8 | did::DIDResolver, 9 | message::{FromPrior, Message}, 10 | secrets::SecretsResolver, 11 | }; 12 | use crate::{did::JsDIDResolver, secrets::JsSecretsResolver}; 13 | 14 | // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global 15 | // allocator. 16 | #[cfg(feature = "wee_alloc")] 17 | #[global_allocator] 18 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 19 | -------------------------------------------------------------------------------- /wasm/src/message/from_prior/mod.rs: -------------------------------------------------------------------------------- 1 | mod pack; 2 | mod unpack; 3 | 4 | use didcomm::error::{ErrorKind, ResultExt}; 5 | use std::rc::Rc; 6 | use wasm_bindgen::prelude::*; 7 | 8 | use crate::{error::JsResult, utils::set_panic_hook}; 9 | 10 | #[wasm_bindgen] 11 | /// Allows building of `from_prior` message header according 12 | /// to DIDComm DID Rotation procedure 13 | /// https://identity.foundation/didcomm-messaging/spec/#did-rotation. 14 | pub struct FromPrior(pub(crate) Rc); 15 | 16 | #[wasm_bindgen] 17 | impl FromPrior { 18 | #[wasm_bindgen(constructor)] 19 | /// Instantiates FromPrior from plain object 20 | pub fn new(value: IFromPrior) -> Result { 21 | // TODO: Better place? 22 | set_panic_hook(); 23 | 24 | let msg = value 25 | .into_serde() 26 | .kind(ErrorKind::Malformed, "Unable deserialize FromPrior") 27 | .as_js()?; 28 | 29 | Ok(FromPrior(Rc::new(msg))) 30 | } 31 | 32 | #[wasm_bindgen(skip_typescript)] 33 | pub fn as_value(&self) -> Result { 34 | let msg = JsValue::from_serde(&*self.0) 35 | .kind(ErrorKind::Malformed, "Unable serialize FromPrior") 36 | .as_js()?; 37 | 38 | Ok(msg) 39 | } 40 | } 41 | 42 | #[wasm_bindgen(typescript_custom_section)] 43 | const MESSAGE_AS_VALUE_TS: &'static str = r#" 44 | interface FromPrior { 45 | /** 46 | * @returns FromPrior representation as plain object 47 | */ 48 | as_value(): IFromPrior; 49 | } 50 | "#; 51 | 52 | #[wasm_bindgen] 53 | extern "C" { 54 | #[wasm_bindgen(typescript_type = "IFromPrior")] 55 | pub type IFromPrior; 56 | } 57 | 58 | #[wasm_bindgen(typescript_custom_section)] 59 | const IMESSAGE_TS: &'static str = r#" 60 | type IFromPrior = { 61 | /** 62 | * new DID after rotation 63 | */ 64 | iss: string, 65 | 66 | /** 67 | * prior DID 68 | */ 69 | sub: string, 70 | 71 | /** 72 | * Datetime of the DID rotation 73 | */ 74 | iat?: number, 75 | } 76 | "#; 77 | -------------------------------------------------------------------------------- /wasm/src/message/from_prior/pack.rs: -------------------------------------------------------------------------------- 1 | use js_sys::{Array, Promise}; 2 | use wasm_bindgen::prelude::*; 3 | use wasm_bindgen_futures::future_to_promise; 4 | 5 | use crate::{ 6 | error::JsResult, DIDResolver, FromPrior, JsDIDResolver, JsSecretsResolver, SecretsResolver, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | impl FromPrior { 11 | #[wasm_bindgen(skip_typescript)] 12 | pub fn pack( 13 | &self, 14 | issuer_kid: Option, 15 | did_resolver: DIDResolver, 16 | secrets_resolver: SecretsResolver, 17 | ) -> Promise { 18 | let from_prior = self.0.clone(); 19 | let did_resolver = JsDIDResolver(did_resolver); 20 | let secrets_resolver = JsSecretsResolver(secrets_resolver); 21 | 22 | future_to_promise(async move { 23 | let (msg, metadata) = from_prior 24 | .pack(issuer_kid.as_deref(), &did_resolver, &secrets_resolver) 25 | .await 26 | .as_js()?; 27 | 28 | let res = { 29 | let res = Array::new_with_length(2); 30 | res.set(0, msg.into()); 31 | res.set(1, metadata.into()); 32 | res 33 | }; 34 | 35 | Ok(res.into()) 36 | }) 37 | } 38 | } 39 | 40 | #[wasm_bindgen(typescript_custom_section)] 41 | const FROM_PRIOR_PACK_TS: &'static str = r#" 42 | interface FromPrior { 43 | /** 44 | * Packs a plaintext `from_prior` value into a signed JWT. 45 | * https://identity.foundation/didcomm-messaging/spec/#did-rotation 46 | * 47 | * @param issuer_kid (optional) identifier of the issuer key being used to sign `from_prior` JWT value 48 | * @param did_resolver instance of `DIDResolver` to resolve DIDs 49 | * @param secrets_resolver instance of `SecretsResolver` to resolve issuer DID keys secrets 50 | * 51 | * @returns promise resolving to a tuple of the signed `from_prior` JWT and the identifier of the issuer key 52 | * actually used to sign `from_prior` 53 | * 54 | * @throws DIDCommMalformed `from_prior` plaintext value has invalid format. 55 | * @throws DIDCommIllegalArgument `issuer_kid` is invalid or does not consist with `from_prior` plaintext value. 56 | * @throws DIDCommDIDNotResolved Issuer DID not found. 57 | * @throws DIDCommDIDUrlNotFound Issuer authentication verification method is not found. 58 | * @throws DIDCommSecretNotFound Issuer secret is not found. 59 | * @throws DIDCommUnsupported Used crypto or method is unsupported. 60 | * @throws DIDCommInvalidState Indicates a library error. 61 | */ 62 | pack( 63 | issuer_kid: string | null, 64 | did_resolver: DIDResolver, 65 | secrets_resolver: SecretsResolver, 66 | ): Promise<[string, string]>; 67 | } 68 | "#; 69 | -------------------------------------------------------------------------------- /wasm/src/message/from_prior/unpack.rs: -------------------------------------------------------------------------------- 1 | use js_sys::{Array, Promise}; 2 | use std::rc::Rc; 3 | use wasm_bindgen::prelude::*; 4 | use wasm_bindgen_futures::future_to_promise; 5 | 6 | use crate::{error::JsResult, utils::set_panic_hook, DIDResolver, FromPrior, JsDIDResolver}; 7 | 8 | #[wasm_bindgen(skip_typescript)] 9 | impl FromPrior { 10 | #[wasm_bindgen(skip_typescript)] 11 | pub fn unpack(from_prior: String, did_resolver: DIDResolver) -> Promise { 12 | // TODO: Better place? 13 | set_panic_hook(); 14 | 15 | let did_resolver = JsDIDResolver(did_resolver); 16 | 17 | future_to_promise(async move { 18 | let (msg, metadata) = didcomm::FromPrior::unpack(&from_prior, &did_resolver) 19 | .await 20 | .as_js()?; 21 | 22 | let res = { 23 | let res = Array::new_with_length(2); 24 | res.set(0, FromPrior(Rc::new(msg)).into()); 25 | res.set(1, metadata.into()); 26 | res 27 | }; 28 | 29 | Ok(res.into()) 30 | }) 31 | } 32 | } 33 | 34 | #[wasm_bindgen(typescript_custom_section)] 35 | const FROM_PRIOR_UNPACK_TS: &'static str = r#" 36 | export namespace FromPrior { 37 | /** 38 | * Unpacks a plaintext value from a signed `from_prior` JWT. 39 | * https://identity.foundation/didcomm-messaging/spec/#did-rotation 40 | * 41 | * @param from_prior_jwt signed `from_prior` JWT 42 | * @param did_resolver instance of `DIDResolver` to resolve DIDs 43 | * 44 | * @returns promise resolving to a tuple of the plaintext `from_prior` value and the identifier 45 | * of the issuer key used to sign `from_prior` 46 | * 47 | * @throws DIDCommMalformed Signed `from_prior` JWT is malformed. 48 | * @throws DIDCommDIDNotResolved Issuer DID not found. 49 | * @throws DIDCommDIDUrlNotFound Issuer authentication verification method is not found. 50 | * @throws DIDCommUnsupported Used crypto or method is unsupported. 51 | */ 52 | function unpack( 53 | from_prior: string, 54 | did_resolver: DIDResolver, 55 | ): Promise<[FromPrior, string]>; 56 | } 57 | "#; 58 | -------------------------------------------------------------------------------- /wasm/src/message/pack_plaintext.rs: -------------------------------------------------------------------------------- 1 | use js_sys::Promise; 2 | use wasm_bindgen::prelude::*; 3 | use wasm_bindgen_futures::future_to_promise; 4 | 5 | use crate::{error::JsResult, DIDResolver, JsDIDResolver, Message}; 6 | 7 | #[wasm_bindgen(skip_typescript)] 8 | impl Message { 9 | #[wasm_bindgen(skip_typescript)] 10 | pub fn pack_plaintext(&self, did_resolver: DIDResolver) -> Promise { 11 | let msg = self.0.clone(); 12 | let did_resolver = JsDIDResolver(did_resolver); 13 | 14 | future_to_promise(async move { 15 | let msg = msg.pack_plaintext(&did_resolver).await.as_js()?; 16 | 17 | Ok(msg.into()) 18 | }) 19 | } 20 | } 21 | 22 | #[wasm_bindgen(typescript_custom_section)] 23 | const MESSAGE_PACK_PLAYNTEXT_TS: &'static str = r#" 24 | interface Message { 25 | /** 26 | * Produces `DIDComm Plaintext Messages` 27 | * https://identity.foundation/didcomm-messaging/spec/#didcomm-plaintext-messages. 28 | * 29 | * A DIDComm message in its plaintext form, not packaged into any protective envelope, 30 | * is known as a DIDComm plaintext message. Plaintext messages lack confidentiality and integrity 31 | * guarantees, and are repudiable. They are therefore not normally transported across security boundaries. 32 | * However, this may be a helpful format to inspect in debuggers, since it exposes underlying semantics, 33 | * and it is the format used in this spec to give examples of headers and other internals. 34 | * Depending on ambient security, plaintext may or may not be an appropriate format for DIDComm data at rest. 35 | * 36 | * @param `did_resolver` instance of `DIDResolver` to resolve DIDs. 37 | * 38 | * @returns a DIDComm plaintext message s JSON string 39 | * 40 | * @throws DIDCommDIDNotResolved 41 | * @throws DIDCommDIDUrlNotFound 42 | * @throws DIDCommIoError 43 | * @throws DIDCommInvalidState 44 | * @throws DIDCommIllegalArgument 45 | */ 46 | pack_plaintext(did_resolver: DIDResolver): Promise; 47 | } 48 | "#; 49 | -------------------------------------------------------------------------------- /wasm/src/message/pack_signed.rs: -------------------------------------------------------------------------------- 1 | use didcomm::error::{ErrorKind, ResultExt}; 2 | use js_sys::{Array, Promise}; 3 | use wasm_bindgen::prelude::*; 4 | use wasm_bindgen_futures::future_to_promise; 5 | 6 | use crate::{ 7 | error::JsResult, DIDResolver, JsDIDResolver, JsSecretsResolver, Message, SecretsResolver, 8 | }; 9 | 10 | #[wasm_bindgen(skip_typescript)] 11 | impl Message { 12 | #[wasm_bindgen(skip_typescript)] 13 | pub fn pack_signed( 14 | &self, 15 | sign_by: String, 16 | did_resolver: DIDResolver, 17 | secrets_resolver: SecretsResolver, 18 | ) -> Promise { 19 | let msg = self.0.clone(); 20 | let did_resolver = JsDIDResolver(did_resolver); 21 | let secrets_resolver = JsSecretsResolver(secrets_resolver); 22 | 23 | future_to_promise(async move { 24 | let (msg, metadata) = msg 25 | .pack_signed(&sign_by, &did_resolver, &secrets_resolver) 26 | .await 27 | .as_js()?; 28 | 29 | let metadata = JsValue::from_serde(&metadata) 30 | .kind( 31 | ErrorKind::InvalidState, 32 | "Unable serialize PackSignedMetadata", 33 | ) 34 | .as_js()?; 35 | 36 | let res = { 37 | let res = Array::new_with_length(2); 38 | res.set(0, msg.into()); 39 | res.set(1, metadata); 40 | res 41 | }; 42 | 43 | Ok(res.into()) 44 | }) 45 | } 46 | } 47 | 48 | #[wasm_bindgen(typescript_custom_section)] 49 | const MESSAGE_PACK_ENCRYPTED_TS: &'static str = r#" 50 | interface Message { 51 | /** 52 | * Produces `DIDComm Signed Message` 53 | * https://identity.foundation/didcomm-messaging/spec/#didcomm-signed-message. 54 | * 55 | * Signed messages are not necessary to provide message integrity (tamper evidence), 56 | * or to prove the sender to the recipient. Both of these guarantees automatically occur 57 | * with the authenticated encryption in DIDComm encrypted messages. Signed messages are only 58 | * necessary when the origin of plaintext must be provable to third parties, 59 | * or when the sender can’t be proven to the recipient by authenticated encryption because 60 | * the recipient is not known in advance (e.g., in a broadcast scenario). 61 | * We therefore expect signed messages to be used in a few cases, but not as a matter of course. 62 | * 63 | * @param `sign_by` a DID or key ID the sender uses for signing 64 | * @param `did_resolver` instance of `DIDResolver` to resolve DIDs. 65 | * @param `secrets_resolver` instance of SecretsResolver` to resolve sender DID keys secrets 66 | * 67 | * @returns Tuple (signed_message, metadata) 68 | * - `signed_message` a DIDComm signed message as JSON string 69 | * - `metadata` additional metadata about this `encrypt` execution like used keys identifiers and algorithms. 70 | * 71 | * @throws DIDCommDIDNotResolved 72 | * @throws DIDCommDIDUrlNotFound 73 | * @throws DIDCommMalformed 74 | * @throws DIDCommIoError 75 | * @throws DIDCommInvalidState 76 | * @throws DIDCommNoCompatibleCrypto 77 | * @throws DIDCommUnsupported 78 | * @throws DIDCommIllegalArgument 79 | */ 80 | pack_signed( 81 | sign_by: string, 82 | did_resolver: DIDResolver, 83 | secrets_resolver: SecretsResolver, 84 | ): Promise<[string, PackSignedMetadata]>; 85 | } 86 | "#; 87 | 88 | #[wasm_bindgen(typescript_custom_section)] 89 | const PACK_SIGNED_METADATA_TS: &'static str = r#" 90 | /** 91 | * Additional metadata about this `pack` method execution like used key identifiers. 92 | */ 93 | type PackSignedMetadata = { 94 | /** 95 | * Identifier (DID URL) of sign key. 96 | */ 97 | sign_by_kid: String, 98 | } 99 | "#; 100 | -------------------------------------------------------------------------------- /wasm/src/message/protocols/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod routing; 2 | -------------------------------------------------------------------------------- /wasm/src/secrets/mod.rs: -------------------------------------------------------------------------------- 1 | mod secret; 2 | mod secrets_resolver; 3 | 4 | pub(crate) use secrets_resolver::JsSecretsResolver; 5 | pub use secrets_resolver::SecretsResolver; 6 | -------------------------------------------------------------------------------- /wasm/src/secrets/secret.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen(typescript_custom_section)] 4 | const SECRET_TS: &'static str = r#" 5 | /** 6 | * Represents secret. 7 | */ 8 | type Secret = { 9 | /** 10 | * A key ID identifying a secret (private key). 11 | */ 12 | id: string, 13 | 14 | /** 15 | * Must have the same semantics as type ('type' field) of the corresponding method in DID Doc containing a public key. 16 | */ 17 | type: SecretType, 18 | 19 | /** 20 | * Possible value of the secret (private key) 21 | */ 22 | privateKeyJwk?: any, 23 | privateKeyMultibase?: string, 24 | privateKeyBase58?: string, 25 | } 26 | "#; 27 | 28 | #[wasm_bindgen(typescript_custom_section)] 29 | const SECRET_TYPE_TS: &'static str = r#" 30 | /** 31 | * Must have the same semantics as type ('type' field) of the corresponding method in DID Doc containing a public key. 32 | */ 33 | type SecretType = 34 | "JsonWebKey2020" | "X25519KeyAgreementKey2019" 35 | | "Ed25519VerificationKey2018" | "EcdsaSecp256k1VerificationKey2019" | string 36 | "#; 37 | -------------------------------------------------------------------------------- /wasm/src/secrets/secrets_resolver.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | use didcomm::{ 3 | error::{err_msg, ErrorKind, Result as _Result, ResultContext, ResultExt}, 4 | secrets::{Secret, SecretsResolver as _SecretsResolver}, 5 | }; 6 | use js_sys::Array; 7 | use wasm_bindgen::{prelude::*, JsCast}; 8 | 9 | use crate::error::FromJsResult; 10 | 11 | #[wasm_bindgen] 12 | extern "C" { 13 | pub type SecretsResolver; 14 | 15 | // Promise resolves to JsValue(object) that can be deserialized to Secret 16 | #[wasm_bindgen(structural, method, catch)] 17 | pub async fn get_secret(this: &SecretsResolver, secret_id: &str) -> Result; 18 | 19 | // Promise resolves to JsValue(object) that can be casted to Array 20 | #[wasm_bindgen(structural, method, catch)] 21 | pub async fn find_secrets( 22 | this: &SecretsResolver, 23 | secret_ids: Array, 24 | ) -> Result; 25 | } 26 | 27 | #[wasm_bindgen(typescript_custom_section)] 28 | const SECRET_RESOLVER_TS: &'static str = r#" 29 | /** 30 | * Interface for secrets resolver. 31 | * Resolves secrets such as private keys to be used for signing and encryption. 32 | */ 33 | interface SecretsResolver { 34 | /** 35 | * Finds secret (usually private key) identified by the given key ID. 36 | * 37 | * @param `secret_id` the ID (in form of DID URL) identifying a secret 38 | * 39 | * @returns A secret (usually private key) or None of there is no secret for the given ID 40 | * 41 | * @throws DIDCommIoError - IO error in resolving process 42 | * @throws DIDCommInvalidState - Code error or unexpected state was detected 43 | * 44 | * ``` 45 | * let e = Error("Unble perform io operation"); 46 | * e.name = "DIDCommIoError" 47 | * throw e 48 | * ``` 49 | */ 50 | get_secret(secret_id: string): Promise; 51 | 52 | /** 53 | * Find all secrets that have one of the given IDs. 54 | * Return secrets only for key IDs for which a secret is present. 55 | * 56 | * @param `secret_ids` the IDs find secrets for 57 | * 58 | * @returns possible empty list of all secrets that have one of the given IDs. 59 | * 60 | * @throws DIDCommIoError - IO error in resolving process 61 | * @throws DIDCommInvalidState - Code error or unexpected state was detected 62 | * 63 | * Note to throw compatible error use code like this 64 | * 65 | * ``` 66 | * let e = Error("Unble perform io operation"); 67 | * e.name = "DIDCommIoError" 68 | * throw e 69 | * ``` 70 | */ 71 | find_secrets(secret_ids: Array): Promise>; 72 | } 73 | "#; 74 | 75 | // TODO: think is it possible to avoid ownership on DIDResolver 76 | pub(crate) struct JsSecretsResolver(pub(crate) SecretsResolver); 77 | 78 | #[async_trait(?Send)] 79 | impl _SecretsResolver for JsSecretsResolver { 80 | async fn get_secret(&self, secret_id: &str) -> _Result> { 81 | // TODO: better error conversion 82 | let secret = self 83 | .0 84 | .get_secret(secret_id) 85 | .await 86 | .from_js() 87 | .context("Unable get secret")?; 88 | 89 | let secret: Option = secret.into_serde().kind( 90 | ErrorKind::InvalidState, 91 | "Unable deserialize Secret from JsValue", 92 | )?; 93 | 94 | Ok(secret) 95 | } 96 | 97 | async fn find_secrets<'a>(&self, secret_ids: &'a [&'a str]) -> _Result> { 98 | let _secret_ids = secret_ids 99 | .into_iter() 100 | .map(|s| JsValue::from_str(s)) 101 | .collect::(); 102 | 103 | // TODO: better error conversion 104 | let found = self 105 | .0 106 | .find_secrets(_secret_ids) 107 | .await 108 | .from_js() 109 | .context("Unable find secrets")?; 110 | 111 | let found: Vec<_> = found 112 | .dyn_into::() 113 | .map_err(|_| { 114 | err_msg( 115 | ErrorKind::InvalidState, 116 | "Unable covert secret ids JsValue to Array", 117 | ) 118 | })? 119 | .iter() 120 | .map(|v| v.as_string()) 121 | .flatten() 122 | .collect(); 123 | 124 | let found: Vec<_> = secret_ids 125 | .iter() 126 | .filter(|&s| found.iter().find(|_s| _s == s).is_some()) 127 | .map(|&s| s) 128 | .collect(); 129 | 130 | Ok(found) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /wasm/src/utils.rs: -------------------------------------------------------------------------------- 1 | pub fn set_panic_hook() { 2 | // When the `console_error_panic_hook` feature is enabled, we can call the 3 | // `set_panic_hook` function at least once during initialization, and then 4 | // we will get better error messages if our code ever panics. 5 | // 6 | // For more details see 7 | // https://github.com/rustwasm/console_error_panic_hook#readme 8 | #[cfg(feature = "console_error_panic_hook")] 9 | console_error_panic_hook::set_once(); 10 | } 11 | -------------------------------------------------------------------------------- /wasm/tests-js/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /wasm/tests-js/.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /wasm/tests-js/jest-puppeteer.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | launch: { 3 | dumpio: true, 4 | headless: true, 5 | args: ["--disable-infobars"], 6 | }, 7 | browserContext: "default", 8 | }; 9 | -------------------------------------------------------------------------------- /wasm/tests-js/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | module.exports = { 3 | testEnvironment: "node", 4 | transform: { 5 | "^.+\\.ts?$": "ts-jest", 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /wasm/tests-js/jest.config.puppeteer.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | module.exports = { 3 | preset: "jest-puppeteer", 4 | transform: { 5 | "^.+\\.ts?$": "ts-jest", 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /wasm/tests-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "didcomm-tests", 3 | "version": "0.3.4", 4 | "description": "JS tests for didcomm", 5 | "scripts": { 6 | "test": "jest", 7 | "test-puppeteer": "jest --config=jest.config.puppeteer.js", 8 | "check": "tslint -c tslint.json 'src/**/*.ts'", 9 | "format": "prettier --write ." 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "didcomm": "file:../pkg", 15 | "typescript": "^4.5.2" 16 | }, 17 | "devDependencies": { 18 | "@types/jest": "^27.0.2", 19 | "@types/jest-environment-puppeteer": "^4.4.1", 20 | "@types/puppeteer": "^5.4.4", 21 | "jest": "^27.3.1", 22 | "jest-puppeteer": "^6.0.0", 23 | "prettier": "2.4.1", 24 | "puppeteer": "^19.6.3", 25 | "ts-jest": "^27.0.7", 26 | "ts-node": "^10.4.0", 27 | "tslint": "^6.1.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /wasm/tests-js/src/forward/try-parse-forward.test.ts: -------------------------------------------------------------------------------- 1 | import { Message, ParsedForward } from "didcomm"; 2 | import { MESSAGE_SIMPLE, FORWARD_MESSAGE } from "../test-vectors"; 3 | 4 | // TODO: more tests 5 | test.each([ 6 | { 7 | case: "Not Forward", 8 | message: MESSAGE_SIMPLE, 9 | }, 10 | ])("Message.try-parse-forward handles $case", async ({ message }) => { 11 | const res = message.try_parse_forward(); 12 | expect(res).toBeNull(); 13 | }); 14 | 15 | test.each([ 16 | { 17 | case: "Forward", 18 | message: FORWARD_MESSAGE, 19 | }, 20 | ])("Message.try-parse-forward handles $case", async ({ message }) => { 21 | const res = message.try_parse_forward(); 22 | expect(res).toEqual(expect.anything()); 23 | }); 24 | -------------------------------------------------------------------------------- /wasm/tests-js/src/forward/wrap-in-forward.test.ts: -------------------------------------------------------------------------------- 1 | import { Message } from "didcomm"; 2 | import { 3 | IMESSAGE_SIMPLE, 4 | ExampleDIDResolver, 5 | ALICE_DID_DOC, 6 | BOB_DID_DOC, 7 | ALICE_DID, 8 | } from "../test-vectors"; 9 | 10 | // TODO: more tests 11 | test.each([ 12 | { 13 | case: "Simple", 14 | message: IMESSAGE_SIMPLE, 15 | headers: { header1: "aaa", header2: "bbb" }, 16 | to: ALICE_DID, 17 | routing_keys: ["did:example:bob#key-x25519-1"], 18 | enc_alg_anon: "A256cbcHs512EcdhEsA256kw", 19 | did_resolver: new ExampleDIDResolver([ALICE_DID_DOC, BOB_DID_DOC]), 20 | }, 21 | ])( 22 | "Message.wrap-in-forward handles $case", 23 | async ({ 24 | message, 25 | headers, 26 | to, 27 | routing_keys, 28 | enc_alg_anon, 29 | did_resolver, 30 | }) => { 31 | const res = await Message.wrap_in_forward( 32 | JSON.stringify(message), 33 | headers, 34 | to, 35 | routing_keys, 36 | enc_alg_anon, 37 | did_resolver 38 | ); 39 | expect(typeof res).toStrictEqual("string"); 40 | expect(res).toContain("ciphertext"); 41 | } 42 | ); 43 | -------------------------------------------------------------------------------- /wasm/tests-js/src/from_prior/new.test.ts: -------------------------------------------------------------------------------- 1 | import { FromPrior } from "didcomm"; 2 | import { IFROM_PRIOR_FULL, IFROM_PRIOR_MINIMAL } from "../test-vectors"; 3 | 4 | test.each([ 5 | { val: IFROM_PRIOR_MINIMAL, case: "Minimal" }, 6 | { val: IFROM_PRIOR_FULL, case: "Full" }, 7 | ])("FromPrior.new works for $case", ({ val }) => { 8 | const fromPrior = new FromPrior(val); 9 | expect(fromPrior.as_value()).toStrictEqual(val); 10 | }); 11 | -------------------------------------------------------------------------------- /wasm/tests-js/src/from_prior/pack.test.ts: -------------------------------------------------------------------------------- 1 | import { FromPrior } from "didcomm"; 2 | import { 3 | ALICE_DID_DOC, 4 | CHARLIE_DID_DOC, 5 | CHARLIE_SECRETS, 6 | CHARLIE_SECRET_AUTH_KEY_ED25519, 7 | ExampleDIDResolver, 8 | ExampleSecretsResolver, 9 | FROM_PRIOR_FULL, 10 | FROM_PRIOR_MINIMAL, 11 | } from "../test-vectors"; 12 | 13 | test.each([ 14 | { 15 | fromPrior: FROM_PRIOR_MINIMAL, 16 | issuerKid: null, 17 | expKid: CHARLIE_SECRET_AUTH_KEY_ED25519.id, 18 | case: "Minimal", 19 | }, 20 | { 21 | fromPrior: FROM_PRIOR_FULL, 22 | issuerKid: null, 23 | expKid: CHARLIE_SECRET_AUTH_KEY_ED25519.id, 24 | case: "Full", 25 | }, 26 | { 27 | fromPrior: FROM_PRIOR_FULL, 28 | issuerKid: CHARLIE_SECRET_AUTH_KEY_ED25519.id, 29 | expKid: CHARLIE_SECRET_AUTH_KEY_ED25519.id, 30 | case: "Explicit key", 31 | }, 32 | ])( 33 | "FromPrior.pack works for $case", 34 | async ({ fromPrior, issuerKid, expKid }) => { 35 | const didResolver = new ExampleDIDResolver([ 36 | ALICE_DID_DOC, 37 | CHARLIE_DID_DOC, 38 | ]); 39 | 40 | const secretsResolver = new ExampleSecretsResolver(CHARLIE_SECRETS); 41 | 42 | const [packed, kid] = await fromPrior.pack( 43 | issuerKid, 44 | didResolver, 45 | secretsResolver 46 | ); 47 | 48 | expect(typeof packed).toStrictEqual("string"); 49 | expect(kid).toStrictEqual(expKid); 50 | 51 | const [unpacked, _] = await FromPrior.unpack(packed, didResolver); 52 | expect(unpacked.as_value()).toStrictEqual(fromPrior.as_value()); 53 | } 54 | ); 55 | -------------------------------------------------------------------------------- /wasm/tests-js/src/from_prior/unpack.test.ts: -------------------------------------------------------------------------------- 1 | import { FromPrior } from "didcomm"; 2 | import { 3 | ALICE_DID_DOC, 4 | CHARLIE_DID_DOC, 5 | CHARLIE_SECRET_AUTH_KEY_ED25519, 6 | ExampleDIDResolver, 7 | FROM_PRIOR_JWT_FULL, 8 | FROM_PRIOR_JWT_INVALID, 9 | FROM_PRIOR_JWT_INVALID_SIGNATURE, 10 | IFROM_PRIOR_FULL, 11 | } from "../test-vectors"; 12 | 13 | test("FromPrior.unpack works", async () => { 14 | const didResolver = new ExampleDIDResolver([ALICE_DID_DOC, CHARLIE_DID_DOC]); 15 | 16 | const [fromPrior, issuerKid] = await FromPrior.unpack( 17 | FROM_PRIOR_JWT_FULL, 18 | didResolver 19 | ); 20 | 21 | // TODO: Use toStrictEq check after reduction of FromPrior fields 22 | expect(fromPrior.as_value()).toMatchObject(IFROM_PRIOR_FULL); 23 | 24 | expect(issuerKid).toStrictEqual(CHARLIE_SECRET_AUTH_KEY_ED25519.id); 25 | }); 26 | 27 | test.each([ 28 | { 29 | jwt: FROM_PRIOR_JWT_INVALID, 30 | exp_err: "Malformed: Unable to parse compactly serialized JWS", 31 | case: "Malformed", 32 | }, 33 | { 34 | jwt: FROM_PRIOR_JWT_INVALID_SIGNATURE, 35 | exp_err: 36 | "Malformed: Unable to verify from_prior signature: Unable decode signature: Invalid last symbol 66, offset 85.", 37 | case: "Invalid signature", 38 | }, 39 | ])("FromPrior.unpack handles $case", async ({ jwt, exp_err }) => { 40 | const didResolver = new ExampleDIDResolver([ALICE_DID_DOC, CHARLIE_DID_DOC]); 41 | const res = FromPrior.unpack(jwt, didResolver); 42 | await expect(res).rejects.toThrowError(exp_err); 43 | }); 44 | -------------------------------------------------------------------------------- /wasm/tests-js/src/message/new.test.ts: -------------------------------------------------------------------------------- 1 | import { Message, IMessage } from "didcomm"; 2 | 3 | test("Message.new works", () => { 4 | const val: IMessage = { 5 | id: "example-1", 6 | typ: "application/didcomm-plain+json", 7 | type: "example/v1", 8 | body: "example-body", 9 | from: "did:example:4", 10 | to: ["did:example:1", "did:example:2", "did:example:3"], 11 | thid: "example-thread-1", 12 | pthid: "example-parent-thread-1", 13 | "example-header-1": "example-header-1-value", 14 | "example-header-2": "example-header-2-value", 15 | created_time: 10000, 16 | expires_time: 20000, 17 | attachments: [ 18 | { 19 | data: { 20 | base64: "ZXhhbXBsZQ==", 21 | }, 22 | id: "attachment1", 23 | }, 24 | { 25 | data: { 26 | json: "example", 27 | }, 28 | id: "attachment2", 29 | }, 30 | { 31 | data: { 32 | json: "example", 33 | }, 34 | id: "attachment3", 35 | }, 36 | ], 37 | }; 38 | 39 | const msg = new Message(val); 40 | expect(msg.as_value()).toStrictEqual(val); 41 | }); 42 | -------------------------------------------------------------------------------- /wasm/tests-js/src/message/pack-encrypted.anoncrypt.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ALICE_AUTH_METHOD_25519, 3 | ALICE_AUTH_METHOD_P256, 4 | ALICE_AUTH_METHOD_SECP256K1, 5 | ALICE_DID, 6 | ALICE_DID_DOC, 7 | ALICE_SECRETS, 8 | BOB_DID, 9 | BOB_DID_DOC, 10 | BOB_SECRET_KEY_AGREEMENT_KEY_P256_1, 11 | BOB_SECRET_KEY_AGREEMENT_KEY_P384_1, 12 | BOB_SECRET_KEY_AGREEMENT_KEY_P521_1, 13 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_1, 14 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_2, 15 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_3, 16 | BOB_SECRETS, 17 | BOB_VERIFICATION_METHOD_KEY_AGREEM_P256_1, 18 | BOB_VERIFICATION_METHOD_KEY_AGREEM_P256_2, 19 | BOB_VERIFICATION_METHOD_KEY_AGREEM_P384_1, 20 | BOB_VERIFICATION_METHOD_KEY_AGREEM_P384_2, 21 | BOB_VERIFICATION_METHOD_KEY_AGREEM_P521_1, 22 | BOB_VERIFICATION_METHOD_KEY_AGREEM_P521_2, 23 | BOB_VERIFICATION_METHOD_KEY_AGREEM_X25519_1, 24 | BOB_VERIFICATION_METHOD_KEY_AGREEM_X25519_2, 25 | BOB_VERIFICATION_METHOD_KEY_AGREEM_X25519_3, 26 | ExampleDIDResolver, 27 | ExampleSecretsResolver, 28 | MESSAGE_SIMPLE, 29 | } from "../test-vectors"; 30 | import { Message } from "didcomm"; 31 | 32 | test.each([ 33 | { 34 | message: MESSAGE_SIMPLE, 35 | signBy: null, 36 | to: BOB_DID, 37 | expMetadata: { 38 | messaging_service: null, 39 | from_kid: null, 40 | sign_by_kid: null, 41 | to_kids: [ 42 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_1.id, 43 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_2.id, 44 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_3.id, 45 | ], 46 | }, 47 | case: "Simple message X25519", 48 | }, 49 | { 50 | message: MESSAGE_SIMPLE, 51 | signBy: null, 52 | to: BOB_SECRET_KEY_AGREEMENT_KEY_P256_1.id, 53 | expMetadata: { 54 | messaging_service: null, 55 | from_kid: null, 56 | sign_by_kid: null, 57 | to_kids: [BOB_SECRET_KEY_AGREEMENT_KEY_P256_1.id], 58 | }, 59 | case: "Simple message P256", 60 | }, 61 | { 62 | message: MESSAGE_SIMPLE, 63 | signBy: ALICE_AUTH_METHOD_25519.id, 64 | to: BOB_DID, 65 | expMetadata: { 66 | messaging_service: null, 67 | from_kid: null, 68 | sign_by_kid: ALICE_AUTH_METHOD_25519.id, 69 | to_kids: [ 70 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_1.id, 71 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_2.id, 72 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_3.id, 73 | ], 74 | }, 75 | case: "Simple message X25519 signed", 76 | }, 77 | { 78 | message: MESSAGE_SIMPLE, 79 | signBy: ALICE_AUTH_METHOD_P256.id, 80 | to: BOB_SECRET_KEY_AGREEMENT_KEY_P256_1.id, 81 | expMetadata: { 82 | messaging_service: null, 83 | from_kid: null, 84 | sign_by_kid: ALICE_AUTH_METHOD_P256.id, 85 | to_kids: [BOB_SECRET_KEY_AGREEMENT_KEY_P256_1.id], 86 | }, 87 | case: "Simple message P256 signed", 88 | }, 89 | ])( 90 | "Message.pack-encrypted anoncrypt works for $case", 91 | async ({ message, signBy, to, expMetadata }) => { 92 | const didResolver = new ExampleDIDResolver([ALICE_DID_DOC, BOB_DID_DOC]); 93 | let secretResolver = new ExampleSecretsResolver(ALICE_SECRETS); 94 | 95 | const [encrypted, metadata] = await message.pack_encrypted( 96 | to, 97 | null, 98 | signBy, 99 | didResolver, 100 | secretResolver, 101 | { 102 | protect_sender: false, 103 | forward: false, 104 | forward_headers: null, 105 | messaging_service: null, 106 | enc_alg_anon: "A256cbcHs512EcdhEsA256kw", 107 | } 108 | ); 109 | 110 | expect(typeof encrypted).toStrictEqual("string"); 111 | expect(metadata).toStrictEqual(expMetadata); 112 | 113 | secretResolver = new ExampleSecretsResolver(BOB_SECRETS); 114 | 115 | const [unpacked, _] = await Message.unpack( 116 | encrypted, 117 | didResolver, 118 | secretResolver, 119 | {} 120 | ); 121 | 122 | expect(unpacked.as_value()).toStrictEqual(message.as_value()); 123 | } 124 | ); 125 | -------------------------------------------------------------------------------- /wasm/tests-js/src/message/pack-plaintext.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | MESSAGE_SIMPLE, 3 | ExampleDIDResolver, 4 | ALICE_DID_DOC, 5 | PLAINTEXT_MSG_SIMPLE, 6 | MESSAGE_MINIMAL, 7 | PLAINTEXT_MSG_MINIMAL, 8 | MESSAGE_FROM_PRIOR, 9 | PLAINTEXT_FROM_PRIOR, 10 | BOB_DID_DOC, 11 | CHARLIE_DID_DOC, 12 | } from "../test-vectors"; 13 | 14 | test.each([ 15 | { 16 | message: MESSAGE_SIMPLE, 17 | expPlaintext: PLAINTEXT_MSG_SIMPLE, 18 | case: "Simple", 19 | }, 20 | { 21 | message: MESSAGE_MINIMAL, 22 | expPlaintext: PLAINTEXT_MSG_MINIMAL, 23 | case: "Minimal", 24 | }, 25 | { 26 | message: MESSAGE_FROM_PRIOR, 27 | expPlaintext: PLAINTEXT_FROM_PRIOR, 28 | case: "FromPrior", 29 | }, 30 | ])( 31 | "Message.pack-plaintext works for $case", 32 | async ({ message, expPlaintext }) => { 33 | const didResolver = new ExampleDIDResolver([ 34 | ALICE_DID_DOC, 35 | BOB_DID_DOC, 36 | CHARLIE_DID_DOC, 37 | ]); 38 | 39 | const plaintext = await message.pack_plaintext(didResolver); 40 | 41 | expect(JSON.parse(plaintext)).toStrictEqual(JSON.parse(expPlaintext)); 42 | } 43 | ); 44 | -------------------------------------------------------------------------------- /wasm/tests-js/src/message/unpack.test.ts: -------------------------------------------------------------------------------- 1 | import { Message } from "didcomm"; 2 | import { 3 | ALICE_DID_DOC, 4 | BOB_DID_DOC, 5 | BOB_SECRETS, 6 | CHARLIE_DID_DOC, 7 | ExampleDIDResolver, 8 | ExampleSecretsResolver, 9 | IMESSAGE_FROM_PRIOR, 10 | IMESSAGE_MINIMAL, 11 | IMESSAGE_SIMPLE, 12 | PLAINTEXT_FROM_PRIOR, 13 | PLAINTEXT_MSG_MINIMAL, 14 | PLAINTEXT_MSG_SIMPLE, 15 | } from "../test-vectors"; 16 | 17 | test.each([ 18 | { 19 | case: "Minimal", 20 | msg: PLAINTEXT_MSG_MINIMAL, 21 | options: {}, 22 | expMsg: IMESSAGE_MINIMAL, 23 | expMetadata: { 24 | anonymous_sender: false, 25 | authenticated: false, 26 | enc_alg_anon: null, 27 | enc_alg_auth: null, 28 | encrypted: false, 29 | encrypted_from_kid: null, 30 | encrypted_to_kids: null, 31 | from_prior: null, 32 | from_prior_issuer_kid: null, 33 | non_repudiation: false, 34 | re_wrapped_in_forward: false, 35 | sign_alg: null, 36 | sign_from: null, 37 | signed_message: null, 38 | }, 39 | }, 40 | { 41 | case: "Simple", 42 | msg: PLAINTEXT_MSG_SIMPLE, 43 | options: {}, 44 | expMsg: IMESSAGE_SIMPLE, 45 | expMetadata: { 46 | anonymous_sender: false, 47 | authenticated: false, 48 | enc_alg_anon: null, 49 | enc_alg_auth: null, 50 | encrypted: false, 51 | encrypted_from_kid: null, 52 | encrypted_to_kids: null, 53 | from_prior: null, 54 | from_prior_issuer_kid: null, 55 | non_repudiation: false, 56 | re_wrapped_in_forward: false, 57 | sign_alg: null, 58 | sign_from: null, 59 | signed_message: null, 60 | }, 61 | }, 62 | { 63 | case: "FromPrior", 64 | msg: PLAINTEXT_FROM_PRIOR, 65 | options: {}, 66 | expMsg: IMESSAGE_FROM_PRIOR, 67 | expMetadata: { 68 | anonymous_sender: false, 69 | authenticated: false, 70 | enc_alg_anon: null, 71 | enc_alg_auth: null, 72 | encrypted: false, 73 | encrypted_from_kid: null, 74 | encrypted_to_kids: null, 75 | from_prior: { 76 | aud: "123", 77 | exp: 1234, 78 | iat: 123456, 79 | iss: "did:example:charlie", 80 | jti: "dfg", 81 | nbf: 12345, 82 | sub: "did:example:alice", 83 | }, 84 | from_prior_issuer_kid: "did:example:charlie#key-1", 85 | non_repudiation: false, 86 | re_wrapped_in_forward: false, 87 | sign_alg: null, 88 | sign_from: null, 89 | signed_message: null, 90 | }, 91 | }, 92 | ])( 93 | "Message.unpack works for $case", 94 | async ({ msg, options, expMsg, expMetadata }) => { 95 | const didResolver = new ExampleDIDResolver([ 96 | ALICE_DID_DOC, 97 | BOB_DID_DOC, 98 | CHARLIE_DID_DOC, 99 | ]); 100 | 101 | const secretsResolver = new ExampleSecretsResolver(BOB_SECRETS); 102 | 103 | const [unpacked, metadata] = await Message.unpack( 104 | msg, 105 | didResolver, 106 | secretsResolver, 107 | options 108 | ); 109 | 110 | expect(unpacked.as_value()).toStrictEqual(expMsg); 111 | expect(metadata).toStrictEqual(expMetadata); 112 | } 113 | ); 114 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/common.ts: -------------------------------------------------------------------------------- 1 | export const ALICE_DID = "did:example:alice"; 2 | export const BOB_DID = "did:example:bob"; 3 | export const CHARLIE_DID = "did:example:charlie"; 4 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/did_doc/alice.ts: -------------------------------------------------------------------------------- 1 | import { DIDDoc, VerificationMethod } from "didcomm"; 2 | 3 | export const ALICE_VERIFICATION_METHOD_KEY_AGREEM_X25519_NOT_IN_SECRET: VerificationMethod = 4 | { 5 | id: "did:example:alice#key-x25519-not-in-secrets-1", 6 | type: "JsonWebKey2020", 7 | controller: "did:example:alice#key-x25519-not-in-secrets-1", 8 | publicKeyJwk: { 9 | crv: "X25519", 10 | kty: "OKP", 11 | x: "avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs", 12 | }, 13 | }; 14 | 15 | export const ALICE_VERIFICATION_METHOD_KEY_AGREEM_X25519: VerificationMethod = { 16 | id: "did:example:alice#key-x25519-1", 17 | type: "JsonWebKey2020", 18 | controller: "did:example:alice#key-x25519-1", 19 | publicKeyJwk: { 20 | crv: "X25519", 21 | kty: "OKP", 22 | x: "avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs", 23 | }, 24 | }; 25 | 26 | export const ALICE_VERIFICATION_METHOD_KEY_AGREEM_P256: VerificationMethod = { 27 | id: "did:example:alice#key-p256-1", 28 | type: "JsonWebKey2020", 29 | controller: "did:example:alice#key-p256-1", 30 | publicKeyJwk: { 31 | crv: "P-256", 32 | kty: "EC", 33 | x: "L0crjMN1g0Ih4sYAJ_nGoHUck2cloltUpUVQDhF2nHE", 34 | y: "SxYgE7CmEJYi7IDhgK5jI4ZiajO8jPRZDldVhqFpYoo", 35 | }, 36 | }; 37 | 38 | export const ALICE_VERIFICATION_METHOD_KEY_AGREEM_P521: VerificationMethod = { 39 | id: "did:example:alice#key-p521-1", 40 | type: "JsonWebKey2020", 41 | controller: "did:example:alice#key-p521-1", 42 | publicKeyJwk: { 43 | crv: "P-521", 44 | kty: "EC", 45 | x: "AHBEVPRhAv-WHDEvxVM9S0px9WxxwHL641Pemgk9sDdxvli9VpKCBdra5gg_4kupBDhz__AlaBgKOC_15J2Byptz", 46 | y: "AciGcHJCD_yMikQvlmqpkBbVqqbg93mMVcgvXBYAQPP-u9AF7adybwZrNfHWCKAQwGF9ugd0Zhg7mLMEszIONFRk", 47 | }, 48 | }; 49 | 50 | export const ALICE_AUTH_METHOD_25519: VerificationMethod = { 51 | id: "did:example:alice#key-1", 52 | type: "JsonWebKey2020", 53 | controller: "did:example:alice#key-1", 54 | publicKeyJwk: { 55 | crv: "Ed25519", 56 | kty: "OKP", 57 | x: "G-boxFB6vOZBu-wXkm-9Lh79I8nf9Z50cILaOgKKGww", 58 | }, 59 | }; 60 | 61 | export const ALICE_AUTH_METHOD_P256: VerificationMethod = { 62 | id: "did:example:alice#key-2", 63 | type: "JsonWebKey2020", 64 | controller: "did:example:alice#key-2", 65 | publicKeyJwk: { 66 | crv: "P-256", 67 | kty: "EC", 68 | x: "2syLh57B-dGpa0F8p1JrO6JU7UUSF6j7qL-vfk1eOoY", 69 | y: "BgsGtI7UPsObMRjdElxLOrgAO9JggNMjOcfzEPox18w", 70 | }, 71 | }; 72 | 73 | export const ALICE_AUTH_METHOD_SECP256K1: VerificationMethod = { 74 | id: "did:example:alice#key-3", 75 | type: "JsonWebKey2020", 76 | controller: "did:example:alice#key-3", 77 | publicKeyJwk: { 78 | crv: "secp256k1", 79 | kty: "EC", 80 | x: "aToW5EaTq5mlAf8C5ECYDSkqsJycrW-e1SQ6_GJcAOk", 81 | y: "JAGX94caA21WKreXwYUaOCYTBMrqaX4KWIlsQZTHWCk", 82 | }, 83 | }; 84 | 85 | export const ALICE_DID_DOC: DIDDoc = { 86 | id: "did:example:alice", 87 | keyAgreement: [ 88 | "did:example:alice#key-x25519-not-in-secrets-1", 89 | "did:example:alice#key-x25519-1", 90 | "did:example:alice#key-p256-1", 91 | "did:example:alice#key-p521-1", 92 | ], 93 | authentication: [ 94 | "did:example:alice#key-1", 95 | "did:example:alice#key-2", 96 | "did:example:alice#key-3", 97 | ], 98 | verificationMethod: [ 99 | ALICE_VERIFICATION_METHOD_KEY_AGREEM_X25519_NOT_IN_SECRET, 100 | ALICE_VERIFICATION_METHOD_KEY_AGREEM_X25519, 101 | ALICE_VERIFICATION_METHOD_KEY_AGREEM_P256, 102 | ALICE_VERIFICATION_METHOD_KEY_AGREEM_P521, 103 | ALICE_AUTH_METHOD_25519, 104 | ALICE_AUTH_METHOD_P256, 105 | ALICE_AUTH_METHOD_SECP256K1, 106 | ], 107 | service: [ 108 | { 109 | id: "service1", 110 | type: "DIDCommMessaging", 111 | serviceEndpoint: { 112 | uri: "https://example.com/path", 113 | accept: ["didcomm/v2", "didcomm/aip2;env=rfc587"], 114 | routingKeys: ["did:example:somemediator#somekey"], 115 | }, 116 | }, 117 | ], 118 | }; 119 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/did_doc/charlie.ts: -------------------------------------------------------------------------------- 1 | import { DIDDoc } from "didcomm"; 2 | 3 | export const CHARLIE_DID_DOC: DIDDoc = { 4 | id: "did:example:charlie", 5 | keyAgreement: ["did:example:charlie#key-x25519-1"], 6 | authentication: ["did:example:charlie#key-1"], 7 | verificationMethod: [ 8 | { 9 | id: "did:example:charlie#key-x25519-1", 10 | type: "JsonWebKey2020", 11 | controller: "did:example:charlie#key-x25519-1", 12 | publicKeyJwk: { 13 | crv: "X25519", 14 | kty: "OKP", 15 | x: "nTiVFj7DChMsETDdxd5dIzLAJbSQ4j4UG6ZU1ogLNlw", 16 | }, 17 | }, 18 | { 19 | id: "did:example:charlie#key-1", 20 | type: "JsonWebKey2020", 21 | controller: "did:example:charlie#key-1", 22 | publicKeyJwk: { 23 | crv: "Ed25519", 24 | kty: "OKP", 25 | x: "VDXDwuGKVq91zxU6q7__jLDUq8_C5cuxECgd-1feFTE", 26 | }, 27 | }, 28 | ], 29 | service: [], 30 | }; 31 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/did_doc/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./alice"; 2 | export * from "./bob"; 3 | export * from "./charlie"; 4 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/did_resolver.ts: -------------------------------------------------------------------------------- 1 | import { DIDResolver, DIDDoc } from "didcomm"; 2 | 3 | export class ExampleDIDResolver implements DIDResolver { 4 | knownDids: DIDDoc[]; 5 | 6 | constructor(knownDids: DIDDoc[]) { 7 | this.knownDids = knownDids; 8 | } 9 | 10 | async resolve(did: string): Promise { 11 | const res = this.knownDids.find((ddoc) => ddoc.id === did); 12 | return res ? res : null; 13 | } 14 | } 15 | 16 | type MockResolve = (did: string) => DIDDoc | null; 17 | 18 | /* tslint:disable:max-classes-per-file */ 19 | export class MockDIDResolver implements DIDResolver { 20 | handlers: MockResolve[]; 21 | fallback: DIDResolver; 22 | 23 | constructor(handlers: MockResolve[], fallback: DIDResolver) { 24 | this.handlers = handlers; 25 | this.fallback = fallback; 26 | } 27 | 28 | async resolve(did: string): Promise { 29 | const handler = this.handlers.pop(); 30 | return handler ? handler(did) : await this.fallback.resolve(did); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/from_prior.ts: -------------------------------------------------------------------------------- 1 | import { FromPrior, IFromPrior } from "didcomm"; 2 | import { ALICE_DID, BOB_DID, CHARLIE_DID } from "."; 3 | 4 | export const IFROM_PRIOR_MINIMAL: IFromPrior = { 5 | iss: CHARLIE_DID, 6 | sub: ALICE_DID, 7 | }; 8 | 9 | export const FROM_PRIOR_MINIMAL = new FromPrior(IFROM_PRIOR_MINIMAL); 10 | 11 | export const IFROM_PRIOR_FULL = { 12 | iss: CHARLIE_DID, 13 | sub: ALICE_DID, 14 | iat: 123456, 15 | }; 16 | 17 | export const FROM_PRIOR_FULL = new FromPrior(IFROM_PRIOR_FULL); 18 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/from_prior_jwt.ts: -------------------------------------------------------------------------------- 1 | export const FROM_PRIOR_JWT_FULL = 2 | "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpleGFtcGxlOmNoYXJsaWUja2V5LTEifQ.eyJpc3MiOiJkaWQ6ZXhhbXBsZTpjaGFybGllIiwic3ViIjoiZGlkOmV4YW1wbGU6YWxpY2UiLCJhdWQiOiIxMjMiLCJleHAiOjEyMzQsIm5iZiI6MTIzNDUsImlhdCI6MTIzNDU2LCJqdGkiOiJkZmcifQ.ir0tegXiGJIZIMagO5P853KwhzGTEw0OpFFAyarUV-nQrtbI_ELbxT9l7jPBoPve_-60ifGJ9v3ArmFjELFlDA"; 3 | 4 | export const FROM_PRIOR_JWT_INVALID = "invalid"; 5 | 6 | export const FROM_PRIOR_JWT_INVALID_SIGNATURE = 7 | "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpleGFtcGxlOmNoYXJsaWUja2V5LTEifQ.eyJpc3MiOiJkaWQ6ZXhhbXBsZTpjaGFybGllIiwic3ViIjoiZGlkOmV4YW1wbGU6YWxpY2UiLCJhdWQiOiIxMjMiLCJleHAiOjEyMzQsIm5iZiI6MTIzNDUsImlhdCI6MTIzNDU2LCJqdGkiOiJkZmcifQ.ir0tegXiGJIZIMagO5P853KwhzGTEw0OpFFAyarUV-nQrtbI_ELbxT9l7jPBoPve_-60ifGJ9v3ArmFjELFlDB"; 8 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./common"; 2 | export * from "./did_doc"; 3 | export * from "./did_resolver"; 4 | export * from "./from_prior"; 5 | export * from "./from_prior_jwt"; 6 | export * from "./message"; 7 | export * from "./plaintext"; 8 | export * from "./secrets"; 9 | export * from "./secrets_resolver"; 10 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/message.ts: -------------------------------------------------------------------------------- 1 | import { Message } from "didcomm"; 2 | 3 | export const IMESSAGE_SIMPLE = { 4 | id: "1234567890", 5 | typ: "application/didcomm-plain+json", 6 | type: "http://example.com/protocols/lets_do_lunch/1.0/proposal", 7 | from: "did:example:alice", 8 | to: ["did:example:bob"], 9 | created_time: 1516269022, 10 | expires_time: 1516385931, 11 | body: { messagespecificattribute: "and its value" }, 12 | }; 13 | 14 | export const MESSAGE_SIMPLE = new Message(IMESSAGE_SIMPLE); 15 | 16 | export const IMESSAGE_MINIMAL = { 17 | id: "1234567890", 18 | typ: "application/didcomm-plain+json", 19 | type: "http://example.com/protocols/lets_do_lunch/1.0/proposal", 20 | body: {}, 21 | }; 22 | 23 | export const MESSAGE_MINIMAL = new Message(IMESSAGE_MINIMAL); 24 | 25 | export const IMESSAGE_FROM_PRIOR = { 26 | id: "1234567890", 27 | typ: "application/didcomm-plain+json", 28 | type: "http://example.com/protocols/lets_do_lunch/1.0/proposal", 29 | from: "did:example:alice", 30 | to: ["did:example:bob"], 31 | created_time: 1516269022, 32 | expires_time: 1516385931, 33 | from_prior: 34 | "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpleGFtcGxlOmNoYXJsaWUja2V5LTEifQ.eyJpc3MiOiJkaWQ6ZXhhbXBsZTpjaGFybGllIiwic3ViIjoiZGlkOmV4YW1wbGU6YWxpY2UiLCJhdWQiOiIxMjMiLCJleHAiOjEyMzQsIm5iZiI6MTIzNDUsImlhdCI6MTIzNDU2LCJqdGkiOiJkZmcifQ.ir0tegXiGJIZIMagO5P853KwhzGTEw0OpFFAyarUV-nQrtbI_ELbxT9l7jPBoPve_-60ifGJ9v3ArmFjELFlDA", 35 | body: { messagespecificattribute: "and its value" }, 36 | }; 37 | 38 | export const MESSAGE_FROM_PRIOR = new Message(IMESSAGE_FROM_PRIOR); 39 | 40 | export const IFORWARD_MESSAGE = { 41 | id: "8404000a-1c6d-4c8c-8c60-e383128d9677", 42 | typ: "application/didcomm-plain+json", 43 | type: "https://didcomm.org/routing/2.0/forward", 44 | body: { 45 | next: "did:example:bob", 46 | }, 47 | attachments: [ 48 | { 49 | data: { 50 | json: { 51 | ciphertext: 52 | "ajYDBYyuuftb0f-pCj9iz7uhSJFK95F_WsXcXSKN2HrfPdojdRb9Ss_xI0zJnTC97yRmO9vmfyR8-MkQ_1gh-KyEHZe6UTM7JWpSWC9onReNLTOLaMoM09W8Fb45ZFbqaqZ1Kt3qvKIXEu2BwrZ2jLRu7r2Lo-cDJhDwzhHux27gd-j9Dhvtct3B2AMzXdu2J4fLqIdz9h0XkiI3PB4tLYsgY6KwDMtLyePDbb747bqViqWoBFgDLX2zgL3R9Okxt7RG4-1vqRHfURgcONofWMpFHEFq3WaplipogvuwouP3hJv3OMppBz2KTo1ULg3WWAdrac7laa2XQ6UE1PUo6Cq7IH7mdVoZwRc2v__swib6_WLTZMTW", 53 | iv: "hC-Frpywx0Pix6Lak-Rwlpw0IbG28rGo", 54 | protected: 55 | "eyJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLWVuY3J5cHRlZCtqc29uIiwiYWxnIjoiRUNESC1FUytBMjU2S1ciLCJlbmMiOiJYQzIwUCIsImFwdiI6Ik5jc3VBbnJSZlBLNjlBLXJrWjBMOVhXVUc0ak12TkMzWmc3NEJQejUzUEEiLCJlcGsiOnsiY3J2IjoiWDI1NTE5Iiwia3R5IjoiT0tQIiwieCI6Ikg0QURobjA0S1VnX1dXQWpiR0s3eTJ3QkQtTmtsbUhXa0lHUl9jeGtKMXcifX0", 56 | recipients: [ 57 | { 58 | encrypted_key: 59 | "Bjk-DOK_2omU_LN13TEGs3WBAwWaimaAQVvtIdE4mmCW83M8kOWKfw", 60 | header: { kid: "did:example:bob#key-x25519-1" }, 61 | }, 62 | { 63 | encrypted_key: 64 | "SuPR0JolzyGPeNiaj9EoD822TsHXRLJbkyQgOnF_MG-DfPdQ5y2Eeg", 65 | header: { kid: "did:example:bob#key-x25519-2" }, 66 | }, 67 | { 68 | encrypted_key: 69 | "6H5qA6Hic0L2B_lzg6q37VbkmHoi8d82seRxswtXp9c1FpTg8cG76w", 70 | header: { kid: "did:example:bob#key-x25519-3" }, 71 | }, 72 | ], 73 | tag: "j4VLGYCa70LhHyDDLUDzKw", 74 | }, 75 | }, 76 | }, 77 | ], 78 | }; 79 | 80 | export const FORWARD_MESSAGE = new Message(IFORWARD_MESSAGE); 81 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/plaintext.ts: -------------------------------------------------------------------------------- 1 | export const PLAINTEXT_MSG_SIMPLE = ` 2 | { 3 | "id": "1234567890", 4 | "typ": "application/didcomm-plain+json", 5 | "type": "http://example.com/protocols/lets_do_lunch/1.0/proposal", 6 | "from": "did:example:alice", 7 | "to": ["did:example:bob"], 8 | "created_time": 1516269022, 9 | "expires_time": 1516385931, 10 | "body": {"messagespecificattribute": "and its value"} 11 | } 12 | `; 13 | 14 | export const PLAINTEXT_MSG_MINIMAL = ` 15 | { 16 | "id": "1234567890", 17 | "typ": "application/didcomm-plain+json", 18 | "type": "http://example.com/protocols/lets_do_lunch/1.0/proposal", 19 | "body": {} 20 | } 21 | `; 22 | 23 | export const PLAINTEXT_FROM_PRIOR = ` 24 | { 25 | "id": "1234567890", 26 | "typ": "application/didcomm-plain+json", 27 | "type": "http://example.com/protocols/lets_do_lunch/1.0/proposal", 28 | "from": "did:example:alice", 29 | "to": ["did:example:bob"], 30 | "created_time": 1516269022, 31 | "expires_time": 1516385931, 32 | "from_prior": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpleGFtcGxlOmNoYXJsaWUja2V5LTEifQ.eyJpc3MiOiJkaWQ6ZXhhbXBsZTpjaGFybGllIiwic3ViIjoiZGlkOmV4YW1wbGU6YWxpY2UiLCJhdWQiOiIxMjMiLCJleHAiOjEyMzQsIm5iZiI6MTIzNDUsImlhdCI6MTIzNDU2LCJqdGkiOiJkZmcifQ.ir0tegXiGJIZIMagO5P853KwhzGTEw0OpFFAyarUV-nQrtbI_ELbxT9l7jPBoPve_-60ifGJ9v3ArmFjELFlDA", 33 | "body": {"messagespecificattribute": "and its value"} 34 | } 35 | `; 36 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/secrets/alice.ts: -------------------------------------------------------------------------------- 1 | import { Secret } from "didcomm"; 2 | 3 | export const ALICE_SECRETS: Secret[] = [ 4 | { 5 | id: "did:example:alice#key-1", 6 | type: "JsonWebKey2020", 7 | privateKeyJwk: { 8 | crv: "Ed25519", 9 | d: "pFRUKkyzx4kHdJtFSnlPA9WzqkDT1HWV0xZ5OYZd2SY", 10 | kty: "OKP", 11 | x: "G-boxFB6vOZBu-wXkm-9Lh79I8nf9Z50cILaOgKKGww", 12 | }, 13 | }, 14 | { 15 | id: "did:example:alice#key-2", 16 | type: "JsonWebKey2020", 17 | privateKeyJwk: { 18 | crv: "P-256", 19 | d: "7TCIdt1rhThFtWcEiLnk_COEjh1ZfQhM4bW2wz-dp4A", 20 | kty: "EC", 21 | x: "2syLh57B-dGpa0F8p1JrO6JU7UUSF6j7qL-vfk1eOoY", 22 | y: "BgsGtI7UPsObMRjdElxLOrgAO9JggNMjOcfzEPox18w", 23 | }, 24 | }, 25 | { 26 | id: "did:example:alice#key-3", 27 | type: "JsonWebKey2020", 28 | privateKeyJwk: { 29 | crv: "secp256k1", 30 | d: "N3Hm1LXA210YVGGsXw_GklMwcLu_bMgnzDese6YQIyA", 31 | kty: "EC", 32 | x: "aToW5EaTq5mlAf8C5ECYDSkqsJycrW-e1SQ6_GJcAOk", 33 | y: "JAGX94caA21WKreXwYUaOCYTBMrqaX4KWIlsQZTHWCk", 34 | }, 35 | }, 36 | { 37 | id: "did:example:alice#key-x25519-1", 38 | type: "JsonWebKey2020", 39 | privateKeyJwk: { 40 | crv: "X25519", 41 | d: "r-jK2cO3taR8LQnJB1_ikLBTAnOtShJOsHXRUWT-aZA", 42 | kty: "OKP", 43 | x: "avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs", 44 | }, 45 | }, 46 | { 47 | id: "did:example:alice#key-p256-1", 48 | type: "JsonWebKey2020", 49 | privateKeyJwk: { 50 | crv: "P-256", 51 | d: "sB0bYtpaXyp-h17dDpMx91N3Du1AdN4z1FUq02GbmLw", 52 | kty: "EC", 53 | x: "L0crjMN1g0Ih4sYAJ_nGoHUck2cloltUpUVQDhF2nHE", 54 | y: "SxYgE7CmEJYi7IDhgK5jI4ZiajO8jPRZDldVhqFpYoo", 55 | }, 56 | }, 57 | { 58 | id: "did:example:alice#key-p521-1", 59 | type: "JsonWebKey2020", 60 | privateKeyJwk: { 61 | crv: "P-521", 62 | d: "AQCQKE7rZpxPnX9RgjXxeywrAMp1fJsyFe4cir1gWj-8t8xWaM_E2qBkTTzyjbRBu-JPXHe_auT850iYmE34SkWi", 63 | kty: "EC", 64 | x: "AHBEVPRhAv-WHDEvxVM9S0px9WxxwHL641Pemgk9sDdxvli9VpKCBdra5gg_4kupBDhz__AlaBgKOC_15J2Byptz", 65 | y: "AciGcHJCD_yMikQvlmqpkBbVqqbg93mMVcgvXBYAQPP-u9AF7adybwZrNfHWCKAQwGF9ugd0Zhg7mLMEszIONFRk", 66 | }, 67 | }, 68 | ]; 69 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/secrets/bob.ts: -------------------------------------------------------------------------------- 1 | import { Secret } from "didcomm"; 2 | 3 | export const BOB_SECRET_KEY_AGREEMENT_KEY_X25519_1: Secret = { 4 | id: "did:example:bob#key-x25519-1", 5 | type: "JsonWebKey2020", 6 | privateKeyJwk: { 7 | crv: "X25519", 8 | d: "b9NnuOCB0hm7YGNvaE9DMhwH_wjZA1-gWD6dA0JWdL0", 9 | kty: "OKP", 10 | x: "GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E", 11 | }, 12 | }; 13 | export const BOB_SECRET_KEY_AGREEMENT_KEY_X25519_2: Secret = { 14 | id: "did:example:bob#key-x25519-2", 15 | type: "JsonWebKey2020", 16 | privateKeyJwk: { 17 | crv: "X25519", 18 | d: "p-vteoF1gopny1HXywt76xz_uC83UUmrgszsI-ThBKk", 19 | kty: "OKP", 20 | x: "UT9S3F5ep16KSNBBShU2wh3qSfqYjlasZimn0mB8_VM", 21 | }, 22 | }; 23 | export const BOB_SECRET_KEY_AGREEMENT_KEY_X25519_3: Secret = { 24 | id: "did:example:bob#key-x25519-3", 25 | type: "JsonWebKey2020", 26 | privateKeyJwk: { 27 | crv: "X25519", 28 | d: "f9WJeuQXEItkGM8shN4dqFr5fLQLBasHnWZ-8dPaSo0", 29 | kty: "OKP", 30 | x: "82k2BTUiywKv49fKLZa-WwDi8RBf0tB0M8bvSAUQ3yY", 31 | }, 32 | }; 33 | export const BOB_SECRET_KEY_AGREEMENT_KEY_P256_1: Secret = { 34 | id: "did:example:bob#key-p256-1", 35 | type: "JsonWebKey2020", 36 | privateKeyJwk: { 37 | crv: "P-256", 38 | d: "PgwHnlXxt8pwR6OCTUwwWx-P51BiLkFZyqHzquKddXQ", 39 | kty: "EC", 40 | x: "FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo", 41 | y: "6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY", 42 | }, 43 | }; 44 | export const BOB_SECRET_KEY_AGREEMENT_KEY_P256_2: Secret = { 45 | id: "did:example:bob#key-p256-2", 46 | type: "JsonWebKey2020", 47 | privateKeyJwk: { 48 | crv: "P-256", 49 | d: "agKz7HS8mIwqO40Q2dwm_Zi70IdYFtonN5sZecQoxYU", 50 | kty: "EC", 51 | x: "n0yBsGrwGZup9ywKhzD4KoORGicilzIUyfcXb1CSwe0", 52 | y: "ov0buZJ8GHzV128jmCw1CaFbajZoFFmiJDbMrceCXIw", 53 | }, 54 | }; 55 | export const BOB_SECRET_KEY_AGREEMENT_KEY_P384_1: Secret = { 56 | id: "did:example:bob#key-p384-1", 57 | type: "JsonWebKey2020", 58 | privateKeyJwk: { 59 | crv: "P-384", 60 | d: "ajqcWbYA0UDBKfAhkSkeiVjMMt8l-5rcknvEv9t_Os6M8s-HisdywvNCX4CGd_xY", 61 | kty: "EC", 62 | x: "MvnE_OwKoTcJVfHyTX-DLSRhhNwlu5LNoQ5UWD9Jmgtdxp_kpjsMuTTBnxg5RF_Y", 63 | y: "X_3HJBcKFQEG35PZbEOBn8u9_z8V1F9V1Kv-Vh0aSzmH-y9aOuDJUE3D4Hvmi5l7", 64 | }, 65 | }; 66 | export const BOB_SECRET_KEY_AGREEMENT_KEY_P384_2: Secret = { 67 | id: "did:example:bob#key-p384-2", 68 | type: "JsonWebKey2020", 69 | privateKeyJwk: { 70 | crv: "P-384", 71 | d: "OiwhRotK188BtbQy0XBO8PljSKYI6CCD-nE_ZUzK7o81tk3imDOuQ-jrSWaIkI-T", 72 | kty: "EC", 73 | x: "2x3HOTvR8e-Tu6U4UqMd1wUWsNXMD0RgIunZTMcZsS-zWOwDgsrhYVHmv3k_DjV3", 74 | y: "W9LLaBjlWYcXUxOf6ECSfcXKaC3-K9z4hCoP0PS87Q_4ExMgIwxVCXUEB6nf0GDd", 75 | }, 76 | }; 77 | export const BOB_SECRET_KEY_AGREEMENT_KEY_P521_1: Secret = { 78 | id: "did:example:bob#key-p521-1", 79 | type: "JsonWebKey2020", 80 | privateKeyJwk: { 81 | crv: "P-521", 82 | d: "AV5ocjvy7PkPgNrSuvCxtG70NMj6iTabvvjSLbsdd8OdI9HlXYlFR7RdBbgLUTruvaIRhjEAE9gNTH6rWUIdfuj6", 83 | kty: "EC", 84 | x: "Af9O5THFENlqQbh2Ehipt1Yf4gAd9RCa3QzPktfcgUIFADMc4kAaYVViTaDOuvVS2vMS1KZe0D5kXedSXPQ3QbHi", 85 | y: "ATZVigRQ7UdGsQ9j-omyff6JIeeUv3CBWYsZ0l6x3C_SYqhqVV7dEG-TafCCNiIxs8qeUiXQ8cHWVclqkH4Lo1qH", 86 | }, 87 | }; 88 | export const BOB_SECRET_KEY_AGREEMENT_KEY_P521_2: Secret = { 89 | id: "did:example:bob#key-p521-2", 90 | type: "JsonWebKey2020", 91 | privateKeyJwk: { 92 | crv: "P-521", 93 | d: "ABixMEZHsyT7SRw-lY5HxdNOofTZLlwBHwPEJ3spEMC2sWN1RZQylZuvoyOBGJnPxg4-H_iVhNWf_OtgYODrYhCk", 94 | kty: "EC", 95 | x: "ATp_WxCfIK_SriBoStmA0QrJc2pUR1djpen0VdpmogtnKxJbitiPq-HJXYXDKriXfVnkrl2i952MsIOMfD2j0Ots", 96 | y: "AEJipR0Dc-aBZYDqN51SKHYSWs9hM58SmRY1MxgXANgZrPaq1EeGMGOjkbLMEJtBThdjXhkS5VlXMkF0cYhZELiH", 97 | }, 98 | }; 99 | 100 | export const BOB_SECRETS: Secret[] = [ 101 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_1, 102 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_2, 103 | BOB_SECRET_KEY_AGREEMENT_KEY_X25519_3, 104 | BOB_SECRET_KEY_AGREEMENT_KEY_P256_1, 105 | BOB_SECRET_KEY_AGREEMENT_KEY_P256_2, 106 | BOB_SECRET_KEY_AGREEMENT_KEY_P521_1, 107 | BOB_SECRET_KEY_AGREEMENT_KEY_P521_2, 108 | BOB_SECRET_KEY_AGREEMENT_KEY_P384_1, 109 | BOB_SECRET_KEY_AGREEMENT_KEY_P384_2, 110 | ]; 111 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/secrets/charlie.ts: -------------------------------------------------------------------------------- 1 | import { Secret } from "didcomm"; 2 | 3 | export const CHARLIE_SECRET_KEY_AGREEMENT_KEY_X25519: Secret = { 4 | id: "did:example:charlie#key-x25519-1", 5 | type: "JsonWebKey2020", 6 | privateKeyJwk: { 7 | crv: "X25519", 8 | d: "Z-BsgFe-eCvhuZlCBX5BV2XiDE2M92gkaORCe68YdZI", 9 | kty: "OKP", 10 | x: "nTiVFj7DChMsETDdxd5dIzLAJbSQ4j4UG6ZU1ogLNlw", 11 | }, 12 | }; 13 | 14 | export const CHARLIE_SECRET_AUTH_KEY_ED25519: Secret = { 15 | id: "did:example:charlie#key-1", 16 | type: "JsonWebKey2020", 17 | privateKeyJwk: { 18 | crv: "Ed25519", 19 | d: "T2azVap7CYD_kB8ilbnFYqwwYb5N-GcD6yjGEvquZXg", 20 | kty: "OKP", 21 | x: "VDXDwuGKVq91zxU6q7__jLDUq8_C5cuxECgd-1feFTE", 22 | }, 23 | }; 24 | 25 | export const CHARLIE_SECRETS: Secret[] = [ 26 | CHARLIE_SECRET_KEY_AGREEMENT_KEY_X25519, 27 | CHARLIE_SECRET_AUTH_KEY_ED25519, 28 | ]; 29 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/secrets/charlie_rotated_to_alice.ts: -------------------------------------------------------------------------------- 1 | import { Secret } from "didcomm"; 2 | 3 | export const CHARLIE_ROTATED_TO_ALICE_SECRETS: Secret[] = [ 4 | { 5 | id: "did:example:charlie#key-x25519-1", 6 | type: "JsonWebKey2020", 7 | privateKeyJwk: { 8 | crv: "X25519", 9 | d: "Z-BsgFe-eCvhuZlCBX5BV2XiDE2M92gkaORCe68YdZI", 10 | kty: "OKP", 11 | x: "nTiVFj7DChMsETDdxd5dIzLAJbSQ4j4UG6ZU1ogLNlw", 12 | }, 13 | }, 14 | { 15 | id: "did:example:charlie#key-1", 16 | type: "JsonWebKey2020", 17 | privateKeyJwk: { 18 | crv: "Ed25519", 19 | d: "T2azVap7CYD_kB8ilbnFYqwwYb5N-GcD6yjGEvquZXg", 20 | kty: "OKP", 21 | x: "VDXDwuGKVq91zxU6q7__jLDUq8_C5cuxECgd-1feFTE", 22 | }, 23 | }, 24 | { 25 | id: "did:example:alice#key-1", 26 | type: "JsonWebKey2020", 27 | privateKeyJwk: { 28 | crv: "Ed25519", 29 | d: "pFRUKkyzx4kHdJtFSnlPA9WzqkDT1HWV0xZ5OYZd2SY", 30 | kty: "OKP", 31 | x: "G-boxFB6vOZBu-wXkm-9Lh79I8nf9Z50cILaOgKKGww", 32 | }, 33 | }, 34 | { 35 | id: "did:example:alice#key-2", 36 | type: "JsonWebKey2020", 37 | privateKeyJwk: { 38 | crv: "P-256", 39 | d: "7TCIdt1rhThFtWcEiLnk_COEjh1ZfQhM4bW2wz-dp4A", 40 | kty: "EC", 41 | x: "2syLh57B-dGpa0F8p1JrO6JU7UUSF6j7qL-vfk1eOoY", 42 | y: "BgsGtI7UPsObMRjdElxLOrgAO9JggNMjOcfzEPox18w", 43 | }, 44 | }, 45 | { 46 | id: "did:example:alice#key-3", 47 | type: "JsonWebKey2020", 48 | privateKeyJwk: { 49 | crv: "secp256k1", 50 | d: "N3Hm1LXA210YVGGsXw_GklMwcLu_bMgnzDese6YQIyA", 51 | kty: "EC", 52 | x: "aToW5EaTq5mlAf8C5ECYDSkqsJycrW-e1SQ6_GJcAOk", 53 | y: "JAGX94caA21WKreXwYUaOCYTBMrqaX4KWIlsQZTHWCk", 54 | }, 55 | }, 56 | { 57 | id: "did:example:alice#key-x25519-1", 58 | type: "JsonWebKey2020", 59 | privateKeyJwk: { 60 | crv: "X25519", 61 | d: "r-jK2cO3taR8LQnJB1_ikLBTAnOtShJOsHXRUWT-aZA", 62 | kty: "OKP", 63 | x: "avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs", 64 | }, 65 | }, 66 | { 67 | id: "did:example:alice#key-p256-1", 68 | type: "JsonWebKey2020", 69 | privateKeyJwk: { 70 | crv: "P-256", 71 | d: "sB0bYtpaXyp-h17dDpMx91N3Du1AdN4z1FUq02GbmLw", 72 | kty: "EC", 73 | x: "L0crjMN1g0Ih4sYAJ_nGoHUck2cloltUpUVQDhF2nHE", 74 | y: "SxYgE7CmEJYi7IDhgK5jI4ZiajO8jPRZDldVhqFpYoo", 75 | }, 76 | }, 77 | { 78 | id: "did:example:alice#key-p521-1", 79 | type: "JsonWebKey2020", 80 | privateKeyJwk: { 81 | crv: "P-521", 82 | d: "AQCQKE7rZpxPnX9RgjXxeywrAMp1fJsyFe4cir1gWj-8t8xWaM_E2qBkTTzyjbRBu-JPXHe_auT850iYmE34SkWi", 83 | kty: "EC", 84 | x: "AHBEVPRhAv-WHDEvxVM9S0px9WxxwHL641Pemgk9sDdxvli9VpKCBdra5gg_4kupBDhz__AlaBgKOC_15J2Byptz", 85 | y: "AciGcHJCD_yMikQvlmqpkBbVqqbg93mMVcgvXBYAQPP-u9AF7adybwZrNfHWCKAQwGF9ugd0Zhg7mLMEszIONFRk", 86 | }, 87 | }, 88 | ]; 89 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/secrets/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./alice"; 2 | export * from "./bob"; 3 | export * from "./charlie"; 4 | export * from "./charlie_rotated_to_alice"; 5 | -------------------------------------------------------------------------------- /wasm/tests-js/src/test-vectors/secrets_resolver.ts: -------------------------------------------------------------------------------- 1 | import { Secret, SecretsResolver } from "didcomm"; 2 | 3 | export class ExampleSecretsResolver implements SecretsResolver { 4 | knownSecrets: Secret[]; 5 | 6 | constructor(knownSecrets: Secret[]) { 7 | this.knownSecrets = knownSecrets; 8 | } 9 | 10 | async get_secret(secretId: string): Promise { 11 | const res = this.knownSecrets.find((secret) => secret.id === secretId); 12 | return res ? res : null; 13 | } 14 | 15 | async find_secrets(secretIds: string[]): Promise { 16 | return secretIds.filter((id) => 17 | this.knownSecrets.find((secret) => secret.id === id) 18 | ); 19 | } 20 | } 21 | 22 | type MockGet = (secretId: string) => Secret | null; 23 | type MockFind = (secretIds: string[]) => string[]; 24 | 25 | /* tslint:disable:max-classes-per-file */ 26 | export class MockSecretsResolver implements SecretsResolver { 27 | getHandlers: MockGet[]; 28 | findHandlers: MockFind[]; 29 | fallback: SecretsResolver; 30 | 31 | constructor( 32 | getHandlers: MockGet[], 33 | findHandlers: MockFind[], 34 | fallback: SecretsResolver 35 | ) { 36 | this.getHandlers = getHandlers; 37 | this.findHandlers = findHandlers; 38 | this.fallback = fallback; 39 | } 40 | 41 | async get_secret(secretId: string): Promise { 42 | const handler = this.getHandlers.pop(); 43 | 44 | return handler 45 | ? handler(secretId) 46 | : await this.fallback.get_secret(secretId); 47 | } 48 | 49 | async find_secrets(secretIds: string[]): Promise { 50 | const handler = this.findHandlers.pop(); 51 | 52 | return handler 53 | ? handler(secretIds) 54 | : await this.fallback.find_secrets(secretIds); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /wasm/tests-js/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:recommended"], 4 | "jsRules": {}, 5 | "rules": {}, 6 | "rulesDirectory": [] 7 | } 8 | -------------------------------------------------------------------------------- /wrappers/swift/README.md: -------------------------------------------------------------------------------- 1 | ## Creating .a file for iOS. 2 | 3 | Opens [Cargo.toml](./../../uniffi/Cargo.toml) file to change the `create-type`: 4 | ``` 5 | [lib] 6 | crate-type = [ 7 | 'lib', 8 | 'staticlib' 9 | ] 10 | ``` 11 | 12 | Go to UNIFFI folder [here](./../../uniffi/) and run: 13 | ```bash 14 | cargo build --release --target aarch64-apple-ios 15 | cargo build --release --target x86_64-apple-ios 16 | 17 | lipo -create target/aarch64-apple-ios/release/libdidcomm_uniffi.a target/x86_64-apple-ios/release/libdidcomm_uniffi.a -output target/libDidcommiOS.a 18 | ``` 19 | We created a libDidcommiOS.a that runs both for iOS Simulator (arm64) and iOS Device (aarch64). 20 | 21 | See the available architectures: 22 | ``` 23 | rustup target list 24 | ``` 25 | 26 | Verify the architecture: 27 | ``` 28 | lipo -info target/libDidcommiOS.a 29 | ``` 30 | Output: Architectures in the fat file: target/libDidcommiOS.a are: x86_64 arm64 31 | 32 | ### Also reed: 33 | 34 | [Dealing with Rust to build PactSwiftMockServer](https://gist.github.com/surpher/bbf88e191e9d1f01ab2e2bbb85f9b528) 35 | [Cross-compiling for Xcode](https://github.com/thombles/dw2019rust/blob/master/modules/02%20-%20Cross-compiling%20for%20Xcode.md) 36 | 37 | -------------------------------------------------------------------------------- /wrappers/swift/didcomm.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sicpa-dlab/didcomm-rust/4388350def84b6d7f6b65cf4a451607200035d8d/wrappers/swift/didcomm.swiftdoc -------------------------------------------------------------------------------- /wrappers/swift/didcomm.swiftsourceinfo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sicpa-dlab/didcomm-rust/4388350def84b6d7f6b65cf4a451607200035d8d/wrappers/swift/didcomm.swiftsourceinfo -------------------------------------------------------------------------------- /wrappers/swift/didcomm/didcomm.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sicpa-dlab/didcomm-rust/4388350def84b6d7f6b65cf4a451607200035d8d/wrappers/swift/didcomm/didcomm.swiftmodule -------------------------------------------------------------------------------- /wrappers/swift/didcomm/didcommFFI.modulemap: -------------------------------------------------------------------------------- 1 | // This file was autogenerated by some hot garbage in the `uniffi` crate. 2 | // Trust me, you don't want to mess with it! 3 | module didcommFFI { 4 | header "didcommFFI.h" 5 | export * 6 | } -------------------------------------------------------------------------------- /wrappers/swift/didcomm/libdidcomm.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sicpa-dlab/didcomm-rust/4388350def84b6d7f6b65cf4a451607200035d8d/wrappers/swift/didcomm/libdidcomm.dylib -------------------------------------------------------------------------------- /wrappers/swift/examples/DidcommExampleiOS/DidcommExampleiOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @main 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | 6 | var window: UIWindow? 7 | 8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 9 | window = UIWindow(frame: UIScreen.main.bounds) 10 | let viewController = ViewController() 11 | window?.backgroundColor = .white 12 | window?.makeKeyAndVisible() 13 | window?.rootViewController = viewController 14 | return true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /wrappers/swift/examples/DidcommExampleiOS/DidcommExampleiOS/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /wrappers/swift/examples/DidcommExampleiOS/DidcommExampleiOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /wrappers/swift/examples/DidcommExampleiOS/DidcommExampleiOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /wrappers/swift/examples/DidcommExampleiOS/DidcommExampleiOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /wrappers/swift/examples/DidcommExampleiOS/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '13.0' 3 | source 'git@github.com:sicpa-dlab/didcomm-rust.git' 4 | 5 | target 'DidcommExampleiOS' do 6 | # Comment the next line if you don't want to use dynamic frameworks 7 | use_frameworks! 8 | pod 'DidcommSDK', '0.3.1' 9 | 10 | end 11 | -------------------------------------------------------------------------------- /wrappers/swift/examples/DidcommExampleiOS/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - DidcommSDK (0.3.1) 3 | 4 | DEPENDENCIES: 5 | - DidcommSDK (= 0.3.1) 6 | 7 | SPEC REPOS: 8 | "git@github.com:rodrigofranzoi/didcomm-rust.git": 9 | - DidcommSDK 10 | 11 | SPEC CHECKSUMS: 12 | DidcommSDK: 99be16fe25310f791171bbccac576419272e217a 13 | 14 | PODFILE CHECKSUM: db7d8bde5395a5700b4977ece27e4bd4af0b4a89 15 | 16 | COCOAPODS: 1.11.3 17 | -------------------------------------------------------------------------------- /wrappers/swift/examples/README.md: -------------------------------------------------------------------------------- 1 | ## Example for iOS 2 | 3 | This is a short description of how to run the example of DidcommSDK. You can find the source code [here](./DidcommExampleiOS). 4 | 5 | Make sure you have pods installed: 6 | 7 | Run on [DidcommExampleiOS](./DidcommExampleiOS) folder. 8 | 9 | ```bash 10 | pod install 11 | ``` 12 | 13 | Then open `DidcommExampleiOS.xcworkspace` created installing pods. 14 | 15 | Now you can run DidcommExampleiOS for any iOS device. See Xcode logs to see the SDK working. -------------------------------------------------------------------------------- /wrappers/swift/examples/base.swift: -------------------------------------------------------------------------------- 1 | // TBD --------------------------------------------------------------------------------