2020-09-21 13:48:42 -06:00
|
|
|
# go-gemini
|
|
|
|
|
2020-09-21 16:28:34 -06:00
|
|
|
[![GoDoc](https://godoc.org/git.sr.ht/~adnano/go-gemini?status.svg)](https://godoc.org/git.sr.ht/~adnano/go-gemini)
|
|
|
|
|
2020-09-21 20:09:50 -06:00
|
|
|
`go-gemini` implements the [Gemini protocol](https://gemini.circumlunar.space)
|
|
|
|
in Go.
|
2020-09-21 13:48:42 -06:00
|
|
|
|
2020-09-21 15:23:51 -06:00
|
|
|
It aims to provide an API similar to that of `net/http` to make it easy to
|
|
|
|
develop Gemini clients and servers.
|
2020-09-21 13:48:42 -06:00
|
|
|
|
2020-09-21 15:23:51 -06:00
|
|
|
## Examples
|
2020-09-21 13:48:42 -06:00
|
|
|
|
2020-09-21 15:23:51 -06:00
|
|
|
See `examples/client` and `examples/server` for an example client and server.
|
2020-09-21 13:48:42 -06:00
|
|
|
|
2020-09-21 15:23:51 -06:00
|
|
|
To run the examples:
|
2020-09-21 13:48:42 -06:00
|
|
|
|
2020-09-21 16:25:31 -06:00
|
|
|
go run -tags=example ./examples/server
|
2020-09-24 18:13:59 -06:00
|
|
|
|
|
|
|
## Overview
|
|
|
|
|
|
|
|
A quick overview of the Gemini protocol:
|
|
|
|
|
|
|
|
1. Client opens connection
|
|
|
|
2. Server accepts connection
|
|
|
|
3. Client and server complete a TLS handshake
|
|
|
|
4. Client validates server certificate
|
|
|
|
5. Client sends request
|
|
|
|
6. Server sends response header
|
|
|
|
7. Server sends response body (only for successful responses)
|
|
|
|
8. Server closes connection
|
|
|
|
9. Client handles response
|
|
|
|
|
|
|
|
The way this is implemented in this package is like so:
|
|
|
|
|
2020-09-25 16:53:20 -06:00
|
|
|
1. Client makes a request with `NewRequest`. The client then sends the request
|
2020-09-25 21:06:54 -06:00
|
|
|
with `(*Client).Send(*Request) (*Response, error)`. The client then determines whether
|
|
|
|
to trust the certificate in `TrustCertificte(*x509.Certificate, *KnownHosts) bool`.
|
|
|
|
(See [TOFU](#tofu)).
|
2020-09-24 18:13:59 -06:00
|
|
|
2. Server recieves the request and constructs a response.
|
|
|
|
The server calls the `Serve(*ResponseWriter, *Request)` method on the
|
|
|
|
`Handler` field. The handler writes the response. The server then closes
|
|
|
|
the connection.
|
2020-09-25 17:53:50 -06:00
|
|
|
3. Client recieves the response as a `*Response`. The client then handles the
|
|
|
|
response.
|
2020-09-25 21:06:54 -06:00
|
|
|
|
|
|
|
## TOFU
|
|
|
|
|
2020-09-25 22:40:28 -06:00
|
|
|
This package provides an easy way to implement Trust On First Use in your
|
|
|
|
clients. Here is a simple client using TOFU to authenticate certificates:
|
2020-09-25 21:06:54 -06:00
|
|
|
|
|
|
|
```go
|
|
|
|
client := &gemini.Client{
|
|
|
|
KnownHosts: gemini.LoadKnownHosts(".local/share/gemini/known_hosts"),
|
|
|
|
TrustCertificate: func(cert *x509.Certificate, knownHosts *gemini.KnownHosts) bool {
|
|
|
|
// If the certificate is in the known hosts list, allow the connection
|
|
|
|
if knownHosts.Has(cert) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
// Prompt the user
|
|
|
|
if userTrustsCertificateTemporarily() {
|
|
|
|
// Temporarily trust the certificate
|
|
|
|
return true
|
|
|
|
} else if userTrustsCertificatePermanently() {
|
|
|
|
// Add the certificate to the known hosts file
|
|
|
|
knownHosts.Add(cert)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
// User does not trust the certificate
|
|
|
|
return false
|
|
|
|
},
|
|
|
|
}
|
|
|
|
```
|