83 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			83 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
use std::io::{Read, Write};
 | 
						|
use std::net::TcpStream;
 | 
						|
 | 
						|
// Minimal RESP helpers
 | 
						|
fn arr(parts: &[&str]) -> String {
 | 
						|
    let mut out = format!("*{}\r\n", parts.len());
 | 
						|
    for p in parts {
 | 
						|
        out.push_str(&format!("${}\r\n{}\r\n", p.len(), p));
 | 
						|
    }
 | 
						|
    out
 | 
						|
}
 | 
						|
fn read_reply(s: &mut TcpStream) -> String {
 | 
						|
    let mut buf = [0u8; 65536];
 | 
						|
    let n = s.read(&mut buf).unwrap();
 | 
						|
    String::from_utf8_lossy(&buf[..n]).to_string()
 | 
						|
}
 | 
						|
fn parse_two_bulk(reply: &str) -> Option<(String,String)> {
 | 
						|
    let mut lines = reply.split("\r\n");
 | 
						|
    if lines.next()? != "*2" { return None; }
 | 
						|
    let _n = lines.next()?;
 | 
						|
    let a = lines.next()?.to_string();
 | 
						|
    let _m = lines.next()?;
 | 
						|
    let b = lines.next()?.to_string();
 | 
						|
    Some((a,b))
 | 
						|
}
 | 
						|
fn parse_bulk(reply: &str) -> Option<String> {
 | 
						|
    let mut lines = reply.split("\r\n");
 | 
						|
    let hdr = lines.next()?;
 | 
						|
    if !hdr.starts_with('$') { return None; }
 | 
						|
    Some(lines.next()?.to_string())
 | 
						|
}
 | 
						|
fn parse_simple(reply: &str) -> Option<String> {
 | 
						|
    let mut lines = reply.split("\r\n");
 | 
						|
    let hdr = lines.next()?;
 | 
						|
    if !hdr.starts_with('+') { return None; }
 | 
						|
    Some(hdr[1..].to_string())
 | 
						|
}
 | 
						|
 | 
						|
fn main() {
 | 
						|
    let mut args = std::env::args().skip(1);
 | 
						|
    let host = args.next().unwrap_or_else(|| "127.0.0.1".into());
 | 
						|
    let port = args.next().unwrap_or_else(|| "6379".into());
 | 
						|
    let addr = format!("{host}:{port}");
 | 
						|
    println!("Connecting to {addr}...");
 | 
						|
    let mut s = TcpStream::connect(addr).expect("connect");
 | 
						|
 | 
						|
    // Generate & persist X25519 enc keys under name "alice"
 | 
						|
    s.write_all(arr(&["age","keygen","alice"]).as_bytes()).unwrap();
 | 
						|
    let (_alice_recip, _alice_ident) = parse_two_bulk(&read_reply(&mut s)).expect("gen enc");
 | 
						|
 | 
						|
    // Generate & persist Ed25519 signing key under name "signer"
 | 
						|
    s.write_all(arr(&["age","signkeygen","signer"]).as_bytes()).unwrap();
 | 
						|
    let (_verify, _secret) = parse_two_bulk(&read_reply(&mut s)).expect("gen sign");
 | 
						|
 | 
						|
    // Encrypt by name
 | 
						|
    let msg = "hello from persistent keys";
 | 
						|
    s.write_all(arr(&["age","encryptname","alice", msg]).as_bytes()).unwrap();
 | 
						|
    let ct_b64 = parse_bulk(&read_reply(&mut s)).expect("ct b64");
 | 
						|
    println!("ciphertext b64: {}", ct_b64);
 | 
						|
 | 
						|
    // Decrypt by name
 | 
						|
    s.write_all(arr(&["age","decryptname","alice", &ct_b64]).as_bytes()).unwrap();
 | 
						|
    let pt = parse_bulk(&read_reply(&mut s)).expect("pt");
 | 
						|
    assert_eq!(pt, msg);
 | 
						|
    println!("decrypted ok");
 | 
						|
 | 
						|
    // Sign by name
 | 
						|
    s.write_all(arr(&["age","signname","signer", msg]).as_bytes()).unwrap();
 | 
						|
    let sig_b64 = parse_bulk(&read_reply(&mut s)).expect("sig b64");
 | 
						|
 | 
						|
    // Verify by name
 | 
						|
    s.write_all(arr(&["age","verifyname","signer", msg, &sig_b64]).as_bytes()).unwrap();
 | 
						|
    let ok = parse_simple(&read_reply(&mut s)).expect("verify");
 | 
						|
    assert_eq!(ok, "1");
 | 
						|
    println!("signature verified");
 | 
						|
 | 
						|
    // List names
 | 
						|
    s.write_all(arr(&["age","list"]).as_bytes()).unwrap();
 | 
						|
    let list = read_reply(&mut s);
 | 
						|
    println!("LIST -> {list}");
 | 
						|
 | 
						|
    println!("✔ persistent AGE workflow complete.");
 | 
						|
} |