Automatic merge back to main (#5156)
This commit is contained in:
56
Cargo.lock
generated
56
Cargo.lock
generated
@@ -3104,7 +3104,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-axum-utils"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -3138,7 +3138,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-cli"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -3211,7 +3211,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-config"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
@@ -3243,7 +3243,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-context"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"console",
|
||||
"opentelemetry",
|
||||
@@ -3259,7 +3259,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-data-model"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"chrono",
|
||||
@@ -3282,7 +3282,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-email"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"lettre",
|
||||
@@ -3293,7 +3293,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-handlers"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"aide",
|
||||
"anyhow",
|
||||
@@ -3373,7 +3373,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-http"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"headers",
|
||||
@@ -3394,7 +3394,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-i18n"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"icu_calendar",
|
||||
@@ -3416,7 +3416,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-i18n-scan"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"clap",
|
||||
@@ -3430,7 +3430,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-iana"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
@@ -3438,7 +3438,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-iana-codegen"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3454,7 +3454,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-jose"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"chrono",
|
||||
@@ -3484,7 +3484,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-keystore"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"base64ct",
|
||||
@@ -3512,7 +3512,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-listener"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -3537,7 +3537,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-matrix"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3547,7 +3547,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-matrix-synapse"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3564,7 +3564,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-oidc-client"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"assert_matches",
|
||||
"async-trait",
|
||||
@@ -3600,7 +3600,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-policy"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -3617,7 +3617,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-router"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"serde",
|
||||
@@ -3628,7 +3628,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-spa"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"serde",
|
||||
@@ -3637,7 +3637,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-storage"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -3659,7 +3659,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-storage-pg"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -3687,7 +3687,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-tasks"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3719,7 +3719,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-templates"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -3749,7 +3749,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mas-tower"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"http",
|
||||
"opentelemetry",
|
||||
@@ -4019,7 +4019,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oauth2-types"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"assert_matches",
|
||||
"base64ct",
|
||||
@@ -6101,7 +6101,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn2mas"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
||||
60
Cargo.toml
60
Cargo.toml
@@ -9,7 +9,7 @@ members = ["crates/*"]
|
||||
resolver = "2"
|
||||
|
||||
# Updated in the CI with a `sed` command
|
||||
package.version = "1.4.0"
|
||||
package.version = "1.4.1"
|
||||
package.license = "AGPL-3.0-only OR LicenseRef-Element-Commercial"
|
||||
package.authors = ["Element Backend Team"]
|
||||
package.edition = "2024"
|
||||
@@ -34,35 +34,35 @@ broken_intra_doc_links = "deny"
|
||||
[workspace.dependencies]
|
||||
|
||||
# Workspace crates
|
||||
mas-axum-utils = { path = "./crates/axum-utils/", version = "=1.4.0" }
|
||||
mas-cli = { path = "./crates/cli/", version = "=1.4.0" }
|
||||
mas-config = { path = "./crates/config/", version = "=1.4.0" }
|
||||
mas-context = { path = "./crates/context/", version = "=1.4.0" }
|
||||
mas-data-model = { path = "./crates/data-model/", version = "=1.4.0" }
|
||||
mas-email = { path = "./crates/email/", version = "=1.4.0" }
|
||||
mas-graphql = { path = "./crates/graphql/", version = "=1.4.0" }
|
||||
mas-handlers = { path = "./crates/handlers/", version = "=1.4.0" }
|
||||
mas-http = { path = "./crates/http/", version = "=1.4.0" }
|
||||
mas-i18n = { path = "./crates/i18n/", version = "=1.4.0" }
|
||||
mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=1.4.0" }
|
||||
mas-iana = { path = "./crates/iana/", version = "=1.4.0" }
|
||||
mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=1.4.0" }
|
||||
mas-jose = { path = "./crates/jose/", version = "=1.4.0" }
|
||||
mas-keystore = { path = "./crates/keystore/", version = "=1.4.0" }
|
||||
mas-listener = { path = "./crates/listener/", version = "=1.4.0" }
|
||||
mas-matrix = { path = "./crates/matrix/", version = "=1.4.0" }
|
||||
mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=1.4.0" }
|
||||
mas-oidc-client = { path = "./crates/oidc-client/", version = "=1.4.0" }
|
||||
mas-policy = { path = "./crates/policy/", version = "=1.4.0" }
|
||||
mas-router = { path = "./crates/router/", version = "=1.4.0" }
|
||||
mas-spa = { path = "./crates/spa/", version = "=1.4.0" }
|
||||
mas-storage = { path = "./crates/storage/", version = "=1.4.0" }
|
||||
mas-storage-pg = { path = "./crates/storage-pg/", version = "=1.4.0" }
|
||||
mas-tasks = { path = "./crates/tasks/", version = "=1.4.0" }
|
||||
mas-templates = { path = "./crates/templates/", version = "=1.4.0" }
|
||||
mas-tower = { path = "./crates/tower/", version = "=1.4.0" }
|
||||
oauth2-types = { path = "./crates/oauth2-types/", version = "=1.4.0" }
|
||||
syn2mas = { path = "./crates/syn2mas", version = "=1.4.0" }
|
||||
mas-axum-utils = { path = "./crates/axum-utils/", version = "=1.4.1" }
|
||||
mas-cli = { path = "./crates/cli/", version = "=1.4.1" }
|
||||
mas-config = { path = "./crates/config/", version = "=1.4.1" }
|
||||
mas-context = { path = "./crates/context/", version = "=1.4.1" }
|
||||
mas-data-model = { path = "./crates/data-model/", version = "=1.4.1" }
|
||||
mas-email = { path = "./crates/email/", version = "=1.4.1" }
|
||||
mas-graphql = { path = "./crates/graphql/", version = "=1.4.1" }
|
||||
mas-handlers = { path = "./crates/handlers/", version = "=1.4.1" }
|
||||
mas-http = { path = "./crates/http/", version = "=1.4.1" }
|
||||
mas-i18n = { path = "./crates/i18n/", version = "=1.4.1" }
|
||||
mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=1.4.1" }
|
||||
mas-iana = { path = "./crates/iana/", version = "=1.4.1" }
|
||||
mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=1.4.1" }
|
||||
mas-jose = { path = "./crates/jose/", version = "=1.4.1" }
|
||||
mas-keystore = { path = "./crates/keystore/", version = "=1.4.1" }
|
||||
mas-listener = { path = "./crates/listener/", version = "=1.4.1" }
|
||||
mas-matrix = { path = "./crates/matrix/", version = "=1.4.1" }
|
||||
mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=1.4.1" }
|
||||
mas-oidc-client = { path = "./crates/oidc-client/", version = "=1.4.1" }
|
||||
mas-policy = { path = "./crates/policy/", version = "=1.4.1" }
|
||||
mas-router = { path = "./crates/router/", version = "=1.4.1" }
|
||||
mas-spa = { path = "./crates/spa/", version = "=1.4.1" }
|
||||
mas-storage = { path = "./crates/storage/", version = "=1.4.1" }
|
||||
mas-storage-pg = { path = "./crates/storage-pg/", version = "=1.4.1" }
|
||||
mas-tasks = { path = "./crates/tasks/", version = "=1.4.1" }
|
||||
mas-templates = { path = "./crates/templates/", version = "=1.4.1" }
|
||||
mas-tower = { path = "./crates/tower/", version = "=1.4.1" }
|
||||
oauth2-types = { path = "./crates/oauth2-types/", version = "=1.4.1" }
|
||||
syn2mas = { path = "./crates/syn2mas", version = "=1.4.1" }
|
||||
|
||||
# OpenAPI schema generation and validation
|
||||
[workspace.dependencies.aide]
|
||||
|
||||
@@ -84,7 +84,7 @@ async fn verify_password_if_needed(
|
||||
password,
|
||||
user_password.hashed_password,
|
||||
)
|
||||
.await;
|
||||
.await?;
|
||||
|
||||
Ok(res.is_ok())
|
||||
Ok(res.is_success())
|
||||
}
|
||||
|
||||
@@ -737,13 +737,14 @@ impl UserMutations {
|
||||
));
|
||||
};
|
||||
|
||||
if let Err(_err) = password_manager
|
||||
if !password_manager
|
||||
.verify(
|
||||
active_password.version,
|
||||
Zeroizing::new(current_password_attempt),
|
||||
active_password.hashed_password,
|
||||
)
|
||||
.await
|
||||
.await?
|
||||
.is_success()
|
||||
{
|
||||
return Ok(SetPasswordPayload {
|
||||
status: SetPasswordStatus::WrongPassword,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
use axum::http::Request;
|
||||
use hyper::StatusCode;
|
||||
use mas_axum_utils::SessionInfoExt;
|
||||
use mas_data_model::{AccessToken, Client, TokenType, User};
|
||||
use mas_matrix::{HomeserverConnection, ProvisionRequest};
|
||||
use mas_router::SimpleRoute;
|
||||
@@ -19,11 +20,9 @@ use oauth2_types::{
|
||||
scope::{OPENID, Scope, ScopeToken},
|
||||
};
|
||||
use sqlx::PgPool;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use crate::{
|
||||
test_utils,
|
||||
test_utils::{RequestBuilderExt, ResponseExt, TestState, setup},
|
||||
};
|
||||
use crate::test_utils::{self, CookieHelper, RequestBuilderExt, ResponseExt, TestState, setup};
|
||||
|
||||
async fn create_test_client(state: &TestState) -> Client {
|
||||
let mut repo = state.repository().await.unwrap();
|
||||
@@ -781,3 +780,301 @@ async fn test_add_user(pool: PgPool) {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/// Test the setPassword mutation where the current password provided is
|
||||
/// wrong.
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_set_password_rejected_wrong_password(pool: PgPool) {
|
||||
setup();
|
||||
let state = TestState::from_pool(pool).await.unwrap();
|
||||
|
||||
let mut rng = state.rng();
|
||||
let mut repo = state.repository().await.unwrap();
|
||||
let user = repo
|
||||
.user()
|
||||
.add(&mut rng, &state.clock, "alice".to_owned())
|
||||
.await
|
||||
.unwrap();
|
||||
let password = Zeroizing::new("current.password.123".to_owned());
|
||||
let (version, hashed_password) = state
|
||||
.password_manager
|
||||
.hash(&mut rng, password)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
repo.user_password()
|
||||
.add(
|
||||
&mut rng,
|
||||
&state.clock,
|
||||
&user,
|
||||
version,
|
||||
hashed_password,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let browser_session = repo
|
||||
.browser_session()
|
||||
.add(&mut rng, &state.clock, &user, None)
|
||||
.await
|
||||
.unwrap();
|
||||
repo.save().await.unwrap();
|
||||
|
||||
let cookie_jar = state.cookie_jar();
|
||||
let cookie_jar = cookie_jar.set_session(&browser_session);
|
||||
|
||||
let user_id = user.id;
|
||||
|
||||
let request = Request::post("/graphql").json(serde_json::json!({
|
||||
"query": format!(r#"
|
||||
mutation {{
|
||||
setPassword(input: {{
|
||||
userId: "user:{user_id}",
|
||||
currentPassword: "wrong.password.123",
|
||||
newPassword: "new.password.123"
|
||||
}}) {{
|
||||
status
|
||||
}}
|
||||
}}
|
||||
"#),
|
||||
}));
|
||||
|
||||
let cookies = CookieHelper::new();
|
||||
cookies.import(cookie_jar);
|
||||
let request = cookies.with_cookies(request);
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let response: GraphQLResponse = response.json();
|
||||
assert!(response.errors.is_empty(), "{:?}", response.errors);
|
||||
assert_eq!(
|
||||
response.data["setPassword"]["status"].as_str(),
|
||||
Some("WRONG_PASSWORD"),
|
||||
"{:?}",
|
||||
response.data
|
||||
);
|
||||
}
|
||||
|
||||
/// Test the startEmailAuthentication mutation where the current password
|
||||
/// provided is invalid.
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_start_email_authentication_rejected_wrong_password(pool: PgPool) {
|
||||
setup();
|
||||
let state = TestState::from_pool(pool).await.unwrap();
|
||||
|
||||
let mut rng = state.rng();
|
||||
let mut repo = state.repository().await.unwrap();
|
||||
let user = repo
|
||||
.user()
|
||||
.add(&mut rng, &state.clock, "alice".to_owned())
|
||||
.await
|
||||
.unwrap();
|
||||
let password = Zeroizing::new("current.password.123".to_owned());
|
||||
let (version, hashed_password) = state
|
||||
.password_manager
|
||||
.hash(&mut rng, password)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
repo.user_password()
|
||||
.add(
|
||||
&mut rng,
|
||||
&state.clock,
|
||||
&user,
|
||||
version,
|
||||
hashed_password,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let browser_session = repo
|
||||
.browser_session()
|
||||
.add(&mut rng, &state.clock, &user, None)
|
||||
.await
|
||||
.unwrap();
|
||||
repo.save().await.unwrap();
|
||||
|
||||
let cookie_jar = state.cookie_jar();
|
||||
let cookie_jar = cookie_jar.set_session(&browser_session);
|
||||
|
||||
let request = Request::post("/graphql").json(serde_json::json!({
|
||||
"query": r#"
|
||||
mutation {
|
||||
startEmailAuthentication(input: {
|
||||
email: "alice@example.org",
|
||||
password: "wrong.password.123"
|
||||
}) {
|
||||
status
|
||||
}
|
||||
}
|
||||
"#,
|
||||
}));
|
||||
|
||||
let cookies = CookieHelper::new();
|
||||
cookies.import(cookie_jar);
|
||||
let request = cookies.with_cookies(request);
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let response: GraphQLResponse = response.json();
|
||||
assert!(response.errors.is_empty(), "{:?}", response.errors);
|
||||
assert_eq!(
|
||||
response.data["startEmailAuthentication"]["status"].as_str(),
|
||||
Some("INCORRECT_PASSWORD"),
|
||||
"{:?}",
|
||||
response.data
|
||||
);
|
||||
}
|
||||
|
||||
/// Test the removeEmail mutation where the current password
|
||||
/// provided is invalid.
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_remove_email_rejected_wrong_password(pool: PgPool) {
|
||||
setup();
|
||||
let state = TestState::from_pool(pool).await.unwrap();
|
||||
|
||||
let mut rng = state.rng();
|
||||
let mut repo = state.repository().await.unwrap();
|
||||
let user = repo
|
||||
.user()
|
||||
.add(&mut rng, &state.clock, "alice".to_owned())
|
||||
.await
|
||||
.unwrap();
|
||||
let password = Zeroizing::new("current.password.123".to_owned());
|
||||
let (version, hashed_password) = state
|
||||
.password_manager
|
||||
.hash(&mut rng, password)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
repo.user_password()
|
||||
.add(
|
||||
&mut rng,
|
||||
&state.clock,
|
||||
&user,
|
||||
version,
|
||||
hashed_password,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let user_email_id = repo
|
||||
.user_email()
|
||||
.add(
|
||||
&mut rng,
|
||||
&state.clock,
|
||||
&user,
|
||||
"alice@example.org".to_owned(),
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.id;
|
||||
let browser_session = repo
|
||||
.browser_session()
|
||||
.add(&mut rng, &state.clock, &user, None)
|
||||
.await
|
||||
.unwrap();
|
||||
repo.save().await.unwrap();
|
||||
|
||||
let cookie_jar = state.cookie_jar();
|
||||
let cookie_jar = cookie_jar.set_session(&browser_session);
|
||||
|
||||
let request = Request::post("/graphql").json(serde_json::json!({
|
||||
"query": format!(r#"
|
||||
mutation {{
|
||||
removeEmail(input: {{
|
||||
userEmailId: "user_email:{user_email_id}",
|
||||
password: "wrong.password.123"
|
||||
}}) {{
|
||||
status
|
||||
}}
|
||||
}}
|
||||
"#),
|
||||
}));
|
||||
|
||||
let cookies = CookieHelper::new();
|
||||
cookies.import(cookie_jar);
|
||||
let request = cookies.with_cookies(request);
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let response: GraphQLResponse = response.json();
|
||||
assert!(response.errors.is_empty(), "{:?}", response.errors);
|
||||
assert_eq!(
|
||||
response.data["removeEmail"]["status"].as_str(),
|
||||
Some("INCORRECT_PASSWORD"),
|
||||
"{:?}",
|
||||
response.data
|
||||
);
|
||||
}
|
||||
|
||||
/// Test the deactivateUser mutation where the current password
|
||||
/// provided is invalid.
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_deactivate_user_rejected_wrong_password(pool: PgPool) {
|
||||
setup();
|
||||
let state = TestState::from_pool(pool).await.unwrap();
|
||||
|
||||
let mut rng = state.rng();
|
||||
let mut repo = state.repository().await.unwrap();
|
||||
let user = repo
|
||||
.user()
|
||||
.add(&mut rng, &state.clock, "alice".to_owned())
|
||||
.await
|
||||
.unwrap();
|
||||
let password = Zeroizing::new("current.password.123".to_owned());
|
||||
let (version, hashed_password) = state
|
||||
.password_manager
|
||||
.hash(&mut rng, password)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
repo.user_password()
|
||||
.add(
|
||||
&mut rng,
|
||||
&state.clock,
|
||||
&user,
|
||||
version,
|
||||
hashed_password,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let browser_session = repo
|
||||
.browser_session()
|
||||
.add(&mut rng, &state.clock, &user, None)
|
||||
.await
|
||||
.unwrap();
|
||||
repo.save().await.unwrap();
|
||||
|
||||
let cookie_jar = state.cookie_jar();
|
||||
let cookie_jar = cookie_jar.set_session(&browser_session);
|
||||
|
||||
let request = Request::post("/graphql").json(serde_json::json!({
|
||||
"query": r#"
|
||||
mutation {
|
||||
deactivateUser(input: {
|
||||
hsErase: true,
|
||||
password: "wrong.password.123"
|
||||
}) {
|
||||
status
|
||||
}
|
||||
}
|
||||
"#,
|
||||
}));
|
||||
|
||||
let cookies = CookieHelper::new();
|
||||
cookies.import(cookie_jar);
|
||||
let request = cookies.with_cookies(request);
|
||||
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let response: GraphQLResponse = response.json();
|
||||
assert!(response.errors.is_empty(), "{:?}", response.errors);
|
||||
assert_eq!(
|
||||
response.data["deactivateUser"]["status"].as_str(),
|
||||
Some("INCORRECT_PASSWORD"),
|
||||
"{:?}",
|
||||
response.data
|
||||
);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ impl<T> PasswordVerificationResult<T> {
|
||||
Self::Failure => PasswordVerificationResult::Failure,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_success(&self) -> bool {
|
||||
matches!(self, Self::Success(_))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for PasswordVerificationResult<()> {
|
||||
|
||||
Reference in New Issue
Block a user