feat: classic ui account deletion
This commit is contained in:
@@ -206,11 +206,7 @@ async fn classic_admin_delete_redirects_to_the_member_list() {
|
||||
let uri = format!("/users/{}/delete", bob.user_id);
|
||||
|
||||
let (status, headers, _) = send(&router, classic_post(&uri, &alice.cookie, PASSWORD)).await;
|
||||
assert_eq!(status, 303);
|
||||
assert!(
|
||||
location(&headers).contains("error="),
|
||||
"non-admin: {headers:?}"
|
||||
);
|
||||
assert_eq!(status, 403, "non-admin: {headers:?}");
|
||||
|
||||
promote(&pool, &alice.user_id).await;
|
||||
let (status, headers, _) = send(&router, classic_post(&uri, &alice.cookie, PASSWORD)).await;
|
||||
@@ -221,3 +217,93 @@ async fn classic_admin_delete_redirects_to_the_member_list() {
|
||||
let (status, _, _) = send(&router, get(&format!("/users/{}", bob.user_id), None)).await;
|
||||
assert_eq!(status, 404);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn classic_admin_delete_requires_the_csrf_token() {
|
||||
let (router, pool, alice, bob) = two_users().await;
|
||||
promote(&pool, &alice.user_id).await;
|
||||
let req = Request::builder()
|
||||
.method(Method::POST)
|
||||
.uri(format!("/users/{}/delete", bob.user_id))
|
||||
.header(header::CONTENT_TYPE, "application/x-www-form-urlencoded")
|
||||
.header(header::COOKIE, &alice.cookie)
|
||||
.body(Body::from(format!("password={PASSWORD}&_csrf=wrong")))
|
||||
.unwrap();
|
||||
let (status, _, _) = send(&router, req).await;
|
||||
assert_eq!(status, 403);
|
||||
let (status, _, _) = send(&router, get(&format!("/users/{}", bob.user_id), None)).await;
|
||||
assert_eq!(status, 200, "target must survive a CSRF rejection");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_non_admin_classic_delete_of_someone_else_is_forbidden() {
|
||||
let (router, _pool, alice, bob) = two_users().await;
|
||||
let uri = format!("/users/{}/delete", bob.user_id);
|
||||
let (status, _, _) = send(&router, classic_post(&uri, &alice.cookie, PASSWORD)).await;
|
||||
assert_eq!(status, 403);
|
||||
let (status, _, _) = send(&router, get(&format!("/users/{}", bob.user_id), None)).await;
|
||||
assert_eq!(status, 200);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn classic_admin_self_delete_logs_out_unless_last_admin() {
|
||||
let (router, pool, alice, bob) = two_users().await;
|
||||
promote(&pool, &alice.user_id).await;
|
||||
let uri = format!("/users/{}/delete", alice.user_id);
|
||||
|
||||
// Sole admin: refused, redirected back with an error, still logged in.
|
||||
let (status, headers, _) = send(&router, classic_post(&uri, &alice.cookie, PASSWORD)).await;
|
||||
assert_eq!(status, 303);
|
||||
assert!(location(&headers).contains("error="), "{headers:?}");
|
||||
assert!(support::cookie_value(&headers, "token").is_none());
|
||||
let (status, _, _) = send(&router, get(&format!("/users/{}", alice.user_id), None)).await;
|
||||
assert_eq!(status, 200);
|
||||
|
||||
// With a second admin the self-delete goes through and ends the session.
|
||||
promote(&pool, &bob.user_id).await;
|
||||
let (status, headers, _) = send(&router, classic_post(&uri, &alice.cookie, PASSWORD)).await;
|
||||
assert_eq!(status, 303);
|
||||
assert_eq!(location(&headers), "/");
|
||||
assert_eq!(
|
||||
support::cookie_value(&headers, "token").as_deref(),
|
||||
Some("")
|
||||
);
|
||||
let (status, _, _) = send(&router, get(&format!("/users/{}", alice.user_id), None)).await;
|
||||
assert_eq!(status, 404);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_forms_render_only_where_they_apply() {
|
||||
let (router, pool, alice, bob) = two_users().await;
|
||||
let own_delete = "action=\"/settings/account/delete\"";
|
||||
let user_delete = |id: &str| format!("action=\"/users/{id}/delete\"");
|
||||
|
||||
let (_, _, body) = send(&router, get("/settings/profile", Some(&alice.cookie))).await;
|
||||
assert!(body.contains(own_delete), "owner settings page");
|
||||
|
||||
// A non-admin viewing someone else, and anonymous viewers, see no form.
|
||||
let bob_page = format!("/users/{}", bob.user_id);
|
||||
let (_, _, body) = send(&router, get(&bob_page, Some(&alice.cookie))).await;
|
||||
assert!(!body.contains(&user_delete(&bob.user_id)), "non-admin");
|
||||
|
||||
promote(&pool, &alice.user_id).await;
|
||||
let (_, _, body) = send(&router, get(&bob_page, Some(&alice.cookie))).await;
|
||||
assert!(body.contains(&user_delete(&bob.user_id)), "admin on other");
|
||||
|
||||
let (_, _, body) = send(
|
||||
&router,
|
||||
get(&format!("/users/{}", alice.user_id), Some(&alice.cookie)),
|
||||
)
|
||||
.await;
|
||||
assert!(
|
||||
!body.contains(&user_delete(&alice.user_id)),
|
||||
"admin on self"
|
||||
);
|
||||
|
||||
let (_, _, body) = send(
|
||||
&router,
|
||||
get(&format!("{bob_page}?embed=true"), Some(&alice.cookie)),
|
||||
)
|
||||
.await;
|
||||
assert!(!body.contains("/delete"), "embed page");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user