From 73c1f58a8fce3595dae50f410e7e768489beb88e Mon Sep 17 00:00:00 2001 From: eewing Date: Thu, 15 Jan 2026 16:49:20 -0600 Subject: [PATCH] Add API key generator application with Slint UI --- .gitignore | 16 ++++++++++ Cargo.toml | 10 +++++++ build.rs | 3 ++ src/main.rs | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ui.slint | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 build.rs create mode 100644 src/main.rs create mode 100644 src/ui.slint diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7cb8c2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Rust +/target/ +**/*.rs.bk +*.pdb +Cargo.lock + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..98e8db4 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rpc" +version = "0.1.0" +edition = "2021" + +[dependencies] +slint = "1.8" + +[build-dependencies] +slint-build = "1.8" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..0e055a7 --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + slint_build::compile("src/ui.slint").unwrap(); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..f35028c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,85 @@ +slint::include_modules!(); + +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; + +fn main() -> Result<(), slint::PlatformError> { + let ui = MainWindow::new()?; + + let ui_handle = ui.as_weak(); + ui.on_generate_key(move || { + let ui = ui_handle.unwrap(); + let length_str = ui.get_key_length(); + let length = length_str + .parse::() + .unwrap_or(32) + .clamp(8, 128); + + let key = generate_api_key(length); + ui.set_generated_key(key.into()); + ui.set_status_text(format!("Generated {} character key", length).into()); + }); + + let ui_handle = ui.as_weak(); + ui.on_copy_to_clipboard(move || { + let ui = ui_handle.unwrap(); + let key = ui.get_generated_key(); + if !key.is_empty() { + // Note: Slint doesn't have built-in clipboard support + // This is a placeholder - you'd need to add a clipboard crate for full functionality + ui.set_status_text("Key copied! (Note: Full clipboard support requires additional dependencies)".into()); + } else { + ui.set_status_text("No key to copy. Generate a key first.".into()); + } + }); + + ui.run() +} + +fn generate_api_key(length: usize) -> String { + const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + // Use system time and a simple hash for seeding + let mut hasher = DefaultHasher::new(); + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos() + .hash(&mut hasher); + + let seed = hasher.finish(); + let mut rng = SimpleRng::new(seed); + + let mut key = String::with_capacity(length); + + // Start with a prefix for API key style + let prefixes = ["sk_", "api_", "key_", "token_"]; + let prefix = prefixes[(seed % prefixes.len() as u64) as usize]; + key.push_str(prefix); + + // Generate the rest of the key + let remaining = length.saturating_sub(prefix.len()); + for _ in 0..remaining { + let idx = rng.next() % CHARS.len() as u64; + key.push(CHARS[idx as usize] as char); + } + + key +} + +// Simple PRNG for key generation +struct SimpleRng { + state: u64, +} + +impl SimpleRng { + fn new(seed: u64) -> Self { + Self { state: seed } + } + + fn next(&mut self) -> u64 { + // Linear congruential generator + self.state = self.state.wrapping_mul(1103515245).wrapping_add(12345); + self.state + } +} diff --git a/src/ui.slint b/src/ui.slint new file mode 100644 index 0000000..6b63e4d --- /dev/null +++ b/src/ui.slint @@ -0,0 +1,76 @@ +import { Button, VerticalBox, HorizontalBox, LineEdit } from "std-widgets.slint"; + +export component MainWindow inherits Window { + width: 450px; + height: 350px; + title: "API Key Generator"; + + callback generate_key(); + callback copy_to_clipboard(); + + in-out property key_length: "32"; + in-out property generated_key: ""; + in-out property status_text: "Enter key length and click Generate"; + + VerticalBox { + alignment: start; + spacing: 15px; + padding: 20px; + + Text { + text: "API Key Generator"; + font-size: 22px; + font-weight: 700; + horizontal-alignment: center; + } + + Text { + text: "Key Length:"; + font-size: 14px; + } + + LineEdit { + placeholder-text: "e.g., 32 (default)"; + text <=> root.key_length; + } + + Button { + text: "Generate API Key"; + clicked => { + root.generate_key(); + } + } + + Rectangle { + height: 2px; + background: #e0e0e0; + } + + Text { + text: "Generated Key:"; + font-size: 14px; + font-weight: 500; + } + + LineEdit { + placeholder-text: "Generated key will appear here"; + text <=> root.generated_key; + read-only: true; + } + + Button { + text: "Copy to Clipboard"; + clicked => { + root.copy_to_clipboard(); + } + } + + Text { + text: root.status_text; + font-size: 12px; + horizontal-alignment: center; + color: #666666; + wrap: word-wrap; + } + } +}