// utils.go // Copyright (C) Andrew Woodlee 2023 // License: Apache-2.0 package backy import ( "errors" "fmt" "os" "os/exec" "path" "path/filepath" "strings" "git.andrewnw.xyz/CyberShell/backy/pkg/logging" "github.com/joho/godotenv" "github.com/knadh/koanf/v2" "github.com/rs/zerolog" "golang.org/x/crypto/ssh" "mvdan.cc/sh/v3/shell" ) func (c *ConfigOpts) LogLvl(level string) BackyOptionFunc { return func(bco *ConfigOpts) { c.BackyLogLvl = &level } } // AddCommands adds commands to ConfigOpts func AddCommands(commands []string) BackyOptionFunc { return func(bco *ConfigOpts) { bco.executeCmds = append(bco.executeCmds, commands...) } } // AddCommandLists adds lists to ConfigOpts func AddCommandLists(lists []string) BackyOptionFunc { return func(bco *ConfigOpts) { bco.executeLists = append(bco.executeLists, lists...) } } // AddPrintLists adds lists to print out func SetListsToSearch(lists []string) BackyOptionFunc { return func(bco *ConfigOpts) { bco.List.Lists = append(bco.List.Lists, lists...) } } // AddPrintLists adds lists to print out func SetCmdsToSearch(cmds []string) BackyOptionFunc { return func(bco *ConfigOpts) { bco.List.Commands = append(bco.List.Commands, cmds...) } } // UseCron enables the execution of command lists at specified times func UseCron() BackyOptionFunc { return func(bco *ConfigOpts) { bco.useCron = true } } func NewOpts(configFilePath string, opts ...BackyOptionFunc) *ConfigOpts { b := &ConfigOpts{} b.ConfigFilePath = configFilePath for _, opt := range opts { if opt != nil { opt(b) } } return b } func injectEnvIntoSSH(envVarsToInject environmentVars, process *ssh.Session, opts *ConfigOpts, log zerolog.Logger) { if envVarsToInject.file != "" { envPath, envPathErr := resolveDir(envVarsToInject.file) if envPathErr != nil { log.Fatal().Str("envFile", envPath).Err(envPathErr).Send() } file, err := os.Open(envPath) if err != nil { log.Fatal().Str("envFile", envPath).Err(err).Send() } defer file.Close() envMap, err := godotenv.Parse(file) if err != nil { log.Error().Str("envFile", envPath).Err(err).Send() goto errEnvFile } for key, val := range envMap { process.Setenv(key, GetVaultKey(val, opts, log)) } } errEnvFile: // fmt.Printf("%v", envVarsToInject.env) for _, envVal := range envVarsToInject.env { // don't append env Vars for Backy if strings.Contains(envVal, "=") { envVarArr := strings.Split(envVal, "=") process.Setenv(envVarArr[0], GetVaultKey(envVarArr[1], opts, log)) } } } func injectEnvIntoLocalCMD(envVarsToInject environmentVars, process *exec.Cmd, log zerolog.Logger) { if envVarsToInject.file != "" { envPath, _ := resolveDir(envVarsToInject.file) file, fileErr := os.Open(envPath) if fileErr != nil { log.Error().Str("envFile", envPath).Err(fileErr).Send() goto errEnvFile } defer file.Close() envMap, err := godotenv.Parse(file) if err != nil { log.Error().Str("envFile", envPath).Err(err).Send() goto errEnvFile } for key, val := range envMap { process.Env = append(process.Env, fmt.Sprintf("%s=%s", key, val)) } } errEnvFile: for _, envVal := range envVarsToInject.env { if strings.Contains(envVal, "=") { process.Env = append(process.Env, envVal) } } process.Env = append(process.Env, os.Environ()...) } func contains(s []string, e string) bool { for _, a := range s { if a == e { return true } } return false } func CheckConfigValues(config *koanf.Koanf, file string) { for _, key := range requiredKeys { isKeySet := config.Exists(key) if !isKeySet { logging.ExitWithMSG(Sprintf("Config key %s is not defined in %s. Please make sure this value is set and has the appropriate keys set.", key, file), 1, nil) } } } func testFile(c string) error { if strings.TrimSpace(c) != "" { file, fileOpenErr := os.Open(c) file.Close() if errors.Is(fileOpenErr, os.ErrNotExist) { return fileOpenErr } } return nil } func IsTerminalActive() bool { return os.Getenv("BACKY_TERM") == "enabled" } func IsCmdStdOutEnabled() bool { return os.Getenv("BACKY_STDOUT") == "enabled" } func resolveDir(path string) (string, error) { if path == "~" { homeDir, err := os.UserHomeDir() if err != nil { return path, err } // In case of "~", which won't be caught by the "else if" path = homeDir } else if strings.HasPrefix(path, "~/") { homeDir, err := os.UserHomeDir() if err != nil { return path, err } // Use strings.HasPrefix so we don't match paths like // "/something/~/something/" path = filepath.Join(homeDir, path[2:]) } return path, nil } func (opts *ConfigOpts) loadEnv() { envFileInConfigDir := fmt.Sprintf("%s/.env", path.Dir(opts.ConfigFilePath)) var backyEnv map[string]string backyEnv, envFileErr := godotenv.Read(envFileInConfigDir) if envFileErr != nil { return } opts.backyEnv = backyEnv } func expandEnvVars(backyEnv map[string]string, envVars []string) { env := func(name string) string { name = strings.ToUpper(name) envVar, found := backyEnv[name] if found { return envVar } return "" } for indx, v := range envVars { if strings.Contains(v, "$") || (strings.Contains(v, "${") && strings.Contains(v, "}")) { out, _ := shell.Expand(v, env) envVars[indx] = out } } }