//! Emit a Google Authenticator export QR for manual testing: //! `cargo run -p da-http-api --example make-google-export -- out.png 8` fn put_varint(v: u64, out: &mut Vec) { let mut v = v; loop { let mut b = (v & 0x7f) as u8; v >>= 7; if v != 0 { b |= 0x80; } out.push(b); if v == 0 { break; } } } fn put_bytes(field: u32, bytes: &[u8], out: &mut Vec) { put_varint((u64::from(field) << 3) | 2, out); put_varint(bytes.len() as u64, out); out.extend_from_slice(bytes); } fn put_uint(field: u32, v: u64, out: &mut Vec) { put_varint(u64::from(field) << 3, out); put_varint(v, out); } fn main() { let mut a = std::env::args().skip(1); let out = a .next() .expect("usage: make-google-export [count]"); let n: usize = a.next().unwrap_or_else(|| "6".into()).parse().unwrap(); let names = [ "Cloudflare", "Plex", "Ubisoft", "GitHub", "Steam", "Proton", "Fastmail", "Namecheap", "Vercel", "Backblaze", ]; let mut payload = Vec::new(); for i in 0..n { let mut e = Vec::new(); put_bytes(1, &[0x41 + i as u8; 20], &mut e); put_bytes(2, b"miles@milesward.dev", &mut e); put_bytes(3, names[i % names.len()].as_bytes(), &mut e); put_uint(4, 1, &mut e); // Give one entry 8 digits so the UI's variant chips get exercised. put_uint(5, if i == 2 { 2 } else { 1 }, &mut e); // And make one HOTP so the "skipped" path shows up. put_uint(6, if i == 4 { 1 } else { 2 }, &mut e); put_bytes(1, &e, &mut payload); } put_uint(2, 1, &mut payload); put_uint(3, 2, &mut payload); // batch_size put_uint(4, 0, &mut payload); // batch_index put_uint(5, 77, &mut payload); use base64::Engine; let b64 = base64::engine::general_purpose::STANDARD.encode(&payload); let escaped = b64 .replace('+', "%2B") .replace('/', "%2F") .replace('=', "%3D"); let uri = format!("otpauth-migration://offline?data={escaped}"); let code = qrcode::QrCode::new(uri.as_bytes()).unwrap(); let img = code .render::>() .module_dimensions(6, 6) .quiet_zone(true) .build(); image::DynamicImage::ImageLuma8(img).save(&out).unwrap(); println!( "wrote {out} ({n} entries, {} bytes of payload)", payload.len() ); }