From 0002455da46cd2767229c7bcc6368c7f5acbea76 Mon Sep 17 00:00:00 2001 From: Garrit Franke Date: Sun, 5 Sep 2021 00:50:01 +0200 Subject: [PATCH] gempress: add bindable server --- .gitignore | 3 +- Cargo.lock | 430 ++++++++++++++++++++++++++++++++ lib/gempress/Cargo.lock | 359 ++++++++++++++++++++++++++ lib/gempress/Cargo.toml | 3 + lib/gempress/examples/simple.rs | 20 +- lib/gempress/make_cert.sh | 6 + lib/gempress/src/error.rs | 28 +++ lib/gempress/src/gemini.rs | 147 +++++++++++ lib/gempress/src/io.rs | 54 ++++ lib/gempress/src/lib.rs | 98 +++++++- lib/gempress/src/logger.rs | 9 + src/main.rs | 12 +- 12 files changed, 1146 insertions(+), 23 deletions(-) create mode 100644 lib/gempress/Cargo.lock create mode 100644 lib/gempress/src/error.rs create mode 100644 lib/gempress/src/gemini.rs create mode 100644 lib/gempress/src/io.rs create mode 100644 lib/gempress/src/logger.rs diff --git a/.gitignore b/.gitignore index 483fa0c..0a6bd2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -/target +target/ *.pem +*.pfx diff --git a/Cargo.lock b/Cargo.lock index ddee082..09ffaff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,436 @@ dependencies = [ "gempress", ] +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core-foundation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + [[package]] name = "gempress" version = "0.1.0" +dependencies = [ + "native-tls", + "thiserror", + "url", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "native-tls" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "openssl" +version = "0.10.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" + +[[package]] +name = "openssl-sys" +version = "0.9.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "security-framework" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "syn" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283d5230e63df9608ac7d9691adc1dfb6e701225436eb64d0b9a7f0a5a04f6ec" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa3884228611f5cd3608e2d409bf7dce832e4eb3135e3f11addbd7e41bd68e71" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "unicode-bidi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/lib/gempress/Cargo.lock b/lib/gempress/Cargo.lock new file mode 100644 index 0000000..3fac5d4 --- /dev/null +++ b/lib/gempress/Cargo.lock @@ -0,0 +1,359 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core-foundation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "gempress" +version = "0.1.0" +dependencies = [ + "native-tls", + "thiserror", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "native-tls" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "openssl" +version = "0.10.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" + +[[package]] +name = "openssl-sys" +version = "0.9.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "security-framework" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "syn" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283d5230e63df9608ac7d9691adc1dfb6e701225436eb64d0b9a7f0a5a04f6ec" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa3884228611f5cd3608e2d409bf7dce832e4eb3135e3f11addbd7e41bd68e71" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/lib/gempress/Cargo.toml b/lib/gempress/Cargo.toml index 1d8e2c0..fa2239b 100644 --- a/lib/gempress/Cargo.toml +++ b/lib/gempress/Cargo.toml @@ -7,3 +7,6 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +native-tls = "0.2.8" +thiserror = "1.0.28" +url = "2.2.2" diff --git a/lib/gempress/examples/simple.rs b/lib/gempress/examples/simple.rs index 9c4fa88..0bcf61a 100644 --- a/lib/gempress/examples/simple.rs +++ b/lib/gempress/examples/simple.rs @@ -1,24 +1,16 @@ -mod gempress; +extern crate gempress; -use gempress::{Gempress, Request, Response}; -use std::path::Path; - -pub fn handler(req: &Box, res: &mut Box) { - res.send("Hello World!\n"); -} +use gempress::Gempress; +use std::path::PathBuf; fn main() { // Run make_cert.sh to generate a certificate - let config = Gempress::Config { - certPath: Path::new("../cert.pem"); - keyPath: Path::new("../key.pem"); - } + let config = gempress::Config::with_identity(PathBuf::from("identity.pfx"), "qqqq".into()); let app = Gempress::new(config); - app.on("/", handler); - app.listen(1965, || { println!("Listening on port 1965"); - }); + }).unwrap(); +} } diff --git a/lib/gempress/make_cert.sh b/lib/gempress/make_cert.sh index fbcb524..8114045 100755 --- a/lib/gempress/make_cert.sh +++ b/lib/gempress/make_cert.sh @@ -1 +1,7 @@ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=localhost' + +openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem + +# Cleanup +rm key.pem cert.pem + diff --git a/lib/gempress/src/error.rs b/lib/gempress/src/error.rs new file mode 100644 index 0000000..ec861c8 --- /dev/null +++ b/lib/gempress/src/error.rs @@ -0,0 +1,28 @@ +use std::io; +use thiserror::Error; + +pub type GempressResult = Result; + +#[derive(Error, Debug)] +pub enum GempressError { + #[error("failed to open identity file: {0}")] + NoIdentity(io::Error), + + #[error("failed parse certificate: {0:#?}")] + InvalidCertificate(#[from] native_tls::Error), + + #[error("invalid request: {0}")] + InvalidRequest(String), + + #[error("invalid Unicode character in the input")] + InvalidUnicode(#[from] std::string::FromUtf8Error), + + #[error("failed to bind: {0}")] + BindFailed(io::Error), + + #[error("could not read the stream")] + StreamReadFailed(io::Error), + + #[error("could not write to the stream")] + StreamWriteFailed(io::Error), +} diff --git a/lib/gempress/src/gemini.rs b/lib/gempress/src/gemini.rs new file mode 100644 index 0000000..b274e8b --- /dev/null +++ b/lib/gempress/src/gemini.rs @@ -0,0 +1,147 @@ +use crate::error::{GempressError, GempressResult}; +use native_tls::TlsStream; +use std::{io::Write, net::TcpStream, str::FromStr}; +use url::Url; + +#[derive(Debug, PartialEq, Eq)] +pub struct Request { + url: Url, +} + +impl Request { + pub fn parse(request: &str) -> GempressResult { + Self::from_str(request) + } + + /// Get file path + pub fn file_path(&self) -> &str { + self.url + .path() + .chars() + .next() + .map_or("", |c| &self.url.path()[c.len_utf8()..]) + } +} + +impl FromStr for Request { + type Err = GempressError; + + fn from_str(s: &str) -> GempressResult { + let mut s = s.to_string(); + + // Add gemini: scheme if not explicitly set + if s.starts_with("//") { + s = format!("gemini:{}", s); + } + + // Check protocol + if let Some(proto_end) = s.find("://") { + // If set, check if it's allowed + let protocol = &s[..proto_end]; + + if protocol != "gemini" { + // TODO: return 53 error instead of dropping + return Err(GempressError::InvalidRequest("invalid protocol".into())); + } + } else { + // If no protocol is found, gemini: is implied + s = format!("gemini://{}", s); + } + + // Extract and parse the url from the request. + let raw = s + .trim_end_matches(0x0 as char) + .strip_suffix("\r\n") + .ok_or_else(|| GempressError::InvalidRequest("malformed request".into()))?; + let url = Url::parse(&raw) + .map_err(|e| GempressError::InvalidRequest(format!("invalid url: {}", e)))?; + + Ok(Self { url }) + } +} + +pub struct Response { + pub status: [u8; 2], + pub meta: Vec, + pub body: Option>, +} + +impl Response { + pub fn success(body: Vec, mime_type: &str) -> Self { + Response { + status: [b'2', b'0'], + meta: mime_type.as_bytes().to_vec(), + body: Some(body), + } + } + + pub fn not_found() -> Self { + Response { + status: [b'5', b'1'], + meta: "Resource not found".into(), + body: None, + } + } + + pub fn send(&self, mut stream: TlsStream) -> GempressResult { + let mut buf: Vec = Vec::new(); + + // + buf.extend(&self.status); + + // + buf.push(0x20); + + // + buf.extend(&self.meta); + + buf.extend(b"\r\n"); + + if let Some(body) = &self.body { + buf.extend(body); + } + + stream.write(&buf).map_err(GempressError::StreamWriteFailed) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn check_request(raw: &str, expected_url: &str) { + let req = Request::parse(raw).unwrap(); + + assert_eq!( + req, + Request { + url: Url::parse(expected_url).unwrap() + } + ); + } + + #[test] + fn parse_request() { + check_request("gemini://example.space\r\n", "gemini://example.space"); + } + + #[test] + fn parse_without_scheme() { + check_request("example.space\r\n", "gemini://example.space"); + } + + #[test] + fn parse_without_scheme_double_slash() { + check_request("//example.space\r\n", "gemini://example.space"); + } + + #[test] + fn parse_malformed_request() { + let raw = "gemini://example.space"; + + match Request::parse(raw) { + Err(TaurusError::InvalidRequest(_)) => {} + x => panic!("expected TaurusError::InvalidRequest, got: {:?}", x), + } + } +} diff --git a/lib/gempress/src/io.rs b/lib/gempress/src/io.rs new file mode 100644 index 0000000..6625d36 --- /dev/null +++ b/lib/gempress/src/io.rs @@ -0,0 +1,54 @@ +use crate::error::{GempressError, GempressResult}; +use native_tls::Identity; +use std::fs::File; +use std::io::{self, Read}; +use std::path::Path; + +/// Read a file into Vec +pub fn read_file(file_path: &str) -> Result, io::Error> { + let mut file = File::open(file_path)?; + let mut buf = Vec::new(); + + file.read_to_end(&mut buf)?; + + Ok(buf) +} + +/// Read certificate file +pub fn load_cert(cert_file: &str, password: &str) -> GempressResult { + let identity = read_file(&cert_file).map_err(GempressError::NoIdentity)?; + let identity = Identity::from_pkcs12(&identity, &password)?; + + Ok(identity) +} + +/// Resolve path to a file, returning index.gmi if a subdirectory is encountered +/// +/// If path points to a file, it is returned. +/// If path points to a directory, `./index.gmi` is returned +pub fn resolve_path(path: &Path) -> String { + if path.is_dir() { + path.join("index.gmi").to_string_lossy().into_owned() + } else { + path.to_string_lossy().into_owned() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn resolve_path_file() { + let path = Path::new("./file.gmi"); + + assert_eq!(resolve_path(&path), String::from("./file.gmi")); + } + + #[test] + fn resolve_path_dir() { + let path = Path::new("./"); + + assert_eq!(resolve_path(&path), String::from("./index.gmi")); + } +} diff --git a/lib/gempress/src/lib.rs b/lib/gempress/src/lib.rs index 028cef9..931a30c 100644 --- a/lib/gempress/src/lib.rs +++ b/lib/gempress/src/lib.rs @@ -1,11 +1,95 @@ -pub fn add(a: u32, b: u32) -> u32 { - return a + b; +extern crate native_tls; + +mod logger; +mod io; +mod error; +mod gemini; + +use std::io::Read; +use native_tls::Identity; +use std::sync::Arc; +use std::path::PathBuf; +use std::net::{TcpListener, TcpStream}; +use std::thread; +use std::path; +use native_tls::{TlsAcceptor, TlsStream}; +use error::{GempressResult, GempressError}; + +pub struct Config { + // Path to the identity file + identityPath: PathBuf, + password: String, +} + +impl Config { + pub fn with_identity(identityPath: PathBuf, password: String) -> Self { + Self { + identityPath, + password, + } + } } -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(add(1, 1), 2); +pub struct Gempress { + pub config: Config, +} + +impl Gempress { + pub fn new(config: Config) -> Self { + Gempress { + config, + } + } + + pub fn listen(&self, port: u16, callback: F) -> GempressResult<()> { + // Read certificate + // TODO: Can a password be optional? + let identity = io::load_cert(&self.config.identityPath.to_str().unwrap_or(""), &self.config.password)?; + + let address = format!("0.0.0.0:{}", port); + let listener = TcpListener::bind(address).map_err(GempressError::BindFailed)?; + let acceptor = TlsAcceptor::new(identity).unwrap(); + let acceptor = Arc::new(acceptor); + + logger::info(format!("Listening on port {}", port)); + + for stream in listener.incoming() { + match stream { + Ok(stream) => { + let acceptor = acceptor.clone(); + + thread::spawn(move || match acceptor.accept(stream) { + Ok(stream) => { + if let Err(e) = handle_client(stream) { + logger::error(format!("Can't handle client: {}", e)); + } + } + Err(e) => { + logger::error(format!("Can't handle stream: {}", e)); + } + }); + } + Err(err) => logger::error(err), + } + } + + Ok(()) } + +} + +fn handle_client(mut stream: TlsStream) -> GempressResult { + let mut buffer = [0; 1024]; + + stream + .read(&mut buffer) + .map_err(GempressError::StreamReadFailed)?; + + let raw_request = String::from_utf8(buffer.to_vec())?; + + let request = gemini::Request::parse(&raw_request)?; + let url_path = request.file_path(); + let file_path = path::Path::new(url_path); + + gemini::Response::success("It Works!\n".into(), "text/gemini").send(stream) } diff --git a/lib/gempress/src/logger.rs b/lib/gempress/src/logger.rs new file mode 100644 index 0000000..9408dfa --- /dev/null +++ b/lib/gempress/src/logger.rs @@ -0,0 +1,9 @@ +use std::fmt::Display; + +pub fn info(message: impl Display) { + println!("[info] {}", message); +} + +pub fn error(message: impl Display) { + println!("[err] {}", message); +} diff --git a/src/main.rs b/src/main.rs index 9930e56..a5d02ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,15 @@ extern crate gempress; +use gempress::Gempress; +use std::path::PathBuf; + fn main() { - println!("{}", gempress::add(1, 1)); + // Run make_cert.sh to generate a certificate + let config = gempress::Config::with_identity(PathBuf::from("identity.pfx"), "qqqq".into()); + + let app = Gempress::new(config); + + app.listen(1965, || { + println!("Listening on port 1965"); + }).unwrap(); }