v0.4.0
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				ci/woodpecker/push/gitea Pipeline was successful
				
			
		
			
				
	
				ci/woodpecker/push/go-lint Pipeline failed
				
			
		
			
				
	
				ci/woodpecker/tag/gitea Pipeline failed
				
			
		
			
				
	
				ci/woodpecker/tag/go-lint Pipeline failed
				
			
		
			
				
	
				ci/woodpecker/tag/publish-docs Pipeline is running
				
			
		
			
				
	
				ci/woodpecker/push/publish-docs Pipeline was successful
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	ci/woodpecker/push/gitea Pipeline was successful
				
			ci/woodpecker/push/go-lint Pipeline failed
				
			ci/woodpecker/tag/gitea Pipeline failed
				
			ci/woodpecker/tag/go-lint Pipeline failed
				
			ci/woodpecker/tag/publish-docs Pipeline is running
				
			ci/woodpecker/push/publish-docs Pipeline was successful
				
			This commit is contained in:
		
							
								
								
									
										13
									
								
								.changes/v0.4.0.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								.changes/v0.4.0.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					## v0.4.0 - 2023-09-08
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Added
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Added `scriptEnvFile` to command object that allows one to specify an environment file (or any file really) when a `scriptFile` is run. Inspired by the practice of keeping environment variables and scripts or commands seperate.
 | 
				
			||||||
 | 
					* Basis for listing commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* BREAKING: Notifications object now takes the form of service.id, where service can be "mail" or "matrix" and id is a unique id for the service.
 | 
				
			||||||
 | 
					* BREAKING: Since the change to the notifications object, cmd-lists' inner map key 'notifications' must be of the form service.id. id must be defined for that service. See notifications docs for aviliable services.
 | 
				
			||||||
 | 
					* Config parser is now the simpler Koanf - Keys are now case-sensitive
 | 
				
			||||||
 | 
					* Log size limited to 50 Mb
 | 
				
			||||||
							
								
								
									
										1
									
								
								.frontmatter/database/taxonomyDb.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.frontmatter/database/taxonomyDb.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{}
 | 
				
			||||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -21,7 +21,7 @@ jobs:
 | 
				
			|||||||
      - run: git fetch --force --tags
 | 
					      - run: git fetch --force --tags
 | 
				
			||||||
      - uses: actions/setup-go@v4
 | 
					      - uses: actions/setup-go@v4
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          go-version: '1.20'
 | 
					          go-version: '1.26'
 | 
				
			||||||
          cache: true
 | 
					          cache: true
 | 
				
			||||||
      # More assembly might be required: Docker logins, GPG, etc. It all depends
 | 
					      # More assembly might be required: Docker logins, GPG, etc. It all depends
 | 
				
			||||||
      # on your needs.
 | 
					      # on your needs.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,10 +32,10 @@ func Backup(cmd *cobra.Command, args []string) {
 | 
				
			|||||||
	backyConfOpts := backy.NewOpts(cfgFile, backy.AddCommandLists(cmdLists))
 | 
						backyConfOpts := backy.NewOpts(cfgFile, backy.AddCommandLists(cmdLists))
 | 
				
			||||||
	backyConfOpts.InitConfig()
 | 
						backyConfOpts.InitConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config := backy.ReadConfig(backyConfOpts)
 | 
						backy.ReadConfig(backyConfOpts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config.RunListConfig("", backyConfOpts)
 | 
						backyConfOpts.RunListConfig("")
 | 
				
			||||||
	for _, host := range config.Hosts {
 | 
						for _, host := range backyConfOpts.Hosts {
 | 
				
			||||||
		if host.SshClient != nil {
 | 
							if host.SshClient != nil {
 | 
				
			||||||
			host.SshClient.Close()
 | 
								host.SshClient.Close()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ var (
 | 
				
			|||||||
func execute(cmd *cobra.Command, args []string) {
 | 
					func execute(cmd *cobra.Command, args []string) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(args) < 1 {
 | 
						if len(args) < 1 {
 | 
				
			||||||
		logging.ExitWithMSG("Please provide a command to run. Pass --help to see options.", 0, nil)
 | 
							logging.ExitWithMSG("Please provide a command to run. Pass --help to see options.", 1, nil)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts := backy.NewOpts(cfgFile, backy.AddCommands(args))
 | 
						opts := backy.NewOpts(cfgFile, backy.AddCommands(args))
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										39
									
								
								cmd/list.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								cmd/list.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					// backup.go
 | 
				
			||||||
 | 
					// Copyright (C) Andrew Woodlee 2023
 | 
				
			||||||
 | 
					// License: Apache-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"git.andrewnw.xyz/CyberShell/backy/pkg/backy"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						listCmd = &cobra.Command{
 | 
				
			||||||
 | 
							Use:   "list [--list=list1,list2,... | -l list1, list2,...] [ -cmd cmd1 cmd2 cmd3...]",
 | 
				
			||||||
 | 
							Short: "Lists commands, lists, or hosts defined in config file.",
 | 
				
			||||||
 | 
							Long:  "Backup lists commands or groups defined in config file.\nUse the --lists or -l flag to list the specified lists. If not flag is not given, all lists will be executed.",
 | 
				
			||||||
 | 
							Run:   List,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var listsToList []string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						listCmd.Flags().StringSliceVarP(&listsToList, "lists", "l", nil, "Accepts comma-separated names of command lists to list.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func List(cmd *cobra.Command, args []string) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opts := backy.NewOpts(cfgFile, backy.SetListsToSearch(cmdLists))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opts.InitConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opts = backy.ReadConfig(opts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opts.ListConfiguration()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -36,5 +36,5 @@ func init() {
 | 
				
			|||||||
	rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "f", "", "config file to read from")
 | 
						rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "f", "", "config file to read from")
 | 
				
			||||||
	rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Sets verbose level")
 | 
						rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Sets verbose level")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rootCmd.AddCommand(backupCmd, execCmd, cronCmd, versionCmd)
 | 
						rootCmd.AddCommand(backupCmd, execCmd, cronCmd, versionCmd, listCmd)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const versionStr = "0.3.1"
 | 
					const versionStr = "0.4.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	versionCmd = &cobra.Command{
 | 
						versionCmd = &cobra.Command{
 | 
				
			||||||
@@ -32,9 +32,6 @@ func version(cmd *cobra.Command, args []string) {
 | 
				
			|||||||
	} else if vPre && !numOnly {
 | 
						} else if vPre && !numOnly {
 | 
				
			||||||
		fmt.Printf("v%s\n", versionStr)
 | 
							fmt.Printf("v%s\n", versionStr)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if vPre && numOnly {
 | 
					 | 
				
			||||||
			fmt.Println("vpre flag and num flag both detected!")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		fmt.Printf("Backy version: %s\n", versionStr)
 | 
							fmt.Printf("Backy version: %s\n", versionStr)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ Available Commands:
 | 
				
			|||||||
  cron        Starts a scheduler that runs lists defined in config file.
 | 
					  cron        Starts a scheduler that runs lists defined in config file.
 | 
				
			||||||
  exec        Runs commands defined in config file in order given.
 | 
					  exec        Runs commands defined in config file in order given.
 | 
				
			||||||
  help        Help about any command
 | 
					  help        Help about any command
 | 
				
			||||||
 | 
					  list        Lists commands, lists, or hosts defined in config file.
 | 
				
			||||||
  version     Prints the version and exits
 | 
					  version     Prints the version and exits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Flags:
 | 
					Flags:
 | 
				
			||||||
@@ -91,7 +92,7 @@ Usage:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Flags:
 | 
					Flags:
 | 
				
			||||||
  -h, --help   help for version
 | 
					  -h, --help   help for version
 | 
				
			||||||
  -n, --num    Output the version number only. (default true)
 | 
					  -n, --num    Output the version number only.
 | 
				
			||||||
  -V, --vpre   Output the version with v prefixed.
 | 
					  -V, --vpre   Output the version with v prefixed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Global Flags:
 | 
					Global Flags:
 | 
				
			||||||
@@ -99,3 +100,20 @@ Global Flags:
 | 
				
			|||||||
  -v, --verbose         Sets verbose level
 | 
					  -v, --verbose         Sets verbose level
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					Backup lists commands or groups defined in config file.
 | 
				
			||||||
 | 
					Use the --lists or -l flag to list the specified lists. If not flag is not given, all lists will be executed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Usage:
 | 
				
			||||||
 | 
					  backy list [--list=list1,list2,... | -l list1, list2,...] [ -cmd cmd1 cmd2 cmd3...] [flags]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Flags:
 | 
				
			||||||
 | 
					  -h, --help            help for list
 | 
				
			||||||
 | 
					  -l, --lists strings   Accepts comma-separated names of command lists to list.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Global Flags:
 | 
				
			||||||
 | 
					  -f, --config string   config file to read from
 | 
				
			||||||
 | 
					  -v, --verbose         Sets verbose level
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,8 +16,8 @@ The top-level object key can be anything you want but not the same as another.
 | 
				
			|||||||
      - test
 | 
					      - test
 | 
				
			||||||
      - test2
 | 
					      - test2
 | 
				
			||||||
    notifications:
 | 
					    notifications:
 | 
				
			||||||
      - prod-email
 | 
					      - mail.prod-email
 | 
				
			||||||
      - matrix
 | 
					      - matrix.sysadmin
 | 
				
			||||||
    cron: "0 * * * * *"
 | 
					    cron: "0 * * * * *"
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,9 +25,9 @@ The top-level object key can be anything you want but not the same as another.
 | 
				
			|||||||
| --- | --- | --- | --- |
 | 
					| --- | --- | --- | --- |
 | 
				
			||||||
| `order` | Defines the sequence of commands to execute | `[]string` | yes |
 | 
					| `order` | Defines the sequence of commands to execute | `[]string` | yes |
 | 
				
			||||||
| `getOutput` | Command(s) output is in the notification(s) | `bool` | no |
 | 
					| `getOutput` | Command(s) output is in the notification(s) | `bool` | no |
 | 
				
			||||||
| `notifications` | The notification IDs to use on success and failure | `[]string` | no |
 | 
					| `notifications` | The notification service(s) and ID(s) to use on success and failure. Must be *`service.id`*. See the [notifications documentation page](/config/notifications/) for more | `[]string` | no |
 | 
				
			||||||
| `name` | Optional name of the list | `string` | no |
 | 
					| `name` | Optional name of the list | `string` | no |
 | 
				
			||||||
| `cron` | Time at which to schedule the list. | `string` | no |
 | 
					| `cron` | Time at which to schedule the list. Only has affect when cron subcommand is run. | `string` | no |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Order
 | 
					### Order
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -43,7 +43,7 @@ order:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Get command output when a notification is sent.
 | 
					Get command output when a notification is sent.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Is not required. Can be `true` or `false`.
 | 
					Is not required. Can be `true` or `false`. Default is `false`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Notifications
 | 
					### Notifications
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,29 +57,30 @@ Name is optional for logging. If name is not defined, name will be the object's
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Backy also has a cron mode, so one can run `backy cron` and start a process that schedules jobs to run at times defined in the configuration file.
 | 
					Backy also has a cron mode, so one can run `backy cron` and start a process that schedules jobs to run at times defined in the configuration file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Adding `cron: 0 0 1 * * *` to a `cmd-configs` object will schedule the list at 1 in the morning. See [https://crontab.guru/](https://crontab.guru/) for reference.
 | 
					Adding `cron: 0 0 1 * * *` to a `cmd-lists` object will schedule the list at 1 in the morning. See [https://crontab.guru/](https://crontab.guru/) for reference.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{% notice tip %}}
 | 
					{{% notice tip %}}
 | 
				
			||||||
Note: Backy uses the second field of cron, so add anything except * to the beginning of a regular cron expression.
 | 
					Note: Backy uses the second field of cron, so add anything except * to the beginning of a regular cron expression.
 | 
				
			||||||
{{% /notice %}}
 | 
					{{% /notice %}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
cmd-configs:
 | 
					cmd-lists:
 | 
				
			||||||
  cmds-to-run: # this can be any name you want
 | 
					  docker-container-backup: # this can be any name you want
 | 
				
			||||||
    # all commands have to be defined
 | 
					    # all commands have to be defined
 | 
				
			||||||
    order:
 | 
					    order:
 | 
				
			||||||
      - stop-docker-container
 | 
					      - stop-docker-container
 | 
				
			||||||
      - backup-docker-container-script
 | 
					      - backup-docker-container-script
 | 
				
			||||||
      - shell-cmd
 | 
					      - shell-cmd
 | 
				
			||||||
      - hostname
 | 
					      - hostname
 | 
				
			||||||
 | 
					      - start-docker-container
 | 
				
			||||||
    notifications:
 | 
					    notifications:
 | 
				
			||||||
      - matrix
 | 
					      - matrix.id
 | 
				
			||||||
    name: backup-some-server
 | 
					    name: backup-some-container
 | 
				
			||||||
    cron: "0 0 1 * * *"
 | 
					    cron: "0 0 1 * * *"
 | 
				
			||||||
  hostname:
 | 
					  hostname:
 | 
				
			||||||
    name: hostname
 | 
					    name: hostname
 | 
				
			||||||
    order:
 | 
					    order:
 | 
				
			||||||
      - hostname
 | 
					      - hostname
 | 
				
			||||||
    notifications:
 | 
					    notifications:
 | 
				
			||||||
      - prod-email
 | 
					      - mail.prod-email
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,33 +10,33 @@ Notifications can be sent on command list completion and failure.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
The supported platforms for notifications are email (SMTP) and [Matrix](https://matrix.org/).
 | 
					The supported platforms for notifications are email (SMTP) and [Matrix](https://matrix.org/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Notifications are defined by type. The top-level object will be the id, and the `type` is required.
 | 
					Notifications are defined by service, with the current form following below. Ids must come after the service.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
notifications:
 | 
					notifications:
 | 
				
			||||||
  prod-email:
 | 
					  mail:
 | 
				
			||||||
    type: mail
 | 
					    prod-email:
 | 
				
			||||||
    host: yourhost.tld
 | 
					      host: yourhost.tld
 | 
				
			||||||
    port: 587
 | 
					      port: 587
 | 
				
			||||||
    senderaddress: email@domain.tld
 | 
					      senderaddress: email@domain.tld
 | 
				
			||||||
    to:
 | 
					      to:
 | 
				
			||||||
      - admin@domain.tld
 | 
					        - admin@domain.tld
 | 
				
			||||||
    username: smtp-username@domain.tld
 | 
					      username: smtp-username@domain.tld
 | 
				
			||||||
    password: your-password-here
 | 
					      password: your-password-here
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  matrix:
 | 
					  matrix:
 | 
				
			||||||
    type: matrix
 | 
					    matrix:
 | 
				
			||||||
    home-server: your-home-server.tld
 | 
					      home-server: your-home-server.tld
 | 
				
			||||||
    room-id: room-id
 | 
					      room-id: room-id
 | 
				
			||||||
    access-token: your-access-token
 | 
					      access-token: your-access-token
 | 
				
			||||||
    user-id: your-user-id
 | 
					      user-id: your-user-id
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Types recognized are `type: mail` and `type: matrix`
 | 
					Sections recognized are `mail` and `matrix`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The type's object and its keys are listed below.
 | 
					There must be a section with an id (eg. `mail.test-svr`) following one of these sections.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### type: mail
 | 
					### mail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| key | description | type
 | 
					| key | description | type
 | 
				
			||||||
| --- | --- | ---
 | 
					| --- | --- | ---
 | 
				
			||||||
@@ -47,7 +47,7 @@ The type's object and its keys are listed below.
 | 
				
			|||||||
| `username` | SMTP username | `string`
 | 
					| `username` | SMTP username | `string`
 | 
				
			||||||
| `password` | SMTP password | `string`
 | 
					| `password` | SMTP password | `string`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### type: matrix
 | 
					### matrix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| key | description | type
 | 
					| key | description | type
 | 
				
			||||||
| --- | --- | ---
 | 
					| --- | --- | ---
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,17 +51,17 @@
 | 
				
			|||||||
  "frontMatter.content.pageFolders": [
 | 
					  "frontMatter.content.pageFolders": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "title": "content",
 | 
					      "title": "content",
 | 
				
			||||||
      "path": "[[workspace]]/content",
 | 
					      "path": "[[workspace]]/docs/content",
 | 
				
			||||||
      "originalPath": "[[workspace]]/content"
 | 
					      "originalPath": "[[workspace]]/docs/content"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "title": "config-main",
 | 
					      "title": "config-main",
 | 
				
			||||||
      "path": "[[workspace]]/content/config",
 | 
					      "path": "[[workspace]]/docs/content/config",
 | 
				
			||||||
      "originalPath": "[[workspace]]/content/config"
 | 
					      "originalPath": "[[workspace]]/docs/content/config"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "title": "gs",
 | 
					      "title": "gs",
 | 
				
			||||||
      "path": "[[workspace]]/content/getting-started"
 | 
					      "path": "[[workspace]]/docs/content/getting-started"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -50,4 +50,11 @@ eval "${BACKYCOMMAND} version -h >>  _index.md"
 | 
				
			|||||||
echo "\`\`\`" >> _index.md
 | 
					echo "\`\`\`" >> _index.md
 | 
				
			||||||
echo "" >> _index.md
 | 
					echo "" >> _index.md
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "## list" >> _index.md
 | 
				
			||||||
 | 
					echo "" >> _index.md
 | 
				
			||||||
 | 
					echo "\`\`\`" >> _index.md
 | 
				
			||||||
 | 
					eval "${BACKYCOMMAND} list -h >>  _index.md"
 | 
				
			||||||
 | 
					echo "\`\`\`" >> _index.md
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mv _index.md "$CLI_PAGE"
 | 
					mv _index.md "$CLI_PAGE"
 | 
				
			||||||
							
								
								
									
										41
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								go.mod
									
									
									
									
									
								
							@@ -3,29 +3,33 @@ module git.andrewnw.xyz/CyberShell/backy
 | 
				
			|||||||
go 1.26
 | 
					go 1.26
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/go-co-op/gocron v1.30.1
 | 
						github.com/go-co-op/gocron v1.33.1
 | 
				
			||||||
	github.com/hashicorp/vault/api v1.9.2
 | 
						github.com/hashicorp/vault/api v1.10.0
 | 
				
			||||||
	github.com/joho/godotenv v1.5.1
 | 
						github.com/joho/godotenv v1.5.1
 | 
				
			||||||
	github.com/kevinburke/ssh_config v1.2.0
 | 
						github.com/kevinburke/ssh_config v1.2.0
 | 
				
			||||||
 | 
						github.com/knadh/koanf/parsers/yaml v0.1.0
 | 
				
			||||||
 | 
						github.com/knadh/koanf/providers/file v0.1.0
 | 
				
			||||||
 | 
						github.com/knadh/koanf/v2 v2.0.1
 | 
				
			||||||
	github.com/mattn/go-isatty v0.0.19
 | 
						github.com/mattn/go-isatty v0.0.19
 | 
				
			||||||
	github.com/nikoksr/notify v0.41.0
 | 
						github.com/nikoksr/notify v0.41.0
 | 
				
			||||||
	github.com/pkg/errors v0.9.1
 | 
						github.com/pkg/errors v0.9.1
 | 
				
			||||||
	github.com/rs/zerolog v1.30.0
 | 
						github.com/rs/zerolog v1.30.0
 | 
				
			||||||
	github.com/spf13/cobra v1.7.0
 | 
						github.com/spf13/cobra v1.7.0
 | 
				
			||||||
	github.com/spf13/viper v1.16.0
 | 
						go.mongodb.org/mongo-driver v1.12.1
 | 
				
			||||||
	go.mongodb.org/mongo-driver v1.12.0
 | 
						golang.org/x/crypto v0.13.0
 | 
				
			||||||
	golang.org/x/crypto v0.11.0
 | 
					 | 
				
			||||||
	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 | 
						gopkg.in/natefinch/lumberjack.v2 v2.2.1
 | 
				
			||||||
	maunium.net/go/mautrix v0.15.4
 | 
						maunium.net/go/mautrix v0.16.0
 | 
				
			||||||
	mvdan.cc/sh/v3 v3.7.0
 | 
						mvdan.cc/sh/v3 v3.7.0
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/cenkalti/backoff/v3 v3.2.2 // indirect
 | 
						github.com/cenkalti/backoff/v3 v3.2.2 // indirect
 | 
				
			||||||
	github.com/davecgh/go-spew v1.1.1 // indirect
 | 
						github.com/davecgh/go-spew v1.1.1 // indirect
 | 
				
			||||||
 | 
						github.com/fatih/structs v1.1.0 // indirect
 | 
				
			||||||
	github.com/fsnotify/fsnotify v1.6.0 // indirect
 | 
						github.com/fsnotify/fsnotify v1.6.0 // indirect
 | 
				
			||||||
	github.com/go-jose/go-jose/v3 v3.0.0 // indirect
 | 
						github.com/go-jose/go-jose/v3 v3.0.0 // indirect
 | 
				
			||||||
	github.com/golang/snappy v0.0.4 // indirect
 | 
						github.com/golang/snappy v0.0.4 // indirect
 | 
				
			||||||
 | 
						github.com/google/uuid v1.3.1 // indirect
 | 
				
			||||||
	github.com/hashicorp/errwrap v1.1.0 // indirect
 | 
						github.com/hashicorp/errwrap v1.1.0 // indirect
 | 
				
			||||||
	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
 | 
						github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
 | 
				
			||||||
	github.com/hashicorp/go-multierror v1.1.1 // indirect
 | 
						github.com/hashicorp/go-multierror v1.1.1 // indirect
 | 
				
			||||||
@@ -33,17 +37,21 @@ require (
 | 
				
			|||||||
	github.com/hashicorp/go-rootcerts v1.0.2 // indirect
 | 
						github.com/hashicorp/go-rootcerts v1.0.2 // indirect
 | 
				
			||||||
	github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect
 | 
						github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect
 | 
				
			||||||
	github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
 | 
						github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
 | 
				
			||||||
	github.com/hashicorp/go-sockaddr v1.0.2 // indirect
 | 
						github.com/hashicorp/go-sockaddr v1.0.5 // indirect
 | 
				
			||||||
	github.com/hashicorp/hcl v1.0.0 // indirect
 | 
						github.com/hashicorp/hcl v1.0.0 // indirect
 | 
				
			||||||
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 | 
						github.com/inconshreveable/mousetrap v1.1.0 // indirect
 | 
				
			||||||
	github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible // indirect
 | 
						github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible // indirect
 | 
				
			||||||
	github.com/klauspost/compress v1.16.7 // indirect
 | 
						github.com/klauspost/compress v1.16.7 // indirect
 | 
				
			||||||
 | 
						github.com/knadh/koanf/maps v0.1.1 // indirect
 | 
				
			||||||
 | 
						github.com/knadh/koanf/providers/structs v0.1.0 // indirect
 | 
				
			||||||
	github.com/magiconair/properties v1.8.7 // indirect
 | 
						github.com/magiconair/properties v1.8.7 // indirect
 | 
				
			||||||
	github.com/mattn/go-colorable v0.1.13 // indirect
 | 
						github.com/mattn/go-colorable v0.1.13 // indirect
 | 
				
			||||||
 | 
						github.com/mitchellh/copystructure v1.2.0 // indirect
 | 
				
			||||||
	github.com/mitchellh/go-homedir v1.1.0 // indirect
 | 
						github.com/mitchellh/go-homedir v1.1.0 // indirect
 | 
				
			||||||
	github.com/mitchellh/mapstructure v1.5.0 // indirect
 | 
						github.com/mitchellh/mapstructure v1.5.0 // indirect
 | 
				
			||||||
 | 
						github.com/mitchellh/reflectwalk v1.0.2 // indirect
 | 
				
			||||||
	github.com/montanaflynn/stats v0.7.1 // indirect
 | 
						github.com/montanaflynn/stats v0.7.1 // indirect
 | 
				
			||||||
	github.com/pelletier/go-toml/v2 v2.0.9 // indirect
 | 
						github.com/pelletier/go-toml/v2 v2.1.0 // indirect
 | 
				
			||||||
	github.com/pmezard/go-difflib v1.0.0 // indirect
 | 
						github.com/pmezard/go-difflib v1.0.0 // indirect
 | 
				
			||||||
	github.com/robfig/cron/v3 v3.0.1 // indirect
 | 
						github.com/robfig/cron/v3 v3.0.1 // indirect
 | 
				
			||||||
	github.com/ryanuber/go-glob v1.0.0 // indirect
 | 
						github.com/ryanuber/go-glob v1.0.0 // indirect
 | 
				
			||||||
@@ -51,10 +59,10 @@ require (
 | 
				
			|||||||
	github.com/spf13/cast v1.5.1 // indirect
 | 
						github.com/spf13/cast v1.5.1 // indirect
 | 
				
			||||||
	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 | 
						github.com/spf13/jwalterweatherman v1.1.0 // indirect
 | 
				
			||||||
	github.com/spf13/pflag v1.0.5 // indirect
 | 
						github.com/spf13/pflag v1.0.5 // indirect
 | 
				
			||||||
	github.com/stretchr/objx v0.5.0 // indirect
 | 
						github.com/stretchr/objx v0.5.1 // indirect
 | 
				
			||||||
	github.com/stretchr/testify v1.8.4 // indirect
 | 
						github.com/stretchr/testify v1.8.4 // indirect
 | 
				
			||||||
	github.com/subosito/gotenv v1.4.2 // indirect
 | 
						github.com/subosito/gotenv v1.6.0 // indirect
 | 
				
			||||||
	github.com/tidwall/gjson v1.15.0 // indirect
 | 
						github.com/tidwall/gjson v1.16.0 // indirect
 | 
				
			||||||
	github.com/tidwall/match v1.1.1 // indirect
 | 
						github.com/tidwall/match v1.1.1 // indirect
 | 
				
			||||||
	github.com/tidwall/pretty v1.2.1 // indirect
 | 
						github.com/tidwall/pretty v1.2.1 // indirect
 | 
				
			||||||
	github.com/tidwall/sjson v1.2.5 // indirect
 | 
						github.com/tidwall/sjson v1.2.5 // indirect
 | 
				
			||||||
@@ -62,12 +70,13 @@ require (
 | 
				
			|||||||
	github.com/xdg-go/scram v1.1.2 // indirect
 | 
						github.com/xdg-go/scram v1.1.2 // indirect
 | 
				
			||||||
	github.com/xdg-go/stringprep v1.0.4 // indirect
 | 
						github.com/xdg-go/stringprep v1.0.4 // indirect
 | 
				
			||||||
	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
 | 
						github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
 | 
				
			||||||
	go.uber.org/atomic v1.9.0 // indirect
 | 
						go.mau.fi/util v0.0.0-20230906155759-14bad39a8718 // indirect
 | 
				
			||||||
	golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
 | 
						go.uber.org/atomic v1.11.0 // indirect
 | 
				
			||||||
	golang.org/x/net v0.12.0 // indirect
 | 
						golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
 | 
				
			||||||
 | 
						golang.org/x/net v0.15.0 // indirect
 | 
				
			||||||
	golang.org/x/sync v0.3.0 // indirect
 | 
						golang.org/x/sync v0.3.0 // indirect
 | 
				
			||||||
	golang.org/x/sys v0.10.0 // indirect
 | 
						golang.org/x/sys v0.12.0 // indirect
 | 
				
			||||||
	golang.org/x/text v0.11.0 // indirect
 | 
						golang.org/x/text v0.13.0 // indirect
 | 
				
			||||||
	golang.org/x/time v0.3.0 // indirect
 | 
						golang.org/x/time v0.3.0 // indirect
 | 
				
			||||||
	gopkg.in/ini.v1 v1.67.0 // indirect
 | 
						gopkg.in/ini.v1 v1.67.0 // indirect
 | 
				
			||||||
	gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
						gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										54
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								go.sum
									
									
									
									
									
								
							@@ -64,11 +64,15 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
 | 
				
			|||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 | 
					github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 | 
				
			||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 | 
					github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 | 
				
			||||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
 | 
					github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
 | 
				
			||||||
 | 
					github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
 | 
				
			||||||
 | 
					github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 | 
				
			||||||
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
 | 
					github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
 | 
				
			||||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
 | 
					github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
 | 
				
			||||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
 | 
					github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
 | 
				
			||||||
github.com/go-co-op/gocron v1.30.1 h1:tjWUvJl5KrcwpkEkSXFSQFr4F9h5SfV/m4+RX0cV2fs=
 | 
					github.com/go-co-op/gocron v1.30.1 h1:tjWUvJl5KrcwpkEkSXFSQFr4F9h5SfV/m4+RX0cV2fs=
 | 
				
			||||||
github.com/go-co-op/gocron v1.30.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y=
 | 
					github.com/go-co-op/gocron v1.30.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y=
 | 
				
			||||||
 | 
					github.com/go-co-op/gocron v1.33.1 h1:wjX+Dg6Ae29a/f9BSQjY1Rl+jflTpW9aDyMqseCj78c=
 | 
				
			||||||
 | 
					github.com/go-co-op/gocron v1.33.1/go.mod h1:NLi+bkm4rRSy1F8U7iacZOz0xPseMoIOnvabGoSe/no=
 | 
				
			||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 | 
					github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 | 
				
			||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
					github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
				
			||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
					github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
				
			||||||
@@ -131,6 +135,8 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
 | 
				
			|||||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 | 
					github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 | 
				
			||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 | 
					github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 | 
				
			||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
					github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
				
			||||||
 | 
					github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
 | 
				
			||||||
 | 
					github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
				
			||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 | 
					github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 | 
				
			||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 | 
					github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 | 
				
			||||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 | 
					github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 | 
				
			||||||
@@ -155,12 +161,16 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9
 | 
				
			|||||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
 | 
					github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
 | 
				
			||||||
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
 | 
					github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
 | 
				
			||||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
 | 
					github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
 | 
				
			||||||
 | 
					github.com/hashicorp/go-sockaddr v1.0.5 h1:dvk7TIXCZpmfOlM+9mlcrWmWjw/wlKT+VDq2wMvfPJU=
 | 
				
			||||||
 | 
					github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI=
 | 
				
			||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 | 
					github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 | 
				
			||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 | 
					github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 | 
				
			||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 | 
					github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 | 
				
			||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 | 
					github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 | 
				
			||||||
github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as=
 | 
					github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as=
 | 
				
			||||||
github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8=
 | 
					github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8=
 | 
				
			||||||
 | 
					github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p2tOJQ=
 | 
				
			||||||
 | 
					github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8=
 | 
				
			||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
					github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
				
			||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
					github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
				
			||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 | 
					github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 | 
				
			||||||
@@ -177,6 +187,16 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
 | 
				
			|||||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 | 
					github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 | 
				
			||||||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
 | 
					github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
 | 
				
			||||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
 | 
					github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP1XFUxVI5w=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/providers/file v0.1.0 h1:fs6U7nrV58d3CFAFh8VTde8TM262ObYf3ODrc//Lp+c=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/providers/file v0.1.0/go.mod h1:rjJ/nHQl64iYCtAW2QQnF0eSmDEX/YZ/eNFj5yR6BvA=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/providers/structs v0.1.0 h1:wJRteCNn1qvLtE5h8KQBvLJovidSdntfdyIbbCzEyE0=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/providers/structs v0.1.0/go.mod h1:sw2YZ3txUcqA3Z27gPlmmBzWn1h8Nt9O6EP/91MkcWE=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g=
 | 
				
			||||||
 | 
					github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus=
 | 
				
			||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 | 
					github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 | 
				
			||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 | 
					github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 | 
				
			||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 | 
					github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 | 
				
			||||||
@@ -198,12 +218,16 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
 | 
				
			|||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
 | 
					github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
 | 
				
			||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 | 
					github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 | 
				
			||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 | 
					github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 | 
				
			||||||
 | 
					github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
 | 
				
			||||||
 | 
					github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
 | 
				
			||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 | 
					github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 | 
				
			||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 | 
					github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 | 
				
			||||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 | 
					github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 | 
				
			||||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 | 
					github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 | 
				
			||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 | 
					github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 | 
				
			||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 | 
					github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 | 
				
			||||||
 | 
					github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
 | 
				
			||||||
 | 
					github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 | 
				
			||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 | 
					github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 | 
				
			||||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
 | 
					github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
 | 
				
			||||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
 | 
					github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
 | 
				
			||||||
@@ -211,6 +235,8 @@ github.com/nikoksr/notify v0.41.0 h1:4LGE41GpWdHX5M3Xo6DlWRwS2WLDbOq1Rk7IzY4vjmQ
 | 
				
			|||||||
github.com/nikoksr/notify v0.41.0/go.mod h1:FoE0UVPeopz1Vy5nm9vQZ+JVmYjEIjQgbFstbkw+cRE=
 | 
					github.com/nikoksr/notify v0.41.0/go.mod h1:FoE0UVPeopz1Vy5nm9vQZ+JVmYjEIjQgbFstbkw+cRE=
 | 
				
			||||||
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
 | 
					github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
 | 
				
			||||||
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
 | 
					github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
 | 
				
			||||||
 | 
					github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
 | 
				
			||||||
 | 
					github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
 | 
				
			||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 | 
					github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 | 
				
			||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 | 
					github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 | 
				
			||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
					github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
				
			||||||
@@ -248,6 +274,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 | 
				
			|||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 | 
					github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 | 
				
			||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
 | 
					github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
 | 
				
			||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 | 
					github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 | 
				
			||||||
 | 
					github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
 | 
				
			||||||
 | 
					github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
 | 
				
			||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 | 
					github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 | 
				
			||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
					github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
				
			||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 | 
					github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 | 
				
			||||||
@@ -261,9 +289,13 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
 | 
				
			|||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 | 
					github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 | 
				
			||||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
 | 
					github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
 | 
				
			||||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
 | 
					github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
 | 
				
			||||||
 | 
					github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 | 
				
			||||||
 | 
					github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 | 
				
			||||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 | 
					github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 | 
				
			||||||
github.com/tidwall/gjson v1.15.0 h1:5n/pM+v3r5ujuNl4YLZLsQ+UE5jlkLVm7jMzT5Mpolw=
 | 
					github.com/tidwall/gjson v1.15.0 h1:5n/pM+v3r5ujuNl4YLZLsQ+UE5jlkLVm7jMzT5Mpolw=
 | 
				
			||||||
github.com/tidwall/gjson v1.15.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 | 
					github.com/tidwall/gjson v1.15.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 | 
				
			||||||
 | 
					github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg=
 | 
				
			||||||
 | 
					github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 | 
				
			||||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
 | 
					github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
 | 
				
			||||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
 | 
					github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
 | 
				
			||||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 | 
					github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 | 
				
			||||||
@@ -285,8 +317,14 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
 | 
				
			|||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 | 
					github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 | 
				
			||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 | 
					github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 | 
				
			||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 | 
					github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 | 
				
			||||||
 | 
					go.mau.fi/util v0.0.0-20230805171708-199bf3eec776 h1:VrxDCO/gLFHLQywGUsJzertrvt2mUEMrZPf4hEL/s18=
 | 
				
			||||||
 | 
					go.mau.fi/util v0.0.0-20230805171708-199bf3eec776/go.mod h1:AxuJUMCxpzgJ5eV9JbPWKRH8aAJJidxetNdUj7qcb84=
 | 
				
			||||||
 | 
					go.mau.fi/util v0.0.0-20230906155759-14bad39a8718 h1:hmm5bZqE0M8+Uvys0HJPCSbAIZIwYtTkBKYPjAWHuMM=
 | 
				
			||||||
 | 
					go.mau.fi/util v0.0.0-20230906155759-14bad39a8718/go.mod h1:AxuJUMCxpzgJ5eV9JbPWKRH8aAJJidxetNdUj7qcb84=
 | 
				
			||||||
go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE=
 | 
					go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE=
 | 
				
			||||||
go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0=
 | 
					go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0=
 | 
				
			||||||
 | 
					go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE=
 | 
				
			||||||
 | 
					go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ=
 | 
				
			||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 | 
					go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 | 
				
			||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 | 
					go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 | 
				
			||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 | 
					go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 | 
				
			||||||
@@ -295,6 +333,8 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 | 
				
			|||||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 | 
					go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 | 
				
			||||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
 | 
					go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
 | 
				
			||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 | 
					go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 | 
				
			||||||
 | 
					go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
 | 
				
			||||||
 | 
					go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
					golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
					golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
					golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
				
			||||||
@@ -308,6 +348,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
 | 
				
			|||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
					golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
				
			||||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
 | 
					golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
 | 
				
			||||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
 | 
					golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
					golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
					golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 | 
					golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 | 
				
			||||||
@@ -320,6 +362,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
 | 
				
			|||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 | 
					golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
 | 
					golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
 | 
					golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
 | 
				
			||||||
 | 
					golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
 | 
				
			||||||
 | 
					golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
 | 
				
			||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 | 
					golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 | 
				
			||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 | 
					golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 | 
				
			||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 | 
					golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 | 
				
			||||||
@@ -379,6 +423,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
 | 
				
			|||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 | 
					golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 | 
				
			||||||
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
 | 
					golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
 | 
				
			||||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
 | 
					golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
 | 
				
			||||||
 | 
					golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
 | 
				
			||||||
 | 
					golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 | 
				
			||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
					golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
				
			||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
					golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
				
			||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
					golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
				
			||||||
@@ -446,6 +492,10 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc
 | 
				
			|||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
 | 
					golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
 | 
				
			||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
					golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
				
			||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 | 
					golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 | 
				
			||||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
 | 
					golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
 | 
				
			||||||
@@ -461,6 +511,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 | 
				
			|||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 | 
					golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 | 
				
			||||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
 | 
					golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
 | 
				
			||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 | 
					golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 | 
				
			||||||
 | 
					golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
 | 
				
			||||||
 | 
					golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 | 
				
			||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
					golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
				
			||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
					golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
				
			||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
					golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
				
			||||||
@@ -630,6 +682,8 @@ maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL
 | 
				
			|||||||
maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho=
 | 
					maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho=
 | 
				
			||||||
maunium.net/go/mautrix v0.15.4 h1:Ug3n2Mo+9Yb94AjZTWJQSNHmShaksEzZi85EPl3S3P0=
 | 
					maunium.net/go/mautrix v0.15.4 h1:Ug3n2Mo+9Yb94AjZTWJQSNHmShaksEzZi85EPl3S3P0=
 | 
				
			||||||
maunium.net/go/mautrix v0.15.4/go.mod h1:dBaDmsnOOBM4a+gKcgefXH73pHGXm+MCJzCs1dXFgrw=
 | 
					maunium.net/go/mautrix v0.15.4/go.mod h1:dBaDmsnOOBM4a+gKcgefXH73pHGXm+MCJzCs1dXFgrw=
 | 
				
			||||||
 | 
					maunium.net/go/mautrix v0.16.0 h1:iUqCzJE2yqBC1ddAK6eAn159My8rLb4X8g4SFtQh2Dk=
 | 
				
			||||||
 | 
					maunium.net/go/mautrix v0.16.0/go.mod h1:XAjE9pTSGcr6vXaiNgQGiip7tddJ8FQV1a29u2QdBG4=
 | 
				
			||||||
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
 | 
					mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
 | 
				
			||||||
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
 | 
					mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
 | 
				
			||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 | 
					rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,12 +17,13 @@ import (
 | 
				
			|||||||
	"embed"
 | 
						"embed"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/rs/zerolog"
 | 
						"github.com/rs/zerolog"
 | 
				
			||||||
 | 
						"github.com/rs/zerolog/log"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//go:embed templates/*.txt
 | 
					//go:embed templates/*.txt
 | 
				
			||||||
var templates embed.FS
 | 
					var templates embed.FS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var requiredKeys = []string{"commands", "cmd-configs"}
 | 
					var requiredKeys = []string{"commands"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var Sprintf = fmt.Sprintf
 | 
					var Sprintf = fmt.Sprintf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,7 +31,7 @@ var Sprintf = fmt.Sprintf
 | 
				
			|||||||
// The environment of local commands will be the machine's environment plus any extra
 | 
					// The environment of local commands will be the machine's environment plus any extra
 | 
				
			||||||
// variables specified in the Env file or Environment.
 | 
					// variables specified in the Env file or Environment.
 | 
				
			||||||
// Dir can also be specified for local commands.
 | 
					// Dir can also be specified for local commands.
 | 
				
			||||||
func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *ConfigOpts) ([]string, error) {
 | 
					func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([]string, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		outputArr     []string
 | 
							outputArr     []string
 | 
				
			||||||
@@ -52,13 +53,13 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
		command.Type = strings.TrimSpace(command.Type)
 | 
							command.Type = strings.TrimSpace(command.Type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if command.Type != "" {
 | 
							if command.Type != "" {
 | 
				
			||||||
			log.Info().Str("Command", fmt.Sprintf("Running script %s on host %s", command.Cmd, *command.Host)).Send()
 | 
								cmdCtxLogger.Info().Str("Command", fmt.Sprintf("Running script %s on host %s", command.Cmd, *command.Host)).Send()
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			log.Info().Str("Command", fmt.Sprintf("Running command %s %s on host %s", command.Cmd, ArgsStr, *command.Host)).Send()
 | 
								cmdCtxLogger.Info().Str("Command", fmt.Sprintf("Running command %s %s on host %s", command.Cmd, ArgsStr, *command.Host)).Send()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if command.RemoteHost.SshClient == nil {
 | 
							if command.RemoteHost.SshClient == nil {
 | 
				
			||||||
			err := command.RemoteHost.ConnectToSSHHost(opts, backyConf)
 | 
								err := command.RemoteHost.ConnectToSSHHost(opts)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -67,7 +68,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Retry connecting to host; if that fails, error. If it does not fail, try to create new session
 | 
							// Retry connecting to host; if that fails, error. If it does not fail, try to create new session
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			connErr := command.RemoteHost.ConnectToSSHHost(opts, backyConf)
 | 
								connErr := command.RemoteHost.ConnectToSSHHost(opts)
 | 
				
			||||||
			if connErr != nil {
 | 
								if connErr != nil {
 | 
				
			||||||
				return nil, fmt.Errorf("error creating session: %v, and error creating new connection to host: %v", err, connErr)
 | 
									return nil, fmt.Errorf("error creating session: %v, and error creating new connection to host: %v", err, connErr)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -80,7 +81,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		defer commandSession.Close()
 | 
							defer commandSession.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		injectEnvIntoSSH(envVars, commandSession, opts, log)
 | 
							injectEnvIntoSSH(envVars, commandSession, opts, cmdCtxLogger)
 | 
				
			||||||
		cmd := command.Cmd
 | 
							cmd := command.Cmd
 | 
				
			||||||
		for _, a := range command.Args {
 | 
							for _, a := range command.Args {
 | 
				
			||||||
			cmd += " " + a
 | 
								cmd += " " + a
 | 
				
			||||||
@@ -98,7 +99,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
			// did the program panic while writing to the buffer?
 | 
								// did the program panic while writing to the buffer?
 | 
				
			||||||
			defer func() {
 | 
								defer func() {
 | 
				
			||||||
				if err := recover(); err != nil {
 | 
									if err := recover(); err != nil {
 | 
				
			||||||
					log.Info().Msg(fmt.Sprintf("panic occured writing to buffer: %x", err))
 | 
										cmdCtxLogger.Info().Msg(fmt.Sprintf("panic occured writing to buffer: %x", err))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}()
 | 
								}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,7 +120,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
						if str, ok := outMap["output"].(string); ok {
 | 
											if str, ok := outMap["output"].(string); ok {
 | 
				
			||||||
							outputArr = append(outputArr, str)
 | 
												outputArr = append(outputArr, str)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						log.Info().Fields(outMap).Send()
 | 
											cmdCtxLogger.Info().Fields(outMap).Send()
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					return outputArr, err
 | 
										return outputArr, err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -211,7 +212,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
						if str, ok := outMap["output"].(string); ok {
 | 
											if str, ok := outMap["output"].(string); ok {
 | 
				
			||||||
							outputArr = append(outputArr, str)
 | 
												outputArr = append(outputArr, str)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						log.Info().Fields(outMap).Send()
 | 
											cmdCtxLogger.Info().Fields(outMap).Send()
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					return outputArr, err
 | 
										return outputArr, err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -224,7 +225,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
					if str, ok := outMap["output"].(string); ok {
 | 
										if str, ok := outMap["output"].(string); ok {
 | 
				
			||||||
						outputArr = append(outputArr, str)
 | 
											outputArr = append(outputArr, str)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					log.Info().Fields(outMap).Send()
 | 
										cmdCtxLogger.Info().Fields(outMap).Send()
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return outputArr, nil
 | 
									return outputArr, nil
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -240,18 +241,18 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
			if str, ok := outMap["output"].(string); ok {
 | 
								if str, ok := outMap["output"].(string); ok {
 | 
				
			||||||
				outputArr = append(outputArr, str)
 | 
									outputArr = append(outputArr, str)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			log.Info().Fields(outMap).Send()
 | 
								cmdCtxLogger.Info().Fields(outMap).Send()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Error().Err(fmt.Errorf("error when running cmd: %s: %w", command.Cmd, err)).Send()
 | 
								cmdCtxLogger.Error().Err(fmt.Errorf("error when running cmd: %s: %w", command.Cmd, err)).Send()
 | 
				
			||||||
			return outputArr, err
 | 
								return outputArr, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var err error
 | 
							var err error
 | 
				
			||||||
		if command.Shell != "" {
 | 
							if command.Shell != "" {
 | 
				
			||||||
			log.Info().Str("Command", fmt.Sprintf("Running command %s %s on local machine in %s", command.Cmd, ArgsStr, command.Shell)).Send()
 | 
								cmdCtxLogger.Info().Str("Command", fmt.Sprintf("Running command %s %s on local machine in %s", command.Cmd, ArgsStr, command.Shell)).Send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ArgsStr = fmt.Sprintf("%s %s", command.Cmd, ArgsStr)
 | 
								ArgsStr = fmt.Sprintf("%s %s", command.Cmd, ArgsStr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -260,7 +261,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
			if command.Dir != nil {
 | 
								if command.Dir != nil {
 | 
				
			||||||
				localCMD.Dir = *command.Dir
 | 
									localCMD.Dir = *command.Dir
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			injectEnvIntoLocalCMD(envVars, localCMD, log)
 | 
								injectEnvIntoLocalCMD(envVars, localCMD, cmdCtxLogger)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			cmdOutWriters = io.MultiWriter(&cmdOutBuf)
 | 
								cmdOutWriters = io.MultiWriter(&cmdOutBuf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -286,12 +287,12 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Error().Err(fmt.Errorf("error when running cmd %s: %w", command.Cmd, err)).Send()
 | 
									cmdCtxLogger.Error().Err(fmt.Errorf("error when running cmd %s: %w", command.Cmd, err)).Send()
 | 
				
			||||||
				return outputArr, err
 | 
									return outputArr, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return outputArr, nil
 | 
								return outputArr, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		log.Info().Str("Command", fmt.Sprintf("Running command %s %s on local machine", command.Cmd, ArgsStr)).Send()
 | 
							cmdCtxLogger.Info().Str("Command", fmt.Sprintf("Running command %s %s on local machine", command.Cmd, ArgsStr)).Send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		localCMD := exec.Command(command.Cmd, command.Args...)
 | 
							localCMD := exec.Command(command.Cmd, command.Args...)
 | 
				
			||||||
		if command.Dir != nil {
 | 
							if command.Dir != nil {
 | 
				
			||||||
@@ -299,7 +300,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		// fmt.Printf("%v\n", envVars.env)
 | 
							// fmt.Printf("%v\n", envVars.env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		injectEnvIntoLocalCMD(envVars, localCMD, log)
 | 
							injectEnvIntoLocalCMD(envVars, localCMD, cmdCtxLogger)
 | 
				
			||||||
		cmdOutWriters = io.MultiWriter(&cmdOutBuf)
 | 
							cmdOutWriters = io.MultiWriter(&cmdOutBuf)
 | 
				
			||||||
		// fmt.Printf("%v\n", localCMD.Environ())
 | 
							// fmt.Printf("%v\n", localCMD.Environ())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -318,46 +319,46 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
 | 
				
			|||||||
			if str, ok := outMap["output"].(string); ok {
 | 
								if str, ok := outMap["output"].(string); ok {
 | 
				
			||||||
				outputArr = append(outputArr, str)
 | 
									outputArr = append(outputArr, str)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			log.Info().Fields(outMap).Send()
 | 
								cmdCtxLogger.Info().Fields(outMap).Send()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Error().Err(fmt.Errorf("error when running cmd %s: %w", command.Cmd, err)).Send()
 | 
								cmdCtxLogger.Error().Err(fmt.Errorf("error when running cmd %s: %w", command.Cmd, err)).Send()
 | 
				
			||||||
			return outputArr, err
 | 
								return outputArr, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return outputArr, nil
 | 
						return outputArr, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigFile, results chan<- string, opts *ConfigOpts) {
 | 
					func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<- string, opts *ConfigOpts) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for list := range jobs {
 | 
						for list := range jobs {
 | 
				
			||||||
		fieldsMap := make(map[string]interface{})
 | 
							fieldsMap := make(map[string]interface{})
 | 
				
			||||||
		fieldsMap["list"] = list.Name
 | 
							fieldsMap["list"] = list.Name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cmdLog := config.Logger.Info()
 | 
							cmdLog := opts.Logger.Info()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var count int
 | 
							var count int
 | 
				
			||||||
		var cmdsRan []string
 | 
							var cmdsRan []string
 | 
				
			||||||
		var outStructArr []outStruct
 | 
							var outStructArr []outStruct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for _, cmd := range list.Order {
 | 
							for _, cmd := range list.Order {
 | 
				
			||||||
			currentCmd := config.Cmds[cmd].Cmd
 | 
								currentCmd := opts.Cmds[cmd].Cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			fieldsMap["cmd"] = config.Cmds[cmd].Cmd
 | 
								fieldsMap["cmd"] = opts.Cmds[cmd].Cmd
 | 
				
			||||||
			cmdToRun := config.Cmds[cmd]
 | 
								cmdToRun := opts.Cmds[cmd]
 | 
				
			||||||
			cmdLog.Fields(fieldsMap).Send()
 | 
								cmdLog.Fields(fieldsMap).Send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			cmdLogger := config.Logger.With().
 | 
								cmdLogger := opts.Logger.With().
 | 
				
			||||||
				Str("backy-cmd", cmd).Str("Host", "local machine").
 | 
									Str("backy-cmd", cmd).Str("Host", "local machine").
 | 
				
			||||||
				Logger()
 | 
									Logger()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if cmdToRun.Host != nil {
 | 
								if cmdToRun.Host != nil {
 | 
				
			||||||
				cmdLogger = config.Logger.With().
 | 
									cmdLogger = opts.Logger.With().
 | 
				
			||||||
					Str("backy-cmd", cmd).Str("Host", *cmdToRun.Host).
 | 
										Str("backy-cmd", cmd).Str("Host", *cmdToRun.Host).
 | 
				
			||||||
					Logger()
 | 
										Logger()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			outputArr, runOutErr := cmdToRun.RunCmd(cmdLogger, config, opts)
 | 
								outputArr, runOutErr := cmdToRun.RunCmd(cmdLogger, opts)
 | 
				
			||||||
			if list.NotifyConfig != nil {
 | 
								if list.NotifyConfig != nil {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if cmdToRun.GetOutput || list.GetOutput {
 | 
									if cmdToRun.GetOutput || list.GetOutput {
 | 
				
			||||||
@@ -380,7 +381,7 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigF
 | 
				
			|||||||
					errStruct["listName"] = list.Name
 | 
										errStruct["listName"] = list.Name
 | 
				
			||||||
					errStruct["Command"] = currentCmd
 | 
										errStruct["Command"] = currentCmd
 | 
				
			||||||
					errStruct["Cmd"] = cmd
 | 
										errStruct["Cmd"] = cmd
 | 
				
			||||||
					errStruct["Args"] = config.Cmds[cmd].Args
 | 
										errStruct["Args"] = opts.Cmds[cmd].Args
 | 
				
			||||||
					errStruct["Err"] = runOutErr
 | 
										errStruct["Err"] = runOutErr
 | 
				
			||||||
					errStruct["CmdsRan"] = cmdsRan
 | 
										errStruct["CmdsRan"] = cmdsRan
 | 
				
			||||||
					errStruct["Output"] = outputArr
 | 
										errStruct["Output"] = outputArr
 | 
				
			||||||
@@ -390,17 +391,17 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigF
 | 
				
			|||||||
					tmpErr := msgTemps.err.Execute(&errMsg, errStruct)
 | 
										tmpErr := msgTemps.err.Execute(&errMsg, errStruct)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if tmpErr != nil {
 | 
										if tmpErr != nil {
 | 
				
			||||||
						config.Logger.Err(tmpErr).Send()
 | 
											opts.Logger.Err(tmpErr).Send()
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					notifySendErr := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s failed on command %s ", list.Name, cmd), errMsg.String())
 | 
										notifySendErr := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s failed", list.Name), errMsg.String())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if notifySendErr != nil {
 | 
										if notifySendErr != nil {
 | 
				
			||||||
						config.Logger.Err(notifySendErr).Send()
 | 
											opts.Logger.Err(notifySendErr).Send()
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				config.Logger.Err(runOutErr).Send()
 | 
									opts.Logger.Err(runOutErr).Send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				break
 | 
									break
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
@@ -420,14 +421,14 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigF
 | 
				
			|||||||
						tmpErr := msgTemps.success.Execute(&successMsg, successStruct)
 | 
											tmpErr := msgTemps.success.Execute(&successMsg, successStruct)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if tmpErr != nil {
 | 
											if tmpErr != nil {
 | 
				
			||||||
							config.Logger.Err(tmpErr).Send()
 | 
												opts.Logger.Err(tmpErr).Send()
 | 
				
			||||||
							break
 | 
												break
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						err := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s succeded", list.Name), successMsg.String())
 | 
											err := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s succeded", list.Name), successMsg.String())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if err != nil {
 | 
											if err != nil {
 | 
				
			||||||
							config.Logger.Err(err).Send()
 | 
												opts.Logger.Err(err).Send()
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
@@ -442,22 +443,22 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigF
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RunListConfig runs a command list from the ConfigFile.
 | 
					// RunListConfig runs a command list from the ConfigFile.
 | 
				
			||||||
func (config *ConfigFile) RunListConfig(cron string, opts *ConfigOpts) {
 | 
					func (opts *ConfigOpts) RunListConfig(cron string) {
 | 
				
			||||||
	mTemps := &msgTemplates{
 | 
						mTemps := &msgTemplates{
 | 
				
			||||||
		err:     template.Must(template.New("error.txt").ParseFS(templates, "templates/error.txt")),
 | 
							err:     template.Must(template.New("error.txt").ParseFS(templates, "templates/error.txt")),
 | 
				
			||||||
		success: template.Must(template.New("success.txt").ParseFS(templates, "templates/success.txt")),
 | 
							success: template.Must(template.New("success.txt").ParseFS(templates, "templates/success.txt")),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	configListsLen := len(config.CmdConfigLists)
 | 
						configListsLen := len(opts.CmdConfigLists)
 | 
				
			||||||
	listChan := make(chan *CmdList, configListsLen)
 | 
						listChan := make(chan *CmdList, configListsLen)
 | 
				
			||||||
	results := make(chan string)
 | 
						results := make(chan string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// This starts up list workers, initially blocked
 | 
						// This starts up list workers, initially blocked
 | 
				
			||||||
	// because there are no jobs yet.
 | 
						// because there are no jobs yet.
 | 
				
			||||||
	for w := 1; w <= configListsLen; w++ {
 | 
						for w := 1; w <= configListsLen; w++ {
 | 
				
			||||||
		go cmdListWorker(mTemps, listChan, config, results, opts)
 | 
							go cmdListWorker(mTemps, listChan, results, opts)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for listName, cmdConfig := range config.CmdConfigLists {
 | 
						for listName, cmdConfig := range opts.CmdConfigLists {
 | 
				
			||||||
		if cmdConfig.Name == "" {
 | 
							if cmdConfig.Name == "" {
 | 
				
			||||||
			cmdConfig.Name = listName
 | 
								cmdConfig.Name = listName
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -475,26 +476,26 @@ func (config *ConfigFile) RunListConfig(cron string, opts *ConfigOpts) {
 | 
				
			|||||||
		<-results
 | 
							<-results
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config.closeHostConnections()
 | 
						opts.closeHostConnections()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (config *ConfigFile) ExecuteCmds(opts *ConfigOpts) {
 | 
					func (config *ConfigOpts) ExecuteCmds(opts *ConfigOpts) {
 | 
				
			||||||
	for _, cmd := range opts.executeCmds {
 | 
						for _, cmd := range opts.executeCmds {
 | 
				
			||||||
		cmdToRun := config.Cmds[cmd]
 | 
							cmdToRun := opts.Cmds[cmd]
 | 
				
			||||||
		cmdLogger := config.Logger.With().
 | 
							cmdLogger := opts.Logger.With().
 | 
				
			||||||
			Str("backy-cmd", cmd).
 | 
								Str("backy-cmd", cmd).
 | 
				
			||||||
			Logger()
 | 
								Logger()
 | 
				
			||||||
		_, runErr := cmdToRun.RunCmd(cmdLogger, config, opts)
 | 
							_, runErr := cmdToRun.RunCmd(cmdLogger, opts)
 | 
				
			||||||
		if runErr != nil {
 | 
							if runErr != nil {
 | 
				
			||||||
			config.Logger.Err(runErr).Send()
 | 
								opts.Logger.Err(runErr).Send()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config.closeHostConnections()
 | 
						opts.closeHostConnections()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *ConfigFile) closeHostConnections() {
 | 
					func (c *ConfigOpts) closeHostConnections() {
 | 
				
			||||||
	for _, host := range c.Hosts {
 | 
						for _, host := range c.Hosts {
 | 
				
			||||||
		c.Logger.Info().Str("server", host.HostName)
 | 
							c.Logger.Info().Str("server", host.HostName)
 | 
				
			||||||
		if host.isProxyHost {
 | 
							if host.isProxyHost {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,40 +10,58 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
 | 
						"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
 | 
				
			||||||
	vault "github.com/hashicorp/vault/api"
 | 
						vault "github.com/hashicorp/vault/api"
 | 
				
			||||||
 | 
						"github.com/knadh/koanf/parsers/yaml"
 | 
				
			||||||
 | 
						"github.com/knadh/koanf/providers/file"
 | 
				
			||||||
 | 
						"github.com/knadh/koanf/v2"
 | 
				
			||||||
	"github.com/mattn/go-isatty"
 | 
						"github.com/mattn/go-isatty"
 | 
				
			||||||
	"github.com/rs/zerolog"
 | 
						"github.com/rs/zerolog"
 | 
				
			||||||
	"github.com/spf13/viper"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (opts *ConfigOpts) InitConfig() {
 | 
					var homeDir string
 | 
				
			||||||
	if opts.viper != nil {
 | 
					var homeDirErr error
 | 
				
			||||||
		return
 | 
					var backyHomeConfDir string
 | 
				
			||||||
	}
 | 
					var configFiles []string
 | 
				
			||||||
	backyViper := viper.New()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if strings.TrimSpace(opts.ConfigFilePath) != "" {
 | 
					func (opts *ConfigOpts) InitConfig() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						homeDir, homeDirErr = os.UserHomeDir()
 | 
				
			||||||
 | 
						if homeDirErr != nil {
 | 
				
			||||||
 | 
							fmt.Println(homeDirErr)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						backyHomeConfDir = homeDir + "/.config/backy/"
 | 
				
			||||||
 | 
						configFiles = []string{"./backy.yml", "./backy.yaml", backyHomeConfDir + "backy.yml", backyHomeConfDir + "backy.yaml"}
 | 
				
			||||||
 | 
						backyKoanf := koanf.New(".")
 | 
				
			||||||
 | 
						opts.ConfigFilePath = strings.TrimSpace(opts.ConfigFilePath)
 | 
				
			||||||
 | 
						if opts.ConfigFilePath != "" {
 | 
				
			||||||
		err := testFile(opts.ConfigFilePath)
 | 
							err := testFile(opts.ConfigFilePath)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			logging.ExitWithMSG(fmt.Sprintf("Could not open config file %s: %v", opts.ConfigFilePath, err), 1, nil)
 | 
								logging.ExitWithMSG(fmt.Sprintf("Could not open config file %s: %v", opts.ConfigFilePath, err), 1, nil)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		backyViper.SetConfigFile(opts.ConfigFilePath)
 | 
					
 | 
				
			||||||
 | 
							if err := backyKoanf.Load(file.Provider(opts.ConfigFilePath), yaml.Parser()); err != nil {
 | 
				
			||||||
 | 
								logging.ExitWithMSG(fmt.Sprintf("error loading config: %v", err), 1, &opts.Logger)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		backyViper.SetConfigName("backy.yml")           // name of config file (with extension)
 | 
					
 | 
				
			||||||
		backyViper.SetConfigName("backy.yaml")          // name of config file (with extension)
 | 
							cFileFalures := 0
 | 
				
			||||||
		backyViper.SetConfigType("yaml")                // REQUIRED if the config file does not have the extension in the name
 | 
							for _, c := range configFiles {
 | 
				
			||||||
		backyViper.AddConfigPath(".")                   // optionally look for config in the working directory
 | 
								if err := backyKoanf.Load(file.Provider(c), yaml.Parser()); err != nil {
 | 
				
			||||||
		backyViper.AddConfigPath("$HOME/.config/backy") // call multiple times to add many search paths
 | 
									cFileFalures++
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									opts.ConfigFilePath = c
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if cFileFalures == len(configFiles) {
 | 
				
			||||||
 | 
								logging.ExitWithMSG(fmt.Sprintf("could not find a config file. Put one in the following paths: %v", configFiles), 1, &opts.Logger)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err := backyViper.ReadInConfig() // Find and read the config file
 | 
					
 | 
				
			||||||
	if err != nil {                  // Handle errors reading the config file
 | 
						opts.koanf = backyKoanf
 | 
				
			||||||
		msg := fmt.Sprintf("fatal error reading config file %s: %v", backyViper.ConfigFileUsed(), err)
 | 
					 | 
				
			||||||
		logging.ExitWithMSG(msg, 1, nil)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	opts.viper = backyViper
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ReadConfig validates and reads the config file.
 | 
					// ReadConfig validates and reads the config file.
 | 
				
			||||||
func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
					func ReadConfig(opts *ConfigOpts) *ConfigOpts {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if isatty.IsTerminal(os.Stdout.Fd()) {
 | 
						if isatty.IsTerminal(os.Stdout.Fd()) {
 | 
				
			||||||
		os.Setenv("BACKY_TERM", "enabled")
 | 
							os.Setenv("BACKY_TERM", "enabled")
 | 
				
			||||||
@@ -53,44 +71,38 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
				
			|||||||
		os.Setenv("BACKY_TERM", "disabled")
 | 
							os.Setenv("BACKY_TERM", "disabled")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	backyConfigFile := NewConfig()
 | 
						backyKoanf := opts.koanf
 | 
				
			||||||
	backyViper := opts.viper
 | 
					
 | 
				
			||||||
	opts.loadEnv()
 | 
						opts.loadEnv()
 | 
				
			||||||
	// envFileInConfigDir := fmt.Sprintf("%s/.env", path.Dir(backyViper.ConfigFileUsed()))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// load the .env file in config file directory
 | 
						if backyKoanf.Bool(getNestedConfig("logging", "cmd-std-out")) {
 | 
				
			||||||
	// _ = godotenv.Load(envFileInConfigDir)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if backyViper.GetBool(getNestedConfig("logging", "cmd-std-out")) {
 | 
					 | 
				
			||||||
		os.Setenv("BACKY_STDOUT", "enabled")
 | 
							os.Setenv("BACKY_STDOUT", "enabled")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CheckConfigValues(backyViper)
 | 
						CheckConfigValues(backyKoanf, opts.ConfigFilePath)
 | 
				
			||||||
	for _, c := range opts.executeCmds {
 | 
						for _, c := range opts.executeCmds {
 | 
				
			||||||
		if !backyViper.IsSet(getCmdFromConfig(c)) {
 | 
							if !backyKoanf.Exists(getCmdFromConfig(c)) {
 | 
				
			||||||
			logging.ExitWithMSG(Sprintf("command %s is not in config file %s", c, backyViper.ConfigFileUsed()), 1, nil)
 | 
								logging.ExitWithMSG(Sprintf("command %s is not in config file %s", c, opts.ConfigFilePath), 1, nil)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, l := range opts.executeLists {
 | 
						for _, l := range opts.executeLists {
 | 
				
			||||||
		if !backyViper.IsSet(getCmdListFromConfig(l)) {
 | 
							if !backyKoanf.Exists(getCmdListFromConfig(l)) {
 | 
				
			||||||
			logging.ExitWithMSG(Sprintf("list %s not found", l), 1, nil)
 | 
								logging.ExitWithMSG(Sprintf("list %s not found", l), 1, nil)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		// backyLoggingOpts *viper.Viper
 | 
					 | 
				
			||||||
		verbose bool
 | 
							verbose bool
 | 
				
			||||||
		logFile string
 | 
							logFile string
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	verbose = backyViper.GetBool(getLoggingKeyFromConfig("verbose"))
 | 
						verbose = backyKoanf.Bool(getLoggingKeyFromConfig("verbose"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	logFile = fmt.Sprintf("%s/backy.log", path.Dir(backyViper.ConfigFileUsed()))
 | 
						logFile = fmt.Sprintf("%s/backy.log", path.Dir(opts.ConfigFilePath))
 | 
				
			||||||
	if backyViper.IsSet(getLoggingKeyFromConfig("file")) {
 | 
						if backyKoanf.Exists(getLoggingKeyFromConfig("file")) {
 | 
				
			||||||
		logFile = backyViper.GetString(getLoggingKeyFromConfig("file"))
 | 
							logFile = backyKoanf.String(getLoggingKeyFromConfig("file"))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
 | 
						zerolog.SetGlobalLevel(zerolog.InfoLevel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if verbose {
 | 
						if verbose {
 | 
				
			||||||
@@ -99,7 +111,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
				
			|||||||
		os.Setenv("BACKY_LOGLEVEL", Sprintf("%v", globalLvl))
 | 
							os.Setenv("BACKY_LOGLEVEL", Sprintf("%v", globalLvl))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	consoleLoggingDisabled := backyViper.GetBool(getLoggingKeyFromConfig("console-disabled"))
 | 
						consoleLoggingDisabled := backyKoanf.Bool(getLoggingKeyFromConfig("console-disabled"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	os.Setenv("BACKY_CONSOLE_LOGGING", "enabled")
 | 
						os.Setenv("BACKY_CONSOLE_LOGGING", "enabled")
 | 
				
			||||||
	// Other qualifiers can go here as well
 | 
						// Other qualifiers can go here as well
 | 
				
			||||||
@@ -111,42 +123,30 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	log := zerolog.New(writers).With().Timestamp().Logger()
 | 
						log := zerolog.New(writers).With().Timestamp().Logger()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	backyConfigFile.Logger = log
 | 
						opts.Logger = log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Info().Str("config file", backyViper.ConfigFileUsed()).Send()
 | 
						log.Info().Str("config file", opts.ConfigFilePath).Send()
 | 
				
			||||||
	commandsMap := backyViper.GetStringMapString("commands")
 | 
					
 | 
				
			||||||
	commandsMapViper := backyViper.Sub("commands")
 | 
						unmarshalErr := backyKoanf.UnmarshalWithConf("commands", &opts.Cmds, koanf.UnmarshalConf{Tag: "yaml"})
 | 
				
			||||||
	unmarshalErr := commandsMapViper.Unmarshal(&backyConfigFile.Cmds)
 | 
					 | 
				
			||||||
	if unmarshalErr != nil {
 | 
						if unmarshalErr != nil {
 | 
				
			||||||
		panic(fmt.Errorf("error unmarshalling cmds struct: %w", unmarshalErr))
 | 
							panic(fmt.Errorf("error unmarshalling cmds struct: %w", unmarshalErr))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hostConfigsMap := make(map[string]*viper.Viper)
 | 
						for cmdName, cmdConf := range opts.Cmds {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	for cmdName, cmdConf := range backyConfigFile.Cmds {
 | 
					 | 
				
			||||||
		envFileErr := testFile(cmdConf.Env)
 | 
							envFileErr := testFile(cmdConf.Env)
 | 
				
			||||||
		if envFileErr != nil {
 | 
							if envFileErr != nil {
 | 
				
			||||||
			backyConfigFile.Logger.Info().Str("cmd", cmdName).Err(envFileErr).Send()
 | 
								opts.Logger.Info().Str("cmd", cmdName).Err(envFileErr).Send()
 | 
				
			||||||
			os.Exit(1)
 | 
								os.Exit(1)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		expandEnvVars(opts.backyEnv, cmdConf.Environment)
 | 
							expandEnvVars(opts.backyEnv, cmdConf.Environment)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		host := cmdConf.Host
 | 
					 | 
				
			||||||
		if host != nil {
 | 
					 | 
				
			||||||
			if backyViper.IsSet(getNestedConfig("hosts", *host)) {
 | 
					 | 
				
			||||||
				hostconfig := backyViper.Sub(getNestedConfig("hosts", *host))
 | 
					 | 
				
			||||||
				hostConfigsMap[*host] = hostconfig
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hostsMapViper := backyViper.Sub("hosts")
 | 
						unmarshalErr = backyKoanf.UnmarshalWithConf("hosts", &opts.Hosts, koanf.UnmarshalConf{Tag: "yaml"})
 | 
				
			||||||
	unmarshalErr = hostsMapViper.Unmarshal(&backyConfigFile.Hosts)
 | 
					 | 
				
			||||||
	if unmarshalErr != nil {
 | 
						if unmarshalErr != nil {
 | 
				
			||||||
		panic(fmt.Errorf("error unmarshalling hosts struct: %w", unmarshalErr))
 | 
							panic(fmt.Errorf("error unmarshalling hosts struct: %w", unmarshalErr))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for hostConfigName, host := range backyConfigFile.Hosts {
 | 
						for hostConfigName, host := range opts.Hosts {
 | 
				
			||||||
		if host.Host == "" {
 | 
							if host.Host == "" {
 | 
				
			||||||
			host.Host = hostConfigName
 | 
								host.Host = hostConfigName
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -155,7 +155,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
				
			|||||||
			if len(proxyHosts) > 1 {
 | 
								if len(proxyHosts) > 1 {
 | 
				
			||||||
				for hostNum, h := range proxyHosts {
 | 
									for hostNum, h := range proxyHosts {
 | 
				
			||||||
					if hostNum > 1 {
 | 
										if hostNum > 1 {
 | 
				
			||||||
						proxyHost, defined := backyConfigFile.Hosts[h]
 | 
											proxyHost, defined := opts.Hosts[h]
 | 
				
			||||||
						if defined {
 | 
											if defined {
 | 
				
			||||||
							host.ProxyHost = append(host.ProxyHost, proxyHost)
 | 
												host.ProxyHost = append(host.ProxyHost, proxyHost)
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
@@ -163,7 +163,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
				
			|||||||
							host.ProxyHost = append(host.ProxyHost, newProxy)
 | 
												host.ProxyHost = append(host.ProxyHost, newProxy)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						proxyHost, defined := backyConfigFile.Hosts[h]
 | 
											proxyHost, defined := opts.Hosts[h]
 | 
				
			||||||
						if defined {
 | 
											if defined {
 | 
				
			||||||
							host.ProxyHost = append(host.ProxyHost, proxyHost)
 | 
												host.ProxyHost = append(host.ProxyHost, proxyHost)
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
@@ -173,7 +173,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				proxyHost, defined := backyConfigFile.Hosts[proxyHosts[0]]
 | 
									proxyHost, defined := opts.Hosts[proxyHosts[0]]
 | 
				
			||||||
				if defined {
 | 
									if defined {
 | 
				
			||||||
					host.ProxyHost = append(host.ProxyHost, proxyHost)
 | 
										host.ProxyHost = append(host.ProxyHost, proxyHost)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
@@ -184,33 +184,29 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmdListCfg := backyViper.Sub("cmd-configs")
 | 
						if backyKoanf.Exists("cmd-lists") {
 | 
				
			||||||
	unmarshalErr = cmdListCfg.Unmarshal(&backyConfigFile.CmdConfigLists)
 | 
							unmarshalErr = backyKoanf.UnmarshalWithConf("cmd-lists", &opts.CmdConfigLists, koanf.UnmarshalConf{Tag: "yaml"})
 | 
				
			||||||
	if unmarshalErr != nil {
 | 
							if unmarshalErr != nil {
 | 
				
			||||||
		panic(fmt.Errorf("error unmarshalling cmd list struct: %w", unmarshalErr))
 | 
								logging.ExitWithMSG((fmt.Sprintf("error unmarshalling cmd list struct: %v", unmarshalErr)), 1, &opts.Logger)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var cmdNotFoundSliceErr []error
 | 
						var cmdNotFoundSliceErr []error
 | 
				
			||||||
	for cmdListName, cmdList := range backyConfigFile.CmdConfigLists {
 | 
						for cmdListName, cmdList := range opts.CmdConfigLists {
 | 
				
			||||||
		if opts.useCron {
 | 
							if opts.useCron {
 | 
				
			||||||
			cron := strings.TrimSpace(cmdList.Cron)
 | 
								cron := strings.TrimSpace(cmdList.Cron)
 | 
				
			||||||
			if cron == "" {
 | 
								if cron == "" {
 | 
				
			||||||
				delete(backyConfigFile.CmdConfigLists, cmdListName)
 | 
									delete(opts.CmdConfigLists, cmdListName)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, cmdInList := range cmdList.Order {
 | 
							for _, cmdInList := range cmdList.Order {
 | 
				
			||||||
			_, cmdNameFound := backyConfigFile.Cmds[cmdInList]
 | 
								_, cmdNameFound := opts.Cmds[cmdInList]
 | 
				
			||||||
			if !cmdNameFound {
 | 
								if !cmdNameFound {
 | 
				
			||||||
				cmdNotFoundStr := fmt.Sprintf("command %s in list %s is not defined in commands section in config file", cmdInList, cmdListName)
 | 
									cmdNotFoundStr := fmt.Sprintf("command %s in list %s is not defined in commands section in config file", cmdInList, cmdListName)
 | 
				
			||||||
				cmdNotFoundErr := errors.New(cmdNotFoundStr)
 | 
									cmdNotFoundErr := errors.New(cmdNotFoundStr)
 | 
				
			||||||
				cmdNotFoundSliceErr = append(cmdNotFoundSliceErr, cmdNotFoundErr)
 | 
									cmdNotFoundSliceErr = append(cmdNotFoundSliceErr, cmdNotFoundErr)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, notificationID := range cmdList.Notifications {
 | 
					 | 
				
			||||||
			if !backyViper.IsSet(getNestedConfig("notifications", notificationID)) {
 | 
					 | 
				
			||||||
				logging.ExitWithMSG(fmt.Sprintf("%s in list %s not found in notifications", notificationID, cmdListName), 1, nil)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(cmdNotFoundSliceErr) > 0 {
 | 
						if len(cmdNotFoundSliceErr) > 0 {
 | 
				
			||||||
@@ -218,39 +214,35 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
				
			|||||||
		cmdNotFoundErrorLog.Errs("commands not found", cmdNotFoundSliceErr).Send()
 | 
							cmdNotFoundErrorLog.Errs("commands not found", cmdNotFoundSliceErr).Send()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.useCron && (len(backyConfigFile.CmdConfigLists) == 0) {
 | 
						if opts.useCron && (len(opts.CmdConfigLists) == 0) {
 | 
				
			||||||
		logging.ExitWithMSG("No cron fields detected in any command lists", 1, nil)
 | 
							logging.ExitWithMSG("No cron fields detected in any command lists", 1, nil)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for c := range commandsMap {
 | 
						for c := range opts.Cmds {
 | 
				
			||||||
		if opts.executeCmds != nil && !contains(opts.executeCmds, c) {
 | 
							if opts.executeCmds != nil && !contains(opts.executeCmds, c) {
 | 
				
			||||||
			delete(backyConfigFile.Cmds, c)
 | 
								delete(opts.Cmds, c)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(opts.executeLists) > 0 {
 | 
						if len(opts.executeLists) > 0 {
 | 
				
			||||||
		for l := range backyConfigFile.CmdConfigLists {
 | 
							for l := range opts.CmdConfigLists {
 | 
				
			||||||
			if !contains(opts.executeLists, l) {
 | 
								if !contains(opts.executeLists, l) {
 | 
				
			||||||
				delete(backyConfigFile.CmdConfigLists, l)
 | 
									delete(opts.CmdConfigLists, l)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if backyViper.IsSet("notifications") {
 | 
						if backyKoanf.Exists("notifications") {
 | 
				
			||||||
		notificationsMap := backyViper.GetStringMap("notifications")
 | 
					
 | 
				
			||||||
		for id := range notificationsMap {
 | 
							unmarshalErr = backyKoanf.UnmarshalWithConf("notifications", &opts.NotificationConf, koanf.UnmarshalConf{Tag: "yaml"})
 | 
				
			||||||
			notifConfig := backyViper.Sub(getNestedConfig("notifications", id))
 | 
							if unmarshalErr != nil {
 | 
				
			||||||
			config := &NotificationsConfig{
 | 
								fmt.Printf("error unmarshalling notifications object: %v", unmarshalErr)
 | 
				
			||||||
				Config:  notifConfig,
 | 
					 | 
				
			||||||
				Enabled: true,
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			backyConfigFile.Notifications[id] = config
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, cmd := range backyConfigFile.Cmds {
 | 
						for _, cmd := range opts.Cmds {
 | 
				
			||||||
		if cmd.Host != nil {
 | 
							if cmd.Host != nil {
 | 
				
			||||||
			host, hostFound := backyConfigFile.Hosts[*cmd.Host]
 | 
								host, hostFound := opts.Hosts[*cmd.Host]
 | 
				
			||||||
			if hostFound {
 | 
								if hostFound {
 | 
				
			||||||
				cmd.RemoteHost = host
 | 
									cmd.RemoteHost = host
 | 
				
			||||||
				cmd.RemoteHost.Host = host.Host
 | 
									cmd.RemoteHost.Host = host.Host
 | 
				
			||||||
@@ -258,19 +250,18 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
 | 
				
			|||||||
					cmd.RemoteHost.HostName = host.HostName
 | 
										cmd.RemoteHost.HostName = host.HostName
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				backyConfigFile.Hosts[*cmd.Host] = &Host{Host: *cmd.Host}
 | 
									opts.Hosts[*cmd.Host] = &Host{Host: *cmd.Host}
 | 
				
			||||||
				cmd.RemoteHost = &Host{Host: *cmd.Host}
 | 
									cmd.RemoteHost = &Host{Host: *cmd.Host}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	backyConfigFile.SetupNotify()
 | 
						opts.SetupNotify()
 | 
				
			||||||
	opts.ConfigFile = backyConfigFile
 | 
					 | 
				
			||||||
	if err := opts.setupVault(); err != nil {
 | 
						if err := opts.setupVault(); err != nil {
 | 
				
			||||||
		log.Err(err).Send()
 | 
							log.Err(err).Send()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	opts.ConfigFile = backyConfigFile
 | 
					
 | 
				
			||||||
	return backyConfigFile
 | 
						return opts
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getNestedConfig(nestedConfig, key string) string {
 | 
					func getNestedConfig(nestedConfig, key string) string {
 | 
				
			||||||
@@ -289,16 +280,16 @@ func getLoggingKeyFromConfig(key string) string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getCmdListFromConfig(list string) string {
 | 
					func getCmdListFromConfig(list string) string {
 | 
				
			||||||
	return fmt.Sprintf("cmd-configs.%s", list)
 | 
						return fmt.Sprintf("cmd-lists.%s", list)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (opts *ConfigOpts) setupVault() error {
 | 
					func (opts *ConfigOpts) setupVault() error {
 | 
				
			||||||
	if !opts.viper.GetBool("vault.enabled") {
 | 
						if !opts.koanf.Bool("vault.enabled") {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	config := vault.DefaultConfig()
 | 
						config := vault.DefaultConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config.Address = opts.viper.GetString("vault.address")
 | 
						config.Address = opts.koanf.String("vault.address")
 | 
				
			||||||
	if strings.TrimSpace(config.Address) == "" {
 | 
						if strings.TrimSpace(config.Address) == "" {
 | 
				
			||||||
		config.Address = os.Getenv("VAULT_ADDR")
 | 
							config.Address = os.Getenv("VAULT_ADDR")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -308,7 +299,7 @@ func (opts *ConfigOpts) setupVault() error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	token := opts.viper.GetString("vault.token")
 | 
						token := opts.koanf.String("vault.token")
 | 
				
			||||||
	if strings.TrimSpace(token) == "" {
 | 
						if strings.TrimSpace(token) == "" {
 | 
				
			||||||
		token = os.Getenv("VAULT_TOKEN")
 | 
							token = os.Getenv("VAULT_TOKEN")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -318,10 +309,9 @@ func (opts *ConfigOpts) setupVault() error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	client.SetToken(token)
 | 
						client.SetToken(token)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmdListCfg := opts.viper.Sub("viper.keys")
 | 
						unmarshalErr := opts.koanf.UnmarshalWithConf("vault.keys", &opts.VaultKeys, koanf.UnmarshalConf{Tag: "yaml"})
 | 
				
			||||||
	unmarshalErr := cmdListCfg.Unmarshal(&opts.VaultKeys)
 | 
					 | 
				
			||||||
	if unmarshalErr != nil {
 | 
						if unmarshalErr != nil {
 | 
				
			||||||
		panic(fmt.Errorf("error unmarshalling viper.keys into struct: %w", unmarshalErr))
 | 
							logging.ExitWithMSG(fmt.Sprintf("error unmarshalling vault.keys into struct: %v", unmarshalErr), 1, &opts.Logger)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts.vaultClient = client
 | 
						opts.vaultClient = client
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,31 +5,34 @@
 | 
				
			|||||||
package backy
 | 
					package backy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
 | 
				
			||||||
	"github.com/go-co-op/gocron"
 | 
						"github.com/go-co-op/gocron"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (opts *ConfigOpts) Cron() {
 | 
					func (opts *ConfigOpts) Cron() {
 | 
				
			||||||
	s := gocron.NewScheduler(time.Local)
 | 
						s := gocron.NewScheduler(time.Local)
 | 
				
			||||||
	s.TagsUnique()
 | 
						s.TagsUnique()
 | 
				
			||||||
	cmdLists := opts.ConfigFile.CmdConfigLists
 | 
						cmdLists := opts.CmdConfigLists
 | 
				
			||||||
	for listName, config := range cmdLists {
 | 
						for listName, config := range cmdLists {
 | 
				
			||||||
		if config.Name == "" {
 | 
							if config.Name == "" {
 | 
				
			||||||
			config.Name = listName
 | 
								config.Name = listName
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cron := strings.TrimSpace(config.Cron)
 | 
							cron := strings.TrimSpace(config.Cron)
 | 
				
			||||||
		if cron != "" {
 | 
							if cron != "" {
 | 
				
			||||||
			opts.ConfigFile.Logger.Info().Str("Scheduling cron list", config.Name).Str("Time", cron).Send()
 | 
								opts.Logger.Info().Str("Scheduling cron list", config.Name).Str("Time", cron).Send()
 | 
				
			||||||
			_, err := s.CronWithSeconds(cron).Tag(config.Name).Do(func(cron string) {
 | 
								_, err := s.CronWithSeconds(cron).Tag(config.Name).Do(func(cron string) {
 | 
				
			||||||
				opts.ConfigFile.RunListConfig(cron, opts)
 | 
									opts.RunListConfig(cron)
 | 
				
			||||||
			}, cron)
 | 
								}, cron)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				panic(err)
 | 
									logging.ExitWithMSG(fmt.Sprintf("error: %v", err), 1, &opts.Logger)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	opts.ConfigFile.Logger.Info().Msg("Starting cron mode...")
 | 
						opts.Logger.Info().Msg("Starting cron mode...")
 | 
				
			||||||
	s.StartBlocking()
 | 
						s.StartBlocking()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								pkg/backy/list.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								pkg/backy/list.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					package backy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (opts *ConfigOpts) ListConfiguration() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -18,7 +18,7 @@ const mongoConfigKey = "global.mongo"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (opts *ConfigOpts) InitMongo() {
 | 
					func (opts *ConfigOpts) InitMongo() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !opts.viper.GetBool(getMongoConfigKey("enabled")) {
 | 
						if !opts.koanf.Bool(getMongoConfigKey("enabled")) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
@@ -27,37 +27,37 @@ func (opts *ConfigOpts) InitMongo() {
 | 
				
			|||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: Get uri and creditials from config
 | 
						// TODO: Get uri and creditials from config
 | 
				
			||||||
	host := opts.viper.GetString(getMongoConfigKey("host"))
 | 
						host := opts.koanf.String(getMongoConfigKey("host"))
 | 
				
			||||||
	port := opts.viper.GetInt32(getMongoConfigKey("port"))
 | 
						port := opts.koanf.Int64(getMongoConfigKey("port"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx, ctxCancel := context.WithTimeout(context.Background(), 10*time.Second)
 | 
						ctx, ctxCancel := context.WithTimeout(context.Background(), 10*time.Second)
 | 
				
			||||||
	defer ctxCancel()
 | 
						defer ctxCancel()
 | 
				
			||||||
	client, err = mongo.Connect(ctx, options.Client().ApplyURI(fmt.Sprintf("mongo://%s:%d", host, port)))
 | 
						client, err = mongo.Connect(ctx, options.Client().ApplyURI(fmt.Sprintf("mongo://%s:%d", host, port)))
 | 
				
			||||||
	if opts.viper.GetBool(getMongoConfigKey("prod")) {
 | 
						if opts.koanf.Bool(getMongoConfigKey("prod")) {
 | 
				
			||||||
		mongoEnvFileSet := opts.viper.IsSet(getMongoConfigKey("env"))
 | 
							mongoEnvFileSet := opts.koanf.Exists(getMongoConfigKey("env"))
 | 
				
			||||||
		if mongoEnvFileSet {
 | 
							if mongoEnvFileSet {
 | 
				
			||||||
			getMongoConfigFromEnv(opts)
 | 
								getMongoConfigFromEnv(opts)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		auth := options.Credential{}
 | 
							auth := options.Credential{}
 | 
				
			||||||
		auth.Password = opts.viper.GetString("global.mongo.password")
 | 
							auth.Password = opts.koanf.String("global.mongo.password")
 | 
				
			||||||
		auth.Username = opts.viper.GetString("global.mongo.username")
 | 
							auth.Username = opts.koanf.String("global.mongo.username")
 | 
				
			||||||
		client, err = mongo.Connect(ctx, options.Client().SetAuth(auth).ApplyURI("mongodb://localhost:27017"))
 | 
							client, err = mongo.Connect(ctx, options.Client().SetAuth(auth).ApplyURI("mongodb://localhost:27017"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		opts.ConfigFile.Logger.Fatal().Err(err).Send()
 | 
							opts.Logger.Fatal().Err(err).Send()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		opts.ConfigFile.Logger.Fatal().Err(err).Send()
 | 
							opts.Logger.Fatal().Err(err).Send()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer client.Disconnect(ctx)
 | 
						defer client.Disconnect(ctx)
 | 
				
			||||||
	err = client.Ping(ctx, readpref.Primary())
 | 
						err = client.Ping(ctx, readpref.Primary())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		opts.ConfigFile.Logger.Fatal().Err(err).Send()
 | 
							opts.Logger.Fatal().Err(err).Send()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	databases, err := client.ListDatabaseNames(ctx, bson.M{})
 | 
						databases, err := client.ListDatabaseNames(ctx, bson.M{})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		opts.ConfigFile.Logger.Fatal().Err(err).Send()
 | 
							opts.Logger.Fatal().Err(err).Send()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fmt.Println(databases)
 | 
						fmt.Println(databases)
 | 
				
			||||||
	backyDB := client.Database("backy")
 | 
						backyDB := client.Database("backy")
 | 
				
			||||||
@@ -68,7 +68,7 @@ func (opts *ConfigOpts) InitMongo() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getMongoConfigFromEnv(opts *ConfigOpts) error {
 | 
					func getMongoConfigFromEnv(opts *ConfigOpts) error {
 | 
				
			||||||
	mongoEnvFile, err := os.Open(opts.viper.GetString("global.mongo.env"))
 | 
						mongoEnvFile, err := os.Open(opts.koanf.String("global.mongo.env"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -84,8 +84,8 @@ func getMongoConfigFromEnv(opts *ConfigOpts) error {
 | 
				
			|||||||
	if !mongoUserFound {
 | 
						if !mongoUserFound {
 | 
				
			||||||
		return errors.New("MONGO_PASSWORD not set in " + mongoEnvFile.Name())
 | 
							return errors.New("MONGO_PASSWORD not set in " + mongoEnvFile.Name())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	opts.viper.Set(mongoConfigKey+".password", mongoPW)
 | 
						opts.koanf.Set(mongoConfigKey+".password", mongoPW)
 | 
				
			||||||
	opts.viper.Set(mongoConfigKey+".username", mongoUser)
 | 
						opts.koanf.Set(mongoConfigKey+".username", mongoUser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,67 +5,76 @@ package backy
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
 | 
				
			||||||
	"github.com/nikoksr/notify"
 | 
						"github.com/nikoksr/notify"
 | 
				
			||||||
	"github.com/nikoksr/notify/service/mail"
 | 
						"github.com/nikoksr/notify/service/mail"
 | 
				
			||||||
	"github.com/nikoksr/notify/service/matrix"
 | 
						"github.com/nikoksr/notify/service/matrix"
 | 
				
			||||||
	"maunium.net/go/mautrix/id"
 | 
						"maunium.net/go/mautrix/id"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type matrixStruct struct {
 | 
					type MatrixStruct struct {
 | 
				
			||||||
	homeserver  string
 | 
						Homeserver  string    `yaml:"homeserver"`
 | 
				
			||||||
	roomid      id.RoomID
 | 
						Roomid      id.RoomID `yaml:"room-id"`
 | 
				
			||||||
	accessToken string
 | 
						AccessToken string    `yaml:"access-token"`
 | 
				
			||||||
	userId      id.UserID
 | 
						UserId      id.UserID `yaml:"user-id"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type mailConfig struct {
 | 
					type MailConfig struct {
 | 
				
			||||||
	senderaddress string
 | 
						Host          string   `yaml:"host"`
 | 
				
			||||||
	host          string
 | 
						Port          string   `yaml:"port"`
 | 
				
			||||||
	to            []string
 | 
						Username      string   `yaml:"username"`
 | 
				
			||||||
	username      string
 | 
						SenderAddress string   `yaml:"senderaddress"`
 | 
				
			||||||
	password      string
 | 
						To            []string `yaml:"to"`
 | 
				
			||||||
	port          string
 | 
						Password      string   `yaml:"password"`
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func SetupCommandsNotifiers(backyConfig ConfigFile, ids ...string) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetupNotify sets up notify instances for each command list.
 | 
					// SetupNotify sets up notify instances for each command list.
 | 
				
			||||||
 | 
					func (opts *ConfigOpts) SetupNotify() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (backyConfig *ConfigFile) SetupNotify() {
 | 
						// check if we have individual commands instead of lists to execute
 | 
				
			||||||
 | 
						if len(opts.executeCmds) != 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, cmdConfig := range backyConfig.CmdConfigLists {
 | 
						for confName, cmdConfig := range opts.CmdConfigLists {
 | 
				
			||||||
		var services []notify.Notifier
 | 
							var services []notify.Notifier
 | 
				
			||||||
		for notifyID := range backyConfig.Notifications {
 | 
							for _, id := range cmdConfig.Notifications {
 | 
				
			||||||
			if contains(cmdConfig.Notifications, notifyID) {
 | 
								if !strings.Contains(id, ".") {
 | 
				
			||||||
 | 
									opts.Logger.Info().Str("id", id).Str("list", cmdConfig.Name).Msg("key does not contain a \".\"  Make sure to follow the docs: https://backy.cybershell.xyz/config/notifications/")
 | 
				
			||||||
 | 
									logging.ExitWithMSG(fmt.Sprintf("notification id %s in cmd list %s does not contain a \".\" \nMake sure to follow the docs: https://backy.cybershell.xyz/config/notifications/", id, cmdConfig.Name), 1, &opts.Logger)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if backyConfig.Notifications[notifyID].Enabled {
 | 
								confSplit := strings.Split(id, ".")
 | 
				
			||||||
					config := backyConfig.Notifications[notifyID].Config
 | 
								confType := confSplit[0]
 | 
				
			||||||
					switch config.GetString("type") {
 | 
								confId := confSplit[1]
 | 
				
			||||||
					case "matrix":
 | 
								switch confType {
 | 
				
			||||||
						mtrx := matrixStruct{
 | 
					
 | 
				
			||||||
							userId:      id.UserID(config.GetString("user-id")),
 | 
								case "mail":
 | 
				
			||||||
							roomid:      id.RoomID(config.GetString("room-id")),
 | 
									conf, ok := opts.NotificationConf.MailConfig[confId]
 | 
				
			||||||
							accessToken: config.GetString("access-token"),
 | 
									if !ok {
 | 
				
			||||||
							homeserver:  config.GetString("homeserver"),
 | 
										opts.Logger.Info().Err(fmt.Errorf("error: ID %s not found in mail object", confId)).Str("list", confName).Send()
 | 
				
			||||||
						}
 | 
										continue
 | 
				
			||||||
						mtrxClient, _ := setupMatrix(mtrx)
 | 
					 | 
				
			||||||
						services = append(services, mtrxClient)
 | 
					 | 
				
			||||||
					case "mail":
 | 
					 | 
				
			||||||
						mailCfg := mailConfig{
 | 
					 | 
				
			||||||
							senderaddress: config.GetString("senderaddress"),
 | 
					 | 
				
			||||||
							password:      config.GetString("password"),
 | 
					 | 
				
			||||||
							username:      config.GetString("username"),
 | 
					 | 
				
			||||||
							to:            config.GetStringSlice("to"),
 | 
					 | 
				
			||||||
							host:          config.GetString("host"),
 | 
					 | 
				
			||||||
							port:          fmt.Sprint(config.GetUint16("port")),
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
						mailClient := setupMail(mailCfg)
 | 
					 | 
				
			||||||
						services = append(services, mailClient)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									mailConf := setupMail(conf)
 | 
				
			||||||
 | 
									services = append(services, mailConf)
 | 
				
			||||||
 | 
								case "matrix":
 | 
				
			||||||
 | 
									conf, ok := opts.NotificationConf.MatrixConfig[confId]
 | 
				
			||||||
 | 
									if !ok {
 | 
				
			||||||
 | 
										opts.Logger.Info().Err(fmt.Errorf("error: ID %s not found in matrix object", confId)).Str("list", confName).Send()
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									mtrxConf, mtrxErr := setupMatrix(conf)
 | 
				
			||||||
 | 
									if mtrxErr != nil {
 | 
				
			||||||
 | 
										opts.Logger.Info().Str("list", confName).Err(fmt.Errorf("error: configuring matrix id %s failed during setup: %w", id, mtrxErr))
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									// append the services
 | 
				
			||||||
 | 
									services = append(services, mtrxConf)
 | 
				
			||||||
 | 
								// service is not recognized
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									opts.Logger.Info().Err(fmt.Errorf("id %s not found", id)).Str("list", confName).Send()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		cmdConfig.NotifyConfig = notify.NewWithServices(services...)
 | 
							cmdConfig.NotifyConfig = notify.NewWithServices(services...)
 | 
				
			||||||
@@ -74,19 +83,18 @@ func (backyConfig *ConfigFile) SetupNotify() {
 | 
				
			|||||||
	// logging.ExitWithMSG("This was a test of notifications", 0, nil)
 | 
						// logging.ExitWithMSG("This was a test of notifications", 0, nil)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func setupMatrix(config matrixStruct) (*matrix.Matrix, error) {
 | 
					func setupMatrix(config MatrixStruct) (*matrix.Matrix, error) {
 | 
				
			||||||
	matrixClient, matrixErr := matrix.New(config.userId, config.roomid, config.homeserver, config.accessToken)
 | 
						matrixClient, matrixErr := matrix.New(config.UserId, config.Roomid, config.Homeserver, config.AccessToken)
 | 
				
			||||||
	if matrixErr != nil {
 | 
						if matrixErr != nil {
 | 
				
			||||||
		panic(matrixErr)
 | 
							return nil, matrixErr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return matrixClient, nil
 | 
						return matrixClient, nil
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func setupMail(config mailConfig) *mail.Mail {
 | 
					func setupMail(config MailConfig) *mail.Mail {
 | 
				
			||||||
	mailClient := mail.New(config.senderaddress, config.host+":"+config.port)
 | 
						mailClient := mail.New(config.SenderAddress, config.Host+":"+config.Port)
 | 
				
			||||||
	mailClient.AuthenticateSMTP("", config.username, config.password, config.host)
 | 
						mailClient.AuthenticateSMTP("", config.Username, config.Password, config.Host)
 | 
				
			||||||
	mailClient.AddReceivers(config.to...)
 | 
						mailClient.AddReceivers(config.To...)
 | 
				
			||||||
	mailClient.BodyFormat(mail.PlainText)
 | 
						mailClient.BodyFormat(mail.PlainText)
 | 
				
			||||||
	return mailClient
 | 
						return mailClient
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@ var TS = strings.TrimSpace
 | 
				
			|||||||
// It returns an ssh.Client used to run commands against.
 | 
					// It returns an ssh.Client used to run commands against.
 | 
				
			||||||
// If configFile is empty, any required configuration is looked up in the default config files
 | 
					// If configFile is empty, any required configuration is looked up in the default config files
 | 
				
			||||||
// If any value is not found, defaults are used
 | 
					// If any value is not found, defaults are used
 | 
				
			||||||
func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts, config *ConfigFile) error {
 | 
					func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// var sshClient *ssh.Client
 | 
						// var sshClient *ssh.Client
 | 
				
			||||||
	var connectErr error
 | 
						var connectErr error
 | 
				
			||||||
@@ -47,6 +47,11 @@ func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts, config *ConfigFile)
 | 
				
			|||||||
	var configFile *os.File
 | 
						var configFile *os.File
 | 
				
			||||||
	var sshConfigFileOpenErr error
 | 
						var sshConfigFileOpenErr error
 | 
				
			||||||
	if !remoteConfig.useDefaultConfig {
 | 
						if !remoteConfig.useDefaultConfig {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
							remoteConfig.ConfigFilePath, err = resolveDir(remoteConfig.ConfigFilePath)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		configFile, sshConfigFileOpenErr = os.Open(remoteConfig.ConfigFilePath)
 | 
							configFile, sshConfigFileOpenErr = os.Open(remoteConfig.ConfigFilePath)
 | 
				
			||||||
		if sshConfigFileOpenErr != nil {
 | 
							if sshConfigFileOpenErr != nil {
 | 
				
			||||||
			return sshConfigFileOpenErr
 | 
								return sshConfigFileOpenErr
 | 
				
			||||||
@@ -66,14 +71,14 @@ func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts, config *ConfigFile)
 | 
				
			|||||||
		return decodeErr
 | 
							return decodeErr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := remoteConfig.GetProxyJumpFromConfig(config.Hosts)
 | 
						err := remoteConfig.GetProxyJumpFromConfig(opts.Hosts)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if remoteConfig.ProxyHost != nil {
 | 
						if remoteConfig.ProxyHost != nil {
 | 
				
			||||||
		for _, proxyHost := range remoteConfig.ProxyHost {
 | 
							for _, proxyHost := range remoteConfig.ProxyHost {
 | 
				
			||||||
			err := proxyHost.GetProxyJumpConfig(config.Hosts, opts)
 | 
								err := proxyHost.GetProxyJumpConfig(opts.Hosts, opts)
 | 
				
			||||||
			opts.ConfigFile.Logger.Info().Msgf("Proxy host: %s", proxyHost.Host)
 | 
								opts.Logger.Info().Msgf("Proxy host: %s", proxyHost.Host)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -101,24 +106,24 @@ func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts, config *ConfigFile)
 | 
				
			|||||||
		return errors.Wrap(err, "could not create hostkeycallback function")
 | 
							return errors.Wrap(err, "could not create hostkeycallback function")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	remoteConfig.ClientConfig.HostKeyCallback = hostKeyCallback
 | 
						remoteConfig.ClientConfig.HostKeyCallback = hostKeyCallback
 | 
				
			||||||
	opts.ConfigFile.Logger.Info().Str("user", remoteConfig.ClientConfig.User).Send()
 | 
						opts.Logger.Info().Str("user", remoteConfig.ClientConfig.User).Send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	remoteConfig.SshClient, connectErr = remoteConfig.ConnectThroughBastion(opts.ConfigFile.Logger)
 | 
						remoteConfig.SshClient, connectErr = remoteConfig.ConnectThroughBastion(opts.Logger)
 | 
				
			||||||
	if connectErr != nil {
 | 
						if connectErr != nil {
 | 
				
			||||||
		return connectErr
 | 
							return connectErr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if remoteConfig.SshClient != nil {
 | 
						if remoteConfig.SshClient != nil {
 | 
				
			||||||
		config.Hosts[remoteConfig.Host] = remoteConfig
 | 
							opts.Hosts[remoteConfig.Host] = remoteConfig
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts.ConfigFile.Logger.Info().Msgf("Connecting to host %s", remoteConfig.HostName)
 | 
						opts.Logger.Info().Msgf("Connecting to host %s", remoteConfig.HostName)
 | 
				
			||||||
	remoteConfig.SshClient, connectErr = ssh.Dial("tcp", remoteConfig.HostName, remoteConfig.ClientConfig)
 | 
						remoteConfig.SshClient, connectErr = ssh.Dial("tcp", remoteConfig.HostName, remoteConfig.ClientConfig)
 | 
				
			||||||
	if connectErr != nil {
 | 
						if connectErr != nil {
 | 
				
			||||||
		return connectErr
 | 
							return connectErr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config.Hosts[remoteConfig.Host] = remoteConfig
 | 
						opts.Hosts[remoteConfig.Host] = remoteConfig
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -148,7 +153,7 @@ func (remoteHost *Host) GetAuthMethods(opts *ConfigOpts) error {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		remoteHost.PrivateKeyPassword, err = GetPrivateKeyPassword(remoteHost.PrivateKeyPassword, opts, opts.ConfigFile.Logger)
 | 
							remoteHost.PrivateKeyPassword, err = GetPrivateKeyPassword(remoteHost.PrivateKeyPassword, opts, opts.Logger)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -167,7 +172,7 @@ func (remoteHost *Host) GetAuthMethods(opts *ConfigOpts) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if remoteHost.Password == "" {
 | 
						if remoteHost.Password == "" {
 | 
				
			||||||
		remoteHost.Password, err = GetPassword(remoteHost.Password, opts, opts.ConfigFile.Logger)
 | 
							remoteHost.Password, err = GetPassword(remoteHost.Password, opts, opts.Logger)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -297,7 +302,7 @@ func GetPrivateKeyPassword(key string, opts *ConfigOpts, log zerolog.Logger) (st
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		prKeyPassword = key
 | 
							prKeyPassword = key
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	prKeyPassword = GetVaultKey(prKeyPassword, opts, opts.ConfigFile.Logger)
 | 
						prKeyPassword = GetVaultKey(prKeyPassword, opts, opts.Logger)
 | 
				
			||||||
	return prKeyPassword, nil
 | 
						return prKeyPassword, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -328,7 +333,7 @@ func GetPassword(pass string, opts *ConfigOpts, log zerolog.Logger) (string, err
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		password = pass
 | 
							password = pass
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	password = GetVaultKey(password, opts, opts.ConfigFile.Logger)
 | 
						password = GetVaultKey(password, opts, opts.Logger)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return password, nil
 | 
						return password, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,9 +6,9 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	vaultapi "github.com/hashicorp/vault/api"
 | 
						vaultapi "github.com/hashicorp/vault/api"
 | 
				
			||||||
	"github.com/kevinburke/ssh_config"
 | 
						"github.com/kevinburke/ssh_config"
 | 
				
			||||||
 | 
						"github.com/knadh/koanf/v2"
 | 
				
			||||||
	"github.com/nikoksr/notify"
 | 
						"github.com/nikoksr/notify"
 | 
				
			||||||
	"github.com/rs/zerolog"
 | 
						"github.com/rs/zerolog"
 | 
				
			||||||
	"github.com/spf13/viper"
 | 
					 | 
				
			||||||
	"go.mongodb.org/mongo-driver/bson/primitive"
 | 
						"go.mongodb.org/mongo-driver/bson/primitive"
 | 
				
			||||||
	"go.mongodb.org/mongo-driver/mongo"
 | 
						"go.mongodb.org/mongo-driver/mongo"
 | 
				
			||||||
	"golang.org/x/crypto/ssh"
 | 
						"golang.org/x/crypto/ssh"
 | 
				
			||||||
@@ -37,7 +37,7 @@ type (
 | 
				
			|||||||
	// Host defines a host to which to connect.
 | 
						// Host defines a host to which to connect.
 | 
				
			||||||
	// If not provided, the values will be looked up in the default ssh config files
 | 
						// If not provided, the values will be looked up in the default ssh config files
 | 
				
			||||||
	Host struct {
 | 
						Host struct {
 | 
				
			||||||
		ConfigFilePath     string `yaml:"configfilepath,omitempty"`
 | 
							ConfigFilePath     string `yaml:"config,omitempty"`
 | 
				
			||||||
		Host               string `yaml:"host,omitempty"`
 | 
							Host               string `yaml:"host,omitempty"`
 | 
				
			||||||
		HostName           string `yaml:"hostname,omitempty"`
 | 
							HostName           string `yaml:"hostname,omitempty"`
 | 
				
			||||||
		KnownHostsFile     string `yaml:"knownhostsfile,omitempty"`
 | 
							KnownHostsFile     string `yaml:"knownhostsfile,omitempty"`
 | 
				
			||||||
@@ -113,35 +113,26 @@ type (
 | 
				
			|||||||
		Notifications []string `yaml:"notifications,omitempty"`
 | 
							Notifications []string `yaml:"notifications,omitempty"`
 | 
				
			||||||
		GetOutput     bool     `yaml:"getOutput,omitempty"`
 | 
							GetOutput     bool     `yaml:"getOutput,omitempty"`
 | 
				
			||||||
		NotifyConfig  *notify.Notify
 | 
							NotifyConfig  *notify.Notify
 | 
				
			||||||
		// NotificationsConfig map[string]*NotificationsConfig
 | 
					 | 
				
			||||||
		// NotifyConfig        map[string]*notify.Notify
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ConfigFile struct {
 | 
						ConfigOpts struct {
 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Cmds holds the commands for a list.
 | 
							// Cmds holds the commands for a list.
 | 
				
			||||||
		// Key is the name of the command,
 | 
							// Key is the name of the command,
 | 
				
			||||||
		Cmds map[string]*Command `yaml:"commands"`
 | 
							Cmds map[string]*Command `yaml:"commands"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// CmdConfigLists holds the lists of commands to be run in order.
 | 
							// CmdConfigLists holds the lists of commands to be run in order.
 | 
				
			||||||
		// Key is the command list name.
 | 
							// Key is the command list name.
 | 
				
			||||||
		CmdConfigLists map[string]*CmdList `yaml:"cmd-configs"`
 | 
							CmdConfigLists map[string]*CmdList `yaml:"cmd-lists"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Hosts holds the Host config.
 | 
							// Hosts holds the Host config.
 | 
				
			||||||
		// key is the host.
 | 
							// key is the host.
 | 
				
			||||||
		Hosts map[string]*Host `yaml:"hosts"`
 | 
							Hosts map[string]*Host `yaml:"hosts"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Notifications holds the config for different notifications.
 | 
					 | 
				
			||||||
		Notifications map[string]*NotificationsConfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Logger zerolog.Logger
 | 
							Logger zerolog.Logger
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ConfigOpts struct {
 | 
					 | 
				
			||||||
		// Global log level
 | 
							// Global log level
 | 
				
			||||||
		BackyLogLvl *string
 | 
							BackyLogLvl *string
 | 
				
			||||||
		// Holds config file
 | 
					
 | 
				
			||||||
		ConfigFile *ConfigFile
 | 
					 | 
				
			||||||
		// Holds config file
 | 
							// Holds config file
 | 
				
			||||||
		ConfigFilePath string
 | 
							ConfigFilePath string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,9 +151,13 @@ type (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		vaultClient *vaultapi.Client
 | 
							vaultClient *vaultapi.Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							List ListConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		VaultKeys []*VaultKey `yaml:"keys"`
 | 
							VaultKeys []*VaultKey `yaml:"keys"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		viper *viper.Viper
 | 
							koanf *koanf.Koanf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NotificationConf *Notifications `yaml:"notifications"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	outStruct struct {
 | 
						outStruct struct {
 | 
				
			||||||
@@ -185,9 +180,9 @@ type (
 | 
				
			|||||||
		Keys    []*VaultKey `yaml:"keys"`
 | 
							Keys    []*VaultKey `yaml:"keys"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	NotificationsConfig struct {
 | 
						Notifications struct {
 | 
				
			||||||
		Config  *viper.Viper
 | 
							MailConfig   map[string]MailConfig   `yaml:"mail,omitempty"`
 | 
				
			||||||
		Enabled bool
 | 
							MatrixConfig map[string]MatrixStruct `yaml:"matrix,omitempty"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CmdOutput struct {
 | 
						CmdOutput struct {
 | 
				
			||||||
@@ -204,4 +199,10 @@ type (
 | 
				
			|||||||
		success *template.Template
 | 
							success *template.Template
 | 
				
			||||||
		err     *template.Template
 | 
							err     *template.Template
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ListConfig struct {
 | 
				
			||||||
 | 
							Lists    []string
 | 
				
			||||||
 | 
							Commands []string
 | 
				
			||||||
 | 
							Hosts    []string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,12 +15,65 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
 | 
						"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
 | 
				
			||||||
	"github.com/joho/godotenv"
 | 
						"github.com/joho/godotenv"
 | 
				
			||||||
 | 
						"github.com/knadh/koanf/v2"
 | 
				
			||||||
	"github.com/rs/zerolog"
 | 
						"github.com/rs/zerolog"
 | 
				
			||||||
	"github.com/spf13/viper"
 | 
					 | 
				
			||||||
	"golang.org/x/crypto/ssh"
 | 
						"golang.org/x/crypto/ssh"
 | 
				
			||||||
	"mvdan.cc/sh/v3/shell"
 | 
						"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) {
 | 
					func injectEnvIntoSSH(envVarsToInject environmentVars, process *ssh.Session, opts *ConfigOpts, log zerolog.Logger) {
 | 
				
			||||||
	if envVarsToInject.file != "" {
 | 
						if envVarsToInject.file != "" {
 | 
				
			||||||
		envPath, envPathErr := resolveDir(envVarsToInject.file)
 | 
							envPath, envPathErr := resolveDir(envVarsToInject.file)
 | 
				
			||||||
@@ -94,12 +147,12 @@ func contains(s []string, e string) bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func CheckConfigValues(config *viper.Viper) {
 | 
					func CheckConfigValues(config *koanf.Koanf, file string) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, key := range requiredKeys {
 | 
						for _, key := range requiredKeys {
 | 
				
			||||||
		isKeySet := config.IsSet(key)
 | 
							isKeySet := config.Exists(key)
 | 
				
			||||||
		if !isKeySet {
 | 
							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, config.ConfigFileUsed()), 1, nil)
 | 
								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)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -116,64 +169,6 @@ func testFile(c string) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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...)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// UseCron enables the execution of command lists at specified times
 | 
					 | 
				
			||||||
func UseCron() BackyOptionFunc {
 | 
					 | 
				
			||||||
	return func(bco *ConfigOpts) {
 | 
					 | 
				
			||||||
		bco.useCron = true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// UseCron enables the execution of command lists at specified times
 | 
					 | 
				
			||||||
func (c *ConfigOpts) AddViper(v *viper.Viper) BackyOptionFunc {
 | 
					 | 
				
			||||||
	return func(bco *ConfigOpts) {
 | 
					 | 
				
			||||||
		c.viper = v
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewOpts(configFilePath string, opts ...BackyOptionFunc) *ConfigOpts {
 | 
					 | 
				
			||||||
	b := &ConfigOpts{}
 | 
					 | 
				
			||||||
	b.ConfigFilePath = configFilePath
 | 
					 | 
				
			||||||
	for _, opt := range opts {
 | 
					 | 
				
			||||||
		if opt != nil {
 | 
					 | 
				
			||||||
			opt(b)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return b
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
NewConfig initializes new config that holds information	from the config file
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
func NewConfig() *ConfigFile {
 | 
					 | 
				
			||||||
	return &ConfigFile{
 | 
					 | 
				
			||||||
		Cmds:           make(map[string]*Command),
 | 
					 | 
				
			||||||
		CmdConfigLists: make(map[string]*CmdList),
 | 
					 | 
				
			||||||
		Hosts:          make(map[string]*Host),
 | 
					 | 
				
			||||||
		Notifications:  make(map[string]*NotificationsConfig),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func IsTerminalActive() bool {
 | 
					func IsTerminalActive() bool {
 | 
				
			||||||
	return os.Getenv("BACKY_TERM") == "enabled"
 | 
						return os.Getenv("BACKY_TERM") == "enabled"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -203,7 +198,7 @@ func resolveDir(path string) (string, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (opts *ConfigOpts) loadEnv() {
 | 
					func (opts *ConfigOpts) loadEnv() {
 | 
				
			||||||
	envFileInConfigDir := fmt.Sprintf("%s/.env", path.Dir(opts.viper.ConfigFileUsed()))
 | 
						envFileInConfigDir := fmt.Sprintf("%s/.env", path.Dir(opts.ConfigFilePath))
 | 
				
			||||||
	var backyEnv map[string]string
 | 
						var backyEnv map[string]string
 | 
				
			||||||
	backyEnv, envFileErr := godotenv.Read(envFileInConfigDir)
 | 
						backyEnv, envFileErr := godotenv.Read(envFileInConfigDir)
 | 
				
			||||||
	if envFileErr != nil {
 | 
						if envFileErr != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user