use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
use url::Url;
use super::{
DeepLinkParseError,
query_params::parse_secret,
typed_deep_link::{DeepLinkIntent, DeepLinkParams, TypedDeepLink},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SecretExportIntent;
impl DeepLinkIntent for SecretExportIntent {
const NAME: &'static str = "secret_export";
}
pub type SeedExportDeepLink = TypedDeepLink<SecretExportIntent, SeedExportParams>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SeedExportParams {
pub secret: [u8; 32],
}
impl DeepLinkParams for SeedExportParams {
fn parse(url: &Url) -> Result<Self, DeepLinkParseError> {
Ok(Self {
secret: parse_secret(url)?,
})
}
fn append_query_pairs(&self, url: &mut Url) {
url.query_pairs_mut()
.append_pair("secret", &URL_SAFE_NO_PAD.encode(self.secret));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::actors::auth::deep_links::DeepLinkScheme;
const SECRET: &str = "kqnceEMgrNQM_xi06oQXjA3cJHX_RQmw1BY6JE1bse8";
const SECRET_BYTES: [u8; 32] = [
146, 169, 220, 120, 67, 32, 172, 212, 12, 255, 24, 180, 234, 132, 23, 140, 13, 220, 36,
117, 255, 69, 9, 176, 212, 22, 58, 36, 77, 91, 177, 239,
];
#[test]
fn parses_seed_export_deep_link() {
let deep_link: SeedExportDeepLink = format!("pubkyring://secret_export?secret={SECRET}")
.parse()
.unwrap();
assert_eq!(deep_link.scheme(), DeepLinkScheme::PubkyRing);
assert_eq!(deep_link.intent(), "secret_export");
assert_eq!(deep_link.params().secret, SECRET_BYTES);
}
#[test]
fn converts_seed_export_deep_link_to_url() {
let deep_link: SeedExportDeepLink = format!("pubkyring://secret_export?secret={SECRET}")
.parse()
.unwrap();
let url = deep_link.to_url();
assert_eq!(url.scheme(), "pubkyring");
assert_eq!(url.host_str(), Some("secret_export"));
assert_eq!(SeedExportDeepLink::parse_url(&url).unwrap(), deep_link);
}
#[test]
fn creates_seed_export_deep_link_from_params() {
let deep_link = SeedExportDeepLink::new(
DeepLinkScheme::PubkyAuth,
SeedExportParams {
secret: SECRET_BYTES,
},
);
let url = deep_link.to_url();
let parsed_again = SeedExportDeepLink::parse_url(&url).unwrap();
assert_eq!(deep_link.scheme(), DeepLinkScheme::PubkyAuth);
assert_eq!(deep_link.intent(), "secret_export");
assert_eq!(deep_link.params().secret, SECRET_BYTES);
assert_eq!(parsed_again, deep_link);
}
#[test]
fn display_formats_as_url() {
let deep_link: SeedExportDeepLink = format!("pubkyauth://secret_export?secret={SECRET}")
.parse()
.unwrap();
assert_eq!(deep_link.to_string(), deep_link.to_url().to_string());
}
#[test]
fn converts_owned_typed_deep_link_into_url() {
let deep_link: SeedExportDeepLink = format!("pubkyauth://secret_export?secret={SECRET}")
.parse()
.unwrap();
let url: Url = deep_link.into();
assert_eq!(url.scheme(), "pubkyauth");
assert_eq!(url.host_str(), Some("secret_export"));
url.query_pairs()
.find(|(key, _)| key == "secret")
.map(|(_, value)| assert_eq!(value, SECRET))
.expect("Expected 'secret' query parameter");
}
}