Files
nx9-wg/crates/nx9-wireguard/src/qr.rs
T
thakaresandCopilot 2ac6c81dfe cli: avoid data-dir initialization for version; create db parent dirs; redact generated passwords in CLI output
- Prevent 'nx9-wg version' from creating data directories by avoiding database initialization.
- Create parent directories when an explicit --database path is provided.
- Redact printed generated administrator passwords; announce file path or redact instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-16 16:26:24 +05:30

86 lines
2.8 KiB
Rust

//! 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<String> {
let code = QrCode::new(content.as_bytes())
.map_err(|e| WireGuardError::Qr(format!("Failed to generate QR code: {e}")))?;
let image = code
.render::<svg::Color>()
.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<Vec<u8>> {
let code = QrCode::new(content.as_bytes())
.map_err(|e| WireGuardError::Qr(format!("Failed to generate QR code: {e}")))?;
let image = code.render::<Luma<u8>>().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<String> {
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<String> {
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<String> {
let code = QrCode::new(content.as_bytes())
.map_err(|e| WireGuardError::Qr(format!("Failed to generate QR code: {e}")))?;
let string = code
.render::<qrcode::render::unicode::Dense1x2>()
.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("<svg"));
let png = generate_qr_png_bytes(text).expect("png");
assert!(!png.is_empty());
assert_eq!(&png[1..4], b"PNG");
let data_url = generate_qr_data_url(text).expect("data url");
assert!(data_url.starts_with("data:image/png;base64,"));
let ascii = generate_qr_ascii(text).expect("ascii");
assert!(!ascii.is_empty());
}
}