Add API key generator application with Slint UI
This commit is contained in:
+16
@@ -0,0 +1,16 @@
|
|||||||
|
# Rust
|
||||||
|
/target/
|
||||||
|
**/*.rs.bk
|
||||||
|
*.pdb
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "rpc"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
slint = "1.8"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
slint-build = "1.8"
|
||||||
+85
@@ -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::<usize>()
|
||||||
|
.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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 <string> key_length: "32";
|
||||||
|
in-out property <string> generated_key: "";
|
||||||
|
in-out property <string> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user