sqlpage.hash_password(NULL) now returns NULL
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user