Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ linters:
- perfsprint
- testpackage
- varnamelen
- wrapcheck
- wsl
- wsl_v5
settings:
Expand Down
3 changes: 3 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ func Load(cfgPath string) (*Config, error) {

// Config is the structure of the JSON configuration file.
type Config struct {
// ListenAddr for the demo site to listen on. Eg, ":443".
ListenAddr string

// Sites is a list of sites to host.
Sites []Site

Expand Down
2 changes: 2 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
func TestLoadConfig(t *testing.T) {
t.Parallel()
expected := config.Config{
ListenAddr: "localhost:8443",

Sites: []config.Site{
{
IssuerCN: "minica root ca 5345e6",
Expand Down
2 changes: 2 additions & 0 deletions config/test.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"listenAddr": "localhost:8443",

"sites": [
{
"issuerCN": "minica root ca 5345e6",
Expand Down
16 changes: 14 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
package main

import (
"crypto/tls"
"flag"
"fmt"
"log/slog"
"os"

"github.com/letsencrypt/test-certs-site/config"
"github.com/letsencrypt/test-certs-site/server"
)

func run(args []string) error {
Expand All @@ -30,9 +32,19 @@ func run(args []string) error {
return fmt.Errorf("loading config: %w", err)
}

slog.Info("Loaded configuration! This program doesn't do anything yet.", slog.String("configFile", *cfgPath), slog.Any("config", cfg))
// This is just a temporary placeholder, using a single static test certificate
// This will normally be provided by the key storage part of this program
cert := os.Getenv("TEST_CERT")
key := os.Getenv("TEST_KEY")
temporaryStaticCert, err := tls.LoadX509KeyPair(cert, key)
if err != nil {
return fmt.Errorf("loading temporary certificate: %w", err)
}
todoGetCert := func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &temporaryStaticCert, nil
}

return nil
return server.Run(cfg.ListenAddr, todoGetCert)
}

func main() {
Expand Down
67 changes: 67 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Package server is the HTTPS server for test-certs-site.
package server

import (
"context"
"crypto/tls"
"fmt"
"log/slog"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)

// handle an http request with a placeholder response.
func handle(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet || r.URL.Path != "/" {
w.WriteHeader(http.StatusNotFound)
_, _ = fmt.Fprint(w, "404 Not Found")

return
}

// This is just a placeholder until we make a nice site.
_, _ = fmt.Fprintf(w, "This is a demontration site for %s", r.TLS.ServerName)
}

// GetCertificateFunc is the type of the TLSConfig.GetCertificate function.
// The webserver will use it to obtain certificates, including fulfilling
// ACME TLS-ALPN-01 challenges.
type GetCertificateFunc func(info *tls.ClientHelloInfo) (*tls.Certificate, error)

// Run the server, until the process is signaled to exit.
func Run(addr string, getCert GetCertificateFunc) error {
// We want http requests to time out relatively quickly, as this server shouldn't be doing much.
const timeout = 5 * time.Second

srv := http.Server{
Addr: addr,
Handler: http.HandlerFunc(handle),

IdleTimeout: timeout,
ReadHeaderTimeout: timeout,
ReadTimeout: timeout,
WriteTimeout: timeout,

TLSConfig: &tls.Config{
GetCertificate: getCert,
MinVersion: tls.VersionTLS12,
},
}

// Wait for a signal to shut down the server.
go func() {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan

err := srv.Shutdown(context.Background())
if err != nil {
slog.Error(err.Error())
}
}()

return srv.ListenAndServeTLS("", "")
}
Loading