mirror of https://github.com/perkeep/perkeep.git
Move TLS setup to config file, not flags. Use jsonconfig for root config.
This commit is contained in:
parent
0d3f7305cb
commit
17a804b7c1
|
@ -1,6 +1,10 @@
|
|||
{ "_for-emacs": "-*- mode: js2;-*-",
|
||||
"baseURL": ["_env", "http://localhost:${CAMLI_PORT}"],
|
||||
"password": ["_env", "${CAMLI_PASSWORD}"],
|
||||
|
||||
"TLSCertFile": ["_env", "${CAMLI_TLS_CRT_FILE}"],
|
||||
"TLSKeyFile": ["_env", "${CAMLI_TLS_KEY_FILE}"],
|
||||
|
||||
"prefixes": {
|
||||
"/": {
|
||||
"handler": "filesystem",
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{ "_for-emacs": "-*- mode: js2;-*-",
|
||||
"baseURL": ["_env", "http://localhost:${CAMLI_PORT}"],
|
||||
"password": ["_env", "${CAMLI_PASSWORD}"],
|
||||
"prefixes": {
|
||||
"/": {
|
||||
"handler": "filesystem",
|
||||
"handlerArgs": {
|
||||
"path": ["_env", "${CAMLI_ROOT}"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIBwTCCASugAwIBAgIBADALBgkqhkiG9w0BAQUwADAeFw0xMTAzMzEyMDI1MDda
|
||||
Fw00OTEyMzEyMzU5NTlaMAAwggCdMAsGCSqGSIb3DQEBAQOCAIwAMIIAhwKCAIB6
|
||||
oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZLKq2sM3gRaimsktIw
|
||||
nNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0SjdZ7vTPnFDPNsHGe
|
||||
KBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBA6NPME0wDgYDVR0PAQH/
|
||||
BAQDAgCgMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwGwYDVR0RBBQw
|
||||
EoIJMTI3LjAuMC4xggVbOjoxXTALBgkqhkiG9w0BAQUDggCBAHC3gbdvc44vs+wD
|
||||
g2kONiENnx8WKc0UTGg/TOXS3gaRb+CUIQtHWja65l8rAfclEovjHgZ7gx8brO0W
|
||||
JuC6p3MUAKsgOssIrrRIx2rpnfcmFVMzguCmrMNVmKUAalw18Yp0F72xYAIitVQl
|
||||
kJrLdIhBajcJRYu/YGltHQRaXuVt
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBkgIBAQKCAIB6oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZL
|
||||
Kq2sM3gRaimsktIwnNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0S
|
||||
jdZ7vTPnFDPNsHGeKBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBAwKC
|
||||
AIBRwh7Bil5Z8cYpZZv7jdQxDvbim7Z7ocRdeDmzZuF2I9RW04QyHHPIIlALnBvI
|
||||
YeF1veASz1gEFGUjzmbUGqKYSbCoTzXoev+F4bmbRxcX9sOmtslqvhMSHRSzA5NH
|
||||
aDVI3Hn4wvBVD8gePu8ACWqvPGbCiql11OKCMfjlPn2uuwJAx/24/F5DjXZ6hQQ7
|
||||
HxScOxKrpx5WnA9r1wZTltOTZkhRRzuLc21WJeE3M15QUdWi3zZxCKRFoth65HEs
|
||||
jy9YHQJAnPueRI44tz79b5QqVbeaOMUr7ZCb1Kp0uo6G+ANPLdlfliAupwij2eIz
|
||||
mHRJOWk0jBtXfRft1McH2H51CpXAyw==
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -5,12 +5,15 @@ use FindBin qw($Bin);
|
|||
use Getopt::Long;
|
||||
|
||||
sub usage {
|
||||
die "Usage: dev-blobserver [--wipe] <portnumber> -- [other_blobserver_opts]";
|
||||
die "Usage: dev-blobserver [--wipe] [--tls] <portnumber> -- [other_blobserver_opts]";
|
||||
}
|
||||
|
||||
my $opt_wipe;
|
||||
GetOptions("wipe" => \$opt_wipe)
|
||||
or usage();
|
||||
my $opt_tls;
|
||||
GetOptions(
|
||||
"wipe" => \$opt_wipe,
|
||||
"tls" => \$opt_tls,
|
||||
) or usage();
|
||||
|
||||
my $port = shift || "3179";
|
||||
usage() unless $port =~ /^\d+$/;
|
||||
|
@ -31,7 +34,10 @@ print "Starting blobserver on http://localhost:$port/ in $root\n";
|
|||
$ENV{CAMLI_PASSWORD} = "pass$port";
|
||||
$ENV{CAMLI_PORT} = $port;
|
||||
$ENV{CAMLI_ROOT} = $root;
|
||||
$ENV{CAMLI_TLS_CRT_FILE} = $opt_tls ? "$Bin/config/dev-tls.crt" : "";
|
||||
$ENV{CAMLI_TLS_KEY_FILE} = $opt_tls ? "$Bin/config/dev-tls.key" : "";
|
||||
exec("$FindBin::Bin/server/go/camlistored/camlistored",
|
||||
"-configfile=$Bin/config/dev-blobserver-config.json",
|
||||
"-listen=:$port",
|
||||
@ARGV);
|
||||
|
||||
|
|
|
@ -24,10 +24,25 @@ import (
|
|||
|
||||
type Obj map[string]interface{}
|
||||
|
||||
func (jc Obj) RequiredObject(key string) Obj {
|
||||
jc.noteKnownKey(key)
|
||||
ei, ok := jc[key]
|
||||
if !ok {
|
||||
jc.appendError(fmt.Errorf("Missing required config key %q (object)", key))
|
||||
return make(Obj)
|
||||
}
|
||||
m, ok := ei.(map[string]interface{})
|
||||
if !ok {
|
||||
jc.appendError(fmt.Errorf("Expected config key %q to be an object, not %T", key, ei))
|
||||
return make(Obj)
|
||||
}
|
||||
return Obj(m)
|
||||
}
|
||||
|
||||
func (jc Obj) RequiredString(key string) string {
|
||||
jc.noteKnownKey(key)
|
||||
ei, ok := jc[key]
|
||||
if !ok {
|
||||
if !ok {
|
||||
jc.appendError(fmt.Errorf("Missing required config key %q (string)", key))
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -32,17 +32,15 @@ import (
|
|||
|
||||
var Listen = flag.String("listen", "0.0.0.0:2856", "host:port to listen on, or :0 to auto-select")
|
||||
|
||||
var flagSelfUrlBase = flag.String("self-base-url", "", "If empty, automatic. Else of form https://foo.com (no trailing slash)")
|
||||
var flagTLS = flag.Bool("tls", false, "Use TLS")
|
||||
var flagCertFile = flag.String("tls-crt", "", "If using TLS, path to cert (public key) file.")
|
||||
var flagKeyFile = flag.String("tls-key", "", "If using TLS, path to private key file.")
|
||||
|
||||
type HandlerPicker func(req *http.Request) (http.HandlerFunc, bool)
|
||||
|
||||
type Server struct {
|
||||
premux []HandlerPicker
|
||||
mux *http.ServeMux
|
||||
listener net.Listener
|
||||
|
||||
enableTLS bool
|
||||
tlsCertFile, tlsKeyFile string
|
||||
}
|
||||
|
||||
func New() *Server {
|
||||
|
@ -52,15 +50,21 @@ func New() *Server {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Server) SetTLS(certFile, keyFile string) {
|
||||
s.enableTLS = true
|
||||
s.tlsCertFile = certFile
|
||||
s.tlsKeyFile = keyFile
|
||||
}
|
||||
|
||||
func (s *Server) BaseURL() string {
|
||||
if *flagSelfUrlBase != "" {
|
||||
// TODO: be automatic for TLS certs? find host name of cert inside it.
|
||||
return *flagSelfUrlBase
|
||||
scheme := "http"
|
||||
if s.enableTLS {
|
||||
scheme = "https"
|
||||
}
|
||||
if strings.HasPrefix(*Listen, ":") {
|
||||
return "http://127.0.0.1" + *Listen
|
||||
return scheme + "://127.0.0.1" + *Listen
|
||||
}
|
||||
return "http://" + strings.Replace(*Listen, "0.0.0.0:", "127.0.0.1:", 1)
|
||||
return scheme + "://" + strings.Replace(*Listen, "0.0.0.0:", "127.0.0.1:", 1)
|
||||
}
|
||||
|
||||
// Register conditional handler-picker functions which get run before
|
||||
|
@ -91,7 +95,7 @@ func (s *Server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
|
||||
func (s *Server) Serve() {
|
||||
if os.Getenv("TESTING_PORT_WRITE_FD") == "" { // Don't make noise during unit tests
|
||||
log.Printf("Starting to listen on http://%v/\n", *Listen)
|
||||
log.Printf("Starting to listen on %s\n", s.BaseURL())
|
||||
}
|
||||
|
||||
var err os.Error
|
||||
|
@ -100,14 +104,14 @@ func (s *Server) Serve() {
|
|||
log.Fatalf("Failed to listen on %s: %v", *Listen, err)
|
||||
}
|
||||
|
||||
if *flagTLS {
|
||||
if s.enableTLS {
|
||||
config := &tls.Config{
|
||||
Rand: rand.Reader,
|
||||
Time: time.Seconds,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
}
|
||||
config.Certificates = make([]tls.Certificate, 1)
|
||||
config.Certificates[0], err = tls.LoadX509KeyPair(*flagCertFile, *flagKeyFile)
|
||||
config.Certificates[0], err = tls.LoadX509KeyPair(s.tlsCertFile, s.tlsKeyFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load TLS cert: %v", err)
|
||||
}
|
||||
|
|
|
@ -204,8 +204,8 @@ func configFileMain() {
|
|||
}
|
||||
defer f.Close()
|
||||
dj := json.NewDecoder(f)
|
||||
config := make(map[string]interface{})
|
||||
if err = dj.Decode(&config); err != nil {
|
||||
rootjson := make(map[string]interface{})
|
||||
if err = dj.Decode(&rootjson); err != nil {
|
||||
extra := ""
|
||||
if serr, ok := err.(*json.SyntaxError); ok {
|
||||
if _, serr := f.Seek(0, os.SEEK_SET); serr != nil {
|
||||
|
@ -218,26 +218,34 @@ func configFileMain() {
|
|||
exitFailure("error parsing JSON object in config file %s%s\n%v",
|
||||
osutil.UserServerConfigPath(), extra, err)
|
||||
}
|
||||
if err := jsonconfig.EvaluateExpressions(config); err != nil {
|
||||
if err := jsonconfig.EvaluateExpressions(rootjson); err != nil {
|
||||
exitFailure("error expanding JSON config expressions in %s: %v", configPath, err)
|
||||
}
|
||||
|
||||
ws := webserver.New()
|
||||
baseURL := ws.BaseURL()
|
||||
|
||||
if password, ok := config["password"].(string); ok {
|
||||
auth.AccessPassword = password
|
||||
// Root configuration
|
||||
config := jsonconfig.Obj(rootjson)
|
||||
|
||||
{
|
||||
cert, key := config.OptionalString("TLSCertFile", ""), config.OptionalString("TLSKeyFile", "")
|
||||
if (cert != "") != (key != "") {
|
||||
exitFailure("TLSCertFile and TLSKeyFile must both be either present or absent")
|
||||
}
|
||||
if cert != "" {
|
||||
ws.SetTLS(cert, key)
|
||||
}
|
||||
}
|
||||
|
||||
if url, ok := config["baseURL"].(string); ok {
|
||||
auth.AccessPassword = config.OptionalString("password", "")
|
||||
if url := config.OptionalString("baseURL", ""); url != "" {
|
||||
baseURL = url
|
||||
}
|
||||
|
||||
prefixes, ok := config["prefixes"].(map[string]interface{})
|
||||
if !ok {
|
||||
exitFailure("No top-level \"prefixes\": {...} in %s", osutil.UserServerConfigPath)
|
||||
prefixes := config.RequiredObject("prefixes")
|
||||
if err := config.Validate(); err != nil {
|
||||
exitFailure("configuration error in root object's keys in %s: %v", configPath, err)
|
||||
}
|
||||
|
||||
createdHandlers := make(map[string]interface{})
|
||||
|
||||
for prefix, vei := range prefixes {
|
||||
|
|
Loading…
Reference in New Issue