diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/enrollments.rs b/implementations/rust/ockam/ockam_api/src/cli_state/enrollments.rs index 77fb9714c3e..2b2db30226a 100644 --- a/implementations/rust/ockam/ockam_api/src/cli_state/enrollments.rs +++ b/implementations/rust/ockam/ockam_api/src/cli_state/enrollments.rs @@ -343,6 +343,13 @@ impl FromStr for ExportedEnrollmentTicket { type Err = ApiError; fn from_str(contents: &str) -> std::result::Result { + // Try to hex-decode the contents + let contents = match hex::decode(contents) { + Ok(decoded) => String::from_utf8(decoded) + .map_err(|_| ApiError::core("Failed to hex decode enrollment ticket"))?, + Err(_) => contents.to_string(), + }; + // Decode as comma-separated text let values: Vec<&str> = contents.split(',').collect(); if values.len() < Self::MANDATORY_FIELDS_NUM { @@ -378,8 +385,8 @@ impl FromStr for ExportedEnrollmentTicket { impl Display for ExportedEnrollmentTicket { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, + let mut output = String::new(); + output.push_str(&format!( "{},{},{},{},{},{}", self.project_route.route, self.project_identifier, @@ -387,10 +394,11 @@ impl Display for ExportedEnrollmentTicket { String::from(&self.one_time_code), self.project_change_history, self.authority_change_history, - )?; + )); if let Some(authority_route) = &self.authority_route { - write!(f, ",{}", authority_route)?; + output.push_str(&format!(",{}", authority_route)); } + write!(f, "{}", hex::encode(output))?; Ok(()) } } @@ -601,25 +609,46 @@ impl EnrollmentTicket { Some(self.authority_route.to_string()), )) } + + pub fn export_legacy(self) -> Result { + let project = self.project()?; + Ok(LegacyEnrollmentTicket::new( + self.one_time_code, + Some(project), + )) + } } #[cfg(test)] mod tests { use super::*; + #[tokio::test] + async fn text_export_as_legacy() { + let ticket = ExportedEnrollmentTicket::new_test(); + let exported = ticket.import().await.unwrap(); + let legacy = exported.clone().export_legacy().unwrap(); + assert_eq!(legacy.one_time_code, exported.one_time_code); + assert_eq!(legacy.project.unwrap(), exported.project().unwrap()); + } + #[test] fn test_exported_enrollment_ticket() { let exported = ExportedEnrollmentTicket::new_test(); let encoded = exported.to_string(); - assert!(encoded.contains(&String::from(&exported.one_time_code))); - assert!(encoded.contains(&exported.project_route.id)); - assert!(encoded.contains(&exported.project_route.route.to_string())); - assert!(encoded.contains(&exported.project_name)); - assert!(encoded.contains(&exported.project_change_history)); - assert!(encoded.contains(&exported.authority_change_history)); + let hex_decoded = String::from_utf8(hex::decode(&encoded).unwrap()).unwrap(); + assert!(hex_decoded.contains(&String::from(&exported.one_time_code))); + assert!(hex_decoded.contains(&exported.project_route.id)); + assert!(hex_decoded.contains(&exported.project_route.route.to_string())); + assert!(hex_decoded.contains(&exported.project_name)); + assert!(hex_decoded.contains(&exported.project_change_history)); + assert!(hex_decoded.contains(&exported.authority_change_history)); let decoded = ExportedEnrollmentTicket::from_str(&encoded).unwrap(); assert_eq!(decoded, exported); + + let decoded = ExportedEnrollmentTicket::from_str(&hex_decoded).unwrap(); + assert_eq!(decoded, exported); } #[test] diff --git a/implementations/rust/ockam/ockam_command/src/project/ticket.rs b/implementations/rust/ockam/ockam_command/src/project/ticket.rs index 0d1f5f41604..0ee68f3fdf0 100644 --- a/implementations/rust/ockam/ockam_command/src/project/ticket.rs +++ b/implementations/rust/ockam/ockam_command/src/project/ticket.rs @@ -144,7 +144,11 @@ impl Command for TicketCommand { .as_ref() .ok_or(miette!("missing authority's change history"))?, project.authority_access_route.as_ref(), - ); + ) + .import() + .await? + .export_legacy()? + .hex_encoded()?; opts.terminal .write_line(fmt_ok!("Created enrollment ticket\n"))?; diff --git a/implementations/rust/ockam/ockam_command/src/value_parsers.rs b/implementations/rust/ockam/ockam_command/src/value_parsers.rs index ceecfa721d7..7b61b73386d 100644 --- a/implementations/rust/ockam/ockam_command/src/value_parsers.rs +++ b/implementations/rust/ockam/ockam_command/src/value_parsers.rs @@ -1,9 +1,7 @@ use crate::util::parsers::hostname_parser; use crate::CommandGlobalOpts; -use colorful::Colorful; use miette::{miette, Context, IntoDiagnostic}; use ockam_api::cli_state::{EnrollmentTicket, ExportedEnrollmentTicket, LegacyEnrollmentTicket}; -use ockam_api::fmt_warn; use std::str::FromStr; use tracing::trace; use url::Url; @@ -27,7 +25,7 @@ where /// Parse an enrollment ticket given a path, a URL or encoded string pub async fn parse_enrollment_ticket( - opts: &CommandGlobalOpts, + _opts: &CommandGlobalOpts, value: &str, ) -> miette::Result { trace!(%value, "parsing enrollment ticket"); @@ -35,11 +33,12 @@ pub async fn parse_enrollment_ticket( // Try to parse it using the old format if let Ok(ticket) = LegacyEnrollmentTicket::from_hex(&contents) { - opts.terminal.write_line(fmt_warn!( - "The enrollment ticket was generated from an old Ockam version" - ))?; - opts.terminal - .write_line(fmt_warn!("Please make sure the machine that generated the ticket is using the latest Ockam version"))?; + // TODO: disabled until release 0.138.0 + // opts.terminal.write_line(fmt_warn!( + // "The enrollment ticket was generated from an old Ockam version" + // ))?; + // opts.terminal + // .write_line(fmt_warn!("Please make sure the machine that generated the ticket is using the latest Ockam version"))?; return Ok(EnrollmentTicket::new_from_legacy(ticket).await?); }