Write an integration test script
This commit is contained in:
parent
b860004196
commit
7674b26c16
8 changed files with 183 additions and 169 deletions
|
@ -176,7 +176,7 @@ mod tests {
|
|||
|
||||
const KEY_ED25519: &str = "Av46g0s6+qCczlLeIkSmD/yD7GX5pDjl8SVTSeVZIhc=";
|
||||
const KEY_RSA2048: &str = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDDYGEHGABdLxLbvqiuaGdYV9ndsFzdO31AaZoSfCVF0TVPeJ5B/YWyUzc6YIr7qFyfA4tiRPu3/Fy2vzYzG2lcYBkSzJsQWkiOWv6C3CpxYX2tBrAKnJx3ADyr9P3whztyKQBbSNLy+CCNJQ5967Z+PCOeiFAX4XvfCFMpwxsUo6Pv2SYi9PwOq8HwzUQHyy39zOs68XIUF85DCXiQ1kztXzu8HX8nuLX7AnLrf0ZiFGrbSbUjj/F7XVPh2QJxcBLZjrnpve73nrrYsIVnbCvfV563CuFq0PvsUofW7Ckbpwdx26AD59ssaOBNp/uK04xqPSQZyADEngcfkOBdqeHlAgMBAAECggEAYqZQd6d7z5FMQV5Uh7O5staw8Anz6dT22kY4AGtk2orXEyiBKCrdjfwMn9JNeuI42iWNBHJ2cyDeo3uK32VQ3s66+k4LYcdkaVSyu9p1J8ilD2+YBdOsAT5CZEUQz5lIv8zKHE16DiqRLRNv7M7O15CAH7UOU/CLfkMS0rxr+Q//dw94mUTXSy+XKwWgdQSxjiqcfEFEArtP4QH+BM2j7Jk+cMm4OlOklOLlcktSgrCSGp4uqt9BYTq86XFSVaZHbirKAheO7mv9xSXj46zenWaSwWDJ/zYSQHUzTwdCcm35gHeGvUvBo/njCzfvNM6xWl+vrMzD9i4pB0PZ6yi0IQKBgQD/97QWjwdCt7ubRv453lLZ2CXDNt/QFKOr+ESlDPkCxmb/DIY8HDqbJpdyPrCm6MHL8lUBLNixSUfkrCFFaGgpHyG6E5qJT0/UVVwSWUAWciOY7SOZXMPgvkahU39GzPDE8m+mihyDPT98vUqX4HTZJzannaSESGeVtADYXN416QKBgQDDZrYuD4bzjft7XNmmbdl52sfCcKgduzmooSMjeIKffSZuCvpVBA0kEgqLalLaMSCjcx95djufqDkU+RBT7lAbZDYd+lD4m4dNzGqy1hgTVfBaPOYCg4iC2WKiHZDIw8n630gFyRZDAn+KINbcSn7V2ZxqDa1ZE6wAWgiBn98CnQKBgQDSmFnytXqjycbw2lgQBHrmAJARLPS3nkOLGZhgs2usfNAAx60ph5AwVnAD7tAogxfvVFHbxaoDMueTnItDL8ODEboN/lMG5dooOJKoBgZUcVQYXgMMCuad4e76jFgLSFJPt6dkvfz3fUzetF7K1kFM6JZvEaRpsaiH4rFPUhkBAQKBgHwXepL94WJDRPYvHToIgRhVzI67JMjc4d0pmDsqiSnoPMOdzSS4ke/aVT/8oelXUbb7oX1tjKf0GWwsUCY9Ljp3Bbc8BLgdbWwG6avxMxD0ftOP4TKvfb47d9wkkpItZNQhgIfMEIs1xvFdsZXs6We97wua6/+p8o22n7hSYzoxAoGBAM9zQgkeV2U++yi4memcNX1sLnRHaBUSShj+IXhOM8Hpw5deyxFKUh2sD537CJxKOx+8XMKvWilY2MFRCZIlTAQBasEfj9+YZSLY7kFHfWKcUKhqVQ+5M+LgbuZjf6X/0Y+2Lqc585NoxmMDc4GC/1t4eagXqMvcuh10S2JP9RWp";
|
||||
const MSG_01_RAW: &[u8] = include_bytes!("../test_samples/single_message_raw.txt");
|
||||
const MSG_01_RAW: &[u8] = include_bytes!("../tests/test_01.msg");
|
||||
const MSG_01_HEADERS: &[&str] = &[
|
||||
"Date",
|
||||
"From",
|
||||
|
@ -189,7 +189,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_simple_simple() {
|
||||
let ref_sig_header = "DKIM-Signature: v=1; a=ed25519-sha256; k=ed25519; c=simple/simple;\r\n\tt=1681595158;\r\n\td=example.org;\r\n\ts=dkim-b3fb546a27bb44dd88a1fd2b4b3e2e96;\r\n\th=Date:From:Resent-Date:Subject:To:cc:reply-to;\r\n\tbh=z85OKVJZHnmg3qFlSpLbpPCZ00irfBdrzQUtabiSl3A=;\r\n\tb=854DPGA77UnhEagQIK+x/PLz/YEzoxZO2PDDk6ojASwhUqcuSkOdy9XiuTsQSgpaSQwjui3OuYm9VG6/j3G+AQ==";
|
||||
let ref_sig_header = "DKIM-Signature: v=1; a=ed25519-sha256; k=ed25519; c=simple/simple;\r\n\tt=1681595158;\r\n\td=example.org;\r\n\ts=dkim-b3fb546a27bb44dd88a1fd2b4b3e2e96;\r\n\th=Date:From:Resent-Date:Subject:To:cc:reply-to;\r\n\tbh=z85OKVJZHnmg3qFlSpLbpPCZ00irfBdrzQUtabiSl3A=;\r\n\tb=YGbtIaodjitU3jNtwRA2+AJ/i5W4VxmZuESKnv08ofZ7nuYLUiqaS1sR3DGeJ1t83R5ZmPSJAQPBYRg3usJxBg==";
|
||||
let msg = ParsedMessage::from_bytes(MSG_01_RAW).unwrap();
|
||||
let mut sig = Signature {
|
||||
algorithm: Algorithm::Ed25519Sha256,
|
||||
|
@ -210,7 +210,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_relaxed_relaxed() {
|
||||
let ref_sig_header = "DKIM-Signature: v=1; a=rsa-sha256; k=rsa; c=relaxed/relaxed;\r\n\tt=1681593844; x=1682889844;\r\n\td=example.org;\r\n\ts=dkim-681d955d9fc84d978d71a7d7f8ce7dd6;\r\n\th=Date:From:Resent-Date:Subject:To:cc:reply-to;\r\n\tbh=z85OKVJZHnmg3qFlSpLbpPCZ00irfBdrzQUtabiSl3A=;\r\n\tb=o83MyMVH6fz4lhGG5za33rmE/D8RJLezFw9Jqds2l6Pt9uDUZCHbh6YjWJjBBbaKJBlrGWGyKBe4x5ns84oHjGyehd8mbyJc9mu1HjJZQVH7bZPPb0N0gt9tl+7hz9S5GvPE6hE4c3VxynhV/KxoJXa6tdM8JUlTKhcaZyacl1kFcgUlFriyMcID9451evmlmEJ8hiGnxqpXdThxVluKNqV9jYlLAlH4/eIqKWh9RkAqeQufTd8jbfokoF7KDCYRaM+y7uoi3Ir6KKt3NuwrYYv6lmhkzuhF4/4+o6CeNtCQ4boAlVBiGFBX5MDKeHg410yfQZqHm/2mlV9pNU+H4g==";
|
||||
let ref_sig_header = "DKIM-Signature: v=1; a=rsa-sha256; k=rsa; c=relaxed/relaxed;\r\n\tt=1681593844; x=1682889844;\r\n\td=example.org;\r\n\ts=dkim-681d955d9fc84d978d71a7d7f8ce7dd6;\r\n\th=Date:From:Resent-Date:Subject:To:cc:reply-to;\r\n\tbh=z85OKVJZHnmg3qFlSpLbpPCZ00irfBdrzQUtabiSl3A=;\r\n\tb=mvdT944tidhpbJHJdbYtIedkXIxNERP7xpAXjWxen5tTULYD72JCQBQy7HbMqix3S0JAex6VVdyqmMjEC053yWNOckVH5E62sGaMyDj8Us1isTmcqIu3VSSQhLpMKkdMv55esqMoaTNC+L+I9p44AHst64sodJmbDA33vLhqoGRja8IylrSK0O4XqgWl2XzGfcyXuDT8miO1NLUU3Hgfgs7edRjBkF2iTMraWiObr0ZW2vI9+Ib9DeuupcC3GMg1MheWlmWNnHlrlSmnkd2VuWEX/ydqlxxXz3/oPjY5ATgYVPBc8apk4KkMDqoQ9EkUvItsvDUz0UhhbXMP3pGGrA==";
|
||||
let msg = ParsedMessage::from_bytes(MSG_01_RAW).unwrap();
|
||||
let mut sig = Signature {
|
||||
algorithm: Algorithm::Rsa2048Sha256,
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
config|smtpd-version|6.8.0p2
|
||||
config|smtp-session-timeout|300
|
||||
config|subsystem|smtp-in
|
||||
config|admd|localhost.localdomain
|
||||
config|ready
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Subject: Test with attachments
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Type: multipart/mixed;
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| boundary="------------E5401F4DD68F2F7A872C2A83"
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Language: en-US
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|This is a multi-part message in MIME format.
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|--------------E5401F4DD68F2F7A872C2A83
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Type: text/html; charset=utf-8
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Transfer-Encoding: 7bit
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|<html>Test with attachments</html>
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|--------------E5401F4DD68F2F7A872C2A83
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Type: application/pdf;
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| name="sample.pdf"
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Transfer-Encoding: base64
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Disposition: attachment;
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| filename="sample.pdf"
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|JVBERi0xLjMNCiXi48/TDQoNCjEgMCBvYmoNCjw8DQovVHlwZSAvQ2F0YWxvZw0KL091dGxp
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|bmVzIDIgMCBSDQovUGFnZXMgMyAwIFINCj4+DQplbmRvYmoNCg0KMiAwIG9iag0KPDwNCi9U
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|eXBlIC9PdXRsaW5lcw0KL0NvdW50IDANCj4+DQplbmRvYmoNCg0KMyAwIG9iag0KPDwNCi9U
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|eXBlIC9QYWdlcw0KL0NvdW50IDINCi9LaWRzIFsgNCAwIFIgNiAwIFIgXSANCj4+DQplbmRv
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|YmoNCg0KNCAwIG9iag0KPDwNCi9UeXBlIC9QYWdlDQovUGFyZW50IDMgMCBSDQovUmVzb3Vy
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Y2VzIDw8DQovRm9udCA8PA0KL0YxIDkgMCBSIA0KPj4NCi9Qcm9jU2V0IDggMCBSDQo+Pg0K
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|L01lZGlhQm94IFswIDAgNjEyLjAwMDAgNzkyLjAwMDBdDQovQ29udGVudHMgNSAwIFINCj4+
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|DQplbmRvYmoNCg0KNSAwIG9iag0KPDwgL0xlbmd0aCAxMDc0ID4+DQpzdHJlYW0NCjIgSg0K
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|QlQNCjAgMCAwIHJnDQovRjEgMDAyNyBUZg0KNTcuMzc1MCA3MjIuMjgwMCBUZA0KKCBBIFNp
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|bXBsZSBQREYgRmlsZSApIFRqDQpFVA0KQlQNCi9GMSAwMDEwIFRmDQo2OS4yNTAwIDY4OC42
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|MDgwIFRkDQooIFRoaXMgaXMgYSBzbWFsbCBkZW1vbnN0cmF0aW9uIC5wZGYgZmlsZSAtICkg
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|VGoNCkVUDQpCVA0KL0YxIDAwMTAgVGYNCjY5LjI1MDAgNjY0LjcwNDAgVGQNCigganVzdCBm
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|b3IgdXNlIGluIHRoZSBWaXJ0dWFsIE1lY2hhbmljcyB0dXRvcmlhbHMuIE1vcmUgdGV4dC4g
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|QW5kIG1vcmUgKSBUag0KRVQNCkJUDQovRjEgMDAxMCBUZg0KNjkuMjUwMCA2NTIuNzUyMCBU
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|ZA0KKCB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|LiApIFRqDQpFVA0KQlQNCi9GMSAwMDEwIFRmDQo2OS4yNTAwIDYyOC44NDgwIFRkDQooIEFu
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|ZCBtb3JlIHRleHQuIEFuZCBtb3JlIHRleHQuIEFuZCBtb3JlIHRleHQuIEFuZCBtb3JlIHRl
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|eHQuIEFuZCBtb3JlICkgVGoNCkVUDQpCVA0KL0YxIDAwMTAgVGYNCjY5LjI1MDAgNjE2Ljg5
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|NjAgVGQNCiggdGV4dC4gQW5kIG1vcmUgdGV4dC4gQm9yaW5nLCB6enp6ei4gQW5kIG1vcmUg
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|dGV4dC4gQW5kIG1vcmUgdGV4dC4gQW5kICkgVGoNCkVUDQpCVA0KL0YxIDAwMTAgVGYNCjY5
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|LjI1MDAgNjA0Ljk0NDAgVGQNCiggbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9y
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|ZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiApIFRqDQpFVA0KQlQNCi9G
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|MSAwMDEwIFRmDQo2OS4yNTAwIDU5Mi45OTIwIFRkDQooIEFuZCBtb3JlIHRleHQuIEFuZCBt
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|b3JlIHRleHQuICkgVGoNCkVUDQpCVA0KL0YxIDAwMTAgVGYNCjY5LjI1MDAgNTY5LjA4ODAg
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|VGQNCiggQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gQW5k
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|IG1vcmUgdGV4dC4gQW5kIG1vcmUgKSBUag0KRVQNCkJUDQovRjEgMDAxMCBUZg0KNjkuMjUw
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|MCA1NTcuMTM2MCBUZA0KKCB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBF
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|dmVuIG1vcmUuIENvbnRpbnVlZCBvbiBwYWdlIDIgLi4uKSBUag0KRVQNCmVuZHN0cmVhbQ0K
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|ZW5kb2JqDQoNCjYgMCBvYmoNCjw8DQovVHlwZSAvUGFnZQ0KL1BhcmVudCAzIDAgUg0KL1Jl
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|c291cmNlcyA8PA0KL0ZvbnQgPDwNCi9GMSA5IDAgUiANCj4+DQovUHJvY1NldCA4IDAgUg0K
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Pj4NCi9NZWRpYUJveCBbMCAwIDYxMi4wMDAwIDc5Mi4wMDAwXQ0KL0NvbnRlbnRzIDcgMCBS
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|DQo+Pg0KZW5kb2JqDQoNCjcgMCBvYmoNCjw8IC9MZW5ndGggNjc2ID4+DQpzdHJlYW0NCjIg
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Sg0KQlQNCjAgMCAwIHJnDQovRjEgMDAyNyBUZg0KNTcuMzc1MCA3MjIuMjgwMCBUZA0KKCBT
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|aW1wbGUgUERGIEZpbGUgMiApIFRqDQpFVA0KQlQNCi9GMSAwMDEwIFRmDQo2OS4yNTAwIDY4
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|OC42MDgwIFRkDQooIC4uLmNvbnRpbnVlZCBmcm9tIHBhZ2UgMS4gWWV0IG1vcmUgdGV4dC4g
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|QW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gKSBUag0KRVQNCkJUDQovRjEgMDAxMCBU
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Zg0KNjkuMjUwMCA2NzYuNjU2MCBUZA0KKCBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSApIFRqDQpFVA0KQlQN
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Ci9GMSAwMDEwIFRmDQo2OS4yNTAwIDY2NC43MDQwIFRkDQooIHRleHQuIE9oLCBob3cgYm9y
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|aW5nIHR5cGluZyB0aGlzIHN0dWZmLiBCdXQgbm90IGFzIGJvcmluZyBhcyB3YXRjaGluZyAp
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|IFRqDQpFVA0KQlQNCi9GMSAwMDEwIFRmDQo2OS4yNTAwIDY1Mi43NTIwIFRkDQooIHBhaW50
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|IGRyeS4gQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gQW5k
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|IG1vcmUgdGV4dC4gKSBUag0KRVQNCkJUDQovRjEgMDAxMCBUZg0KNjkuMjUwMCA2NDAuODAw
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|MCBUZA0KKCBCb3JpbmcuICBNb3JlLCBhIGxpdHRsZSBtb3JlIHRleHQuIFRoZSBlbmQsIGFu
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|ZCBqdXN0IGFzIHdlbGwuICkgVGoNCkVUDQplbmRzdHJlYW0NCmVuZG9iag0KDQo4IDAgb2Jq
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|DQpbL1BERiAvVGV4dF0NCmVuZG9iag0KDQo5IDAgb2JqDQo8PA0KL1R5cGUgL0ZvbnQNCi9T
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|dWJ0eXBlIC9UeXBlMQ0KL05hbWUgL0YxDQovQmFzZUZvbnQgL0hlbHZldGljYQ0KL0VuY29k
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|aW5nIC9XaW5BbnNpRW5jb2RpbmcNCj4+DQplbmRvYmoNCg0KMTAgMCBvYmoNCjw8DQovQ3Jl
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|YXRvciAoUmF2ZSBcKGh0dHA6Ly93d3cubmV2cm9uYS5jb20vcmF2ZVwpKQ0KL1Byb2R1Y2Vy
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|IChOZXZyb25hIERlc2lnbnMpDQovQ3JlYXRpb25EYXRlIChEOjIwMDYwMzAxMDcyODI2KQ0K
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Pj4NCmVuZG9iag0KDQp4cmVmDQowIDExDQowMDAwMDAwMDAwIDY1NTM1IGYNCjAwMDAwMDAw
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|MTkgMDAwMDAgbg0KMDAwMDAwMDA5MyAwMDAwMCBuDQowMDAwMDAwMTQ3IDAwMDAwIG4NCjAw
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|MDAwMDAyMjIgMDAwMDAgbg0KMDAwMDAwMDM5MCAwMDAwMCBuDQowMDAwMDAxNTIyIDAwMDAw
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|IG4NCjAwMDAwMDE2OTAgMDAwMDAgbg0KMDAwMDAwMjQyMyAwMDAwMCBuDQowMDAwMDAyNDU2
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|IDAwMDAwIG4NCjAwMDAwMDI1NzQgMDAwMDAgbg0KDQp0cmFpbGVyDQo8PA0KL1NpemUgMTEN
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Ci9Sb290IDEgMCBSDQovSW5mbyAxMCAwIFINCj4+DQoNCnN0YXJ0eHJlZg0KMjcxNA0KJSVF
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|T0YNCg==
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|--------------E5401F4DD68F2F7A872C2A83
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Type: text/plain; charset=UTF-8;
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| name="sample.txt"
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Transfer-Encoding: base64
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Disposition: attachment;
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| filename="sample.txt"
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|dHh0IGZpbGUgY29udGV4dCBmb3IgZW1haWwgY29sbGVjdG9yCjEyMzQ1Njc4OTA5ODc2NTQz
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|MjEK
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|--------------E5401F4DD68F2F7A872C2A83--
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|.
|
|
@ -1,20 +0,0 @@
|
|||
config|smtpd-version|6.8.0p2
|
||||
config|smtp-session-timeout|300
|
||||
config|subsystem|smtp-in
|
||||
config|admd|localhost.localdomain
|
||||
config|ready
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Received: from example.com (localhost.localdomain [::1])
|
||||
filter|0.6|1679685611.545184|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| by localhost.localdomain (OpenSMTPD) with SMTP id 8b29bb25
|
||||
filter|0.6|1679685611.545186|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| for <derp.derpson@example.org>;
|
||||
filter|0.6|1679685611.545200|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| Fri, 24 Mar 2023 19:20:11 +0000 (UTC)
|
||||
filter|0.6|1679685617.258766|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|From: Derp Sender <derp.sender@example.org>
|
||||
filter|0.6|1679685627.765325|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|To: derp.derpson@localhost
|
||||
filter|0.6|1679685627.765542|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Resent-Date: Fri, 24 Mar 2023 09:42:21 +0100
|
||||
filter|0.6|1679685627.765973|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Subject: This is a test
|
||||
filter|0.6|1679685627.766188|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|MIME-Version: 1.0
|
||||
filter|0.6|1679685627.766200|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Transfer-Encoding: 8bit
|
||||
filter|0.6|1679685627.766221|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Message-Id: <a8a30401-ee61-45d8-bca3-4262f6ebc44e@localhost>
|
||||
filter|0.6|1679685627.766224|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Date: Mon, 13 Mar 2023 10:04:21 +0100
|
||||
filter|0.6|1679685627.766227|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685627.766227|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Hello World!
|
||||
filter|0.6|1679685640.319648|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|.
|
|
@ -1,14 +0,0 @@
|
|||
Received: from example.com (localhost.localdomain [::1])
|
||||
by localhost.localdomain (OpenSMTPD) with SMTP id 8b29bb25
|
||||
for <derp.derpson@example.org>;
|
||||
Fri, 24 Mar 2023 19:20:11 +0000 (UTC)
|
||||
From: Derp Sender <derp.sender@example.org>
|
||||
To: derp.derpson@localhost
|
||||
Resent-Date: Fri, 24 Mar 2023 09:42:21 +0100
|
||||
Subject: This is a test
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Message-Id: <a8a30401-ee61-45d8-bca3-4262f6ebc44e@localhost>
|
||||
Date: Mon, 13 Mar 2023 10:04:21 +0100
|
||||
|
||||
Hello World!
|
|
@ -1,40 +0,0 @@
|
|||
config|smtpd-version|6.8.0p2
|
||||
config|smtp-session-timeout|300
|
||||
config|subsystem|smtp-in
|
||||
config|admd|localhost.localdomain
|
||||
config|ready
|
||||
filter|0.6|1679685611.545169|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Received: from example.com (localhost.localdomain [::1])
|
||||
filter|0.6|1679685611.545184|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| by localhost.localdomain (OpenSMTPD) with SMTP id 8b29bb25
|
||||
filter|0.6|1679685611.545186|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| for <derp.derpson@example.org>;
|
||||
filter|0.6|1679685611.545200|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b| Fri, 24 Mar 2023 19:20:11 +0000 (UTC)
|
||||
filter|0.6|1679685617.258766|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|From: Derp Sender <derp.sender@example.org>
|
||||
filter|0.6|1679685627.765325|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|To: derp.derpson@localhost
|
||||
filter|0.6|1679685627.765542|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Resent-Date: Fri, 24 Mar 2023 09:42:21 +0100
|
||||
filter|0.6|1679685627.765973|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Subject: This is a test
|
||||
filter|0.6|1679685627.766188|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|MIME-Version: 1.0
|
||||
filter|0.6|1679685627.766196|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Type: multipart/alternative; charset=UTF-8; boundary="MSGBOUNDARY"
|
||||
filter|0.6|1679685627.766200|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Transfer-Encoding: 8bit
|
||||
filter|0.6|1679685627.766221|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Message-Id: <a8a30401-ee61-45d8-bca3-4262f6ebc44e@localhost>
|
||||
filter|0.6|1679685627.766224|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Date: Mon, 13 Mar 2023 10:04:21 +0100
|
||||
filter|0.6|1679685627.766227|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685627.766231|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|--MSGBOUNDARY
|
||||
filter|0.6|1679685627.766246|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Type: text/plain; charset=UTF-8
|
||||
filter|0.6|1679685627.766249|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Transfer-Encoding: 8bit
|
||||
filter|0.6|1679685627.766252|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Hello, world!
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|--MSGBOUNDARY
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Type: text/html; charset=UTF-8
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|Content-Transfer-Encoding: 8bit
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|<!DOCTYPE html>
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|<html lang="fr">
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|<head>
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|<title>test</title>
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|</head>
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|<body>
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|<h1>Hello, world!</h1>
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|</body>
|
||||
filter|0.6|1679685627.766266|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|</html>
|
||||
filter|0.6|1679685636.505171|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|
|
||||
filter|0.6|1679685638.642533|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|--MSGBOUNDARY--
|
||||
filter|0.6|1679685640.319648|smtp-in|data-line|b6004c087262f6d4|ca08b19d70c81a8b|.
|
BIN
tests/key-db.sqlite3
Normal file
BIN
tests/key-db.sqlite3
Normal file
Binary file not shown.
170
tests/start_test.py
Executable file
170
tests/start_test.py
Executable file
|
@ -0,0 +1,170 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import dkim
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import smtplib
|
||||
import sqlite3
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
ADDR_FROM = "test.from@example.org"
|
||||
ADDR_TO = "test@example.com"
|
||||
DB_NAME = "key-db.sqlite3"
|
||||
DEFAULT_PORT = 2525
|
||||
|
||||
|
||||
def cp_tmp_file(path, executable=False):
|
||||
file = tempfile.NamedTemporaryFile(suffix=f"-{path.name}", delete=False)
|
||||
with open(path, mode="rb") as f:
|
||||
file.write(f.read())
|
||||
file.flush()
|
||||
flags = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
|
||||
if executable:
|
||||
flags = flags | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
|
||||
os.chmod(file.name, flags)
|
||||
file.close()
|
||||
return file
|
||||
|
||||
|
||||
def get_cmd_filter_dkimout(test_dir, algorithm, canonicalization, target):
|
||||
filter_path = test_dir.parent / "target" / target / "filter-dkimout"
|
||||
filter_path = cp_tmp_file(filter_path, executable=True).name
|
||||
db_path = test_dir / DB_NAME
|
||||
db_path = cp_tmp_file(db_path).name
|
||||
return (
|
||||
filter_path,
|
||||
db_path,
|
||||
f"{filter_path} --algorithm '{algorithm}' --canonicalization '{canonicalization}' --key-data-base '{db_path}' --domain 'example.com' --domain 'example.org' --dns-update-cmd 'builtin:none'",
|
||||
)
|
||||
|
||||
|
||||
def get_opensmtpd_config(port, filter_cmd, maildir_path):
|
||||
cfg_content = f"""# OpenSMTPD test configuration
|
||||
|
||||
# DKIM filter
|
||||
filter "dkim" proc-exec "{filter_cmd}"
|
||||
|
||||
# Users
|
||||
table vuser {{ "test" = "1000:100:{maildir_path}" }}
|
||||
|
||||
# Listening
|
||||
listen on 127.0.0.1 port {port} filter "dkim"
|
||||
listen on ::1 port {port} filter "dkim"
|
||||
|
||||
# Delivering
|
||||
action "deliver" maildir userbase <vuser>
|
||||
match from any for any action "deliver"
|
||||
"""
|
||||
cfg_file = tempfile.NamedTemporaryFile(prefix="smtpd-", suffix=".conf")
|
||||
cfg_file.write(cfg_content.encode())
|
||||
cfg_file.flush()
|
||||
return cfg_file
|
||||
|
||||
|
||||
def get_smtp_session(port):
|
||||
return smtplib.SMTP(host="localhost", port=port)
|
||||
|
||||
|
||||
def send_msg(smtp, msg_file):
|
||||
with open(msg_file) as f:
|
||||
msg = f.read()
|
||||
smtp.sendmail(ADDR_FROM, ADDR_TO, msg)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def custom_get_txt(name, timeout=5):
|
||||
db_path = pathlib.Path(__file__).parent.resolve() / DB_NAME
|
||||
algs_assoc = {
|
||||
"ed25519-sha256": "ed25519",
|
||||
"rsa2048-sha256": "rsa",
|
||||
"rsa3072-sha256": "rsa",
|
||||
"rsa4096-sha256": "rsa",
|
||||
}
|
||||
name = name.decode("UTF-8")
|
||||
selector, domain = name.split("._domainkey.")
|
||||
if domain.endswith("."):
|
||||
domain = domain[:-1]
|
||||
con = sqlite3.connect(db_path)
|
||||
cur = con.cursor()
|
||||
res = cur.execute(
|
||||
"SELECT algorithm, public_key FROM key_db WHERE selector = ? AND sdid = ? LIMIT 1",
|
||||
(selector, domain),
|
||||
)
|
||||
key = res.fetchone()
|
||||
if key:
|
||||
algorithm = algs_assoc[key[0]]
|
||||
key = key[1]
|
||||
key = f"v=DKIM1; k={algorithm}; p={key}"
|
||||
return key
|
||||
|
||||
|
||||
def test_dkim(message_path):
|
||||
with open(message_path, mode="rb") as f:
|
||||
msg = f.read()
|
||||
d = dkim.DKIM(msg, logger=logging)
|
||||
if d.verify(dnsfunc=custom_get_txt):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def start_tests(test_dir, maildir, smtp_port):
|
||||
# Sending emails to OpenSMTPD
|
||||
f, d, filter_cmd = get_cmd_filter_dkimout(
|
||||
test_dir, "ed25519-sha256", "relaxed/relaxed", "debug"
|
||||
)
|
||||
nb = 0
|
||||
nb_total = 0
|
||||
try:
|
||||
cfg_path = get_opensmtpd_config(smtp_port, filter_cmd, maildir.name)
|
||||
print("Start OpenSMTPD using the following command then press enter:")
|
||||
print(f'smtpd -d -f "{cfg_path.name}"')
|
||||
input("")
|
||||
with get_smtp_session(smtp_port) as smtp_session:
|
||||
for test_msg in glob.iglob(f"{test_dir}/*.msg"):
|
||||
nb_total += 1
|
||||
nb += send_msg(smtp_session, test_msg)
|
||||
finally:
|
||||
os.remove(f)
|
||||
os.remove(d)
|
||||
msg = "messages" if nb > 1 else "message"
|
||||
print(f"{nb} {msg} delivered")
|
||||
nb_failed = nb_total - nb
|
||||
if nb_failed > 0:
|
||||
msg = "messages" if nb_failed > 1 else "message"
|
||||
print(f"{nb_failed} {msg} could not be delivered")
|
||||
|
||||
# Testing DKIM signatures
|
||||
nb_dkim_ok = 0
|
||||
nb_dkim_total = 0
|
||||
maildir_glob = f"{maildir.name}/Maildir/new/*"
|
||||
while len(glob.glob(maildir_glob)) < nb_total:
|
||||
time.sleep(1)
|
||||
for test_msg in glob.glob(maildir_glob):
|
||||
nb_dkim_total += 1
|
||||
nb_dkim_ok += test_dkim(test_msg)
|
||||
msg = "messages" if nb_dkim_ok > 1 else "message"
|
||||
print(f"{nb_dkim_ok} {msg} passed the DKIM signature test")
|
||||
nb_failed = nb_dkim_total - nb_dkim_ok
|
||||
if nb_failed > 0:
|
||||
msg = "messages" if nb_failed > 1 else "message"
|
||||
print(f"{nb_failed} {msg} failed the DKIM signature test")
|
||||
|
||||
input("\nPress enter to exit.")
|
||||
|
||||
|
||||
def main():
|
||||
test_dir = pathlib.Path(__file__).parent.resolve()
|
||||
os.chdir(test_dir.parent)
|
||||
maildir = tempfile.TemporaryDirectory(prefix="Maildir_")
|
||||
start_tests(test_dir, maildir, DEFAULT_PORT)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
10
tests/test_01.msg
Normal file
10
tests/test_01.msg
Normal file
|
@ -0,0 +1,10 @@
|
|||
From: Test Sender <test.from@example.org>
|
||||
To: test@example.com
|
||||
Resent-Date: Fri, 24 Mar 2023 09:42:21 +0100
|
||||
Subject: This is a test
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Message-Id: <a8a30401-ee61-45d8-bca3-4262f6ebc44e@localhost>
|
||||
Date: Mon, 13 Mar 2023 10:04:21 +0100
|
||||
|
||||
Hello World!
|
Loading…
Reference in a new issue