Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(): validated oob invitation #287

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 37 additions & 16 deletions crates/web-plugins/oob-messages/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ use std::io::Result as IoResult;
// ```

#[derive(Debug, Serialize, Deserialize, Clone)]
struct OobMessage {
pub(crate) struct OobMessage {
#[serde(rename = "type")]
oob_type: String,
id: String,
from: String,
body: Body,
}
type Ooburl = String;
Christiantyemele marked this conversation as resolved.
Show resolved Hide resolved

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename = "use")]
Expand All @@ -55,7 +56,11 @@ struct Body {
label: String,
accept: Vec<String>,
}

impl Default for OobMessage {
fn default() -> Self {
OobMessage::new("")
}
}
impl OobMessage {
Christiantyemele marked this conversation as resolved.
Show resolved Hide resolved
fn new(did: &str) -> Self {
let id = uuid::Uuid::new_v4().to_string();
Expand All @@ -74,20 +79,21 @@ impl OobMessage {
}
}

fn serialize_oob_message(oob_message: &OobMessage, url: &str) -> Result<String, String> {
fn serialize_oob_message(oob_message: &OobMessage, url: &str) -> Result<Ooburl, String> {
let plaintext =
to_string(oob_message).map_err(|e| format!("Serialization error: {}", e))?;
let encoded_jwm = Base64Url.encode(plaintext.as_bytes());

Ok(format!("{}?_oob={}", url, encoded_jwm))
let ooburl = format!("{}/_oob{}", url, encoded_jwm);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You changed the format of the oob_url. Is there any reason to that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes i want to use the oob jwm as a routing path to the out band message and the previous format contains query parameters which will be misinterpreted if used as route path

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't have to do what you plan to do. Plus, note that the OOB URL format is normative. Check https://identity.foundation/didcomm-messaging/spec/#standard-message-encoding.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let ooburl = format!("{}/_oob{}", url, encoded_jwm);
let oob_url = format!("{}/_oob{}", url, encoded_jwm);


Ok(ooburl)
}
}

// Receives server path/port and local storage path and returns a String with the OOB URL.
pub(crate) fn retrieve_or_generate_oob_inv<F>(
fs: &mut F,
server_public_domain: &str,
server_local_port: &str,
storage_dirpath: &str,
) -> Result<String, String>
where
Expand All @@ -112,7 +118,7 @@ where

let did = diddoc.id.clone();
let oob_message = OobMessage::new(&did);
let url: &String = &format!("{}:{}", server_public_domain, server_local_port);
let url: &String = &format!("{}", server_public_domain);
let oob_url = OobMessage::serialize_oob_message(&oob_message, url)
Comment on lines +121 to 122
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conversion here is unnecessary.

Suggested change
let url: &String = &format!("{}", server_public_domain);
let oob_url = OobMessage::serialize_oob_message(&oob_message, url)
let oob_url = OobMessage::serialize_oob_message(&oob_message, server_public_domain)

.map_err(|err| format!("Serialization error: {err}"))?;

Expand Down Expand Up @@ -205,8 +211,10 @@ use std::path::Path;

#[cfg(test)]
mod tests {

use super::*;
use mockall::{predicate::*, *};
use multibase::Base::Base64Url;

mock! {
pub FileSystem {}
Expand All @@ -218,6 +226,15 @@ mod tests {
fn write_with_lock(&self, path: &Path, content: &str) -> IoResult<()>;
}
}
fn test_serialize_oobmessage() -> String {
let did = "did:key:z6MkfyTREjTxQ8hUwSwBPeDHf3uPL3qCjSSuNPwsyMpWUGH7#z6LSbuUXWSgPfpiDBjUK6E7yiCKMN2eKJsXn5b55ZgqGz6Mr";
let oobmessage = OobMessage::new(did);
let server_public_domain = "https://example.com";

let url = format!("{}", server_public_domain);
let encoded_oob = OobMessage::serialize_oob_message(&oobmessage, &url).unwrap();
encoded_oob
Comment on lines +234 to +236
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an assert_eq! to validate what you expect as valid output.

}

#[test]
fn test_create_oob_message() {
Expand Down Expand Up @@ -249,15 +266,23 @@ mod tests {
.unwrap_or_else(|err| panic!("Failed to serialize oob message: {}", err));

assert!(!oob_url.is_empty());
assert!(oob_url.starts_with(&format!("{}?_oob=", url)));
assert!(oob_url.contains("_oob="));
assert!(oob_url.starts_with(&format!("{}/_oob", url)));
assert!(oob_url.contains("_oob"));
}
#[test]
fn test_deserialize_oob_message() {
let did = "did:key:z6MkfyTREjTxQ8hUwSwBPeDHf3uPL3qCjSSuNPwsyMpWUGH7#z6LSbuUXWSgPfpiDBjUK6E7yiCKMN2eKJsXn5b55ZgqGz6Mr";
let serialized_msg = test_serialize_oobmessage();
let oobmessage: Vec<&str> = serialized_msg.split("/_oob").collect();
let oobmessage = oobmessage.get(1).unwrap().to_string();
Comment on lines +275 to +277
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that _oob must be a query parameter in a compliant OOB URL.

Comment on lines +276 to +277
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let oobmessage: Vec<&str> = serialized_msg.split("/_oob").collect();
let oobmessage = oobmessage.get(1).unwrap().to_string();
let oob_message: Vec<&str> = serialized_msg.split("/_oob").collect();
let oob_message = oobmessage.get(1).unwrap().to_string();

let decode_msg = Base64Url.decode(oobmessage).unwrap();
let oobmessage: OobMessage = serde_json::from_slice(&decode_msg).unwrap();
assert_eq!(oobmessage.from, did);
}

#[test]
fn test_retrieve_or_generate_oob_inv() {
// Test data
let server_public_domain = "https://example.com";
let server_local_port = "8080";
let storage_dirpath = "testpath";

let mut mock_fs = MockFileSystem::new();
Expand Down Expand Up @@ -295,12 +320,8 @@ mod tests {
.withf(|path, _content| path == Path::new("testpath/oob_invitation.txt"))
.returning(|_, _| Ok(()));

let result = retrieve_or_generate_oob_inv(
&mut mock_fs,
server_public_domain,
server_local_port,
storage_dirpath,
);
let result =
retrieve_or_generate_oob_inv(&mut mock_fs, server_public_domain, storage_dirpath);

assert!(result.is_ok());
}
Expand Down
29 changes: 12 additions & 17 deletions crates/web-plugins/oob-messages/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ pub struct OOBMessages {
struct OOBMessagesEnv {
storage_dirpath: String,
server_public_domain: String,
server_local_port: String,
}

#[derive(Clone)]
pub(crate) struct OOBMessagesState {
pub(crate) filesystem: Arc<Mutex<dyn FileSystem>>,
pub(crate) oobmessage: String,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the purpose of the field you added here?

}

fn get_env() -> Result<OOBMessagesEnv, PluginError> {
Expand All @@ -33,14 +33,9 @@ fn get_env() -> Result<OOBMessagesEnv, PluginError> {
PluginError::InitError("SERVER_PUBLIC_DOMAIN env variable required".to_owned())
})?;

let server_local_port = std::env::var("SERVER_LOCAL_PORT").map_err(|_| {
PluginError::InitError("SERVER_LOCAL_PORT env variable required".to_owned())
})?;

Ok(OOBMessagesEnv {
storage_dirpath,
server_public_domain,
server_local_port,
})
}

Expand All @@ -53,17 +48,13 @@ impl Plugin for OOBMessages {
let env = get_env()?;
let mut fs = StdFileSystem;

let oob_inv = retrieve_or_generate_oob_inv(
&mut fs,
&env.server_public_domain,
&env.server_local_port,
&env.storage_dirpath,
)
.map_err(|err| {
PluginError::InitError(format!(
"Error retrieving or generating OOB invitation: {err}"
))
})?;
let oob_inv =
retrieve_or_generate_oob_inv(&mut fs, &env.server_public_domain, &env.storage_dirpath)
Christiantyemele marked this conversation as resolved.
Show resolved Hide resolved
.map_err(|err| {
PluginError::InitError(format!(
"Error retrieving or generating OOB invitation: {err}"
))
})?;

tracing::debug!("Out Of Band Invitation: {}", oob_inv);

Expand All @@ -74,8 +65,12 @@ impl Plugin for OOBMessages {
})?;

self.env = Some(env);
let oobmessage: Vec<&str> = oob_inv.split("/_").collect();
let oobmessage = oobmessage.get(1).unwrap_or(&"").to_string();

self.state = Some(OOBMessagesState {
filesystem: Arc::new(Mutex::new(fs)),
oobmessage,
});
Comment on lines +68 to 74
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I don't see the point of extracting something like "oob=abcd...xyz", when you already have the full string...
  • Did you run cargo clippy on your changes? I feel like you can use unwrap_or_default here.


Ok(())
Expand Down
14 changes: 12 additions & 2 deletions crates/web-plugins/oob-messages/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,24 @@ use crate::{
web::handler::{handler_landing_page_oob, handler_oob_inv, handler_oob_qr},
};
use axum::{routing::get, Router};
use handler::decode_oob_inv;
use std::sync::Arc;

pub(crate) fn routes(state: Arc<OOBMessagesState>) -> Router {
let invitation_path = format!("/_{}", &state.oobmessage);
Router::new() //
.route("/oob_url", get(handler_oob_inv))
.route("/oob_qr", get(handler_oob_qr))
.route("/", get(handler_landing_page_oob))
// handle oob invitation to invitation message
.route(&invitation_path, get(decode_oob_inv))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont understand what the new route is and why you added it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The qr_code and and oob url have no handled route, what i mean is if you can the oob qr_code you get nothing even the oob_url takes you no where as the route has not been handled and as such you can have its content without decoding it, that's where this route comes in

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The oob_url should not necessarily take you to somewhere.

.with_state(state)
}

#[cfg(test)]
mod tests {
use crate::models::retrieve_or_generate_oob_inv;

use super::*;
use axum::{
body::Body,
Expand All @@ -30,10 +36,14 @@ mod tests {
std::env::set_var("STORAGE_DIRPATH", "tmp");
std::env::set_var("SERVER_PUBLIC_DOMAIN", "example.com");
std::env::set_var("SERVER_LOCAL_PORT", "8080");

let fs = MockFileSystem;
let server_public_domain = std::env::var("SERVER_PUBLIC_DOMAIN").unwrap();
let storage_dirpath = std::env::var("STORAGE_DIRPATH").unwrap();
let mut fs = MockFileSystem;
let oobmessage =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let oobmessage =
let oob_message =

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have check all the comments and from our discussions it seems this PR actually solves no issue or brings and adjustments so, i guess it should be closed @Hermann-Core @IngridPuppet

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would agree. Also check the comment I left on the issue before planning to close it as well.

retrieve_or_generate_oob_inv(&mut fs, &server_public_domain, &storage_dirpath).unwrap();
let state = Arc::new(OOBMessagesState {
filesystem: Arc::new(Mutex::new(fs)),
oobmessage,
});
let app = routes(state.clone());

Expand Down
Loading
Loading