atagen

macltok

public
Star0
Watch0
713205a95af25a47e69b765f3f76902360fe75dd
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git
tests/account.rsRust132 lines4.1 KB
1
#![cfg(feature = "sqlite")]
2
mod support;
3
4
use std::{path::PathBuf, time::SystemTime};
5
6
use macltok::{
7
    EncryptedSessionStore, EngineConfig, Event, PasswordLogin, Session, SessionRecord,
8
    SessionStore, StoreConfig,
9
};
10
use matrix_sdk::{ruma::api::client::sync::sync_events::v5, test_utils::mocks::MatrixMockServer};
11
12
#[tokio::test]
13
async fn password_session_round_trips_and_discards_with_its_store() {
14
    let server = MatrixMockServer::new().await;
15
    server
16
        .mock_versions()
17
        .with_simplified_sliding_sync()
18
        .ok()
19
        .mount()
20
        .await;
21
    server.mock_login().ok().mount().await;
22
    server
23
        .mock_sliding_sync()
24
        .ok(v5::Response::new("1".to_owned()))
25
        .mount()
26
        .await;
27
    let root = temporary_path();
28
    let store_path = root.join("store");
29
    let record_path = root.join("records").join("session");
30
    let sessions = || {
31
        EncryptedSessionStore::file(
32
            &record_path,
33
            StoreConfig::sqlite(&store_path, "test store passphrase"),
34
        )
35
    };
36
    let config = EngineConfig::default().with_initial_history_limit(0);
37
    let session = Session::login_password(
38
        PasswordLogin::new(server.uri(), "example", "wordpass")
39
            .with_device_display_name("macltok test"),
40
        &sessions(),
41
    )
42
    .await
43
    .unwrap();
44
    let (engine, handle, mut events) = session.build(config.clone()).await.unwrap();
45
    let running = tokio::spawn(engine.run());
46
    support::receive_until(&mut events, |event| {
47
        matches!(event, Event::Authenticated { .. })
48
    })
49
    .await;
50
    support::shut_down(&handle, &mut events, running).await;
51
    drop(handle);
52
53
    let wrong = EncryptedSessionStore::file(
54
        &record_path,
55
        StoreConfig::sqlite(&store_path, "someone else's passphrase"),
56
    );
57
    assert!(wrong.load().await.is_err());
58
59
    let sessions = sessions();
60
    let session = Session::restore(&sessions).await.unwrap().unwrap();
61
    let (engine, handle, mut events) = session.build(config).await.unwrap();
62
    let running = tokio::spawn(engine.run());
63
    support::receive_until(&mut events, |event| {
64
        matches!(event, Event::Authenticated { .. })
65
    })
66
    .await;
67
    support::shut_down(&handle, &mut events, running).await;
68
    drop(handle);
69
70
    sessions.discard().await.unwrap();
71
    assert!(!record_path.exists());
72
    assert!(!store_path.exists());
73
    assert!(Session::restore(&sessions).await.unwrap().is_none());
74
    std::fs::remove_dir_all(root).unwrap();
75
}
76
77
#[tokio::test]
78
async fn a_torn_or_failed_save_leaves_the_old_record() {
79
    let root = temporary_path();
80
    let record_path = root.join("session");
81
    let sessions = || {
82
        EncryptedSessionStore::file(
83
            &record_path,
84
            StoreConfig::sqlite(root.join("store"), "test store passphrase"),
85
        )
86
    };
87
    let temporary = root.join("session.tmp");
88
    sessions()
89
        .save(&record("https://old.example"))
90
        .await
91
        .unwrap();
92
93
    std::fs::write(&temporary, b"half a rec").unwrap();
94
    let loaded = sessions().load().await.unwrap().unwrap();
95
    assert_eq!(loaded.homeserver(), "https://old.example");
96
97
    std::fs::remove_file(&temporary).unwrap();
98
    std::fs::create_dir(&temporary).unwrap();
99
    assert!(
100
        sessions()
101
            .save(&record("https://new.example"))
102
            .await
103
            .is_err()
104
    );
105
    let loaded = sessions().load().await.unwrap().unwrap();
106
    assert_eq!(loaded.homeserver(), "https://old.example");
107
108
    std::fs::remove_dir_all(root).unwrap();
109
}
110
111
fn record(homeserver: &str) -> SessionRecord {
112
    serde_json::from_value(serde_json::json!({
113
        "homeserver": homeserver,
114
        "authentication": {
115
            "type": "matrix",
116
            "session": {
117
                "user_id": "@example:example.org",
118
                "device_id": "DEVICE",
119
                "access_token": "secret",
120
            },
121
        },
122
    }))
123
    .unwrap()
124
}
125
126
fn temporary_path() -> PathBuf {
127
    let nonce = SystemTime::now()
128
        .duration_since(SystemTime::UNIX_EPOCH)
129
        .unwrap()
130
        .as_nanos();
131
    PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join(format!("macltok-account-{nonce}"))
132
}