Skip to content

Commit c1fa414

Browse files
authored
Forward support in WASM (#57)
Forward support in JS
1 parent 6af22be commit c1fa414

File tree

11 files changed

+277
-14
lines changed

11 files changed

+277
-14
lines changed

src/protocols/routing/forward.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
use serde::Serialize;
12
use serde_json::Value;
23

34
use crate::Message;
45

6+
#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
57
pub struct ParsedForward<'a> {
68
pub msg: &'a Message,
79
pub next: String,

wasm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ default = ['console_error_panic_hook']
2121
async-trait = '0.1'
2222
wasm-bindgen-futures = '0.4'
2323
js-sys = '0.3'
24+
serde_json = '1.0'
2425

2526
[dependencies.didcomm]
2627
path = '..'

wasm/demo/src/advanced-params.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ async function main() {
3636
didResolver,
3737
secretsResolver,
3838
{
39-
forward: false,
39+
forward: false, // TODO: should be true by default
4040
protect_sender: true,
4141
enc_alg_anon: "A256cbcHs512EcdhEsA256kw",
4242
messaging_service: "did:example:bob#didcomm-1",

wasm/demo/src/attachments.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ async function main() {
4646
didResolver,
4747
secretsResolver,
4848
{
49-
forward: false,
49+
forward: false, // TODO: should be true by default
5050
}
5151
);
5252

wasm/demo/src/main.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,7 @@ import {
77
BOB_SECRETS,
88
} from "./test-vectors";
99

10-
import {
11-
Message,
12-
DIDDoc,
13-
DIDResolver,
14-
Secret,
15-
SecretsResolver,
16-
} from "didcomm";
10+
import { Message, DIDDoc, DIDResolver, Secret, SecretsResolver } from "didcomm";
1711
import {
1812
CHARLIE_DID,
1913
CHARLIE_DID_DOC,
@@ -95,7 +89,7 @@ async function nonRepudiableEncryption() {
9589
didResolver,
9690
secretsResolver,
9791
{
98-
forward: false,
92+
forward: false, // TODO: should be true by default
9993
}
10094
);
10195

@@ -147,7 +141,7 @@ async function multiRecipient() {
147141
didResolver,
148142
secretsResolver,
149143
{
150-
forward: false,
144+
forward: false, // TODO: should be true by default
151145
}
152146
);
153147

@@ -165,7 +159,7 @@ async function multiRecipient() {
165159
didResolver,
166160
secretsResolver,
167161
{
168-
forward: false,
162+
forward: false, // TODO: should be true by default
169163
}
170164
);
171165

@@ -236,7 +230,7 @@ async function repudiableAuthentcatedEncryption() {
236230
didResolver,
237231
secretsResolver,
238232
{
239-
forward: false,
233+
forward: false, // TODO: should be true by default
240234
}
241235
);
242236

@@ -284,7 +278,7 @@ async function repudiableNonAuthentcatedEncryption() {
284278
didResolver,
285279
secretsResolver,
286280
{
287-
forward: false,
281+
forward: false, // TODO: should be true by default
288282
}
289283
);
290284

@@ -388,3 +382,5 @@ async function plaintext() {
388382
}
389383

390384
main().catch((e) => console.log(e));
385+
386+
// TODO: add examples for Forward (routing) and Mediators

wasm/src/message/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod from_prior;
22
mod pack_encrypted;
33
mod pack_plaintext;
44
mod pack_signed;
5+
mod protocols;
56
mod unpack;
67

78
use didcomm::error::{ErrorKind, ResultExt};

wasm/src/message/protocols/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod routing;
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
use std::{collections::HashMap, rc::Rc};
2+
3+
use crate::{did::JsDIDResolver, error::JsResult, DIDResolver};
4+
use crate::{utils::set_panic_hook, Message};
5+
use didcomm::{
6+
algorithms::AnonCryptAlg,
7+
error::{ErrorKind, ResultExt},
8+
protocols::routing::{try_parse_forward, wrap_in_forward},
9+
};
10+
use js_sys::Promise;
11+
use serde_json::Value;
12+
use wasm_bindgen::prelude::*;
13+
use wasm_bindgen_futures::future_to_promise;
14+
15+
#[wasm_bindgen]
16+
pub struct ParsedForward(pub(crate) Rc<didcomm::protocols::routing::ParsedForward<'static>>);
17+
18+
#[wasm_bindgen]
19+
impl ParsedForward {
20+
#[wasm_bindgen(skip_typescript)]
21+
pub fn as_value(&self) -> Result<JsValue, JsValue> {
22+
let msg = JsValue::from_serde(&*self.0)
23+
.kind(ErrorKind::Malformed, "Unable serialize ParsedForward")
24+
.as_js()?;
25+
26+
Ok(msg)
27+
}
28+
}
29+
30+
#[wasm_bindgen]
31+
impl Message {
32+
#[wasm_bindgen(skip_typescript)]
33+
pub fn wrap_in_forward(
34+
msg: String,
35+
headers: JsValue,
36+
to: String,
37+
routing_keys: JsValue,
38+
enc_alg_anon: JsValue,
39+
did_resolver: DIDResolver,
40+
) -> Promise {
41+
// TODO: Better place?
42+
set_panic_hook();
43+
44+
let did_resolver = JsDIDResolver(did_resolver);
45+
future_to_promise(async move {
46+
let headers: HashMap<String, Value> = headers
47+
.into_serde()
48+
.kind(ErrorKind::Malformed, "headers param is malformed")
49+
.as_js()?;
50+
51+
let routing_keys: Vec<String> = routing_keys
52+
.into_serde()
53+
.kind(ErrorKind::Malformed, "routing_keys param is malformed")
54+
.as_js()?;
55+
56+
let enc_alg_anon: AnonCryptAlg = enc_alg_anon
57+
.into_serde()
58+
.kind(ErrorKind::Malformed, "enc_alg_anon param is malformed")
59+
.as_js()?;
60+
61+
let res = wrap_in_forward(
62+
&msg,
63+
Some(&headers),
64+
&to,
65+
&routing_keys,
66+
&enc_alg_anon,
67+
&did_resolver,
68+
)
69+
.await
70+
.as_js()?;
71+
72+
Ok(res.into())
73+
})
74+
}
75+
76+
#[wasm_bindgen(skip_typescript)]
77+
pub fn try_parse_forward(&self) -> Result<JsValue, JsValue> {
78+
let msg = self.0.clone();
79+
let parsed_message = try_parse_forward(&msg);
80+
Ok(JsValue::from_serde(&parsed_message)
81+
.kind(
82+
ErrorKind::Malformed,
83+
"Unable serialize parsed forward message",
84+
)
85+
.as_js()?)
86+
}
87+
}
88+
89+
#[wasm_bindgen(typescript_custom_section)]
90+
const PARSED_FORWARD_AS_VALUE_TS: &'static str = r#"
91+
interface ParsedForward {
92+
as_value(): IParsedForward;
93+
}
94+
"#;
95+
96+
#[wasm_bindgen]
97+
extern "C" {
98+
#[wasm_bindgen(typescript_type = "IParsedForward")]
99+
pub type IParsedForward;
100+
}
101+
102+
#[wasm_bindgen(typescript_custom_section)]
103+
const IPARSED_FORWARD_TS: &'static str = r#"
104+
type IParsedForward = {
105+
msg: Message,
106+
next: string,
107+
forwarded_msg: any
108+
}
109+
"#;
110+
111+
#[wasm_bindgen(typescript_custom_section)]
112+
const MESSAGE_WRAP_IN_FORWARD_TS: &'static str = r#"
113+
export namespace Message {
114+
/**
115+
* Resolves recipient DID DOC Service and Builds Forward envelops if needed.
116+
*
117+
* Wraps the given packed DIDComm message in Forward messages for every routing key.
118+
*
119+
* @param msg the message to be wrapped in Forward messages
120+
* @param headers optional headers for Forward message
121+
* @param to recipient's DID (DID URL)
122+
* @param routing_keys list of routing keys
123+
* @param enc_alg_anon The encryption algorithm to be used for anonymous encryption (anon_crypt)
124+
* @param did_resolver instance of `DIDResolver` to resolve DIDs.
125+
*
126+
* @returns a top-level packed Forward message as JSON string
127+
*
128+
* @throws DIDCommDIDNotResolved
129+
* @throws DIDCommDIDUrlNotFound
130+
* @throws DIDCommIoError
131+
* @throws DIDCommInvalidState
132+
* @throws DIDCommIllegalArgument
133+
*/
134+
function wrap_in_forward(
135+
msg: string,
136+
headers: Record<string, string>,
137+
to: string,
138+
routing_keys: Array<string>,
139+
enc_alg_anon: string,
140+
did_resolver: DIDResolver,
141+
): Promise<string>;
142+
}
143+
"#;
144+
145+
#[wasm_bindgen(typescript_custom_section)]
146+
const MESSAGE_TRY_PARSE_FORWARD_TS: &'static str = r#"
147+
interface Message {
148+
/**
149+
* Tries to parse the Message to a Forward message
150+
*
151+
* @returns a parsed message or null
152+
*/
153+
try_parse_forward(): ParsedForward;
154+
}
155+
"#;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
});
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
);

wasm/tests-js/src/test-vectors/message.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,45 @@ export const IMESSAGE_FROM_PRIOR = {
3636
};
3737

3838
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);

0 commit comments

Comments
 (0)