mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-19 14:19:06 -04:00
feat(crypto-js): Request types have fields extracted from their “body” directly
feat(crypto-js): Request types have fields extracted from their “body” directly
This commit is contained in:
@@ -130,7 +130,7 @@ impl UserIdentity {
|
||||
}
|
||||
|
||||
/// Create a `VerificationRequest` object after the verification
|
||||
/// request content has been sent out. }
|
||||
/// request content has been sent out.
|
||||
#[wasm_bindgen(js_name = "requestVerification")]
|
||||
pub fn request_verification(
|
||||
&self,
|
||||
|
||||
@@ -638,8 +638,15 @@ impl OlmMachine {
|
||||
/// This method can be used to pass verification events that are happening
|
||||
/// in rooms to the `OlmMachine`. The event should be in the decrypted form.
|
||||
#[wasm_bindgen(js_name = "receiveVerificationEvent")]
|
||||
pub fn receive_verification_event(&self, event: &str) -> Result<Promise, JsError> {
|
||||
let event: ruma::events::AnyMessageLikeEvent = serde_json::from_str(event)?;
|
||||
pub fn receive_verification_event(
|
||||
&self,
|
||||
event: &str,
|
||||
room_id: &identifiers::RoomId,
|
||||
) -> Result<Promise, JsError> {
|
||||
let room_id = room_id.inner.clone();
|
||||
let event: ruma::events::AnySyncMessageLikeEvent = serde_json::from_str(event)?;
|
||||
let event = event.into_full_event(room_id);
|
||||
|
||||
let me = self.inner.clone();
|
||||
|
||||
Ok(future_to_promise(async move {
|
||||
|
||||
@@ -11,10 +11,13 @@ use matrix_sdk_crypto::{
|
||||
},
|
||||
OutgoingRequests,
|
||||
};
|
||||
use ruma::api::client::keys::{
|
||||
claim_keys::v3::Request as OriginalKeysClaimRequest,
|
||||
upload_keys::v3::Request as OriginalKeysUploadRequest,
|
||||
upload_signatures::v3::Request as OriginalSignatureUploadRequest,
|
||||
use ruma::{
|
||||
api::client::keys::{
|
||||
claim_keys::v3::Request as OriginalKeysClaimRequest,
|
||||
upload_keys::v3::Request as OriginalKeysUploadRequest,
|
||||
upload_signatures::v3::Request as OriginalSignatureUploadRequest,
|
||||
},
|
||||
events::EventContent,
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
@@ -33,11 +36,10 @@ pub struct KeysUploadRequest {
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub id: Option<JsString>,
|
||||
|
||||
/// A JSON-encoded object of form:
|
||||
/// A JSON-encoded string containing the rest of the payload: `device_keys`,
|
||||
/// `one_time_keys`, `fallback_keys`.
|
||||
///
|
||||
/// ```json
|
||||
/// {"device_keys": …, "one_time_keys": …, "fallback_keys": …}
|
||||
/// ```
|
||||
/// It represents the body of the HTTP request.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub body: JsString,
|
||||
}
|
||||
@@ -70,11 +72,10 @@ pub struct KeysQueryRequest {
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub id: Option<JsString>,
|
||||
|
||||
/// A JSON-encoded object of form:
|
||||
/// A JSON-encoded string containing the rest of the payload: `timeout`,
|
||||
/// `device_keys`, `token`.
|
||||
///
|
||||
/// ```json
|
||||
/// {"timeout": …, "device_keys": …, "token": …}
|
||||
/// ```
|
||||
/// It represents the body of the HTTP request.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub body: JsString,
|
||||
}
|
||||
@@ -108,11 +109,10 @@ pub struct KeysClaimRequest {
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub id: Option<JsString>,
|
||||
|
||||
/// A JSON-encoded object of form:
|
||||
/// A JSON-encoded string containing the rest of the payload: `timeout`,
|
||||
/// `one_time_keys`.
|
||||
///
|
||||
/// ```json
|
||||
/// {"timeout": …, "one_time_keys": …}
|
||||
/// ```
|
||||
/// It represents the body of the HTTP request.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub body: JsString,
|
||||
}
|
||||
@@ -145,11 +145,18 @@ pub struct ToDeviceRequest {
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub id: Option<JsString>,
|
||||
|
||||
/// A JSON-encoded object of form:
|
||||
/// A string representing the type of event being sent to each devices.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub event_type: JsString,
|
||||
|
||||
/// A string representing a request identifier unique to the access token
|
||||
/// used to send the request.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub txn_id: JsString,
|
||||
|
||||
/// A JSON-encoded string containing the rest of the payload: `messages`.
|
||||
///
|
||||
/// ```json
|
||||
/// {"event_type": …, "txn_id": …, "messages": …}
|
||||
/// ```
|
||||
/// It represents the body of the HTTP request.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub body: JsString,
|
||||
}
|
||||
@@ -158,8 +165,13 @@ pub struct ToDeviceRequest {
|
||||
impl ToDeviceRequest {
|
||||
/// Create a new `ToDeviceRequest`.
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(id: JsString, body: JsString) -> ToDeviceRequest {
|
||||
Self { id: Some(id), body }
|
||||
pub fn new(
|
||||
id: JsString,
|
||||
event_type: JsString,
|
||||
txn_id: JsString,
|
||||
body: JsString,
|
||||
) -> ToDeviceRequest {
|
||||
Self { id: Some(id), event_type, txn_id, body }
|
||||
}
|
||||
|
||||
/// Get its request type.
|
||||
@@ -182,11 +194,9 @@ pub struct SignatureUploadRequest {
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub id: Option<JsString>,
|
||||
|
||||
/// A JSON-encoded object of form:
|
||||
/// A JSON-encoded string containing the rest of the payload: `signed_keys`.
|
||||
///
|
||||
/// ```json
|
||||
/// {"signed_keys": …, "txn_id": …, "messages": …}
|
||||
/// ```
|
||||
/// It represents the body of the HTTP request.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub body: JsString,
|
||||
}
|
||||
@@ -217,21 +227,39 @@ pub struct RoomMessageRequest {
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub id: Option<JsString>,
|
||||
|
||||
/// A JSON-encoded object of form:
|
||||
///
|
||||
/// ```json
|
||||
/// {"room_id": …, "txn_id": …, "content": …}
|
||||
/// ```
|
||||
/// A string representing the room to send the event to.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub body: JsString,
|
||||
pub room_id: JsString,
|
||||
|
||||
/// A string representing the transaction ID for this event.
|
||||
///
|
||||
/// Clients should generate an ID unique across requests with the same
|
||||
/// access token; it will be used by the server to ensure idempotency of
|
||||
/// requests.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub txn_id: JsString,
|
||||
|
||||
/// A string representing the type of even from the message's content.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub event_type: JsString,
|
||||
|
||||
/// A JSON-encoded string containing the message's body.
|
||||
#[wasm_bindgen(readonly, js_name = "body")]
|
||||
pub content: JsString,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RoomMessageRequest {
|
||||
/// Create a new `RoomMessageRequest`.
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(id: JsString, body: JsString) -> RoomMessageRequest {
|
||||
Self { id: Some(id), body }
|
||||
pub fn new(
|
||||
id: JsString,
|
||||
room_id: JsString,
|
||||
txn_id: JsString,
|
||||
event_type: JsString,
|
||||
content: JsString,
|
||||
) -> RoomMessageRequest {
|
||||
Self { id: Some(id), room_id, txn_id, event_type, content }
|
||||
}
|
||||
|
||||
/// Get its request type.
|
||||
@@ -252,32 +280,9 @@ pub struct KeysBackupRequest {
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub id: Option<JsString>,
|
||||
|
||||
/// A JSON-encoded object of form:
|
||||
/// A JSON-encoded string containing the rest of the payload: `rooms`.
|
||||
///
|
||||
/// ```json
|
||||
/// {"rooms": …}
|
||||
/// ```
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub body: JsString,
|
||||
}
|
||||
|
||||
/** Other Requests * */
|
||||
|
||||
/// Request that will publish a cross signing identity.
|
||||
///
|
||||
/// This uploads the public cross signing key triplet.
|
||||
#[wasm_bindgen(getter_with_clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct SigningKeysUploadRequest {
|
||||
/// The request ID.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub id: Option<JsString>,
|
||||
|
||||
/// A JSON-encoded object of form:
|
||||
///
|
||||
/// ```json
|
||||
/// {"master_key": …, "self_signing_key": …, "user_signing_key": …}
|
||||
/// ```
|
||||
/// It represents the body of the HTTP request.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub body: JsString,
|
||||
}
|
||||
@@ -297,28 +302,42 @@ impl KeysBackupRequest {
|
||||
}
|
||||
}
|
||||
|
||||
/** Other Requests * */
|
||||
|
||||
/// Request that will publish a cross signing identity.
|
||||
///
|
||||
/// This uploads the public cross signing key triplet.
|
||||
#[wasm_bindgen(getter_with_clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct SigningKeysUploadRequest {
|
||||
/// The request ID.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub id: Option<JsString>,
|
||||
|
||||
/// A JSON-encoded string containing the rest of the payload: `master_key`,
|
||||
/// `self_signing_key`, `user_signing_key`.
|
||||
///
|
||||
/// It represents the body of the HTTP request.
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub body: JsString,
|
||||
}
|
||||
|
||||
macro_rules! request {
|
||||
($destination_request:ident from $source_request:ident maps fields $( $field:ident ),+ $(,)? ) => {
|
||||
impl $destination_request {
|
||||
pub(crate) fn to_json(request: &$source_request) -> Result<String, serde_json::Error> {
|
||||
let mut map = serde_json::Map::new();
|
||||
$(
|
||||
map.insert(stringify!($field).to_owned(), serde_json::to_value(&request.$field).unwrap());
|
||||
)+
|
||||
let object = serde_json::Value::Object(map);
|
||||
|
||||
serde_json::to_string(&object)
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
$destination_request:ident from $source_request:ident
|
||||
$( extracts $( $field_name:ident : $field_type:tt ),+ $(,)? )?
|
||||
$( $( and )? groups $( $grouped_field_name:ident ),+ $(,)? )?
|
||||
) => {
|
||||
impl TryFrom<&$source_request> for $destination_request {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(request: &$source_request) -> Result<Self, Self::Error> {
|
||||
Ok($destination_request {
|
||||
id: None,
|
||||
body: Self::to_json(request)?.into(),
|
||||
})
|
||||
request!(
|
||||
@__try_from $destination_request from $source_request
|
||||
(request_id = None, request = request)
|
||||
$( extracts [ $( $field_name : $field_type, )+ ] )?
|
||||
$( groups [ $( $grouped_field_name, )+ ] )?
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,26 +347,73 @@ macro_rules! request {
|
||||
fn try_from(
|
||||
(request_id, request): (String, &$source_request),
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok($destination_request {
|
||||
id: Some(request_id.into()),
|
||||
body: Self::to_json(request)?.into(),
|
||||
})
|
||||
request!(
|
||||
@__try_from $destination_request from $source_request
|
||||
(request_id = Some(request_id.into()), request = request)
|
||||
$( extracts [ $( $field_name : $field_type, )+ ] )?
|
||||
$( groups [ $( $grouped_field_name, )+ ] )?
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(
|
||||
@__try_from $destination_request:ident from $source_request:ident
|
||||
(request_id = $request_id:expr, request = $request:expr)
|
||||
$( extracts [ $( $field_name:ident : $field_type:tt ),* $(,)? ] )?
|
||||
$( groups [ $( $grouped_field_name:ident ),* $(,)? ] )?
|
||||
) => {
|
||||
{
|
||||
Ok($destination_request {
|
||||
id: $request_id,
|
||||
$(
|
||||
$(
|
||||
$field_name: request!(@__field $field_name : $field_type ; request = $request),
|
||||
)*
|
||||
)?
|
||||
$(
|
||||
body: {
|
||||
let mut map = serde_json::Map::new();
|
||||
$(
|
||||
map.insert(stringify!($grouped_field_name).to_owned(), serde_json::to_value(&$request.$grouped_field_name).unwrap());
|
||||
)*
|
||||
let object = serde_json::Value::Object(map);
|
||||
|
||||
serde_json::to_string(&object)?.into()
|
||||
}
|
||||
)?
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
( @__field $field_name:ident : $field_type:ident ; request = $request:expr ) => {
|
||||
request!(@__field_type as $field_type ; request = $request, field_name = $field_name)
|
||||
};
|
||||
|
||||
( @__field_type as string ; request = $request:expr, field_name = $field_name:ident ) => {
|
||||
$request.$field_name.to_string().into()
|
||||
};
|
||||
|
||||
( @__field_type as json ; request = $request:expr, field_name = $field_name:ident ) => {
|
||||
serde_json::to_string(&$request.$field_name)?.into()
|
||||
};
|
||||
|
||||
( @__field_type as event_type ; request = $request:expr, field_name = $field_name:ident ) => {
|
||||
$request.content.event_type().to_string().into()
|
||||
};
|
||||
}
|
||||
|
||||
// Outgoing Requests
|
||||
request!(KeysUploadRequest from OriginalKeysUploadRequest maps fields device_keys, one_time_keys, fallback_keys);
|
||||
request!(KeysQueryRequest from OriginalKeysQueryRequest maps fields timeout, device_keys, token);
|
||||
request!(KeysClaimRequest from OriginalKeysClaimRequest maps fields timeout, one_time_keys);
|
||||
request!(ToDeviceRequest from OriginalToDeviceRequest maps fields event_type, txn_id, messages);
|
||||
request!(SignatureUploadRequest from OriginalSignatureUploadRequest maps fields signed_keys);
|
||||
request!(RoomMessageRequest from OriginalRoomMessageRequest maps fields room_id, txn_id, content);
|
||||
request!(KeysBackupRequest from OriginalKeysBackupRequest maps fields rooms);
|
||||
request!(KeysUploadRequest from OriginalKeysUploadRequest groups device_keys, one_time_keys, fallback_keys);
|
||||
request!(KeysQueryRequest from OriginalKeysQueryRequest groups timeout, device_keys, token);
|
||||
request!(KeysClaimRequest from OriginalKeysClaimRequest groups timeout, one_time_keys);
|
||||
request!(ToDeviceRequest from OriginalToDeviceRequest extracts event_type: string, txn_id: string and groups messages);
|
||||
request!(SignatureUploadRequest from OriginalSignatureUploadRequest groups signed_keys);
|
||||
request!(RoomMessageRequest from OriginalRoomMessageRequest extracts room_id: string, txn_id: string, event_type: event_type, content: json);
|
||||
request!(KeysBackupRequest from OriginalKeysBackupRequest groups rooms);
|
||||
|
||||
// Other Requests
|
||||
request!(SigningKeysUploadRequest from OriginalUploadSigningKeysRequest maps fields master_key, self_signing_key, user_signing_key);
|
||||
request!(SigningKeysUploadRequest from OriginalUploadSigningKeysRequest groups master_key, self_signing_key, user_signing_key);
|
||||
|
||||
// JavaScript has no complex enums like Rust. To return structs of
|
||||
// different types, we have no choice that hiding everything behind a
|
||||
|
||||
@@ -6,7 +6,7 @@ describe(Attachment.name, () => {
|
||||
const textDecoder = new TextDecoder();
|
||||
|
||||
let encryptedAttachment;
|
||||
|
||||
|
||||
test('can encrypt data', () => {
|
||||
encryptedAttachment = Attachment.encrypt(textEncoder.encode(originalData));
|
||||
|
||||
|
||||
@@ -172,14 +172,12 @@ describe('Key Verification', () => {
|
||||
expect(verificationRequest1.isCancelled()).toStrictEqual(false);
|
||||
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.request');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId1.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId2.toString()][deviceId2.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId2.toString()][deviceId2.toString()],
|
||||
}];
|
||||
|
||||
// Let's send the verification request to `m2`.
|
||||
@@ -225,13 +223,12 @@ describe('Key Verification', () => {
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
// The request verification is ready.
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.ready');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId2.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId1.toString()][deviceId1.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId1.toString()][deviceId1.toString()],
|
||||
}];
|
||||
|
||||
// Let's send the verification ready to `m1`.
|
||||
@@ -279,14 +276,12 @@ describe('Key Verification', () => {
|
||||
expect(sas2.decimals()).toBeUndefined();
|
||||
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.start');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId2.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId1.toString()][deviceId1.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId1.toString()][deviceId1.toString()],
|
||||
}];
|
||||
|
||||
// Let's send the SAS start to `m1`.
|
||||
@@ -324,15 +319,14 @@ describe('Key Verification', () => {
|
||||
|
||||
// Let's accept thet SAS start request.
|
||||
let outgoingVerificationRequest = sas1.accept();
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.accept');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId1.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId2.toString()][deviceId2.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId2.toString()][deviceId2.toString()],
|
||||
}];
|
||||
|
||||
// Let's send the SAS accept to `m2`.
|
||||
@@ -350,22 +344,18 @@ describe('Key Verification', () => {
|
||||
let toDeviceRequest = outgoingRequests.find((request) => request.type == RequestType.ToDevice);
|
||||
|
||||
expect(toDeviceRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
const toDeviceRequestId = toDeviceRequest.id;
|
||||
const toDeviceRequestType = toDeviceRequest.type;
|
||||
|
||||
toDeviceRequest = JSON.parse(toDeviceRequest.body);
|
||||
expect(toDeviceRequest.event_type).toStrictEqual('m.key.verification.key');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId2.toString(),
|
||||
type: toDeviceRequest.event_type,
|
||||
content: toDeviceRequest.messages[userId1.toString()][deviceId1.toString()],
|
||||
content: JSON.parse(toDeviceRequest.body).messages[userId1.toString()][deviceId1.toString()],
|
||||
}];
|
||||
|
||||
// Let's send te SAS key to `m1`.
|
||||
await m1.receiveSyncChanges(JSON.stringify(toDeviceEvents), new DeviceLists(), new Map(), new Set());
|
||||
|
||||
m2.markRequestAsSent(toDeviceRequestId, toDeviceRequestType, '{}');
|
||||
m2.markRequestAsSent(toDeviceRequest.id, toDeviceRequest.type, '{}');
|
||||
});
|
||||
|
||||
test('other side sends back verification key (`m.key.verification.key`)', async () => {
|
||||
@@ -374,22 +364,18 @@ describe('Key Verification', () => {
|
||||
let toDeviceRequest = outgoingRequests.find((request) => request.type == RequestType.ToDevice);
|
||||
|
||||
expect(toDeviceRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
const toDeviceRequestId = toDeviceRequest.id;
|
||||
const toDeviceRequestType = toDeviceRequest.type;
|
||||
|
||||
toDeviceRequest = JSON.parse(toDeviceRequest.body);
|
||||
expect(toDeviceRequest.event_type).toStrictEqual('m.key.verification.key');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId1.toString(),
|
||||
type: toDeviceRequest.event_type,
|
||||
content: toDeviceRequest.messages[userId2.toString()][deviceId2.toString()],
|
||||
content: JSON.parse(toDeviceRequest.body).messages[userId2.toString()][deviceId2.toString()],
|
||||
}];
|
||||
|
||||
// Let's send te SAS key to `m2`.
|
||||
await m2.receiveSyncChanges(JSON.stringify(toDeviceEvents), new DeviceLists(), new Map(), new Set());
|
||||
|
||||
m1.markRequestAsSent(toDeviceRequestId, toDeviceRequestType, '{}');
|
||||
m1.markRequestAsSent(toDeviceRequest.id, toDeviceRequest.type, '{}');
|
||||
});
|
||||
|
||||
test('emojis match from both sides', () => {
|
||||
@@ -447,14 +433,12 @@ describe('Key Verification', () => {
|
||||
let outgoingVerificationRequest = outgoingVerificationRequests[0];
|
||||
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.mac');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId1.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId2.toString()][deviceId2.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId2.toString()][deviceId2.toString()],
|
||||
}];
|
||||
|
||||
// Let's send te SAS confirmation to `m2`.
|
||||
@@ -473,14 +457,12 @@ describe('Key Verification', () => {
|
||||
let outgoingVerificationRequest = outgoingVerificationRequests[0];
|
||||
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.mac');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId2.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId1.toString()][deviceId1.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId1.toString()][deviceId1.toString()],
|
||||
}];
|
||||
|
||||
// Let's send te SAS confirmation to `m1`.
|
||||
@@ -492,14 +474,12 @@ describe('Key Verification', () => {
|
||||
let outgoingVerificationRequest = outgoingVerificationRequests[1];
|
||||
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.done');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId2.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId1.toString()][deviceId1.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId1.toString()][deviceId1.toString()],
|
||||
}];
|
||||
|
||||
// Let's send te SAS done to `m1`.
|
||||
@@ -514,22 +494,18 @@ describe('Key Verification', () => {
|
||||
let toDeviceRequest = outgoingRequests.find((request) => request.type == RequestType.ToDevice);
|
||||
|
||||
expect(toDeviceRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
const toDeviceRequestId = toDeviceRequest.id;
|
||||
const toDeviceRequestType = toDeviceRequest.type;
|
||||
|
||||
toDeviceRequest = JSON.parse(toDeviceRequest.body);
|
||||
expect(toDeviceRequest.event_type).toStrictEqual('m.key.verification.done');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId1.toString(),
|
||||
type: toDeviceRequest.event_type,
|
||||
content: toDeviceRequest.messages[userId2.toString()][deviceId2.toString()],
|
||||
content: JSON.parse(toDeviceRequest.body).messages[userId2.toString()][deviceId2.toString()],
|
||||
}];
|
||||
|
||||
// Let's send te SAS key to `m2`.
|
||||
await m2.receiveSyncChanges(JSON.stringify(toDeviceEvents), new DeviceLists(), new Map(), new Set());
|
||||
|
||||
m1.markRequestAsSent(toDeviceRequestId, toDeviceRequestType, '{}');
|
||||
m1.markRequestAsSent(toDeviceRequest.id, toDeviceRequest.type, '{}');
|
||||
});
|
||||
|
||||
test('can see if verification is done', () => {
|
||||
@@ -604,14 +580,12 @@ describe('Key Verification', () => {
|
||||
expect(verificationRequest1.isCancelled()).toStrictEqual(false);
|
||||
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.request');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId1.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId2.toString()][deviceId2.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId2.toString()][deviceId2.toString()],
|
||||
}];
|
||||
|
||||
// Let's send the verification request to `m2`.
|
||||
@@ -660,13 +634,12 @@ describe('Key Verification', () => {
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
// The request verification is ready.
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.ready');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId2.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId1.toString()][deviceId1.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId1.toString()][deviceId1.toString()],
|
||||
}];
|
||||
|
||||
// Let's send the verification ready to `m1`.
|
||||
@@ -818,14 +791,12 @@ describe('Key Verification', () => {
|
||||
let outgoingVerificationRequest = qr1.reciprocate();
|
||||
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.start');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId1.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId2.toString()][deviceId2.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId2.toString()][deviceId2.toString()],
|
||||
}];
|
||||
|
||||
// Let's send the verification request to `m2`.
|
||||
@@ -840,14 +811,12 @@ describe('Key Verification', () => {
|
||||
let outgoingVerificationRequest = qr2.confirmScanning();
|
||||
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(ToDeviceRequest);
|
||||
|
||||
outgoingVerificationRequest = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.done');
|
||||
|
||||
const toDeviceEvents = [{
|
||||
sender: userId2.toString(),
|
||||
type: outgoingVerificationRequest.event_type,
|
||||
content: outgoingVerificationRequest.messages[userId1.toString()][deviceId1.toString()],
|
||||
content: JSON.parse(outgoingVerificationRequest.body).messages[userId1.toString()][deviceId1.toString()],
|
||||
}];
|
||||
|
||||
// Let's send the verification request to `m2`.
|
||||
|
||||
@@ -30,6 +30,7 @@ async function addMachineToMachine(machineToAdd, machine) {
|
||||
expect(outgoingRequests[0]).toBeInstanceOf(KeysUploadRequest);
|
||||
expect(outgoingRequests[0].id).toBeDefined();
|
||||
expect(outgoingRequests[0].type).toStrictEqual(RequestType.KeysUpload);
|
||||
expect(outgoingRequests[0].body).toBeDefined();
|
||||
|
||||
const body = JSON.parse(outgoingRequests[0].body);
|
||||
expect(body.device_keys).toBeDefined();
|
||||
@@ -45,14 +46,13 @@ async function addMachineToMachine(machineToAdd, machine) {
|
||||
const marked = await machineToAdd.markRequestAsSent(outgoingRequests[0].id, outgoingRequests[0].type, hypothetical_response);
|
||||
expect(marked).toStrictEqual(true);
|
||||
|
||||
keysUploadRequest = body;
|
||||
keysUploadRequest = outgoingRequests[0];
|
||||
}
|
||||
|
||||
{
|
||||
expect(outgoingRequests[1]).toBeInstanceOf(KeysQueryRequest);
|
||||
|
||||
let [signingKeysUploadRequest, _] = await machineToAdd.bootstrapCrossSigning(true);
|
||||
signingKeysUploadRequest = JSON.parse(signingKeysUploadRequest.body);
|
||||
|
||||
// Let's forge a `KeysQuery`'s response.
|
||||
let keyQueryResponse = {
|
||||
@@ -64,10 +64,12 @@ async function addMachineToMachine(machineToAdd, machine) {
|
||||
const userId = machineToAdd.userId.toString();
|
||||
const deviceId = machineToAdd.deviceId.toString();
|
||||
keyQueryResponse.device_keys[userId] = {};
|
||||
keyQueryResponse.device_keys[userId][deviceId] = keysUploadRequest.device_keys;
|
||||
keyQueryResponse.master_keys[userId] = signingKeysUploadRequest.master_key;
|
||||
keyQueryResponse.self_signing_keys[userId] = signingKeysUploadRequest.self_signing_key;
|
||||
keyQueryResponse.user_signing_keys[userId] = signingKeysUploadRequest.user_signing_key;
|
||||
keyQueryResponse.device_keys[userId][deviceId] = JSON.parse(keysUploadRequest.body).device_keys;
|
||||
|
||||
const keys = JSON.parse(signingKeysUploadRequest.body);
|
||||
keyQueryResponse.master_keys[userId] = keys.master_key;
|
||||
keyQueryResponse.self_signing_keys[userId] = keys.self_signing_key;
|
||||
keyQueryResponse.user_signing_keys[userId] = keys.user_signing_key;
|
||||
|
||||
const marked = await machine.markRequestAsSent(outgoingRequests[1].id, outgoingRequests[1].type, JSON.stringify(keyQueryResponse));
|
||||
expect(marked).toStrictEqual(true);
|
||||
|
||||
@@ -5,6 +5,7 @@ const {
|
||||
DeviceKeyId,
|
||||
DeviceLists,
|
||||
EncryptionSettings,
|
||||
EventId,
|
||||
InboundGroupSession,
|
||||
KeysClaimRequest,
|
||||
KeysQueryRequest,
|
||||
@@ -14,9 +15,11 @@ const {
|
||||
OwnUserIdentity,
|
||||
RequestType,
|
||||
RoomId,
|
||||
RoomMessageRequest,
|
||||
SignatureUploadRequest,
|
||||
ToDeviceRequest,
|
||||
UserId,
|
||||
UserIdentity,
|
||||
VerificationRequest,
|
||||
VerificationState,
|
||||
} = require('../pkg/matrix_sdk_crypto_js');
|
||||
@@ -99,7 +102,7 @@ describe(OlmMachine.name, () => {
|
||||
test('can drop/close', async () => {
|
||||
m = await machine();
|
||||
m.close();
|
||||
})
|
||||
});
|
||||
|
||||
test('can drop/close with a store', async () => {
|
||||
let store_name = 'temporary';
|
||||
@@ -133,7 +136,7 @@ describe(OlmMachine.name, () => {
|
||||
deleting.onerror = () => { throw new Error('failed to remove the database (error)') };
|
||||
deleting.onblocked = () => { throw new Error('failed to remove the database (blocked)') };
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
test('can read user ID', async () => {
|
||||
expect((await machine()).userId.toString()).toStrictEqual(user.toString());
|
||||
@@ -198,6 +201,7 @@ describe(OlmMachine.name, () => {
|
||||
expect(outgoingRequests[0]).toBeInstanceOf(KeysUploadRequest);
|
||||
expect(outgoingRequests[0].id).toBeDefined();
|
||||
expect(outgoingRequests[0].type).toStrictEqual(RequestType.KeysUpload);
|
||||
expect(outgoingRequests[0].body).toBeDefined();
|
||||
|
||||
const body = JSON.parse(outgoingRequests[0].body);
|
||||
expect(body.device_keys).toBeDefined();
|
||||
@@ -208,6 +212,7 @@ describe(OlmMachine.name, () => {
|
||||
expect(outgoingRequests[1]).toBeInstanceOf(KeysQueryRequest);
|
||||
expect(outgoingRequests[1].id).toBeDefined();
|
||||
expect(outgoingRequests[1].type).toStrictEqual(RequestType.KeysQuery);
|
||||
expect(outgoingRequests[1].body).toBeDefined();
|
||||
|
||||
const body = JSON.parse(outgoingRequests[1].body);
|
||||
expect(body.timeout).toBeDefined();
|
||||
@@ -622,4 +627,196 @@ describe(OlmMachine.name, () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('can do in-room verification', () => {
|
||||
let m;
|
||||
const user = new UserId('@alice:example.org');
|
||||
const device = new DeviceId('JLAFKJWSCS');
|
||||
const room = new RoomId('!test:localhost');
|
||||
|
||||
beforeAll(async () => {
|
||||
m = await machine(user, device);
|
||||
});
|
||||
|
||||
test('can inject devices from someone else', async () => {
|
||||
{
|
||||
const hypothetical_response = JSON.stringify({
|
||||
"device_keys": {
|
||||
"@example:morpheus.localhost": {
|
||||
"ATRLDCRXAC": {
|
||||
"algorithms": [
|
||||
"m.olm.v1.curve25519-aes-sha2",
|
||||
"m.megolm.v1.aes-sha2"
|
||||
],
|
||||
"device_id": "ATRLDCRXAC",
|
||||
"keys": {
|
||||
"curve25519:ATRLDCRXAC": "cAVT5Es3Z3F5pFD+2w3HT7O9+R3PstzYVkzD51X/FWQ",
|
||||
"ed25519:ATRLDCRXAC": "V2w/T/x7i7AXiCCtS6JldrpbvRliRoef3CqTUNqMRHA"
|
||||
},
|
||||
"signatures": {
|
||||
"@example:morpheus.localhost": {
|
||||
"ed25519:ATRLDCRXAC": "ro2BjO5J6089B/JOANHnFmGrogrC2TIdMlgJbJO00DjOOcGxXfvOezCFIORTwZNHvkHU617YIGl/4keTDIWvBQ"
|
||||
}
|
||||
},
|
||||
"user_id": "@example:morpheus.localhost",
|
||||
"unsigned": {
|
||||
"device_display_name": "Element Desktop: Linux"
|
||||
}
|
||||
},
|
||||
"EYYGYTCTNC": {
|
||||
"algorithms": [
|
||||
"m.olm.v1.curve25519-aes-sha2",
|
||||
"m.megolm.v1.aes-sha2"
|
||||
],
|
||||
"device_id": "EYYGYTCTNC",
|
||||
"keys": {
|
||||
"curve25519:EYYGYTCTNC": "Pqu50fo472wgb6NjKkaUxjuqoAIEAmhln2gw/zSQ7Ek",
|
||||
"ed25519:EYYGYTCTNC": "Pf/2QPvui8lDty6TCTglVPRVM+irNHYavNNkyv5yFpU"
|
||||
},
|
||||
"signatures": {
|
||||
"@example:morpheus.localhost": {
|
||||
"ed25519:EYYGYTCTNC": "pnP5BYLEUUaxDgrvdzCznkjNDbvY1/MFBr1JejdnLiXlcmxRULQpIWZUCO7QTbULsCwMsYQNGn50nfmjBQX3CQ"
|
||||
}
|
||||
},
|
||||
"user_id": "@example:morpheus.localhost",
|
||||
"unsigned": {
|
||||
"device_display_name": "WeeChat-Matrix-rs"
|
||||
}
|
||||
},
|
||||
"SUMODVLSIU": {
|
||||
"algorithms": [
|
||||
"m.olm.v1.curve25519-aes-sha2",
|
||||
"m.megolm.v1.aes-sha2"
|
||||
],
|
||||
"device_id": "SUMODVLSIU",
|
||||
"keys": {
|
||||
"curve25519:SUMODVLSIU": "geQXWGWc++gcUHk0JcFmEVSjyzDOnk2mjVsUQwbNqQU",
|
||||
"ed25519:SUMODVLSIU": "ccktaQ3g+B18E6FwVhTBYie26OlHbvDUzDEtxOQ4Qcs"
|
||||
},
|
||||
"signatures": {
|
||||
"@example:morpheus.localhost": {
|
||||
"ed25519:SUMODVLSIU": "Yn+AOxHRt1GQpY2xT2Jcqqn8jh5+Vw23ctA7NXyDiWPsLPLNTpjGWHMjZdpUqflQvpiKfhODPICoIa7Pu0iSAg",
|
||||
"ed25519:rUiMNDjIu6gqsrhJPbj3phyIzuEtuQGrLOEa9mCbtTM": "Cio6k/sq289XNTOvTCWre7Q6zg+A3euzMUe7Uy1T3gPqYFzX+kt7EAxrhbPqx1HyXAEz9zD0D/uw9VEXFCvWBQ"
|
||||
}
|
||||
},
|
||||
"user_id": "@example:morpheus.localhost",
|
||||
"unsigned": {
|
||||
"device_display_name": "Element Desktop (Linux)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"failures": {},
|
||||
"master_keys": {
|
||||
"@example:morpheus.localhost": {
|
||||
"user_id": "@example:morpheus.localhost",
|
||||
"usage": [
|
||||
"master"
|
||||
],
|
||||
"keys": {
|
||||
"ed25519:ZzU4WCyBfOFitdGmfKCq6F39iQCDk/zhNNTsi+tWH7A": "ZzU4WCyBfOFitdGmfKCq6F39iQCDk/zhNNTsi+tWH7A"
|
||||
},
|
||||
"signatures": {
|
||||
"@example:morpheus.localhost": {
|
||||
"ed25519:SUMODVLSIU": "RL6WOuuzB/mZ+edfUFG/KeEcmKh+NaWpM6m2bUYmDnJrtTCYyoU+pgHJuL2/6nynemmONo18JEHBuqtNcMq2AQ"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"self_signing_keys": {
|
||||
"@example:morpheus.localhost": {
|
||||
"user_id": "@example:morpheus.localhost",
|
||||
"usage": [
|
||||
"self_signing"
|
||||
],
|
||||
"keys": {
|
||||
"ed25519:rUiMNDjIu6gqsrhJPbj3phyIzuEtuQGrLOEa9mCbtTM": "rUiMNDjIu6gqsrhJPbj3phyIzuEtuQGrLOEa9mCbtTM"
|
||||
},
|
||||
"signatures": {
|
||||
"@example:morpheus.localhost": {
|
||||
"ed25519:ZzU4WCyBfOFitdGmfKCq6F39iQCDk/zhNNTsi+tWH7A": "uCBn9rpeg6umY8H97ejN26UMp6QDwNL98869t1DoVGL50J8adLN05OZd8lYk9QzwTr2d56ZTGYSYX8kv28SDDA"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_signing_keys": {
|
||||
"@example:morpheus.localhost": {
|
||||
"user_id": "@example:morpheus.localhost",
|
||||
"usage": [
|
||||
"user_signing"
|
||||
],
|
||||
"keys": {
|
||||
"ed25519:GLhEKLQ50jnF6IMEPsO2ucpHUNIUEnbBXs5gYbHg4Aw": "GLhEKLQ50jnF6IMEPsO2ucpHUNIUEnbBXs5gYbHg4Aw"
|
||||
},
|
||||
"signatures": {
|
||||
"@example:morpheus.localhost": {
|
||||
"ed25519:ZzU4WCyBfOFitdGmfKCq6F39iQCDk/zhNNTsi+tWH7A": "4fIyWlVzuz1pgoegNLZASycORXqKycVS0dNq5vmmwsVEudp1yrPhndnaIJ3fjF8LDHvwzXTvohOid7DiU1j0AA"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const marked = await m.markRequestAsSent('foo', RequestType.KeysQuery, hypothetical_response);
|
||||
}
|
||||
});
|
||||
|
||||
test('can start an in-room SAS verification', async () => {
|
||||
let _ = m.bootstrapCrossSigning(true);
|
||||
const identity = await m.getIdentity(new UserId('@example:morpheus.localhost'));
|
||||
|
||||
expect(identity).toBeInstanceOf(UserIdentity);
|
||||
expect(identity.isVerified()).toStrictEqual(false);
|
||||
|
||||
const eventId = new EventId('$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg');
|
||||
const verificationRequest = await identity.requestVerification(room, eventId);
|
||||
expect(verificationRequest).toBeInstanceOf(VerificationRequest);
|
||||
|
||||
await m.receiveVerificationEvent(
|
||||
JSON.stringify({
|
||||
"sender": "@example:morpheus.localhost",
|
||||
"type": "m.key.verification.ready",
|
||||
"event_id": "$QguWmaeMt6Hao7Ea6XHDInvr8ndknev79t9a2eBxlz0",
|
||||
"origin_server_ts": 1674037263075,
|
||||
"content": {
|
||||
"methods": [
|
||||
"m.sas.v1",
|
||||
"m.qr_code.show.v1",
|
||||
"m.reciprocate.v1"
|
||||
],
|
||||
"from_device": "SUMODVLSIU",
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.reference",
|
||||
"event_id": eventId.toString(),
|
||||
}
|
||||
}
|
||||
}),
|
||||
room
|
||||
);
|
||||
|
||||
expect(verificationRequest.roomId.toString()).toStrictEqual(room.toString());
|
||||
|
||||
const [_sas, outgoingVerificationRequest] = await verificationRequest.startSas();
|
||||
|
||||
expect(outgoingVerificationRequest).toBeInstanceOf(RoomMessageRequest);
|
||||
expect(outgoingVerificationRequest.id).toBeDefined();
|
||||
expect(outgoingVerificationRequest.room_id).toStrictEqual(room.toString());
|
||||
expect(outgoingVerificationRequest.txn_id).toBeDefined();
|
||||
expect(outgoingVerificationRequest.event_type).toStrictEqual('m.key.verification.start');
|
||||
expect(outgoingVerificationRequest.body).toBeDefined();
|
||||
|
||||
const body = JSON.parse(outgoingVerificationRequest.body);
|
||||
expect(body).toMatchObject({
|
||||
from_device: expect.any(String),
|
||||
method: 'm.sas.v1',
|
||||
key_agreement_protocols: [expect.any(String)],
|
||||
hashes: [expect.any(String)],
|
||||
message_authentication_codes: [expect.any(String), expect.any(String)],
|
||||
short_authentication_string: ['decimal', 'emoji'],
|
||||
'm.relates_to': {
|
||||
rel_type: 'm.reference',
|
||||
event_id: eventId.toString(),
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,25 +11,3 @@ describe('RequestType', () => {
|
||||
expect(RequestType.KeysBackup).toStrictEqual(6);
|
||||
});
|
||||
});
|
||||
|
||||
for (const [request, requestType] of [
|
||||
[KeysUploadRequest, RequestType.KeysUpload],
|
||||
[KeysQueryRequest, RequestType.KeysQuery],
|
||||
[KeysClaimRequest, RequestType.KeysClaim],
|
||||
[ToDeviceRequest, RequestType.ToDevice],
|
||||
[SignatureUploadRequest, RequestType.SignatureUpload],
|
||||
[RoomMessageRequest, RequestType.RoomMessage],
|
||||
[KeysBackupRequest, RequestType.KeysBackup],
|
||||
]) {
|
||||
describe(request.name, () => {
|
||||
test('can be instantiated', () => {
|
||||
const r = new (request)('foo', '{"bar": "baz"}');
|
||||
|
||||
expect(r).toBeInstanceOf(request);
|
||||
expect(r.id).toStrictEqual('foo');
|
||||
expect(r.body).toStrictEqual('{"bar": "baz"}');
|
||||
expect(r.type).toStrictEqual(requestType);
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user