//go:build mage // +build mage package main import ( "context" "encoding/json" "io/ioutil" "os" "path/filepath" "strings" "github.com/magefile/mage/mg" "github.com/magefile/mage/sh" "github.com/magefile/mage/target" "github.com/xlgmokha/x/pkg/env" "github.com/xlgmokha/x/pkg/x" ) type Step mg.Namespace func (s Step) Clean() error { globs := []string{ "tmp/step/*/*", } for _, item := range globs { fs, err := filepath.Glob(item) if err != nil { return err } for _, f := range fs { if strings.HasSuffix(f, "/.keep") { continue } if err := os.RemoveAll(f); err != nil { return err } } } return nil } func (s Step) Setup() { mg.SerialDeps(s.mkPassword, s.createCA, s.enableACMEProvisioner) } func (s Step) Install() error { return sh.RunWithV( s.env(), "step", "certificate", "install", s.pathPlus("/certs/root_ca.crt"), ) } func (s Step) Server(ctx context.Context) error { mg.SerialDeps(s.Setup) return sh.RunWithV( s.env(), "step-ca", s.pathPlus("config/ca.json"), "--password-file="+s.pathPlus("password.txt"), ) } func (s Step) Provisioners() error { return sh.RunV("curl", "-k", "-s", "https://localhost:8081/provisioners") } func (s Step) ACME() error { return sh.RunV("curl", "-k", "-s", "https://localhost:8081/acme/acme/directory") } func (s Step) Status() { mg.SerialDeps(s.Provisioners, s.ACME) } func (s Step) mkPassword() error { file := s.passwordFile() if ok, err := target.Dir(file); err != nil || !ok { return nil } return os.WriteFile(file, []byte("password"), 0600) } func (s Step) createCA() error { if ok, err := target.Dir(s.pathPlus("config/ca.json"), s.passwordFile()); err != nil || !ok { return nil } return sh.RunWithV( s.env(), "step", "ca", "init", "--deployment-type=standalone", "--address=localhost:8081", "--dns=localhost", "--dns=*.localhost", "--name=CA", "--provisioner=example", "--provisioner-password-file="+s.passwordFile(), "--password-file="+s.passwordFile(), ) } func (s Step) enableACMEProvisioner() error { bytes, err := ioutil.ReadFile(s.pathPlus("config/ca.json")) if err != nil { return err } items := map[string]interface{}{} if err := json.Unmarshal(bytes, &items); err != nil { return err } provisioners := items["authority"].(map[string]interface{})["provisioners"].([]interface{}) if len(provisioners) < 2 { return sh.RunWithV(s.env(), "step", "ca", "provisioner", "add", "acme", "--type", "ACME") } return nil } func (step Step) passwordFile() string { return step.pathPlus("password.txt") } func (s Step) path() string { return env.Fetch("STEPPATH", filepath.Join(x.Must(os.Getwd()), "/tmp/step")) } func (s Step) env() map[string]string { return map[string]string{ "STEPPATH": s.path(), "HOST": "localhost", "PORT": "8081", } } func (s Step) pathPlus(path string) string { return filepath.Join(s.path(), path) }