~boringcactus/gemifedi

d0dca716cf3aaffa03e99e5fa18b77c83946e339 — Melody Horn a month ago 3e64e4a
generate certs internally
4 files changed, 129 insertions(+), 90 deletions(-)

M Cargo.lock
M Cargo.toml
M README.md
M src/main.rs
M Cargo.lock => Cargo.lock +102 -29
@@ 161,9 161,9 @@ version = "0.9.0"
source = "git+https://github.com/FlorianUekermann/async-tls.git#92d1ba4a53c8a000d0498b3440217d0f6558aac0"
dependencies = [
 "futures 0.3.5",
 "rustls",
 "rustls 0.18.1",
 "webpki",
 "webpki-roots",
 "webpki-roots 0.20.0",
]

[[package]]


@@ 526,6 526,15 @@ dependencies = [
]

[[package]]
name = "ct-logs"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d3686f5fa27dbc1d76c751300376e167c5a43387f44bb451fd1c24776e49113"
dependencies = [
 "sct",
]

[[package]]
name = "data-encoding"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 857,7 866,7 @@ dependencies = [

[[package]]
name = "gemifedi"
version = "0.3.0"
version = "0.3.1"
dependencies = [
 "async-std",
 "async-trait",


@@ 867,10 876,10 @@ dependencies = [
 "maj",
 "markup5ever",
 "markup5ever_rcdom",
 "native-tls",
 "percent-encoding 2.1.0",
 "pretty_env_logger",
 "rustls",
 "rcgen",
 "rustls 0.18.1",
 "serde",
 "sha2",
 "structopt",


@@ 1094,16 1103,20 @@ dependencies = [
]

[[package]]
name = "hyper-tls"
version = "0.3.2"
name = "hyper-rustls"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f"
checksum = "719d85c7df4a7f309a77d145340a063ea929dcb2e025bae46a80345cffec2952"
dependencies = [
 "bytes 0.4.12",
 "ct-logs",
 "futures 0.1.29",
 "hyper",
 "native-tls",
 "rustls 0.16.0",
 "tokio-io",
 "tokio-rustls 0.10.3",
 "webpki",
 "webpki-roots 0.17.0",
]

[[package]]


@@ 1258,14 1271,14 @@ dependencies = [
 "num-derive",
 "num-traits",
 "once_cell",
 "rustls",
 "rustls 0.18.1",
 "structopt",
 "thiserror",
 "tokio 0.2.22",
 "tokio-rustls",
 "tokio-rustls 0.14.1",
 "url 2.1.1",
 "webpki",
 "webpki-roots",
 "webpki-roots 0.20.0",
]

[[package]]


@@ 1602,15 1615,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"

[[package]]
name = "openssl-src"
version = "111.11.0+1.1.1h"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380fe324132bea01f45239fadfec9343adb044615f29930d039bec1ae7b9fa5b"
dependencies = [
 "cc",
]

[[package]]
name = "openssl-sys"
version = "0.9.58"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1619,7 1623,6 @@ dependencies = [
 "autocfg 1.0.1",
 "cc",
 "libc",
 "openssl-src",
 "pkg-config",
 "vcpkg",
]


@@ 1657,6 1660,17 @@ dependencies = [
]

[[package]]
name = "pem"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59698ea79df9bf77104aefd39cc3ec990cb9693fb59c3b0a70ddf2646fdffb4b"
dependencies = [
 "base64 0.12.3",
 "once_cell",
 "regex",
]

[[package]]
name = "percent-encoding"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1746,18 1760,18 @@ dependencies = [

[[package]]
name = "pin-project"
version = "0.4.23"
version = "0.4.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa"
checksum = "f48fad7cfbff853437be7cf54d7b993af21f53be7f0988cbfe4a51535aa77205"
dependencies = [
 "pin-project-internal",
]

[[package]]
name = "pin-project-internal"
version = "0.4.23"
version = "0.4.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f"
checksum = "24c6d293bdd3ca5a1697997854c6cf7855e43fb6a0ba1c47af57a5bcafd158ae"
dependencies = [
 "proc-macro2",
 "quote",


@@ 2070,6 2084,18 @@ dependencies = [
]

[[package]]
name = "rcgen"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4974f7e96ee51fa3c90c3022e02c3a7117e71cb2a84518a55e44360135200c25"
dependencies = [
 "chrono",
 "pem",
 "ring",
 "yasna",
]

[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 2126,11 2152,11 @@ dependencies = [
 "futures 0.1.29",
 "http 0.1.21",
 "hyper",
 "hyper-tls",
 "hyper-rustls",
 "log",
 "mime",
 "mime_guess",
 "native-tls",
 "rustls 0.16.0",
 "serde",
 "serde_json",
 "serde_urlencoded 0.5.5",


@@ 2138,10 2164,12 @@ dependencies = [
 "tokio 0.1.22",
 "tokio-executor",
 "tokio-io",
 "tokio-rustls 0.10.3",
 "tokio-threadpool",
 "tokio-timer",
 "url 1.7.2",
 "uuid",
 "webpki-roots 0.17.0",
 "winreg",
]



@@ 2177,6 2205,19 @@ dependencies = [

[[package]]
name = "rustls"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e"
dependencies = [
 "base64 0.10.1",
 "log",
 "ring",
 "sct",
 "webpki",
]

[[package]]
name = "rustls"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81"


@@ 2746,12 2787,26 @@ dependencies = [

[[package]]
name = "tokio-rustls"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d7cf08f990090abd6c6a73cab46fed62f85e8aef8b99e4b918a9f4a637f0676"
dependencies = [
 "bytes 0.4.12",
 "futures 0.1.29",
 "iovec",
 "rustls 0.16.0",
 "tokio-io",
 "webpki",
]

[[package]]
name = "tokio-rustls"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a"
dependencies = [
 "futures-core",
 "rustls",
 "rustls 0.18.1",
 "tokio 0.2.22",
 "webpki",
]


@@ 3099,6 3154,15 @@ dependencies = [

[[package]]
name = "webpki-roots"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a262ae37dd9d60f60dd473d1158f9fbebf110ba7b6a5051c8160460f6043718b"
dependencies = [
 "webpki",
]

[[package]]
name = "webpki-roots"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f20dea7535251981a9670857150d571846545088359b28e4951d350bdaf179f"


@@ 3188,3 3252,12 @@ dependencies = [
 "markup5ever",
 "time",
]

[[package]]
name = "yasna"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de7bff972b4f2a06c85f6d8454b09df153af7e3a4ec2aac81db1b105b684ddb"
dependencies = [
 "chrono",
]

M Cargo.toml => Cargo.toml +3 -3
@@ 1,6 1,6 @@
[package]
name = "gemifedi"
version = "0.3.0"
version = "0.3.1"
authors = ["Melody Horn <melody@boringcactus.com>"]
description = "a gemini frontend to the fediverse"
edition = "2018"


@@ 9,15 9,15 @@ license = "AGPL-3.0-or-later"
[dependencies]
async-std = { version = "1.6.4", features = ["attributes"] }
async-trait = "0.1.40"
elefren = { version = "0.22", features = ["toml"] }
elefren = { version = "0.22", default-features = false, features = ["toml", "rustls-tls"] }
html5ever = "0.25.1"
log = "0.4.11"
maj = { version = "0.6.0", git = "https://tulpa.dev/boringcactus/maj.git", branch = "preserve-client-certs" }
markup5ever = "0.10.0"
markup5ever_rcdom = "0.1.0"
native-tls = { version = "0.2.4", features = ["vendored"] }
percent-encoding = "2.1.0"
pretty_env_logger = "0.4.0"
rcgen = "0.8.5"
rustls = "0.18.1"
serde = { version = "1.0.116", features = ["derive"] }
sha2 = "0.9.1"

M README.md => README.md +1 -1
@@ 12,7 12,7 @@ currently mostly awful.

1. get a `gemifedi` binary through either method:

   a. `cargo install --git https://git.sr.ht/~boringcactus/gemifedi`.
   a. `cargo install --git https://git.sr.ht/~boringcactus/gemifedi --branch main`.

   b. hit up [the latest passing build](https://builds.sr.ht/~boringcactus/gemifedi) and download the Linux binary from the Artifacts panel.
2. run `gemifedi localhost` to attach it to `localhost`, or run `gemifedi --help` for more comprehensive options.

M src/main.rs => src/main.rs +23 -57
@@ 406,68 406,34 @@ async fn main() -> Result<(), Error> {
    let handler = Handler::new(&options);

    let key_file = options.key.unwrap_or(PathBuf::from(format!("./{}.key", options.domain)));

    if !key_file.exists() {
        log::info!("couldn't find key file {}, generating", key_file.display());
        use std::process::Command;
        let genrsa = Command::new("openssl")
            .args(&["genrsa", "-out"])
            .arg(&key_file)
            .arg("2048")
            .output();
        match genrsa {
            Err(err) => {
                eprintln!("Failed to generate key file");
                return Err(Box::new(err));
            }
            Ok(output) if !output.status.success() => {
                eprintln!("Error generating key file");
                return Err(format!("{:#?}", output).into());
            }
            _ => {
                log::debug!("generated key file OK")
            }
        }
    }

    let cert_file = options.cert.unwrap_or(PathBuf::from(format!("./{}.cert", options.domain)));

    if !cert_file.exists() {
        log::info!("couldn't find certificate file {}, generating", cert_file.display());
        let mut temp_file = tempfile::NamedTempFile::new()?;
        use std::io::Write;
        writeln!(temp_file, "[req]\ndistinguished_name=req\n[SAN]\nsubjectAltName=DNS:{}", options.domain)?;
        use std::process::Command;
        let req = Command::new("openssl")
            .args(&["req", "-new", "-x509", "-key"])
            .arg(&key_file)
            .arg("-out")
            .arg(&cert_file)
            .args(&["-days", "3650", "-subj"])
            .arg(format!("/CN={}", options.domain))
            .args(&["-extensions", "SAN", "-config"])
            .arg(temp_file.path())
            .output();
        match req {
            Err(err) => {
                eprintln!("Failed to generate certificate file");
                return Err(Box::new(err));
            }
            Ok(output) if !output.status.success() => {
                eprintln!("Error generating certificate file");
                return Err(format!("{:#?}", output).into());
            }
            _ => {
                log::debug!("generated certificate file OK")
            }
        }
    if !key_file.exists() || !cert_file.exists() {
        let missing = if key_file.exists() {
            format!("cert file {}", cert_file.display())
        } else if cert_file.exists() {
            format!("key file {}", key_file.display())
        } else {
            format!("key file {} or cert file {}", key_file.display(), cert_file.display())
        };
        log::info!("couldn't find {}, generating", missing);
        let params = rcgen::CertificateParams::new(vec![options.domain.clone()]);
        let cert = rcgen::Certificate::from_params(params)?;
        fs::write(&key_file, cert.serialize_private_key_pem())?;
        fs::write(&cert_file, cert.serialize_pem()?)?;
    }

    let mut tls_config = ServerConfig::new(TrustAnyClientCertOrAnonymous::new());
    let mut cert_file = BufReader::new(File::open(cert_file)?);
    let mut key_file = BufReader::new(File::open(key_file)?);
    let keys = rustls::internal::pemfile::rsa_private_keys(&mut key_file).unwrap();
    let key = keys.into_iter().next().unwrap();
    let rsa_keys = {
        let mut key_file = BufReader::new(File::open(&key_file)?);
        rustls::internal::pemfile::rsa_private_keys(&mut key_file).unwrap()
    };
    let pkcs8_keys = {
        let mut key_file = BufReader::new(File::open(key_file)?);
        rustls::internal::pemfile::pkcs8_private_keys(&mut key_file).unwrap()
    };
    let key = rsa_keys.into_iter().chain(pkcs8_keys).next().unwrap();
    tls_config.set_single_cert(
        rustls::internal::pemfile::certs(&mut cert_file).unwrap(),
        key,


@@ 478,7 444,7 @@ async fn main() -> Result<(), Error> {
    maj::server::serve(
        Arc::new(handler),
        tls_config,
        options.domain,
        options.domain, // or 0.0.0.0 to accept all network requests on that port
        options.port,
    ).await
}