go-gemini/gemini.go
2020-09-25 21:43:13 -04:00

90 lines
2.3 KiB
Go

package gemini
import (
"crypto/x509"
"errors"
"log"
"os"
"path/filepath"
)
// Status codes.
const (
StatusInput = 10
StatusSensitiveInput = 11
StatusSuccess = 20
StatusRedirectTemporary = 30
StatusRedirectPermanent = 31
StatusTemporaryFailure = 40
StatusServerUnavailable = 41
StatusCGIError = 42
StatusProxyError = 43
StatusSlowDown = 44
StatusPermanentFailure = 50
StatusNotFound = 51
StatusGone = 52
StatusProxyRequestRefused = 53
StatusBadRequest = 59
StatusClientCertificateRequired = 60
StatusCertificateNotAuthorised = 61
StatusCertificateNotValid = 62
)
// Status code categories.
const (
StatusClassInput = 1
StatusClassSuccess = 2
StatusClassRedirect = 3
StatusClassTemporaryFailure = 4
StatusClassPermanentFailure = 5
StatusClassClientCertificateRequired = 6
)
var (
crlf = []byte("\r\n")
)
// TOFUClient is a client that implements Trust-On-First-Use.
type TOFUClient struct {
// Trusts, if not nil, will be called to determine whether the client should
// trust the provided certificate.
Trusts func(cert *x509.Certificate, req *Request) bool
}
func (t *TOFUClient) VerifyCertificate(cert *x509.Certificate, req *Request) error {
if knownHosts.Has(req.URL.Host, cert) {
return nil
}
if t.Trusts != nil && t.Trusts(cert, req) {
host := NewKnownHost(cert)
knownHosts = append(knownHosts, host)
knownHostsFile, err := os.OpenFile(knownHostsPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Print(err)
}
if _, err := host.Write(knownHostsFile); err != nil {
log.Print(err)
}
return nil
}
return errors.New("gemini: certificate not trusted")
}
var (
knownHosts KnownHosts
knownHostsPath string
knownHostsFile *os.File
)
func init() {
configDir, err := os.UserConfigDir()
knownHostsPath = filepath.Join(configDir, "gemini")
os.MkdirAll(knownHostsPath, 0755)
knownHostsPath = filepath.Join(knownHostsPath, "known_hosts")
knownHostsFile, err = os.OpenFile(knownHostsPath, os.O_CREATE|os.O_RDONLY, 0644)
if err != nil {
return
}
knownHosts = ParseKnownHosts(knownHostsFile)
}