blob: a05687894b0c9d71df014acebe84baaf20be374e [file] [log] [blame]
// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Keyserver is a wrapper for a key implementation that presents it as an HTTP
// interface. It provides the common code used by all keyserver commands.
package keyserver // import "upspin.io/serverutil/keyserver"
import (
"flag"
"io/ioutil"
"net/http"
"upspin.io/cloud/mail"
"upspin.io/cloud/mail/sendgrid"
"upspin.io/config"
"upspin.io/errors"
"upspin.io/flags"
"upspin.io/key/inprocess"
"upspin.io/key/server"
"upspin.io/log"
"upspin.io/rpc/keyserver"
"upspin.io/serverutil/signup"
"upspin.io/upspin"
// Load required transports
_ "upspin.io/key/transports"
yaml "gopkg.in/yaml.v2"
)
// mailConfig specifies a config file name for the mail service.
// The format of the email config file must be lines: api key, incoming email
// provider user name and password.
var mailConfigFile = flag.String("mail_config", "", "config file name for mail service")
// Main starts the keyserver. If setup is not nil it is called with the
// instantiated KeyServer.
func Main(setup func(upspin.KeyServer)) {
flags.Parse(flags.Server, "kind", "serverconfig")
cfg, err := config.FromFile(flags.Config)
if err != nil {
log.Fatal(err)
}
// Create a new key implementation.
var key upspin.KeyServer
switch flags.ServerKind {
case "inprocess":
key = inprocess.New()
case "server":
key, err = server.New(flags.ServerConfig...)
default:
err = errors.Errorf("bad -kind %q", flags.ServerKind)
}
if err != nil {
log.Fatalf("Setting up KeyServer: %v", err)
}
if setup != nil {
setup(key)
}
http.Handle("/api/Key/", keyserver.New(cfg, key, upspin.NetAddr(flags.NetAddr)))
if logger, ok := key.(server.Logger); ok {
http.Handle("/log", logHandler{logger: logger})
}
signupURL := "https://" + flags.NetAddr + "/signup"
f := cfg.Factotum()
if f == nil {
log.Fatal("keyserver: supplied config must include keys")
}
var mc *signup.MailConfig
if *mailConfigFile == "" {
log.Info.Printf("keyserver: WARNING: -mail_config not supplied; no emails will be sent, they will be logged instead")
mc = &signup.MailConfig{Mail: mail.Logger(log.Info)}
} else {
data, err := ioutil.ReadFile(*mailConfigFile)
if err != nil {
log.Fatalf("keyserver: %v", err)
}
mc, err = parseMailConfig(data)
if err != nil {
log.Fatalf("keyserver: %v", err)
}
}
http.Handle("/signup", signup.NewHandler(signupURL, f, key, mc))
}
// parseMailConfig reads YAML data and returns a signup.MailConfig
// apikey: SENDGRID_API_KEY
// notify: notify-signups@email.com
// from: sender@email.com
// project: test
func parseMailConfig(data []byte) (*signup.MailConfig, error) {
c := make(map[string]string)
if err := yaml.Unmarshal(data, &c); err != nil {
return nil, errors.E(errors.IO, err)
}
for _, k := range []string{"apikey", "notify", "project", "from"} {
if c[k] == "" {
return nil, errors.E(errors.Invalid, errors.Errorf(`key "%s" is missing in config (need "apikey", "notify", "project" and "from")`, k))
}
}
return &signup.MailConfig{
Project: c["project"],
Notify: c["notify"],
From: c["from"],
Mail: sendgrid.New(c["apikey"]),
}, nil
}