atagen

macltok

public
Star0
Watch0
713205a95af25a47e69b765f3f76902360fe75dd
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git

Blame: tests/account.rs

96fdf90aacd6atagen2026-09-08 08:24 UTC1
#![cfg(feature = "sqlite")]
31ce2453c82fatagen2026-09-24 13:07 UTC2
mod support;
96fdf90aacd6atagen2026-09-08 08:24 UTC3
713205a95af2atagen2026-09-26 09:24 UTC4
use std::{path::PathBuf, time::SystemTime};
31ce2453c82fatagen2026-09-24 13:07 UTC5
713205a95af2atagen2026-09-26 09:24 UTC6
use macltok::{
713205a95af2atagen2026-09-26 09:24 UTC7
    EncryptedSessionStore, EngineConfig, Event, PasswordLogin, Session, SessionRecord,
713205a95af2atagen2026-09-26 09:24 UTC8
    SessionStore, StoreConfig,
713205a95af2atagen2026-09-26 09:24 UTC9
};
96fdf90aacd6atagen2026-09-08 08:24 UTC10
use matrix_sdk::{ruma::api::client::sync::sync_events::v5, test_utils::mocks::MatrixMockServer};
96fdf90aacd6atagen2026-09-08 08:24 UTC11
96fdf90aacd6atagen2026-09-08 08:24 UTC12
#[tokio::test]
713205a95af2atagen2026-09-26 09:24 UTC13
async fn password_session_round_trips_and_discards_with_its_store() {
96fdf90aacd6atagen2026-09-08 08:24 UTC14
    let server = MatrixMockServer::new().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC15
    server
96fdf90aacd6atagen2026-09-08 08:24 UTC16
        .mock_versions()
96fdf90aacd6atagen2026-09-08 08:24 UTC17
        .with_simplified_sliding_sync()
96fdf90aacd6atagen2026-09-08 08:24 UTC18
        .ok()
96fdf90aacd6atagen2026-09-08 08:24 UTC19
        .mount()
96fdf90aacd6atagen2026-09-08 08:24 UTC20
        .await;
96fdf90aacd6atagen2026-09-08 08:24 UTC21
    server.mock_login().ok().mount().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC22
    server
96fdf90aacd6atagen2026-09-08 08:24 UTC23
        .mock_sliding_sync()
96fdf90aacd6atagen2026-09-08 08:24 UTC24
        .ok(v5::Response::new("1".to_owned()))
96fdf90aacd6atagen2026-09-08 08:24 UTC25
        .mount()
96fdf90aacd6atagen2026-09-08 08:24 UTC26
        .await;
713205a95af2atagen2026-09-26 09:24 UTC27
    let root = temporary_path();
713205a95af2atagen2026-09-26 09:24 UTC28
    let store_path = root.join("store");
713205a95af2atagen2026-09-26 09:24 UTC29
    let record_path = root.join("records").join("session");
713205a95af2atagen2026-09-26 09:24 UTC30
    let sessions = || {
713205a95af2atagen2026-09-26 09:24 UTC31
        EncryptedSessionStore::file(
713205a95af2atagen2026-09-26 09:24 UTC32
            &record_path,
713205a95af2atagen2026-09-26 09:24 UTC33
            StoreConfig::sqlite(&store_path, "test store passphrase"),
713205a95af2atagen2026-09-26 09:24 UTC34
        )
713205a95af2atagen2026-09-26 09:24 UTC35
    };
96fdf90aacd6atagen2026-09-08 08:24 UTC36
    let config = EngineConfig::default().with_initial_history_limit(0);
96fdf90aacd6atagen2026-09-08 08:24 UTC37
    let session = Session::login_password(
31ce2453c82fatagen2026-09-24 13:07 UTC38
        PasswordLogin::new(server.uri(), "example", "wordpass")
31ce2453c82fatagen2026-09-24 13:07 UTC39
            .with_device_display_name("macltok test"),
713205a95af2atagen2026-09-26 09:24 UTC40
        &sessions(),
96fdf90aacd6atagen2026-09-08 08:24 UTC41
    )
96fdf90aacd6atagen2026-09-08 08:24 UTC42
    .await
96fdf90aacd6atagen2026-09-08 08:24 UTC43
    .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC44
    let (engine, handle, mut events) = session.build(config.clone()).await.unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC45
    let running = tokio::spawn(engine.run());
31ce2453c82fatagen2026-09-24 13:07 UTC46
    support::receive_until(&mut events, |event| {
31ce2453c82fatagen2026-09-24 13:07 UTC47
        matches!(event, Event::Authenticated { .. })
31ce2453c82fatagen2026-09-24 13:07 UTC48
    })
31ce2453c82fatagen2026-09-24 13:07 UTC49
    .await;
31ce2453c82fatagen2026-09-24 13:07 UTC50
    support::shut_down(&handle, &mut events, running).await;
713205a95af2atagen2026-09-26 09:24 UTC51
    drop(handle);
96fdf90aacd6atagen2026-09-08 08:24 UTC52
713205a95af2atagen2026-09-26 09:24 UTC53
    let wrong = EncryptedSessionStore::file(
713205a95af2atagen2026-09-26 09:24 UTC54
        &record_path,
713205a95af2atagen2026-09-26 09:24 UTC55
        StoreConfig::sqlite(&store_path, "someone else's passphrase"),
713205a95af2atagen2026-09-26 09:24 UTC56
    );
713205a95af2atagen2026-09-26 09:24 UTC57
    assert!(wrong.load().await.is_err());
713205a95af2atagen2026-09-26 09:24 UTC58
713205a95af2atagen2026-09-26 09:24 UTC59
    let sessions = sessions();
713205a95af2atagen2026-09-26 09:24 UTC60
    let session = Session::restore(&sessions).await.unwrap().unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC61
    let (engine, handle, mut events) = session.build(config).await.unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC62
    let running = tokio::spawn(engine.run());
31ce2453c82fatagen2026-09-24 13:07 UTC63
    support::receive_until(&mut events, |event| {
31ce2453c82fatagen2026-09-24 13:07 UTC64
        matches!(event, Event::Authenticated { .. })
31ce2453c82fatagen2026-09-24 13:07 UTC65
    })
31ce2453c82fatagen2026-09-24 13:07 UTC66
    .await;
31ce2453c82fatagen2026-09-24 13:07 UTC67
    support::shut_down(&handle, &mut events, running).await;
713205a95af2atagen2026-09-26 09:24 UTC68
    drop(handle);
713205a95af2atagen2026-09-26 09:24 UTC69
713205a95af2atagen2026-09-26 09:24 UTC70
    sessions.discard().await.unwrap();
713205a95af2atagen2026-09-26 09:24 UTC71
    assert!(!record_path.exists());
713205a95af2atagen2026-09-26 09:24 UTC72
    assert!(!store_path.exists());
713205a95af2atagen2026-09-26 09:24 UTC73
    assert!(Session::restore(&sessions).await.unwrap().is_none());
713205a95af2atagen2026-09-26 09:24 UTC74
    std::fs::remove_dir_all(root).unwrap();
713205a95af2atagen2026-09-26 09:24 UTC75
}
713205a95af2atagen2026-09-26 09:24 UTC76
713205a95af2atagen2026-09-26 09:24 UTC77
#[tokio::test]
713205a95af2atagen2026-09-26 09:24 UTC78
async fn a_torn_or_failed_save_leaves_the_old_record() {
713205a95af2atagen2026-09-26 09:24 UTC79
    let root = temporary_path();
713205a95af2atagen2026-09-26 09:24 UTC80
    let record_path = root.join("session");
713205a95af2atagen2026-09-26 09:24 UTC81
    let sessions = || {
713205a95af2atagen2026-09-26 09:24 UTC82
        EncryptedSessionStore::file(
713205a95af2atagen2026-09-26 09:24 UTC83
            &record_path,
713205a95af2atagen2026-09-26 09:24 UTC84
            StoreConfig::sqlite(root.join("store"), "test store passphrase"),
713205a95af2atagen2026-09-26 09:24 UTC85
        )
713205a95af2atagen2026-09-26 09:24 UTC86
    };
713205a95af2atagen2026-09-26 09:24 UTC87
    let temporary = root.join("session.tmp");
713205a95af2atagen2026-09-26 09:24 UTC88
    sessions()
713205a95af2atagen2026-09-26 09:24 UTC89
        .save(&record("https://old.example"))
713205a95af2atagen2026-09-26 09:24 UTC90
        .await
713205a95af2atagen2026-09-26 09:24 UTC91
        .unwrap();
713205a95af2atagen2026-09-26 09:24 UTC92
713205a95af2atagen2026-09-26 09:24 UTC93
    std::fs::write(&temporary, b"half a rec").unwrap();
713205a95af2atagen2026-09-26 09:24 UTC94
    let loaded = sessions().load().await.unwrap().unwrap();
713205a95af2atagen2026-09-26 09:24 UTC95
    assert_eq!(loaded.homeserver(), "https://old.example");
713205a95af2atagen2026-09-26 09:24 UTC96
713205a95af2atagen2026-09-26 09:24 UTC97
    std::fs::remove_file(&temporary).unwrap();
713205a95af2atagen2026-09-26 09:24 UTC98
    std::fs::create_dir(&temporary).unwrap();
713205a95af2atagen2026-09-26 09:24 UTC99
    assert!(
713205a95af2atagen2026-09-26 09:24 UTC100
        sessions()
713205a95af2atagen2026-09-26 09:24 UTC101
            .save(&record("https://new.example"))
713205a95af2atagen2026-09-26 09:24 UTC102
            .await
713205a95af2atagen2026-09-26 09:24 UTC103
            .is_err()
713205a95af2atagen2026-09-26 09:24 UTC104
    );
713205a95af2atagen2026-09-26 09:24 UTC105
    let loaded = sessions().load().await.unwrap().unwrap();
713205a95af2atagen2026-09-26 09:24 UTC106
    assert_eq!(loaded.homeserver(), "https://old.example");
713205a95af2atagen2026-09-26 09:24 UTC107
713205a95af2atagen2026-09-26 09:24 UTC108
    std::fs::remove_dir_all(root).unwrap();
713205a95af2atagen2026-09-26 09:24 UTC109
}
96fdf90aacd6atagen2026-09-08 08:24 UTC110
713205a95af2atagen2026-09-26 09:24 UTC111
fn record(homeserver: &str) -> SessionRecord {
713205a95af2atagen2026-09-26 09:24 UTC112
    serde_json::from_value(serde_json::json!({
713205a95af2atagen2026-09-26 09:24 UTC113
        "homeserver": homeserver,
713205a95af2atagen2026-09-26 09:24 UTC114
        "authentication": {
713205a95af2atagen2026-09-26 09:24 UTC115
            "type": "matrix",
713205a95af2atagen2026-09-26 09:24 UTC116
            "session": {
713205a95af2atagen2026-09-26 09:24 UTC117
                "user_id": "@example:example.org",
713205a95af2atagen2026-09-26 09:24 UTC118
                "device_id": "DEVICE",
713205a95af2atagen2026-09-26 09:24 UTC119
                "access_token": "secret",
713205a95af2atagen2026-09-26 09:24 UTC120
            },
713205a95af2atagen2026-09-26 09:24 UTC121
        },
713205a95af2atagen2026-09-26 09:24 UTC122
    }))
713205a95af2atagen2026-09-26 09:24 UTC123
    .unwrap()
96fdf90aacd6atagen2026-09-08 08:24 UTC124
}
96fdf90aacd6atagen2026-09-08 08:24 UTC125
713205a95af2atagen2026-09-26 09:24 UTC126
fn temporary_path() -> PathBuf {
96fdf90aacd6atagen2026-09-08 08:24 UTC127
    let nonce = SystemTime::now()
96fdf90aacd6atagen2026-09-08 08:24 UTC128
        .duration_since(SystemTime::UNIX_EPOCH)
96fdf90aacd6atagen2026-09-08 08:24 UTC129
        .unwrap()
96fdf90aacd6atagen2026-09-08 08:24 UTC130
        .as_nanos();
713205a95af2atagen2026-09-26 09:24 UTC131
    PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join(format!("macltok-account-{nonce}"))
96fdf90aacd6atagen2026-09-08 08:24 UTC132
}