atagen

malice

public
Star0
Watch0
d67da9aec471fb9247bdddcbce01c951d6ae9854
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
crates/malice-push/tests/send.rsRust107 lines3.6 KB
1
use aws_lc_rs::agreement::{ECDH_P256, PrivateKey};
2
use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
3
use malice_push::{Allowlist, Message, Outcome, Sender, Subscription, Urgency, Vapid, ece};
4
use wiremock::{
5
    Mock, MockServer, ResponseTemplate,
6
    matchers::{header, method, path},
7
};
8
9
struct Browser {
10
    private: PrivateKey,
11
    auth: [u8; 16],
12
}
13
14
impl Browser {
15
    fn new() -> Self {
16
        Self {
17
            private: PrivateKey::generate(&ECDH_P256).unwrap(),
18
            auth: [3; 16],
19
        }
20
    }
21
22
    fn subscription(&self, endpoint: String) -> Subscription {
23
        Subscription {
24
            endpoint,
25
            p256dh: URL_SAFE_NO_PAD.encode(self.private.compute_public_key().unwrap().as_ref()),
26
            auth: URL_SAFE_NO_PAD.encode(self.auth),
27
        }
28
    }
29
}
30
31
async fn sender(server: &MockServer, dir: &tempfile::TempDir) -> Sender {
32
    let authority = server.address().to_string();
33
    Sender::new(
34
        Vapid::load_or_create(&dir.path().join("vapid.pk8")).unwrap(),
35
        "mailto:test@example.org".to_owned(),
36
        Allowlist::with_extra([authority]),
37
    )
38
    .unwrap()
39
}
40
41
#[tokio::test]
42
async fn delivers_encrypted_and_reports_gone_retry_and_refusal() {
43
    let server = MockServer::start().await;
44
    Mock::given(method("POST"))
45
        .and(path("/push/ok"))
46
        .and(header("content-encoding", "aes128gcm"))
47
        .and(header("urgency", "high"))
48
        .and(header("ttl", "43200"))
49
        .respond_with(ResponseTemplate::new(201))
50
        .expect(1)
51
        .mount(&server)
52
        .await;
53
    Mock::given(method("POST"))
54
        .and(path("/push/gone"))
55
        .respond_with(ResponseTemplate::new(410))
56
        .mount(&server)
57
        .await;
58
    Mock::given(method("POST"))
59
        .and(path("/push/flaky"))
60
        .respond_with(ResponseTemplate::new(503))
61
        .up_to_n_times(1)
62
        .with_priority(1)
63
        .mount(&server)
64
        .await;
65
    Mock::given(method("POST"))
66
        .and(path("/push/flaky"))
67
        .respond_with(ResponseTemplate::new(201))
68
        .with_priority(2)
69
        .mount(&server)
70
        .await;
71
72
    let dir = tempfile::tempdir().unwrap();
73
    let sender = sender(&server, &dir).await;
74
    let browser = Browser::new();
75
    let message = Message {
76
        payload: br#"{"web_push":8030}"#,
77
        urgency: Urgency::High,
78
        topic: "!room:example.org",
79
    };
80
81
    let ok = browser.subscription(format!("{}/push/ok", server.uri()));
82
    assert_eq!(sender.send(&ok, &message).await, Outcome::Delivered);
83
    let requests = server.received_requests().await.unwrap();
84
    let request = &requests[0];
85
    let authorization = request.headers["authorization"].to_str().unwrap();
86
    assert!(authorization.starts_with("vapid t="));
87
    assert!(authorization.ends_with(&format!("k={}", sender.vapid_public_key())));
88
    assert_eq!(request.headers["topic"].to_str().unwrap().len(), 32);
89
    let plain = ece::decrypt(&browser.private, &browser.auth, &request.body).unwrap();
90
    assert_eq!(plain, message.payload);
91
92
    let gone = browser.subscription(format!("{}/push/gone", server.uri()));
93
    let outcome = sender.send(&gone, &message).await;
94
    assert_eq!(outcome, Outcome::Gone);
95
    assert!(outcome.drops_subscription());
96
97
    let flaky = browser.subscription(format!("{}/push/flaky", server.uri()));
98
    assert_eq!(sender.send(&flaky, &message).await, Outcome::Delivered);
99
100
    let elsewhere = browser.subscription("https://example.org/push".to_owned());
101
    assert_eq!(sender.send(&elsewhere, &message).await, Outcome::Refused);
102
    let bad_keys = Subscription {
103
        p256dh: "AAAA".to_owned(),
104
        ..ok
105
    };
106
    assert_eq!(sender.send(&bad_keys, &message).await, Outcome::Refused);
107
}