diff --git a/Cargo.lock b/Cargo.lock
index b4f3867..9e66c8f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -111,6 +111,12 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
[[package]]
name = "arrayvec"
version = "0.7.2"
@@ -158,6 +164,18 @@ version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813"
+[[package]]
+name = "bitvec"
+version = "0.19.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -458,9 +476,11 @@ name = "domani"
version = "0.1.0"
dependencies = [
"acme2",
+ "bytes",
"clap",
"env_logger",
"futures",
+ "gemini",
"gix",
"handlebars",
"hex",
@@ -660,6 +680,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
+[[package]]
+name = "funty"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
+
[[package]]
name = "futures"
version = "0.3.28"
@@ -749,6 +775,18 @@ dependencies = [
"slab",
]
+[[package]]
+name = "gemini"
+version = "0.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12a820f5a9ac6f433b34944dc8d17b759d5009275c8fe12f73b873153dbcd4e0"
+dependencies = [
+ "nom 6.1.2",
+ "paste",
+ "thiserror",
+ "url",
+]
+
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -828,7 +866,7 @@ dependencies = [
"btoi",
"gix-date",
"itoa",
- "nom",
+ "nom 7.1.3",
"thiserror",
]
@@ -891,7 +929,7 @@ dependencies = [
"gix-sec",
"log",
"memchr",
- "nom",
+ "nom 7.1.3",
"once_cell",
"smallvec",
"thiserror",
@@ -1100,7 +1138,7 @@ dependencies = [
"gix-validate",
"hex",
"itoa",
- "nom",
+ "nom 7.1.3",
"smallvec",
"thiserror",
]
@@ -1195,7 +1233,7 @@ dependencies = [
"gix-hash",
"gix-transport",
"maybe-async",
- "nom",
+ "nom 7.1.3",
"thiserror",
]
@@ -1226,7 +1264,7 @@ dependencies = [
"gix-tempfile",
"gix-validate",
"memmap2",
- "nom",
+ "nom 7.1.3",
"thiserror",
]
@@ -1767,6 +1805,19 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+[[package]]
+name = "lexical-core"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
+dependencies = [
+ "arrayvec 0.5.2",
+ "bitflags 1.3.2",
+ "cfg-if",
+ "ryu",
+ "static_assertions",
+]
+
[[package]]
name = "libc"
version = "0.2.142"
@@ -1954,6 +2005,19 @@ dependencies = [
"smallvec",
]
+[[package]]
+name = "nom"
+version = "6.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
+dependencies = [
+ "bitvec",
+ "funty",
+ "lexical-core",
+ "memchr",
+ "version_check",
+]
+
[[package]]
name = "nom"
version = "7.1.3"
@@ -2081,6 +2145,12 @@ dependencies = [
"windows-sys 0.45.0",
]
+[[package]]
+name = "paste"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+
[[package]]
name = "pem"
version = "2.0.1"
@@ -2249,6 +2319,12 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "radium"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
+
[[package]]
name = "radix_trie"
version = "0.2.1"
@@ -2805,6 +2881,12 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
[[package]]
name = "tempdir"
version = "0.3.7"
@@ -3121,7 +3203,7 @@ version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "794a32261a1f5eb6a4462c81b59cec87b5c27d5deea7dd1ac8fc781c41d226db"
dependencies = [
- "arrayvec",
+ "arrayvec 0.7.2",
]
[[package]]
@@ -3508,3 +3590,9 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
+
+[[package]]
+name = "wyz"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
diff --git a/Cargo.toml b/Cargo.toml
index 937cf7e..7fcf078 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,7 +31,7 @@ mime_guess = "2.0.4"
hyper = { version = "0.14.26", features = [ "server", "stream" ]}
http = "0.2.9"
serde_urlencoded = "0.7.1"
-tokio-util = "0.7.8"
+tokio-util = { version = "0.7.8", features = [ "io" ]}
acme2 = "0.5.1"
openssl = "0.10.52"
rustls = "0.21.1"
@@ -45,6 +45,8 @@ serde_yaml = "0.9.22"
rand = "0.8.5"
reqwest = "0.11.18"
hyper-reverse-proxy = "0.5.1"
+gemini = "0.0.5"
+bytes = "1.4.0"
[patch.crates-io]
tokio-rustls = { git = "https://code.betamike.com/micropelago/tokio-rustls.git", branch = "start-handshake-into-inner" }
diff --git a/README.md b/README.md
index ae8367a..a58add3 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,17 @@ their DNS server.
[Demo which may or may not be live](https://domani.mediocregopher.com)
+Domani supports serving domains using the following protocols:
+
+- HTTP
+- HTTPS (with SSL certificates automatically retrieved using LetsEncrypt)
+- [Gemini](https://gemini.circumlunar.space/)
+
+Files are served as-is, with their extension being used to determine
+Content-Type. If a directory is requested (e.g. `/some/dir/`) then `index.html`
+will be requested if the protocol is HTTP, or `index.gmi` if the protocol is
+gemini.
+
## Build
Domani uses nix flakes for building and setting up the development environment.
@@ -60,13 +71,13 @@ domain:
# An example built-in domain backed by a git repo.
#git.example.com:
- # kind: git
- # url: "https://somewhere.com/some/repo.git"
- # branch_name: main
- #
- # # If true then the built-in will be included in the web interface's
- # # domain list, but will not be configurable in the web interface
- # public: false
+ #kind: git
+ #url: "https://somewhere.com/some/repo.git"
+ #branch_name: main
+
+ # If true then the built-in will be included in the web interface's
+ # domain list, but will not be configurable in the web interface
+ #public: false
service:
@@ -102,8 +113,9 @@ service:
# https_addr is set.
#http_addr: "[::]:3080"
- # The address to listen for HTTPS requests on. This is optional.
- #https_addr: "[::]:443"
+ # The address to listen for HTTPS requests on. Defaults to not having HTTP
+ # enabled. You can enable HTTPS by setting this to "[::]:443".
+ #https_addr: null
#proxied_domains:
@@ -117,7 +129,6 @@ service:
# * dns.resolver_addr is ignored and the system-wide dns is used
#
#proxy.example.com:
- # kind: http_proxy
# url: "http://some.other.service.com"
#
# # Extra headers to add to proxied requests
@@ -126,6 +137,25 @@ service:
# value: "yet.another.service.com"
# - name: X-HEADER-TO-DELETE
# value: ""
+
+ #gemini:
+
+ # The address to listen for gemini requests on. Set this to null to disable
+ # gemini support.
+ #gemini_addr: "[::]:3965"
+
+ #proxied_domains:
+
+ # An example built-in domain backed by a reverse-proxy to some other
+ # gemini server. Requests to this domain will have connections
+ # transparently proxied to the backing server.
+ #
+ # Proxies are currently limited in the following ways:
+ # * url must be to a gemini endpoint
+ # * dns.resolver_addr is ignored and the system-wide dns is used
+ #
+ #proxy.example.com:
+ # url: "gemini://some.other.service.com"
```
The YAML config file can be passed to the Domani process via the `--config-path`
@@ -159,10 +189,25 @@ nix develop
Within the shell which opens you can do `cargo run` to start a local instance.
+Using the default configuration, the domain `domani-test.localhost` should be
+immediately available at:
+
+* `http://domani-test.localhost:3080`
+* `gemini://domani-test.localhost:3965`
+
## Roadmap
+* Better web interface design.
+* Tutorials aimed at beginner users.
+
* Support for more backends than just git repositories, including:
* IPFS/IPNS
* Small static files (e.g. for well-knowns)
* Google Drive
* Dropbox
+
+* Automatic HTTP/gemtext rendering for markdown files.
+* Automatic HTTP rendering for gemtext files.
+
+* Ability to disable the web interface.
+* Ability to disable HTTP completely.
diff --git a/src/domain/gemini.rs b/src/domain/gemini.rs
index 3dd335d..927b109 100644
--- a/src/domain/gemini.rs
+++ b/src/domain/gemini.rs
@@ -4,7 +4,21 @@ use crate::{domain, util};
use serde::{Deserialize, Serialize};
-use std::{fs, path, sync};
+use std::{fs, path};
+
+pub trait Store {
+ fn get_certificate(
+ &self,
+ domain: &domain::Name,
+ ) -> unexpected::Result