#![deny(missing_docs)]
pub use qrcode_generator::QrCodeEcc;
use std::io::Write;
pub fn encode_as_matrix(
wifi_credentials: &WifiCredentials,
qr_code_error_checking: QrCodeEcc,
) -> Result<Vec<Vec<bool>>, std::io::Error> {
qrcode_generator::to_matrix(wifi_credentials.encode(), qr_code_error_checking)
}
pub fn encode_as_image(
wifi_credentials: &WifiCredentials,
qr_code_error_checking: QrCodeEcc,
image_size: usize,
) -> Result<Vec<u8>, std::io::Error> {
qrcode_generator::to_image(
wifi_credentials.encode(),
qr_code_error_checking,
image_size,
)
}
pub fn encode_as_png(
wifi_credentials: &WifiCredentials,
qr_code_error_checking: QrCodeEcc,
image_size: usize,
writer: impl Write,
) -> Result<(), std::io::Error> {
qrcode_generator::to_png(
wifi_credentials.encode(),
qr_code_error_checking,
image_size,
writer,
)
}
pub fn encode_as_svg(
wifi_credentials: &WifiCredentials,
qr_code_error_checking: QrCodeEcc,
image_size: usize,
description: Option<&str>,
writer: impl Write,
) -> Result<(), std::io::Error> {
qrcode_generator::to_svg(
wifi_credentials.encode(),
qr_code_error_checking,
image_size,
description,
writer,
)
}
pub enum AuthenticationType {
WEP(String),
WPA(String),
NoPassword,
}
impl AuthenticationType {
fn encode(&self) -> String {
match self {
Self::WEP(password) => format!("T:WEP;P:{};", escape(password)),
Self::WPA(password) => format!("T:WPA;P:{};", escape(password)),
Self::NoPassword => String::from("T:nopass;"),
}
}
}
pub enum Visibility {
Visible,
Hidden,
}
impl Visibility {
fn encode(&self) -> String {
match self {
Self::Visible => String::from("H:false;"),
Self::Hidden => String::from("H:true;"),
}
}
}
pub struct WifiCredentials {
pub ssid: String,
pub authentication_type: AuthenticationType,
pub visibility: Visibility,
}
impl WifiCredentials {
pub fn encode(&self) -> String {
format!(
"WIFI:{}{}{};",
self.encode_ssid(),
self.authentication_type.encode(),
self.visibility.encode()
)
}
fn encode_ssid(&self) -> String {
format!("S:{};", escape(&self.ssid))
}
}
fn escape(input: &str) -> String {
String::from(input)
.replace(r#"\"#, r#"\\"#)
.replace(r#"""#, r#"\""#)
.replace(";", r#"\;"#)
.replace(",", r#"\,"#)
.replace(":", r#"\:"#)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_encodes_valid_wifi_forms() {
let wifi_credentials = WifiCredentials {
ssid: String::from("test ssid"),
authentication_type: AuthenticationType::WEP(String::from("test password")),
visibility: Visibility::Visible,
};
assert_eq!(
"WIFI:S:test ssid;T:WEP;P:test password;H:false;;",
&wifi_credentials.encode()
);
let wifi_credentials = WifiCredentials {
ssid: String::from("test ssid"),
authentication_type: AuthenticationType::WPA(String::from("test password")),
visibility: Visibility::Hidden,
};
assert_eq!(
"WIFI:S:test ssid;T:WPA;P:test password;H:true;;",
&wifi_credentials.encode()
);
let wifi_credentials = WifiCredentials {
ssid: String::from("test ssid"),
authentication_type: AuthenticationType::NoPassword,
visibility: Visibility::Visible,
};
assert_eq!(
"WIFI:S:test ssid;T:nopass;H:false;;",
&wifi_credentials.encode()
);
}
#[test]
fn it_properly_handles_escaped_characters() {
let wifi_credentials = WifiCredentials {
ssid: String::from(r#"special_characters ";,:\"#),
authentication_type: AuthenticationType::WEP(String::from(
r#"special_characters ";,:\"#,
)),
visibility: Visibility::Visible,
};
assert_eq!(
r#"WIFI:S:special_characters \"\;\,\:\\;T:WEP;P:special_characters \"\;\,\:\\;H:false;;"#,
&wifi_credentials.encode()
);
}
}