sqlpage.hash_password(NULL) now returns NULL

This commit is contained in:
lovasoa
2024-05-11 19:14:27 +02:00
parent 848a49df31
commit 4d4de00df5
7 changed files with 34 additions and 9 deletions
+4
View File
@@ -1,5 +1,9 @@
# CHANGELOG.md
## unreleased
- `sqlpage.hash_password(NULL)` now returns `NULL` instead of throwing an error. This behavior was changed unintentionally in 0.20.5 and could have broken existing SQLPage websites.
## 0.20.5 (2024-05-07)
- Searchable multi-valued selects in the form component
+1
View File
@@ -400,6 +400,7 @@ fn expr_to_stmt_param(arg: &mut Expr) -> Option<StmtParam> {
Expr::Value(Value::Number(param_value, _is_long)) => {
Some(StmtParam::Literal(param_value.clone()))
}
Expr::Value(Value::Null) => Some(StmtParam::Null),
Expr::BinaryOp {
// 'str1' || 'str2'
left,
@@ -49,6 +49,13 @@ impl<'a> FunctionParamType<'a> for String {
}
}
impl<'a> FunctionParamType<'a> for Option<String> {
type TargetType = Self;
fn from_args(arg: &mut std::vec::IntoIter<Option<Cow<'a, str>>>) -> anyhow::Result<Self> {
<Option<Cow<'a, str>>>::from_args(arg).map(|x| x.map(Cow::into_owned))
}
}
/// similar to `FromStr`, but borrows the input string
pub(super) trait BorrowFromStr<'a>: Sized {
fn borrow_from_str(s: Cow<'a, str>) -> anyhow::Result<Self>;
@@ -97,12 +104,6 @@ trait IntoCow<'a> {
fn into_cow(self) -> Option<Cow<'a, str>>;
}
impl<'a> IntoCow<'a> for Option<Cow<'a, str>> {
fn into_cow(self) -> Option<Cow<'a, str>> {
self
}
}
impl<'a> IntoCow<'a> for Cow<'a, str> {
fn into_cow(self) -> Option<Cow<'a, str>> {
Some(self)
@@ -120,3 +121,9 @@ impl<'a> IntoCow<'a> for &'a str {
Some(Cow::Borrowed(self))
}
}
impl<'a, T: IntoCow<'a>> IntoCow<'a> for Option<T> {
fn into_cow(self) -> Option<Cow<'a, str>> {
self.and_then(IntoCow::into_cow)
}
}
@@ -16,7 +16,7 @@ super::function_definition_macro::sqlpage_functions! {
fetch(http_request: SqlPageFunctionParam<super::http_fetch_request::HttpFetchRequest<'_>>);
hash_password(password: String);
hash_password(password: Option<String>);
header((&RequestInfo), name: Cow<str>);
path((&RequestInfo));
@@ -159,7 +159,10 @@ async fn fetch(
Ok(response_str)
}
pub(crate) async fn hash_password(password: String) -> anyhow::Result<String> {
pub(crate) async fn hash_password(password: Option<String>) -> anyhow::Result<Option<String>> {
let Some(password) = password else {
return Ok(None);
};
actix_web::rt::task::spawn_blocking(move || {
// Hashes a password using Argon2. This is a CPU-intensive blocking operation.
let phf = argon2::Argon2::default();
@@ -169,6 +172,7 @@ pub(crate) async fn hash_password(password: String) -> anyhow::Result<String> {
Ok(password_hash.to_string())
})
.await?
.map(Some)
}
async fn header<'a>(request: &'a RequestInfo, name: Cow<'a, str>) -> Option<Cow<'a, str>> {
@@ -390,7 +394,10 @@ async fn run_sql<'a>(
#[tokio::test]
async fn test_hash_password() {
let s = hash_password("password".to_string()).await.unwrap();
let s = hash_password(Some("password".to_string()))
.await
.unwrap()
.unwrap();
assert!(s.starts_with("$argon2"));
}
@@ -45,6 +45,7 @@ pub(super) async fn extract_req_param<'a>(
.map(SingleOrVec::as_json_str),
StmtParam::Error(x) => anyhow::bail!("{}", x),
StmtParam::Literal(x) => Some(Cow::Owned(x.to_string())),
StmtParam::Null => None,
StmtParam::Concat(args) => concat_params(&args[..], request).await?,
StmtParam::FunctionCall(func) => func.evaluate(request).await.with_context(|| {
format!(
+2
View File
@@ -21,6 +21,7 @@ pub(crate) enum StmtParam {
GetOrPost(String),
Error(String),
Literal(String),
Null,
Concat(Vec<StmtParam>),
FunctionCall(SqlPageFunctionCall),
}
@@ -32,6 +33,7 @@ impl std::fmt::Display for StmtParam {
StmtParam::Post(name) => write!(f, ":{name}"),
StmtParam::GetOrPost(name) => write!(f, "${name}"),
StmtParam::Literal(x) => write!(f, "'{}'", x.replace('\'', "''")),
StmtParam::Null => write!(f, "NULL"),
StmtParam::Concat(items) => {
write!(f, "CONCAT(")?;
for item in items {
@@ -0,0 +1,3 @@
SELECT 'text' as component,
case when sqlpage.hash_password(null) is null then 'It works !' else 'Error !' end
as contents;