mod socket;
use super::{AuthUpdate, Connection};
use crate::axum08::SignedIn;
use crate::types::{Impersonator, NewUser, RegisterRequest, Role, UserInfo};
use crate::{Auth, AuthEvent, BootstrapAdmin, MemoryStore, generate_session_key};
const PASSWORD: &str = "password1";
fn auth() -> Auth {
Auth::builder(MemoryStore::new(), generate_session_key())
.impersonation(true)
.build()
}
async fn root(auth: &Auth) -> SignedIn {
let url = auth
.bootstrap_admin(&BootstrapAdmin::login("root"))
.await
.unwrap()
.unwrap();
let token = url.rsplit('/').next().unwrap();
register(auth, token).await
}
async fn pending(auth: &Auth, admin: &SignedIn, login: &str, role: Role) -> (UserInfo, String) {
let new = NewUser {
login: Some(login.to_owned()),
email: None,
role,
};
let (entry, link) = auth.create_user(&admin.user, &new).await.unwrap();
(entry.user, link.token)
}
async fn user(auth: &Auth, admin: &SignedIn, login: &str, role: Role) -> SignedIn {
let (_, token) = pending(auth, admin, login, role).await;
register(auth, &token).await
}
async fn register(auth: &Auth, token: &str) -> SignedIn {
let request = RegisterRequest {
password: PASSWORD.to_owned(),
};
let (user, session) = auth.register(token, &request).await.unwrap();
SignedIn { user, session }
}
fn list_events(other: &UserInfo) -> Vec<(AuthEvent, AuthUpdate)> {
vec![
(
AuthEvent::UserCreated(other.clone()),
AuthUpdate::UserCreated(other.clone()),
),
(
AuthEvent::UserChanged(other.clone()),
AuthUpdate::UserChanged(other.clone()),
),
(
AuthEvent::UserDeleted(other.id),
AuthUpdate::UserDeleted(other.id),
),
]
}
fn ending_events(conn: &SignedIn) -> Vec<AuthEvent> {
vec![
AuthEvent::SessionEnded(conn.session.id.clone()),
AuthEvent::SessionEnded("other".to_owned()),
AuthEvent::UserSessionsEnded {
user: conn.user.id,
keep: None,
},
AuthEvent::UserSessionsEnded {
user: conn.user.id,
keep: Some(conn.session.id.clone()),
},
]
}
#[tokio::test]
async fn an_admin_sees_itself_and_the_user_list() {
let auth = auth();
let root = root(&auth).await;
let (other, _) = pending(&auth, &root, "erin", Role::Regular).await;
let conn = Connection::new(auth.clone(), &root);
let me = AuthEvent::UserChanged(root.user.info());
assert_eq!(
conn.update(&me).await.unwrap(),
Some(AuthUpdate::Me(root.user.info()))
);
for (event, update) in list_events(&other) {
assert_eq!(
conn.update(&event).await.unwrap(),
Some(update),
"{event:?}"
);
}
for event in ending_events(&root) {
assert_eq!(conn.update(&event).await.unwrap(), None, "{event:?}");
}
}
#[tokio::test]
async fn an_admin_sees_real_operations() {
let auth = auth();
let root = root(&auth).await;
let ada = user(&auth, &root, "ada", Role::Admin).await;
let conn = Connection::new(auth.clone(), &ada);
let mut events = auth.events();
let new = NewUser {
login: Some("erin".to_owned()),
email: None,
role: Role::Regular,
};
let (entry, _) = auth.create_user(&root.user, &new).await.unwrap();
let event = events.recv().await.unwrap();
assert_eq!(
conn.update(&event).await.unwrap(),
Some(AuthUpdate::UserCreated(entry.user.clone()))
);
auth.delete_user(&root.user, entry.user.id).await.unwrap();
let mut updates = Vec::new();
while let Ok(event) = events.try_recv() {
updates.extend(conn.update(&event).await.unwrap());
}
assert_eq!(updates, [AuthUpdate::UserDeleted(entry.user.id)]);
}
#[tokio::test]
async fn a_regular_user_sees_only_itself() {
let auth = auth();
let root = root(&auth).await;
let erin = user(&auth, &root, "erin", Role::Regular).await;
let conn = Connection::new(auth.clone(), &erin);
let me = AuthEvent::UserChanged(erin.user.info());
assert_eq!(
conn.update(&me).await.unwrap(),
Some(AuthUpdate::Me(erin.user.info()))
);
for (event, _) in list_events(&root.user.info()) {
assert_eq!(conn.update(&event).await.unwrap(), None, "{event:?}");
}
for event in ending_events(&erin) {
assert_eq!(conn.update(&event).await.unwrap(), None, "{event:?}");
}
}
#[tokio::test]
async fn me_follows_a_role_change() {
let auth = auth();
let root = root(&auth).await;
let erin = user(&auth, &root, "erin", Role::Regular).await;
let conn = Connection::new(auth.clone(), &erin);
let promoted = auth
.set_role(&root.user, erin.user.id, Role::Admin)
.await
.unwrap();
let me = AuthEvent::UserChanged(promoted.info());
assert_eq!(
conn.update(&me).await.unwrap(),
Some(AuthUpdate::Me(promoted.info()))
);
let (event, update) = list_events(&root.user.info()).remove(0);
assert_eq!(conn.update(&event).await.unwrap(), Some(update));
}
#[tokio::test]
async fn an_impersonated_session_keeps_its_marker() {
let auth = auth();
let root = root(&auth).await;
let (erin, _) = pending(&auth, &root, "erin", Role::Regular).await;
let (erin, session) = auth
.impersonate(&root.user, &root.session, erin.id)
.await
.unwrap();
let info = erin.info();
let conn = Connection::new(
auth.clone(),
&SignedIn {
user: erin,
session,
},
);
let mut expected = info.clone();
expected.impersonated_by = Some(Impersonator {
id: root.user.id,
name: "root".to_owned(),
});
let me = AuthEvent::UserChanged(info);
assert_eq!(
conn.update(&me).await.unwrap(),
Some(AuthUpdate::Me(expected))
);
for (event, _) in list_events(&root.user.info()) {
assert_eq!(conn.update(&event).await.unwrap(), None, "{event:?}");
}
}
#[tokio::test]
async fn a_demoted_admin_stops_seeing_the_user_list() {
let auth = auth();
let root = root(&auth).await;
let ada = user(&auth, &root, "ada", Role::Admin).await;
let (erin, _) = pending(&auth, &root, "erin", Role::Regular).await;
let conn = Connection::new(auth.clone(), &ada);
let (event, update) = list_events(&erin).remove(0);
assert_eq!(conn.update(&event).await.unwrap(), Some(update));
let demoted = auth
.set_role(&root.user, ada.user.id, Role::Regular)
.await
.unwrap();
for (event, _) in list_events(&erin) {
assert_eq!(conn.update(&event).await.unwrap(), None, "{event:?}");
}
let me = AuthEvent::UserChanged(demoted.info());
assert_eq!(
conn.update(&me).await.unwrap(),
Some(AuthUpdate::Me(demoted.info()))
);
}
#[tokio::test]
async fn an_ended_session_sees_nothing() {
let auth = auth();
let root = root(&auth).await;
let ada = user(&auth, &root, "ada", Role::Admin).await;
let (erin, _) = pending(&auth, &root, "erin", Role::Regular).await;
let conn = Connection::new(auth.clone(), &ada);
let revoked = auth.revoke_access(&root.user, ada.user.id).await.unwrap();
let me = AuthEvent::UserChanged(revoked.info());
assert_eq!(conn.update(&me).await.unwrap(), None);
for (event, _) in list_events(&erin) {
assert_eq!(conn.update(&event).await.unwrap(), None, "{event:?}");
}
let conn = Connection::new(auth.clone(), &root);
auth.sign_out(&root.session.id).await.unwrap();
let me = AuthEvent::UserChanged(root.user.info());
assert_eq!(conn.update(&me).await.unwrap(), None);
for (event, _) in list_events(&erin) {
assert_eq!(conn.update(&event).await.unwrap(), None, "{event:?}");
}
}
#[tokio::test]
async fn a_lag_resyncs_an_admin_and_refreshes_anyone_else() {
let auth = auth();
let root = root(&auth).await;
let ada = user(&auth, &root, "ada", Role::Admin).await;
let erin = user(&auth, &root, "erin", Role::Regular).await;
let conn = Connection::new(auth.clone(), &root);
assert_eq!(
conn.lagged().await.unwrap(),
Some(AuthUpdate::Resync(root.user.info()))
);
let conn = Connection::new(auth.clone(), &erin);
assert_eq!(
conn.lagged().await.unwrap(),
Some(AuthUpdate::Me(erin.user.info()))
);
let conn = Connection::new(auth.clone(), &ada);
let demoted = auth
.set_role(&root.user, ada.user.id, Role::Regular)
.await
.unwrap();
assert_eq!(
conn.lagged().await.unwrap(),
Some(AuthUpdate::Me(demoted.info()))
);
let (erin, session) = auth
.impersonate(&root.user, &root.session, erin.user.id)
.await
.unwrap();
let mut expected = erin.info();
expected.impersonated_by = Some(Impersonator {
id: root.user.id,
name: "root".to_owned(),
});
let conn = Connection::new(
auth.clone(),
&SignedIn {
user: erin,
session,
},
);
assert_eq!(conn.lagged().await.unwrap(), Some(AuthUpdate::Me(expected)));
}
#[tokio::test]
async fn a_lag_on_an_ended_session_sends_nothing() {
let auth = auth();
let root = root(&auth).await;
let ada = user(&auth, &root, "ada", Role::Admin).await;
let conn = Connection::new(auth.clone(), &ada);
auth.revoke_access(&root.user, ada.user.id).await.unwrap();
assert_eq!(conn.lagged().await.unwrap(), None);
let conn = Connection::new(auth.clone(), &root);
auth.sign_out(&root.session.id).await.unwrap();
assert_eq!(conn.lagged().await.unwrap(), None);
}