Skip to content

Commit 79a6682

Browse files
authored
enhance: add functions for daemon servers for mTLS (#87)
Signed-off-by: Grant Linville <[email protected]>
1 parent 2ddfb8e commit 79a6682

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

pkg/daemon/daemon.go

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package daemon
2+
3+
import (
4+
"crypto/tls"
5+
"crypto/x509"
6+
"encoding/base64"
7+
"errors"
8+
"fmt"
9+
"net/http"
10+
"os"
11+
)
12+
13+
type Server struct {
14+
mux *http.ServeMux
15+
tlsConfig *tls.Config
16+
}
17+
18+
// CreateServer creates a new HTTP server with TLS configured for GPTScript.
19+
// This function should be used when creating a new server for a daemon tool.
20+
// The server should then be started with the StartServer function.
21+
func CreateServer() (*Server, error) {
22+
return CreateServerWithMux(http.DefaultServeMux)
23+
}
24+
25+
// CreateServerWithMux creates a new HTTP server with TLS configured for GPTScript.
26+
// This function should be used when creating a new server for a daemon tool with a custom ServeMux.
27+
// The server should then be started with the StartServer function.
28+
func CreateServerWithMux(mux *http.ServeMux) (*Server, error) {
29+
tlsConfig, err := getTLSConfig()
30+
if err != nil {
31+
return nil, fmt.Errorf("failed to get TLS config: %v", err)
32+
}
33+
34+
return &Server{
35+
mux: mux,
36+
tlsConfig: tlsConfig,
37+
}, nil
38+
}
39+
40+
// Start starts an HTTP server created by the CreateServer function.
41+
// This is for use with daemon tools.
42+
func (s *Server) Start() error {
43+
server := &http.Server{
44+
Addr: fmt.Sprintf("127.0.0.1:%s", os.Getenv("PORT")),
45+
TLSConfig: s.tlsConfig,
46+
Handler: s.mux,
47+
}
48+
49+
if err := server.ListenAndServeTLS("", ""); err != nil && !errors.Is(err, http.ErrServerClosed) {
50+
return fmt.Errorf("stopped serving: %v", err)
51+
}
52+
return nil
53+
}
54+
55+
func (s *Server) HandleFunc(pattern string, handler http.HandlerFunc) {
56+
s.mux.HandleFunc(pattern, handler)
57+
}
58+
59+
func getTLSConfig() (*tls.Config, error) {
60+
certB64 := os.Getenv("CERT")
61+
privateKeyB64 := os.Getenv("PRIVATE_KEY")
62+
gptscriptCertB64 := os.Getenv("GPTSCRIPT_CERT")
63+
64+
if certB64 == "" {
65+
return nil, fmt.Errorf("CERT not set")
66+
} else if privateKeyB64 == "" {
67+
return nil, fmt.Errorf("PRIVATE_KEY not set")
68+
} else if gptscriptCertB64 == "" {
69+
return nil, fmt.Errorf("GPTSCRIPT_CERT not set")
70+
}
71+
72+
certBytes, err := base64.StdEncoding.DecodeString(certB64)
73+
if err != nil {
74+
return nil, fmt.Errorf("failed to decode cert base64: %v", err)
75+
}
76+
77+
privateKeyBytes, err := base64.StdEncoding.DecodeString(privateKeyB64)
78+
if err != nil {
79+
return nil, fmt.Errorf("failed to decode private key base64: %v", err)
80+
}
81+
82+
gptscriptCertBytes, err := base64.StdEncoding.DecodeString(gptscriptCertB64)
83+
if err != nil {
84+
return nil, fmt.Errorf("failed to decode gptscript cert base64: %v", err)
85+
}
86+
87+
cert, err := tls.X509KeyPair(certBytes, privateKeyBytes)
88+
if err != nil {
89+
return nil, fmt.Errorf("failed to create X509 key pair: %v", err)
90+
}
91+
92+
pool := x509.NewCertPool()
93+
if !pool.AppendCertsFromPEM(gptscriptCertBytes) {
94+
return nil, fmt.Errorf("failed to append gptscript cert to pool")
95+
}
96+
97+
return &tls.Config{
98+
Certificates: []tls.Certificate{cert},
99+
ClientCAs: pool,
100+
ClientAuth: tls.RequireAndVerifyClientCert,
101+
}, nil
102+
}

0 commit comments

Comments
 (0)