summaryrefslogtreecommitdiff
path: root/vendor/github.com/authzed/zed/internal/storage/config.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/authzed/zed/internal/storage/config.go')
-rw-r--r--vendor/github.com/authzed/zed/internal/storage/config.go194
1 files changed, 194 insertions, 0 deletions
diff --git a/vendor/github.com/authzed/zed/internal/storage/config.go b/vendor/github.com/authzed/zed/internal/storage/config.go
new file mode 100644
index 0000000..1fca679
--- /dev/null
+++ b/vendor/github.com/authzed/zed/internal/storage/config.go
@@ -0,0 +1,194 @@
+package storage
+
+import (
+ "encoding/json"
+ "errors"
+ "io/fs"
+ "os"
+ "path/filepath"
+ "runtime"
+
+ "github.com/jzelinskie/stringz"
+)
+
+const configFileName = "config.json"
+
+// ErrConfigNotFound is returned if there is no Config in a ConfigStore.
+var ErrConfigNotFound = errors.New("config did not exist")
+
+// ErrTokenNotFound is returned if there is no Token in a ConfigStore.
+var ErrTokenNotFound = errors.New("token does not exist")
+
+// Config represents the contents of a zed configuration file.
+type Config struct {
+ Version string
+ CurrentToken string
+}
+
+// ConfigStore is anything that can persistently store a Config.
+type ConfigStore interface {
+ Get() (Config, error)
+ Put(Config) error
+ Exists() (bool, error)
+}
+
+// TokenWithOverride returns a Token that retrieves its values from the reference Token, and has its values overridden
+// any of the non-empty/non-nil values of the overrideToken.
+func TokenWithOverride(overrideToken Token, referenceToken Token) (Token, error) {
+ insecure := referenceToken.Insecure
+ if overrideToken.Insecure != nil {
+ insecure = overrideToken.Insecure
+ }
+
+ // done so that logging messages don't show nil for the resulting context
+ if insecure == nil {
+ bFalse := false
+ insecure = &bFalse
+ }
+
+ noVerifyCA := referenceToken.NoVerifyCA
+ if overrideToken.NoVerifyCA != nil {
+ noVerifyCA = overrideToken.NoVerifyCA
+ }
+
+ // done so that logging messages don't show nil for the resulting context
+ if noVerifyCA == nil {
+ bFalse := false
+ noVerifyCA = &bFalse
+ }
+
+ caCert := referenceToken.CACert
+ if overrideToken.CACert != nil {
+ caCert = overrideToken.CACert
+ }
+
+ return Token{
+ Name: referenceToken.Name,
+ Endpoint: stringz.DefaultEmpty(overrideToken.Endpoint, referenceToken.Endpoint),
+ APIToken: stringz.DefaultEmpty(overrideToken.APIToken, referenceToken.APIToken),
+ Insecure: insecure,
+ NoVerifyCA: noVerifyCA,
+ CACert: caCert,
+ }, nil
+}
+
+// CurrentToken is a convenient way to obtain the CurrentToken field from the
+// current Config.
+func CurrentToken(cs ConfigStore, ss SecretStore) (token Token, err error) {
+ cfg, err := cs.Get()
+ if err != nil {
+ return Token{}, err
+ }
+
+ return GetTokenIfExists(cfg.CurrentToken, ss)
+}
+
+// SetCurrentToken is a convenient way to set the CurrentToken field in a
+// the current config.
+func SetCurrentToken(name string, cs ConfigStore, ss SecretStore) error {
+ // Ensure the token exists
+ exists, err := TokenExists(name, ss)
+ if err != nil {
+ return err
+ }
+
+ if !exists {
+ return ErrTokenNotFound
+ }
+
+ cfg, err := cs.Get()
+ if err != nil {
+ if errors.Is(err, ErrConfigNotFound) {
+ cfg = Config{Version: "v1"}
+ } else {
+ return err
+ }
+ }
+
+ cfg.CurrentToken = name
+ return cs.Put(cfg)
+}
+
+// JSONConfigStore implements a ConfigStore that stores its Config in a JSON file at the provided ConfigPath.
+type JSONConfigStore struct {
+ ConfigPath string
+}
+
+// Enforce that our implementation satisfies the interface.
+var _ ConfigStore = JSONConfigStore{}
+
+// Get parses a Config from the filesystem.
+func (s JSONConfigStore) Get() (Config, error) {
+ cfgBytes, err := os.ReadFile(filepath.Join(s.ConfigPath, configFileName))
+ if errors.Is(err, fs.ErrNotExist) {
+ return Config{}, ErrConfigNotFound
+ } else if err != nil {
+ return Config{}, err
+ }
+
+ var cfg Config
+ if err := json.Unmarshal(cfgBytes, &cfg); err != nil {
+ return Config{}, err
+ }
+
+ return cfg, nil
+}
+
+// Put overwrites a Config on the filesystem.
+func (s JSONConfigStore) Put(cfg Config) error {
+ if err := os.MkdirAll(s.ConfigPath, 0o774); err != nil {
+ return err
+ }
+
+ cfgBytes, err := json.Marshal(cfg)
+ if err != nil {
+ return err
+ }
+
+ return atomicWriteFile(filepath.Join(s.ConfigPath, configFileName), cfgBytes, 0o774)
+}
+
+func (s JSONConfigStore) Exists() (bool, error) {
+ if _, err := os.Stat(filepath.Join(s.ConfigPath, configFileName)); errors.Is(err, fs.ErrNotExist) {
+ return false, nil
+ } else if err != nil {
+ return false, err
+ }
+ return true, nil
+}
+
+// atomicWriteFile writes data to filename+some suffix, then renames it into
+// filename.
+//
+// Copyright (c) 2019 Tailscale Inc & AUTHORS All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// at the following URL:
+// https://github.com/tailscale/tailscale/blob/main/LICENSE
+func atomicWriteFile(filename string, data []byte, perm os.FileMode) (err error) {
+ f, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename)+".tmp")
+ if err != nil {
+ return err
+ }
+ tmpName := f.Name()
+ defer func() {
+ if err != nil {
+ f.Close()
+ os.Remove(tmpName)
+ }
+ }()
+ if _, err := f.Write(data); err != nil {
+ return err
+ }
+ if runtime.GOOS != "windows" {
+ if err := f.Chmod(perm); err != nil {
+ return err
+ }
+ }
+ if err := f.Sync(); err != nil {
+ return err
+ }
+ if err := f.Close(); err != nil {
+ return err
+ }
+ return os.Rename(tmpName, filename)
+}