-
Notifications
You must be signed in to change notification settings - Fork 34
/
utils.go
172 lines (137 loc) · 4.6 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//
// simplecert
//
// Created by Philipp Mieden
// Contact: dreadl0ck@protonmail.ch
// Copyright © 2018 bestbytes. All rights reserved.
//
package simplecert
import (
"crypto/tls"
"fmt"
"log"
"net/http"
"os"
"os/exec"
"strings"
"github.com/foomo/tlsconfig"
)
// internal date of the backup to allow restoring in case of an error
// even if renewal happens just before midnight and restoring afterwards
var backupDate string
const localhost = "127.0.0.1"
/*
* Utils
*/
// ListenAndServeTLSCustom allows to specify the simplecert and TLS configuration
// and does not redirect the traffic arriving at port 80
func ListenAndServeTLSCustom(addr string, handler http.Handler, cfg *Config, tlsconf *tls.Config, cleanup func(), domains ...string) error {
certReloader, err := Init(cfg, cleanup)
if err != nil {
log.Fatal("[FATAL] simplecert init failed: ", err)
}
// now set GetCertificate to the reloaders GetCertificateFunc to enable hot reload
tlsconf.GetCertificate = certReloader.GetCertificateFunc()
// init server
s := &http.Server{
Addr: addr,
TLSConfig: tlsconf,
Handler: handler,
}
log.Println("serving: https://" + cfg.Domains[0])
// lets go
return s.ListenAndServeTLS("", "")
}
// ListenAndServeTLSLocal is a util to use simplecert for local development
func ListenAndServeTLSLocal(addr string, handler http.Handler, cleanup func(), domains ...string) error {
cfg := Default
cfg.Domains = domains
cfg.CacheDir = "simplecert"
cfg.Local = true
certReloader, err := Init(cfg, cleanup)
if err != nil {
log.Fatal("[FATAL] simplecert init failed: ", err)
}
// redirect HTTP to HTTPS
log.Println("starting HTTP Listener on Port 80")
go http.ListenAndServe(":80", http.HandlerFunc(Redirect))
// init strict tlsConfig with certReloader
tlsconf := tlsconfig.NewServerTLSConfig(tlsconfig.TLSModeServerStrict)
// now set GetCertificate to the reloaders GetCertificateFunc to enable hot reload
tlsconf.GetCertificate = certReloader.GetCertificateFunc()
// init server
s := &http.Server{
Addr: addr,
TLSConfig: tlsconf,
Handler: handler,
}
log.Println("serving: https://" + cfg.Domains[0])
// lets go
return s.ListenAndServeTLS("", "")
}
// ListenAndServeTLS is a util to use simplecert in production
func ListenAndServeTLS(addr string, handler http.Handler, mail string, cleanup func(), domains ...string) error {
cfg := Default
cfg.Domains = domains
cfg.CacheDir = "simplecert"
cfg.SSLEmail = mail
certReloader, err := Init(cfg, cleanup)
if err != nil {
log.Fatal("[FATAL] simplecert init failed: ", err)
}
// redirect HTTP to HTTPS
log.Println("starting HTTP Listener on Port 80")
go http.ListenAndServe(":80", http.HandlerFunc(Redirect))
// init strict tlsConfig with certReloader
tlsconf := tlsconfig.NewServerTLSConfig(tlsconfig.TLSModeServerStrict)
// now set GetCertificate to the reloaders GetCertificateFunc to enable hot reload
tlsconf.GetCertificate = certReloader.GetCertificateFunc()
// init server
s := &http.Server{
Addr: addr,
TLSConfig: tlsconf,
Handler: handler,
}
log.Println("serving: https://" + cfg.Domains[0])
// lets go
return s.ListenAndServeTLS("", "")
}
// Redirect a request to HTTPS and strips the www. subdomain
func Redirect(w http.ResponseWriter, req *http.Request) {
target := "https://" + strings.TrimPrefix(req.Host, "www.") + req.URL.Path
if len(req.URL.RawQuery) > 0 {
target += "?" + req.URL.RawQuery
}
fmt.Println("redirecting client to https: ", target, " ("+req.Host+")", "UserAgent:", req.UserAgent())
http.Redirect(w, req, target, http.StatusTemporaryRedirect)
}
////////////////////
// Private
///////////////////
// ensures the cacheDir exists, fatals on error
func ensureCacheDirExists(cacheDir string) {
log.Println("[INFO] simplecert: checking if cacheDir " + cacheDir + " exists...")
// create cacheDir if necessary
info, err := os.Stat(cacheDir)
if err != nil {
log.Println("[INFO] simplecert: cacheDir does not exist - creating it")
err = os.MkdirAll(c.CacheDir, c.CacheDirPerm)
if err != nil {
log.Fatal("[FATAL] simplecert: could not create cacheDir: ", err)
}
} else {
// exists. make sure its a directory
if !info.IsDir() {
log.Fatal("[FATAL] simplecert: cacheDir: expected a directory but got a file?!")
}
}
}
// runCommand executes the named command with the supplied arguments
// and fatals on error
func runCommand(cmd string, args ...string) {
out, err := exec.Command(cmd, args...).CombinedOutput()
if err != nil {
log.Println("[ERROR] failed to run command: ", cmd+strings.Join(args, " "))
log.Fatal("[FATAL] simplecert: error: ", err, ", output: ", string(out))
}
}