Skip to main content

genrs_lib/
lib.rs

1//! # genrs Library
2//!
3//! A versatile key and UUID generation library that allows you to:
4//!
5//! - Generate secure random keys of arbitrary length
6//! - Encode keys in either hexadecimal (`Hex`) or Base64 (`Base64`) format
7//! - Generate UUIDs of any version (V1, V3, V4, V5)
8//!
9//! ## Example usage
10//!
11//! ```
12//! use genrs_lib::{encode_key, generate_key, generate_uuid, EncodingFormat, UuidVersion};
13//!
14//! // Generate a random key
15//! let key = generate_key(32);
16//! let encoded_key = encode_key(key, EncodingFormat::Base64).unwrap();
17//! println!("Generated and encoded key: {}", encoded_key);
18//!
19//! // Generate a UUID V4
20//! let uuid_v4 = generate_uuid(UuidVersion::V4, None, None).unwrap();
21//! println!("Generated UUID V4: {}", uuid_v4);
22//! ```
23//!
24//! ## Features
25//!
26//! - **Key Generation**: Uses a cryptographically secure random number generator (CSPRNG) to generate random keys of arbitrary length.
27//! - **Key Encoding**: Supports `Hex` and `Base64` encoding formats for ease of transmission and storage.
28//! - **UUID Generation**: Create universally unique identifiers (UUIDs) for V1 (timestamp-based), V3 (namespace + name, MD5), V4 (random), and V5 (namespace + name, SHA-1).
29//!
30//! ### Referenced Libraries
31//!
32//! - [`rand`](https://docs.rs/rand/0.8.4/rand/) for secure random number generation.
33//! - [`uuid`](https://docs.rs/uuid/0.8.2/uuid/) for UUID generation.
34//! - [`hex`](https://docs.rs/hex/0.4.2/hex/) for encoding keys in hexadecimal format.
35//! - [`base64`](https://docs.rs/base64/0.13.0/base64/) for encoding keys in Base64 format.
36
37use base64::Engine;
38use rand::{rngs::OsRng, Rng, RngCore};
39use uuid::{Context, Timestamp, Uuid};
40
41/// Enum to represent the encoding format for the key.
42///
43/// # Examples
44///
45/// ```
46/// use genrs_lib::{encode_key, generate_key, EncodingFormat};
47///
48/// let key = generate_key(32);
49/// let encoded_key = encode_key(key, EncodingFormat::Base64).unwrap();
50/// println!("Generated and encoded key: {}", encoded_key);
51/// ```
52///
53/// Refer to the `encode_key` function for encoding usage.
54pub enum EncodingFormat {
55    Hex,
56    Base64,
57}
58
59/// Generates a random key of the given length in bytes.
60///
61/// # Examples
62///
63/// ```
64/// use genrs_lib::generate_key;
65///
66/// let key = generate_key(16);
67/// assert_eq!(key.len(), 16);
68/// ```
69///
70/// This function fills a vector of the specified length with secure random bytes
71/// using the system's entropy source.
72///
73/// # Panics
74///
75/// Will panic if the system's entropy source is unavailable.
76///
77/// Refer to the `encode_key` function for encoding the generated key.
78pub fn generate_key(length: usize) -> Vec<u8> {
79    let mut key = vec![0u8; length];
80    OsRng.try_fill_bytes(&mut key).expect(
81        "Failed to generate secure random bytes. \
82        Ensure that the system's entropy source is available and functioning correctly.",
83    );
84    key
85}
86
87/// Encodes the given key into the specified format (`Hex` or `Base64`).
88///
89/// # Examples
90///
91/// ```
92/// use genrs_lib::{encode_key, generate_key, EncodingFormat};
93///
94/// let key = generate_key(16);
95/// let encoded_key = encode_key(key, EncodingFormat::Hex).unwrap();
96/// println!("Hex encoded key: {}", encoded_key);
97/// ```
98///
99/// # Errors
100///
101/// Returns an error if the format is unsupported. However, this should never happen,
102/// as the format is now restricted to the `EncodingFormat` enum.
103pub fn encode_key(key: Vec<u8>, format: EncodingFormat) -> Result<String, String> {
104    match format {
105        EncodingFormat::Hex => Ok(hex::encode(key)),
106        EncodingFormat::Base64 => Ok(base64::engine::general_purpose::STANDARD.encode(key)),
107    }
108}
109
110/// Enum to represent UUID versions.
111///
112/// # Examples
113///
114/// ```
115/// use genrs_lib::{generate_uuid, UuidVersion};
116///
117/// let uuid_v4 = generate_uuid(UuidVersion::V4, None, None).unwrap();
118/// println!("Generated UUID V4: {}", uuid_v4);
119/// ```
120///
121/// Refer to the `generate_uuid` function for usage.
122pub enum UuidVersion {
123    V1,
124    V3,
125    V4,
126    V5,
127}
128
129/// Generates a UUID of the specified version.
130///
131/// - **UUID V1**: Generates a UUID based on the current system time and a random node ID.
132/// - **UUID V3 and V5**: Require a namespace and name for generating a UUID based on the MD5 or SHA-1 hash.
133/// - **UUID V4**: Generates a purely random UUID.
134///
135/// # Examples
136///
137/// ```
138/// use uuid::Uuid;
139/// use genrs_lib::{generate_uuid, UuidVersion};
140///
141/// let uuid_v1 = generate_uuid(UuidVersion::V1, None, None).unwrap();
142/// println!("Generated UUID V1: {}", uuid_v1);
143///
144/// let namespace = Uuid::new_v4();
145/// let uuid_v3 = generate_uuid(UuidVersion::V3, Some(namespace), Some("example")).unwrap();
146/// println!("Generated UUID V3: {}", uuid_v3);
147/// ```
148///
149/// # Errors
150///
151/// Returns an error if the required parameters (namespace, name) for UUID V3 or V5 are missing.
152pub fn generate_uuid(version: UuidVersion, namespace: Option<Uuid>, name: Option<&str>) -> Result<Uuid, String> {
153    match version {
154        UuidVersion::V1 => {
155            let context = Context::new(OsRng.next_u64() as u16);
156            let ts = Timestamp::now(&context);
157            let node_id: [u8; 6] = OsRng.gen();
158
159            Ok(Uuid::new_v1(ts, &node_id))
160        }
161        UuidVersion::V3 => {
162            if let (Some(namespace), Some(name)) = (namespace, name) {
163                Ok(Uuid::new_v3(&namespace, name.as_bytes()))
164            } else {
165                Err("Namespace and name are required for UUID V3".to_string())
166            }
167        }
168        UuidVersion::V4 => Ok(Uuid::new_v4()),
169        UuidVersion::V5 => {
170            if let (Some(namespace), Some(name)) = (namespace, name) {
171                Ok(Uuid::new_v5(&namespace, name.as_bytes()))
172            } else {
173                Err("Namespace and name are required for UUID V5".to_string())
174            }
175        }
176    }
177}