tavern/start/command.go

161 lines
3.6 KiB
Go

package start
import (
"bytes"
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"runtime"
"github.com/getsentry/sentry-go"
"github.com/urfave/cli/v2"
"go.uber.org/zap"
"golang.org/x/crypto/bcrypt"
"github.com/ngerakines/tavern/config"
"github.com/ngerakines/tavern/g"
"github.com/ngerakines/tavern/storage"
)
var Command = cli.Command{
Name: "init",
Usage: "Initialize the server",
Flags: []cli.Flag{
&config.EnvironmentFlag,
&config.ListenFlag,
&config.DomainFlag,
&config.DatabaseFlag,
&config.TranslationsFlag,
&cli.StringFlag{
Name: "admin-email",
Usage: "The email address of the admin user",
Required: true,
},
&cli.StringFlag{
Name: "admin-password",
Usage: "The password of the admin user",
Required: true,
},
&cli.StringFlag{
Name: "admin-locale",
Usage: "The locale of the admin user",
Value: "en",
},
&cli.StringFlag{
Name: "admin-name",
Usage: "The name of the admin user",
Required: true,
},
&cli.StringFlag{
Name: "admin-displayname",
Usage: "The display name of the admin user",
},
&cli.StringFlag{
Name: "admin-about",
Usage: "The 'about me' of the admin user",
},
},
Action: serverCommandAction,
}
func serverCommandAction(cliCtx *cli.Context) error {
logger, err := config.Logger(cliCtx)
if err != nil {
return err
}
domain := cliCtx.String("domain")
siteBase := fmt.Sprintf("https://%s", domain)
logger.Info("Starting",
zap.String("command", cliCtx.Command.Name),
zap.String("GOOS", runtime.GOOS),
zap.String("site", siteBase),
zap.String("env", cliCtx.String("environment")))
sentryConfig, err := config.NewSentryConfig(cliCtx)
if err != nil {
return err
}
if sentryConfig.Enabled {
err = sentry.Init(sentry.ClientOptions{
Dsn: sentryConfig.Key,
Environment: cliCtx.String("environment"),
Release: fmt.Sprintf("%s-%s", g.ReleaseCode, g.GitCommit),
})
if err != nil {
return err
}
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTags(map[string]string{"container": "server"})
})
defer sentry.Recover()
}
db, dbClose, err := config.DB(cliCtx, logger)
if err != nil {
return err
}
defer dbClose()
s := storage.DefaultStorage(db)
userID := storage.NewV4()
name := cliCtx.String("admin-name")
displayName := cliCtx.String("admin-displayname")
if len(displayName) == 0 {
displayName = name
}
about := cliCtx.String("admin-about")
if len(about) == 0 {
about = "Just a user"
}
encPassword, err := bcrypt.GenerateFromPassword([]byte(cliCtx.String("admin-password")), bcrypt.DefaultCost)
if err != nil {
return err
}
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return err
}
privateKeyBytes := x509.MarshalPKCS1PrivateKey(key)
var privateKeyBuffer bytes.Buffer
if err := pem.Encode(&privateKeyBuffer, &pem.Block{
Type: "PRIVATE KEY",
Bytes: privateKeyBytes,
}); err != nil {
return err
}
privateKey := string(privateKeyBuffer.Bytes())
publicKeyBytes, err := x509.MarshalPKIXPublicKey(key.Public())
if err != nil {
return err
}
var publicKeyBuffer bytes.Buffer
if err = pem.Encode(&publicKeyBuffer, &pem.Block{
Type: "PUBLIC KEY",
Bytes: publicKeyBytes,
}); err != nil {
return err
}
publicKey := string(publicKeyBuffer.Bytes())
err = s.CreateUser(context.Background(), userID, cliCtx.String("admin-email"), cliCtx.String("admin-locale"), name, displayName, about, publicKey, privateKey, encPassword)
if err != nil {
logger.Error("unable to create user", zap.Error(err))
return err
}
return nil
}