//! QR Code generation for WireGuard mobile enrollment. use crate::error::{Result, WireGuardError}; use base64::Engine; use image::Luma; use qrcode::QrCode; use qrcode::render::svg; /// Generate SVG string for a WireGuard configuration. pub fn generate_qr_svg(content: &str) -> Result { let code = QrCode::new(content.as_bytes()) .map_err(|e| WireGuardError::Qr(format!("Failed to generate QR code: {e}")))?; let image = code .render::() .min_dimensions(256, 256) .dark_color(svg::Color("#000000")) .light_color(svg::Color("#ffffff")) .build(); Ok(image) } /// Generate PNG bytes for a WireGuard configuration. pub fn generate_qr_png_bytes(content: &str) -> Result> { let code = QrCode::new(content.as_bytes()) .map_err(|e| WireGuardError::Qr(format!("Failed to generate QR code: {e}")))?; let image = code.render::>().min_dimensions(300, 300).build(); let mut buffer = std::io::Cursor::new(Vec::new()); image .write_to(&mut buffer, image::ImageFormat::Png) .map_err(|e| WireGuardError::Qr(format!("Failed to encode QR PNG: {e}")))?; Ok(buffer.into_inner()) } /// Generate base64-encoded PNG string for a WireGuard configuration. pub fn generate_qr_base64(content: &str) -> Result { let png_bytes = generate_qr_png_bytes(content)?; Ok(base64::engine::general_purpose::STANDARD.encode(png_bytes)) } /// Generate base64 Data URL (data:image/png;base64,...) for embedding in HTML / UI. pub fn generate_qr_data_url(content: &str) -> Result { let b64 = generate_qr_base64(content)?; Ok(format!("data:image/png;base64,{b64}")) } /// Generate ASCII QR code for direct CLI rendering. pub fn generate_qr_ascii(content: &str) -> Result { let code = QrCode::new(content.as_bytes()) .map_err(|e| WireGuardError::Qr(format!("Failed to generate QR code: {e}")))?; let string = code .render::() .dark_color(qrcode::render::unicode::Dense1x2::Dark) .light_color(qrcode::render::unicode::Dense1x2::Light) .build(); Ok(string) } #[cfg(test)] mod tests { use super::*; #[test] fn test_qr_generation_svg_png_ascii() { let text = "[Interface]\nPrivateKey = aaaa\n"; let svg = generate_qr_svg(text).expect("svg"); assert!(svg.contains("