config

package
v1.4.0-beta Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 24, 2022 License: MIT Imports: 26 Imported by: 1

README

config package

The config package wraps the common viper methods and types but adds some custom processing.

This probably could be done using custom decode hooks for viper, but I have not had time to understand them in detail.

Using a wrapper also allows custom methods on config for further functionality.

Unless the file format is given to LoadConfig then all the viper formats are supported.

Expansion of values

The following package functions and type methods are overridden to add expansion of embedded strings of the form ${name} and $name:

The string values are passed to ExpandString which supports a range of data substitutions.

Documentation

Overview

Package config adds support for value expansion over viper based configurations.

A number of the most common access methods from viper are replaced with local versions that add support for ExpandString. Additionally, there are a number of functions to simplify programs including LoadConfig.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Checksum

func Checksum(r io.Reader) (c uint32, err error)

func ChecksumFile

func ChecksumFile(path string) (c uint32, err error)

func ChecksumString

func ChecksumString(in string) (c uint32, err error)

func EncodePasswordPrompt added in v1.4.1

func EncodePasswordPrompt(keyfile string, expandable bool) (out string, err error)

EncodePasswordPrompt prompts the user for a password and again to verify, offering up to three attempts until the password match. When the two match the plaintext is encoded using the supplied keyfile. If expandable is true then the encoded password is returned in a format useable by the Expand function and includes a path to the keyfile.

func EncodeWithKey added in v1.4.1

func EncodeWithKey(plaintext []byte, key []byte) (out string, err error)

EncodeWithKey encodes the plaintext using the AES key in the byte slice given. The encoded password is returned in `Geneos AES256` format, with the `+encs+` prefix.

func EncodeWithKeyReader added in v1.4.1

func EncodeWithKeyReader(plaintext []byte, r io.Reader) (out string, err error)

EncodeWithKey encodes the plaintext using the AES key read from the io.Reader given. The encoded password is returned in `Geneos AES256` format, with the `+encs+` prefix.

func EncodeWithKeyfile added in v1.4.1

func EncodeWithKeyfile(plaintext []byte, keyfile string, expandable bool) (out string, err error)

EncodeWithKey encodes the plaintext using the AES key read from the file given. The encoded password is returned in `Geneos AES256` format, with the `+encs+` prefix, unless expandable is set to true in which case it is returned in a format that can be used with the Expand function and includes a reference to the keyfile.

If the keyfile is located under the user's configuration directory, as defined by UserConfigDir, then the function will replace any home directory prefix with `~/' to shorten the keyfile path.

func Expand added in v1.4.1

func Expand(input string, values ...map[string]string) (value []byte)

Expand behaves like ExpandString but returns a byte slice.

This should be used where the return value may contain sensitive data and an immutable string cannot be destroyed after use.

func ExpandString added in v1.3.0

func ExpandString(input string, values ...map[string]string) (value string)

ExpandString returns the input with all occurrences of the form ${name} replaced using an os.Expand-like function (but without support for bare names) for the formats (in the order of priority) below. It operates on the global config instance, referencing any other configuration values in the global package context.

${enc:keyfile[|keyfile...]:encodedvalue}

   The item "encodedvalue" is an AES256 ciphertext in Geneos format
   - or a reference to one - which will be decoded using the key
   file(s) given. Each "keyfile" must be one of either an absolute
   path, a path relative to the working directory of the program, or
   if prefixed with "~/" then relative to the home directory of the
   user running the program. The first valid decode (see below) is
   returned.

   The "encodedvalue" must be either prefixed "+encs+" to align with
   Geneos or will otherwise be looked up using the forms of any of
   the other references below, but without the surrounding
   dollar-brackets "${...}".

   To minimise (but not wholly eliminate) any false-positive decodes
   that occur in some circumstances when using the wrong key file,
   the decoded value is only returned if it is a valid UTF-8 string
   as per [utf8.Valid].

   Examples:

   * password: ${enc:~/.keyfile:+encs+9F2C3871E105EC21E4F0D5A7921A937D}
   * password: ${enc:/etc/geneos/keyfile.aes:env:ENCODED_PASSWORD}
   * password: ${enc:~/.config/geneos/keyfile1.aes:app.password}
   * password: ${enc:~/.keyfile.aes:config:mySecret}

