Notes
Prepare the side account for the IRS bill.
2024
Rust
These are the notes from Remy regarding the first file of the kbve
package!
I am going to place them here and then move them into the library.
For Password character checking, Remy suggested this:
match password.chars().count() {
// Check if the password is long enough (e.g., at least 8 characters)
0..=7 => return Err("Password is too short"),
// Check if the password is not too long (e.g., no more than 255 characters)
256..=usize::MAX => return Err("Password is too long"),
_ => ()
}
Here is an example of the fold method for checking the characters:
let conditions = password.chars().fold([false; 4], |mut acc, c| {
let acc1 = [char::is_uppercase, char::is_lowercase, |c: char| c.is_digit(10), |c: char| !c.is_alphanumeric()].map(|f| f(c));
(0..4).for_each(|i| acc[i] |= acc1[i]);
acc
});
if conditions.into_iter().fold(false, |acc, cond| (acc|!cond)) {
return Err(
"Password must include uppercase, lowercase, digits, and special characters"
);
}
If we expand the acc1
, then we can do this instead:
let conditions = password.chars().fold([false; 4], |mut acc, c| {
let acc1 = [char::is_uppercase, char::is_lowercase, |c: char| c.is_digit(10), |c: char| !c.is_alphanumeric()].map(|f| f(c));
(0..acc1.len()).for_each(|i| acc[i] |= acc1[i]);
acc
});
if conditions.into_iter().fold(false, |acc, cond| (acc|!cond)) {
return Err(
"Password must include uppercase, lowercase, digits, and special characters"
);
}
Here is a better way of writing the sanitize_path
function:
pub fn sanitize_path(input: &str) -> String {
let mut sanitized: String = input
.chars()
.filter(|c| matches!(c, 'a'..='z'|'A'..='Z'|'/'|'?'|'@'|'%'|'$'|'#') )
.collect();
if sanitized.chars().count() > 255 {
sanitized.truncate(255);
}
sanitized
}
Next, we have a better way to do the ulid string to bytes:
pub fn convert_ulid_string_to_bytes(ulid_str: &str) -> Result<Vec<u8>, String> {
Ulid::from_str(ulid_str)
.map(|o| ulid.to_bytes().to_vec())
.map_err(|_| "Invalid ULID string".to_string())
}
And vice versa, for bytes to string:
pub fn convert_ulid_bytes_to_string(ulid_bytes: &[u8]) -> Result<String, String> {
let 16 = ulid_bytes.len() else {
return Err("Invalid ULID bytes length".to_string());
};
// Convert the slice to an array
let ulid_array_ref: [u8; 16] = ulid_bytes.try_into().map_err(|_|"Failed to convert slice to array")?;
// Convert the Ulid to a string
Ok(Ulid::from_bytes(ulid_array_ref).to_string())
}
We could clean up the cors_service()
function as well:
pub fn cors_service() -> CorsLayer {
let orgins = [
"https://herbmail.com",
"https://kbve.com",
"https://discord.sh",
"https://hoppscotch.io",
"http://localhost:3000",
"http://localhost:4321",
"https://kbve.itch.io",
"https://html-classic.itch.zone",
].map(|url| url.parse::<HeaderValue>().unwrap());
CorsLayer::new()
.allow_origin(orgins)
.allow_methods([Method::PUT, Method::GET, Method::DELETE, Method::POST])
.allow_credentials(true)
.allow_headers([
AUTHORIZATION,
ACCEPT,
CONTENT_TYPE,
HeaderName::from_static("x-kbve-shieldwall"),
HeaderName::from_static("x-kbve-api"),
])
}
Last two were the health check, which would look like this:
pub async fn health_check(Extension(pool): Extension<Arc<Pool>>) -> Result<
Json<WizardResponse>,
StatusCode
> {
let connection_result = task::spawn_blocking(move || { pool.get() }).await.flatten();
match connection_result {
Ok(_conn) => {
Ok(
Json(WizardResponse {
data: serde_json::json!({"status": "online"}),
message: serde_json::json!({"health": "ok"}),
})
)
}
_ => { Err(StatusCode::SERVICE_UNAVAILABLE) }
}
}
and finally the speed_test
, which would look like this:
pub async fn speed_test(Extension(pool): Extension<Arc<Pool>>) -> Result<
Json<WizardResponse>,
StatusCode
> {
let start_time = Instant::now();
// Use `block_in_place` or `spawn_blocking` for the blocking database operation
let query_result = task::block_in_place(|| {
let mut conn = pool.get().map_err(|_| StatusCode::SERVICE_UNAVAILABLE)?;
// Execute a simple query
diesel
::sql_query("SELECT 1")
.execute(&mut conn)
.map_err(|_| StatusCode::SERVICE_UNAVAILABLE)
});
query_result?;
let elapsed_time = start_time.elapsed().as_millis() as u64;
Ok(
Json(WizardResponse {
data: serde_json::json!({"status": "time"}),
message: serde_json::json!({"time": elapsed_time.to_string()}),
})
)
}
Bonus function , getting the environmental variable function:
fn get_env_var(name: &str) -> Result<String, String> {
let file_path = env::var(name);
if let Ok(_) = &file_path {
return file_path;
};
let Ok(file_path) = env::var(format!("{}_FILE", name)) else {
return Err(format!(
"Environment variable {} or {}_FILE must be set",
name, name
));
};
fs::read_to_string(file_path).map_err(|err| format!("Error reading file for {}: {}", name, err))