1use crate::config::Config;
2use ansi_term::Colour::Green;
3use anyhow::{Context, Result};
4use log::info;
5use md5::compute;
6use rand::{thread_rng, Rng};
7use std::fs;
8use std::path::Path;
9
10pub fn gen(target: &Path) -> Result<()> {
12 let target = target.to_path_buf();
13
14 if target.exists() {
16 info!("target already exists");
17 return Ok(());
18 }
19
20 fs::create_dir_all(&target).context(format!("Failed to create directory {:?}", &target))?;
21 info!("creating path: {:?}", target);
22
23 let config = Config::default();
24 let config_str = serde_yaml::to_string(&config)
25 .context("Failed to serialize default configuration to YAML")?;
26
27 let config_path = target.join("config.yml");
29 fs::write(&config_path, config_str)
30 .context(format!("Failed to write config to {:?}", config_path))?;
31 info!("Generated: {:?}", config_path);
32
33 Ok(())
34}
35
36pub fn gen_password(
38 length: u8,
39 no_special: bool,
40 username: Option<String>,
41 password: Option<String>,
42) {
43 let password = match password {
45 Some(p) => p,
46 None => {
47 let chars: &[u8] = if no_special {
48 b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
49 abcdefghijklmnopqrstuvwxyz\
50 0123456789"
51 } else {
52 b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
53 abcdefghijklmnopqrstuvwxyz\
54 0123456789)(*&^%#!~"
55 };
56
57 let mut rng = thread_rng();
59 let password: String = (0..length)
60 .map(|_| {
61 let idx = rng.gen_range(0..chars.len());
62 chars[idx] as char
63 })
64 .collect();
65
66 password
67 }
68 };
69
70 println!("Generated password: {}", Green.paint(password.clone()));
71
72 if let Some(username) = username {
73 let password_hash = gen_md5_password(&password, &username);
74 println!(
75 "Generated MD5 (user: {}): {}",
76 username,
77 Green.paint(password_hash)
78 );
79 println!("\nHint: https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_USER.html");
80 } else {
81 println!("\nHint: Please provide --username to generate MD5");
82 }
83}
84
85fn gen_md5_password(password: &str, username: &str) -> String {
91 format!(
92 "md5{:x}",
93 compute(format!("{}{}", password, username).as_bytes())
94 )
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
103 fn test_gen_password() {
104 gen_password(10, true, None, None);
105 gen_password(10, true, Some("test".to_string()), None);
106 gen_password(10, true, Some("test".to_string()), Some("test".to_string()));
107 gen_password(10, false, None, None);
108 gen_password(10, false, Some("test".to_string()), None);
109 gen_password(
110 10,
111 false,
112 Some("test".to_string()),
113 Some("test".to_string()),
114 );
115 }
116
117 #[test]
119 fn test_gen_md5_password() {
120 assert_eq!(
121 gen_md5_password("test", "test"),
122 "md505a671c66aefea124cc08b76ea6d30bb"
123 );
124 }
125}