${config:key} or ${path.to.config}

   Fetch the "key" configuration value (for single layered
   configurations, where a sub-level dot cannot be used) or if any
   value containing one or more dots "." will be looked-up in the
   existing configuration that the method is called on. The
   underlying configuration is not changed and values are resolved
   each time ExpandString() is called. No locking of the
   configuration is done.

 ${key}

   "key" will be substituted with the value of the first matching
   key from the maps "values...", in the order passed to the
   function. If no "values" are passed (as opposed to the key not
   being found in any of the maps) then name is looked up
   as an environment variable, as 4. below.

 ${env:name}

   "name" will be substituted with the contents of the environment
   variable of the same name.

 ${~/file} or ${/path/to/file} or ${file://path/to/file} or ${file:~/path/to/file}

   The contents of the referenced file will be read. Multiline files
   are used as-is; this can, for example, be used to read PEM
   certificate files or keys. If the path is prefixed with "~/" (or
   as an addition to a standard file url, if the first "/" is
   replaced with a tilde "~") then the path is relative to the home
   directory of the user running the process.

   Examples:

   * certfile ${file://etc/ssl/cert.pem}
   * template: ${file:~/templates/autogen.gotmpl}

 ${https://host/path} or ${http://host/path}

   The contents of the URL are fetched and used similarly as for
   local files above. The URL is passed to [http.Get] and supports
   proxies, embedded Basic Authentication and other features from
   that function.

The bare form "$name" is NOT supported, unlike os.Expand as this can unexpectedly match values containing valid literal dollar signs.

Expansion is not recursive. Configuration values are read and stored as literals and are expanded each time they are used. For each substitution any leading and trailing whitespace are removed. External sources are fetched each time they are used and so there may be a performance impact as well as the value unexpectedly changing during a process lifetime.

Any errors (particularly from substitutions from external files or remote URLs) may result in an empty or corrupt string being returned. Error returns are intentionally discarded and an empty string substituted. Where a value contains multiple expandable items processing will continue even after an error for one of them.

It is not currently possible to escape the syntax supported by ExpandString and if it is necessary to have a configuration value be a literal of the form "${name}" then you can set an otherwise unused item to the value and refer to it using the dotted syntax, e.g. for YAML

config:
  real: ${config.literal}
  literal: "${unchanged}"

In the above a reference to ${config.real} will return the literal string ${unchanged} as there is no recursive lookups.

func GetByteSlice added in v1.4.1

func GetByteSlice(s string, values ...map[string]string) []byte

GetByteSlice functions like viper.GetString but additionally calls Expand with the configuration value, passing any "values" maps and returning a byte slice

func GetString

func GetString(s string, values ...map[string]string) string

GetString functions like viper.GetString but additionally calls ExpandString with the configuration value, passing any "values" maps

func GetStringMapString

func GetStringMapString(s string, values ...map[string]string) map[string]string

GetStringMapString functions like viper.GetStringMapString but additionally calls ExpandString on each value element of the map, passing any "values" maps

func GetStringSlice

func GetStringSlice(s string, values ...map[string]string) []string

GetStringSlice functions like viper.GetStringSlice but additionally calls ExpandString on each element of the slice, passing any "values" maps

func ReadPasswordFile added in v1.4.1

func ReadPasswordFile(path string) []byte

func ReadPasswordPrompt added in v1.4.1

func ReadPasswordPrompt(prompt ...string) []byte

func UserConfigDir added in v1.3.2

func UserConfigDir(username ...string) (path string, err error)

Types

type AESValues

type AESValues struct {
	Key []byte
	IV  []byte
}

An AESValues structure contains the values required to create a Geneos Gateway AES key file and then to encode and decode AES passwords in configurations

func NewAESValues

func NewAESValues() (a AESValues, err error)

NewAESValues returns a new AESValues structure or an error

func ReadAESValues

func ReadAESValues(r io.Reader) (a AESValues, err error)

ReadAESValues returns an AESValues struct populated with the contents read from r. The caller must close the Reader on return.

func ReadAESValuesFile

func ReadAESValuesFile(path string) (a AESValues, err error)

ReadAESValuesFile returns an AESValues struct populated with the contents of the file passed as path.

func (*AESValues) Checksum

func (a *AESValues) Checksum() (c uint32, err error)

Checksum returns the CRC32 checksum of the AESValue it is called on.

func (AESValues) DecodeAES

func (a AESValues) DecodeAES(in []byte) (out []byte, err error)

func (AESValues) DecodeAESString

func (a AESValues) DecodeAESString(in string) (out string, err error)

DecodeAESString returns a plain text of the input or an error

func (AESValues) EncodeAES

func (a AESValues) EncodeAES(in []byte) (out []byte, err error)

func (AESValues) EncodeAESBytes added in v1.4.1

func (a AESValues) EncodeAESBytes(in []byte) (out []byte, err error)

func (AESValues) EncodeAESString

func (a AESValues) EncodeAESString(in string) (out string, err error)

func (AESValues) String

func (a AESValues) String() string

String method for AESValues

The output is in the format for suitable for use as a gateway key file for secure passwords as described in: https://docs.itrsgroup.com/docs/geneos/current/Gateway_Reference_Guide/gateway_secure_passwords.htm

func (AESValues) WriteAESValues

func (a AESValues) WriteAESValues(w io.Writer) error

WriteAESValues writes the AESValues structure to the io.Writer. Each fields acts as if it were being marshalled with an ",omitempty" tag.

type Config

type Config struct {
	*viper.Viper
	Type string
}

Config embeds Viper and also exposes the config type used

func GetConfig

func GetConfig() *Config

GetConfig returns the global Config instance

func LoadConfig

func LoadConfig(configName string, options ...Options) (c *Config, err error)

LoadConfig loads configuration files from internal defaults, external defaults and the given configuration file. The configuration file can be passed as an option. Each layer is only loaded once, if given. Internal defaults are passed as a byte slice - this is typically loaded from an embedded file but can be supplied from any source. External defaults and the main configuration file are passed as ordered slices of strings. The first match is loaded.

LoadConfig("geneos")

//go:embed somefile.json
var myDefaults []byte
LoadConfig("geneos", config.SetDefaults(myDefaults, "json"), config.SetConfigFile(configPath))

Options can be passed to change the default behaviour and to pass any embedded defaults or an existing viper.

for defaults see: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html ... find windows equiv

func New

func New() *Config

New returns a Config instance initialised with a new viper instance

func ReadHOCONFile added in v1.4.1

func ReadHOCONFile(path string) (cf *Config, err error)

func (*Config) Expand added in v1.4.1

func (c *Config) Expand(input string, values ...map[string]string) (value []byte)

Expand behaves like the ExpandString method but returns a byte slice.

func (*Config) ExpandAllSettings

func (c *Config) ExpandAllSettings(values ...map[string]string) (all map[string]interface{})

ExpandAllSettings returns all the settings from c applying ExpandString() to all string values and all string slice values. "values" maps are passed to ExpandString as-is. Further types may be added over time.

func (*Config) ExpandString

func (c *Config) ExpandString(input string, values ...map[string]string) (value string)

ExpandString works just like the package level ExpandString but on a specific config instance.

func (*Config) GetByteSlice added in v1.4.1

func (c *Config) GetByteSlice(s string, values ...map[string]string) []byte

GetByteSlice functions like viper.GetString on a Config instance, but additionally calls Expand with the configuration value, passing any "values" maps and returning a byte slice

func (*Config) GetString

func (c *Config) GetString(s string, values ...map[string]string) string

GetString functions like viper.GetString on a Config instance, but additionally calls ExpandString with the configuration value, passing any "values" maps

func (*Config) GetStringMapString

func (c *Config) GetStringMapString(s string, values ...map[string]string) (m map[string]string)

GetStringMapString functions like viper.GetStringMapString on a Config instance but additionally calls ExpandString on each value element of the map, passing any "values" maps

func (*Config) GetStringSlice

func (c *Config) GetStringSlice(s string, values ...map[string]string) (slice []string)

GetStringSlice functions like viper.GetStringSlice on a Config instance but additionally calls ExpandString on each element of the slice, passing any "values" maps

func (*Config) MergeHOCONConfig added in v1.4.1

func (cf *Config) MergeHOCONConfig(conf string) (err error)

MergeHOCONConfig parses the HOCON configuration in conf and merges the results into the cf *config.Config object

func (*Config) MergeHOCONFile added in v1.4.1

func (cf *Config) MergeHOCONFile(path string) (err error)

MergeHOCONFile reads a HOCON configuration file in path and merges the settings into the cf *config.Config object

func (*Config) Sub

func (c *Config) Sub(key string) *Config

Sub returns a Config instance for the sub-key passed

type Options

type Options func(*configOptions)

func AddConfigDirs

func AddConfigDirs(paths ...string) Options

AddConfigDirs() adds one or more directories to search for the configuration and defaults files. Directories are searched in FIFO order, so any directories given are checked before the built-in list. This option can be given multiple times as each call only appends to the list which has already bee initialised.

func Global added in v1.4.1

func Global() Options

Global() tells LoadConfig() to set values in the global config instead of creating a new instance, and the global configuration instance is returned.

func IgnoreSystemDir

func IgnoreSystemDir() Options

IgnoreSystemDir() tells LoadConfig() not to search in the system configuration directory. This only applies on UNIX-like systems and is normally /etc/[AppName]

func IgnoreUserConfDir

func IgnoreUserConfDir() Options

IgnoreUserConfDir() tells LoadConfig() not to search under the user config directory (The user config directory is as per Go os.UserConfDir() and a sub-directory of AppName)

func IgnoreWorkingDir

func IgnoreWorkingDir() Options

IgnoreWorkingDir() tells LoadConfig not to search the working directory for configuration files. This should be used when the caller may be running in an unknown or untrusted location.

func MergeSettings added in v1.4.1

func MergeSettings() Options

MergeSettings() change the default behaviour which loads the first configuration file found, instead loading each configuration file found in the directories given and merges the settings together. Merging is done using viper.MergeConfigMap and should result in the last definition of each configuration item being used.

MergeSettings() applies to both default and main settings.

func SetAppName

func SetAppName(name string) Options

SetAppName() overrides to mapping of the configName to the application name. AppName is used for directories while configName is used for the files in those directories.

func SetConfigFile

func SetConfigFile(path string) Options

SetConfigFile() allows the caller to override the searching for a config file in the given directories and instead loads only the given file (after defaults are loaded as normal).

func SetDefaults

func SetDefaults(defaults []byte, format string) Options

SetDefaults() takes a []byte slice and a format type to set configuration defaults. This can be used in conjunction with `embed` to read a defaults file in the source tree to a byte slice and set those, e.g.

	//go:embed "defaults.yaml"
	var defaults []byte
    ...
	c, err := config.LoadConfig("appname", config.SetDefaults(defaults, "yaml"))

Similarly, the defaults could be loaded from a well known URL and so on.

func UseDefaults added in v1.4.1

func UseDefaults(b bool) Options

UseDefaults() tells LoadConfig() to load defaults or not. The default is true.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL