commands_admin

package
v0.22.3 Latest Latest
Warning

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

Go to latest
Published: Jan 8, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AdminCmd = &cli.Command{
	Name:        "admin",
	Usage:       "Admin Operations",
	Description: "Run administration operations for the server.",
	MaxArgs:     cli.NoArgs,
	Flags: []cli.Flag{

		&cli.BoolFlag{
			Name:         "mysql-enabled",
			Usage:        "Enable MySQL database backend.",
			ConfigPath:   []string{"server.mysql.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_ENABLED"},
			DefaultValue: false,
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "mysql-host",
			Usage:        "The MySQL host to connect to.",
			ConfigPath:   []string{"server.mysql.host"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_HOST"},
			DefaultValue: "localhost",
			Global:       true,
		},
		&cli.IntFlag{
			Name:         "mysql-port",
			Usage:        "The MySQL port to connect to.",
			ConfigPath:   []string{"server.mysql.port"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_PORT"},
			DefaultValue: 3306,
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "mysql-user",
			Usage:        "The MySQL user to connect as.",
			ConfigPath:   []string{"server.mysql.user"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_USER"},
			DefaultValue: "root",
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "mysql-password",
			Usage:        "The MySQL password to use.",
			ConfigPath:   []string{"server.mysql.password"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_PASSWORD"},
			DefaultValue: "",
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "mysql-database",
			Usage:        "The MySQL database to use.",
			ConfigPath:   []string{"server.mysql.database"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_DATABASE"},
			DefaultValue: "knot",
			Global:       true,
		},
		&cli.IntFlag{
			Name:         "mysql-connection-max-idle",
			Usage:        "The maximum number of idle connections in the connection pool.",
			ConfigPath:   []string{"server.mysql.connection_max_idle"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_CONNECTION_MAX_IDLE"},
			DefaultValue: 10,
			Global:       true,
		},
		&cli.IntFlag{
			Name:         "mysql-connection-max-open",
			Usage:        "The maximum number of open connections to the database.",
			ConfigPath:   []string{"server.mysql.connection_max_open"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_CONNECTION_MAX_OPEN"},
			DefaultValue: 100,
			Global:       true,
		},
		&cli.IntFlag{
			Name:         "mysql-connection-max-lifetime",
			Usage:        "The maximum amount of time in minutes a connection may be reused.",
			ConfigPath:   []string{"server.mysql.connection_max_lifetime"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_CONNECTION_MAX_LIFETIME"},
			DefaultValue: 5,
			Global:       true,
		},

		&cli.BoolFlag{
			Name:         "badgerdb-enabled",
			Usage:        "Enable BadgerDB database backend.",
			ConfigPath:   []string{"server.badgerdb.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_BADGERDB_ENABLED"},
			DefaultValue: false,
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "badgerdb-path",
			Usage:        "The path to the BadgerDB database.",
			ConfigPath:   []string{"server.badgerdb.path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_BADGERDB_PATH"},
			DefaultValue: "./badger",
			Global:       true,
		},

		&cli.BoolFlag{
			Name:         "redis-enabled",
			Usage:        "Enable Redis database backend.",
			ConfigPath:   []string{"server.redis.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_ENABLED"},
			DefaultValue: false,
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "redis-host",
			Usage:        "The redis server.",
			ConfigPath:   []string{"server.redis.host"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_HOST"},
			DefaultValue: "localhost:6379",
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "redis-password",
			Usage:        "The password to use for the redis server.",
			ConfigPath:   []string{"server.redis.password"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_PASSWORD"},
			DefaultValue: "",
			Global:       true,
		},
		&cli.IntFlag{
			Name:         "redis-db",
			Usage:        "The redis database to use.",
			ConfigPath:   []string{"server.redis.db"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_DB"},
			DefaultValue: 0,
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "redis-master-name",
			Usage:        "The name of the master to use for failover clients.",
			ConfigPath:   []string{"server.redis.master_name"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_MASTER_NAME"},
			DefaultValue: "",
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "redis-key-prefix",
			Usage:        "The prefix to use for all keys in the redis database.",
			ConfigPath:   []string{"server.redis.key_prefix"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_KEY_PREFIX"},
			DefaultValue: "",
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "encrypt",
			Usage:        "The encryption key to use for encrypting stored variables.",
			ConfigPath:   []string{"server.encrypt"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_ENCRYPT"},
			DefaultValue: "",
			Global:       true,
		},
	},
	Commands: []*cli.Command{
		RenameZoneCmd,
		SetPasswordCmd,
		ResetTOTPCmd,
		BackupCmd,
		RestoreCmd,
	},
	PreRun: func(ctx context.Context, cmd *cli.Command) (context.Context, error) {
		var err error

		if ctx, err = cmd.GetRootCmd().PreRun(ctx, cmd); err != nil {
			return ctx, err
		}

		serverCfg := &config.ServerConfig{
			EncryptionKey: cmd.GetString("encrypt"),
			MySQL: config.MySQLConfig{
				Enabled:               cmd.GetBool("mysql-enabled"),
				Host:                  cmd.GetString("mysql-host"),
				Port:                  cmd.GetInt("mysql-port"),
				User:                  cmd.GetString("mysql-user"),
				Password:              cmd.GetString("mysql-password"),
				Database:              cmd.GetString("mysql-database"),
				ConnectionMaxIdle:     cmd.GetInt("mysql-connection-max-idle"),
				ConnectionMaxOpen:     cmd.GetInt("mysql-connection-max-open"),
				ConnectionMaxLifetime: cmd.GetInt("mysql-connection-max-lifetime"),
			},
			BadgerDB: config.BadgerDBConfig{
				Enabled: cmd.GetBool("badgerdb-enabled"),
				Path:    cmd.GetString("badgerdb-path"),
			},
			Redis: config.RedisConfig{
				Enabled:    cmd.GetBool("redis-enabled"),
				Hosts:      cmd.GetStringSlice("redis-hosts"),
				Password:   cmd.GetString("redis-password"),
				DB:         cmd.GetInt("redis-db"),
				MasterName: cmd.GetString("redis-master-name"),
				KeyPrefix:  cmd.GetString("redis-key-prefix"),
			},
			Audit: config.AuditConfig{
				Retention: cmd.GetInt("audit-retention"),
			},
		}
		config.SetServerConfig(serverCfg)

		return ctx, nil
	},
}
View Source
var BackupCmd = &cli.Command{
	Name:        "backup",
	Usage:       "Backup to File",
	Description: "Backup the database to a backup file.",
	Arguments: []cli.Argument{
		&cli.StringArg{
			Name:     "backupfile",
			Usage:    "The name of the backup file",
			Required: true,
		},
	},
	MaxArgs: cli.NoArgs,
	Flags: []cli.Flag{
		&cli.BoolFlag{
			Name:       "templates",
			Aliases:    []string{"t"},
			Usage:      "Backup templates",
			ConfigPath: []string{"backup.templates"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_TEMPLATES"},
		},
		&cli.BoolFlag{
			Name:       "template-vars",
			Aliases:    []string{"v"},
			Usage:      "Backup template variables",
			ConfigPath: []string{"backup.template_vars"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_TEMPLATE_VARS"},
		},
		&cli.BoolFlag{
			Name:       "volumes",
			Aliases:    []string{"l"},
			Usage:      "Backup volumes",
			ConfigPath: []string{"backup.volumes"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_VOLUMES"},
		},
		&cli.BoolFlag{
			Name:       "groups",
			Aliases:    []string{"g"},
			Usage:      "Backup groups",
			ConfigPath: []string{"backup.groups"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_GROUPS"},
		},
		&cli.BoolFlag{
			Name:       "roles",
			Aliases:    []string{"r"},
			Usage:      "Backup roles",
			ConfigPath: []string{"backup.roles"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_ROLES"},
		},
		&cli.BoolFlag{
			Name:       "spaces",
			Aliases:    []string{"s"},
			Usage:      "Backup user spaces",
			ConfigPath: []string{"backup.spaces"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_SPACES"},
		},
		&cli.BoolFlag{
			Name:       "users",
			Aliases:    []string{"u"},
			Usage:      "Backup users",
			ConfigPath: []string{"backup.users"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_USERS"},
		},
		&cli.BoolFlag{
			Name:       "tokens",
			Aliases:    []string{"k"},
			Usage:      "Backup user tokens",
			ConfigPath: []string{"backup.tokens"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_TOKENS"},
		},
		&cli.BoolFlag{
			Name:       "cfg-values",
			Aliases:    []string{"o"},
			Usage:      "Backup configuration values",
			ConfigPath: []string{"backup.cfg_values"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_CFG_VALUES"},
		},
		&cli.BoolFlag{
			Name:       "audit-logs",
			Usage:      "Backup audit logs",
			ConfigPath: []string{"backup.audit_logs"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_AUDIT_LOGS"},
		},
		&cli.BoolFlag{
			Name:         "all",
			Aliases:      []string{"a"},
			Usage:        "Backup everything",
			ConfigPath:   []string{"backup.all"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_BACKUP_ALL"},
			DefaultValue: true,
		},
		&cli.StringFlag{
			Name:       "limit-user",
			Usage:      "Limit the backup to a specific user by username.",
			ConfigPath: []string{"backup.limit_user"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_LIMIT_USER"},
		},
		&cli.StringFlag{
			Name:       "limit-template",
			Usage:      "Limit the backup to a specific template by name.",
			ConfigPath: []string{"backup.limit_template"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_LIMIT_TEMPLATE"},
		},
		&cli.StringFlag{
			Name:       "encrypt-key",
			Aliases:    []string{"e"},
			Usage:      "Encrypt the backup file with the given key. The key must be 32 bytes long.",
			ConfigPath: []string{"backup.encrypt_key"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BACKUP_ENCRYPT_KEY"},
		},
	},
	Run: func(ctx context.Context, cmd *cli.Command) error {
		outputFile := cmd.GetStringArg("backupfile")
		fmt.Println("Backing up database to file: ", outputFile)

		backupTemplates := cmd.GetBool("templates")
		backupVars := cmd.GetBool("template-vars")
		backupVolumes := cmd.GetBool("volumes")
		backupGroups := cmd.GetBool("groups")
		backupRoles := cmd.GetBool("roles")
		backupUsers := cmd.GetBool("users")
		backupSpaces := cmd.GetBool("spaces")
		backupTokens := cmd.GetBool("tokens")
		backupCfgValues := cmd.GetBool("cfg-values")
		backupAuditLogs := cmd.GetBool("audit-logs")
		backupAll := cmd.GetBool("all")

		if backupTemplates || backupVars || backupVolumes || backupGroups || backupRoles || backupUsers || backupSpaces || backupTokens || backupCfgValues || backupAuditLogs {
			backupAll = false
		}

		if backupAll {
			backupTemplates = true
			backupVars = true
			backupVolumes = true
			backupGroups = true
			backupRoles = true
			backupUsers = true
			backupSpaces = true
			backupTokens = true
			backupCfgValues = true
			backupAuditLogs = true
		}

		limitUser := cmd.GetString("limit-user")
		limitTemplate := cmd.GetString("limit-template")

		key := cmd.GetString("encrypt-key")
		if key != "" && len(key) != 32 {
			return fmt.Errorf("Error: Encrypt key must be 32 bytes long.")
		}

		db := database.GetInstance()
		backupData := backupData{}

		if backupAuditLogs {
			fmt.Println("Backing up audit logs...")
			auditLogs, err := db.GetAuditLogs(0, 0)
			if err != nil {
				return fmt.Errorf("Error getting audit logs: %w", err)
			}
			backupData.AuditLogs = make([]*model.AuditLogEntry, len(auditLogs))
			copy(backupData.AuditLogs, auditLogs)
		}

		if backupCfgValues {
			fmt.Println("Backing up configuration values...")
			cfgValues, err := db.GetCfgValues()
			if err != nil {
				return fmt.Errorf("Error getting configuration values: %w", err)
			}
			backupData.CfgValues = make([]*model.CfgValue, len(cfgValues))
			copy(backupData.CfgValues, cfgValues)
		}

		if backupTemplates {
			fmt.Println("Backing up templates...")
			templates, err := db.GetTemplates()
			if err != nil {
				return fmt.Errorf("Error getting templates: %w", err)
			}
			backupData.Templates = make([]*model.Template, 0, len(templates))
			for _, t := range templates {
				if limitTemplate == "" || t.Name == limitTemplate {
					backupData.Templates = append(backupData.Templates, t)
				}
			}
			backupData.Templates = slices.Clip(backupData.Templates)
		}

		if backupVars {
			fmt.Println("Backing up template variables...")
			variables, err := db.GetTemplateVars()
			if err != nil {
				return fmt.Errorf("Error getting template variables: %w", err)
			}
			backupData.TemplateVars = make([]*model.TemplateVar, len(variables))
			for i, v := range variables {
				backupData.TemplateVars[i] = v
			}
		}

		if backupVolumes {
			fmt.Println("Backing up volumes...")
			volumes, err := db.GetVolumes()
			if err != nil {
				return fmt.Errorf("Error getting volumes: %w", err)
			}
			backupData.Volumes = make([]*model.Volume, len(volumes))
			copy(backupData.Volumes, volumes)
		}

		if backupGroups {
			fmt.Println("Backing up groups...")
			groups, err := db.GetGroups()
			if err != nil {
				return fmt.Errorf("Error getting groups: %w", err)
			}
			backupData.Groups = make([]*model.Group, len(groups))
			copy(backupData.Groups, groups)
		}

		if backupRoles {
			fmt.Println("Backing up roles...")
			roles, err := db.GetRoles()
			if err != nil {
				return fmt.Errorf("Error getting roles: %w", err)
			}
			backupData.Roles = make([]*model.Role, len(roles))
			copy(backupData.Roles, roles)
		}

		if backupUsers {
			fmt.Println("Backing up users...")
			users, err := db.GetUsers()
			if err != nil {
				return fmt.Errorf("Error getting users: %w", err)
			}
			backupData.Users = make([]backupUser, 0, len(users))
			for _, u := range users {
				if limitUser != "" && u.Username != limitUser {
					continue
				}
				bu := backupUser{
					User: u,
				}
				if backupTokens {
					tokens, err := db.GetTokensForUser(u.Id)
					if err != nil {
						return fmt.Errorf("Error getting tokens for user: %w", err)
					}
					bu.Tokens = make([]*model.Token, len(tokens))
					copy(bu.Tokens, tokens)
				}
				if backupSpaces {
					spaces, err := db.GetSpacesForUser(u.Id)
					if err != nil {
						return fmt.Errorf("Error getting spaces: %w", err)
					}
					bu.Spaces = make([]*model.Space, len(spaces))
					for j, s := range spaces {
						space, err := db.GetSpace(s.Id)
						if err != nil {
							return fmt.Errorf("Error getting space: %w", err)
						}
						bu.Spaces[j] = space
					}
				}
				backupData.Users = append(backupData.Users, bu)
			}
			backupData.Users = slices.Clip(backupData.Users)
		}

		data, err := json.Marshal(backupData)
		if err != nil {
			return fmt.Errorf("Error marshalling backup data: %w", err)
		}

		if key != "" {
			data = []byte(crypt.Encrypt(key, string(data)))
		}

		err = os.WriteFile(outputFile, data, 0644)
		if err != nil {
			return fmt.Errorf("Error writing backup file: %w", err)
		}

		fmt.Println("Database backup completed successfully.")
		return nil
	},
}
View Source
var RenameZoneCmd = &cli.Command{
	Name:  "rename-zone",
	Usage: "Rename a Zone",
	Description: `Rename a zone.

The zone name is updated within the database however spaces and volumes are not moved.`,
	Arguments: []cli.Argument{
		&cli.StringArg{
			Name:     "old",
			Usage:    "The old zone name",
			Required: true,
		},
		&cli.StringArg{
			Name:     "new",
			Usage:    "The new zone name",
			Required: true,
		},
	},
	MaxArgs: cli.NoArgs,
	Run: func(ctx context.Context, cmd *cli.Command) error {
		oldZone := cmd.GetStringArg("old")
		newZone := cmd.GetStringArg("new")

		fmt.Println("Renaming zone", oldZone, "to", newZone)
		fmt.Print("This command will not move any spaces or volumes between zones.\n\n")

		// Prompt the user to confirm the deletion
		var confirm string
		fmt.Printf("Are you sure you want to rename zone %s (yes/no): ", oldZone)
		fmt.Scanln(&confirm)
		if confirm != "yes" {
			fmt.Println("Rename cancelled.")
			return nil
		}

		db := database.GetInstance()

		fmt.Print("Updating volumes\n")
		volumes, err := db.GetVolumes()
		if err != nil {
			fmt.Println("Error getting volumes: ", err)
			return nil
		}

		for _, volume := range volumes {
			fmt.Print("Checking Volume: ", volume.Name)
			if volume.Zone == oldZone {
				volume.Zone = newZone
				volume.UpdatedAt = hlc.Now()
				err := db.SaveVolume(volume, []string{"Zone", "UpdatedAt"})
				if err != nil {
					fmt.Println("Error updating volume: ", err)
					return nil
				}
				fmt.Print(" - Updated\n")
			} else {
				fmt.Print(" - Skipping\n")
			}
		}

		fmt.Print("\nUpdating spaces\n")
		spaces, err := db.GetSpaces()
		if err != nil {
			fmt.Println("Error getting spaces: ", err)
			return nil
		}

		for _, space := range spaces {
			fmt.Print("Checking Space: ", space.Name)
			if space.Zone == oldZone {
				space.Zone = newZone
				space.UpdatedAt = hlc.Now()
				err := db.SaveSpace(space, []string{"Zone", "UpdatedAt"})
				if err != nil {
					fmt.Println("Error updating space: ", err)
					return nil
				}
				fmt.Print(" - Updated\n")
			} else {
				fmt.Print(" - Skipping\n")
			}
		}

		fmt.Print("\nZone renamed\n")
		return nil
	},
}
View Source
var ResetTOTPCmd = &cli.Command{
	Name:        "reset-totp",
	Usage:       "Reset a users TOTP",
	Description: "Clear the current TOTP for the specified user so that on next login a new secret is generated.",
	Arguments: []cli.Argument{
		&cli.StringArg{
			Name:     "email-address",
			Usage:    "The email address of the user to reset the TOTP for",
			Required: true,
		},
	},
	MaxArgs: cli.NoArgs,
	Run: func(ctx context.Context, cmd *cli.Command) error {
		email := cmd.GetStringArg("email-address")

		fmt.Println("Resetting TOTP for user: ", email)

		db := database.GetInstance()

		user, err := db.GetUserByEmail(email)
		if err != nil {
			fmt.Println("Error getting user: ", err)
			return nil
		}

		user.TOTPSecret = ""
		user.UpdatedAt = hlc.Now()

		err = db.SaveUser(user, []string{"TOTPSecret", "UpdatedAt"})
		if err != nil {
			fmt.Println("Error saving user: ", err)
			return nil
		}

		fmt.Print("\nTOTP Reset\n")
		return nil
	},
}
View Source
var RestoreCmd = &cli.Command{
	Name:        "restore",
	Usage:       "Restore a backup file",
	Description: "Restore the database from a backup file.",
	Arguments: []cli.Argument{
		&cli.StringArg{
			Name:     "backupfile",
			Usage:    "The name of the backup file to restore",
			Required: true,
		},
	},
	MaxArgs: cli.NoArgs,
	Flags: []cli.Flag{
		&cli.StringFlag{
			Name:    "encrypt-key",
			Aliases: []string{"e"},
			Usage:   "Encrypt the backup file with the given key. The key must be 32 bytes long.",
			EnvVars: []string{config.CONFIG_ENV_PREFIX + "_RESTORE_ENCRYPT_KEY"},
		},
	},
	Run: func(ctx context.Context, cmd *cli.Command) error {
		inputFile := cmd.GetStringArg("backupfile")
		key := cmd.GetString("encrypt-key")
		if key != "" && len(key) != 32 {
			return fmt.Errorf("Error: Encrypt key must be 32 bytes long.")
		}

		fmt.Println("Restoring database from file: ", inputFile)
		db := database.GetInstance()
		backupData := backupData{}

		data, err := os.ReadFile(inputFile)
		if err != nil {
			return fmt.Errorf("Error loading backup file: %w", err)
		}

		if key != "" {

			data = []byte(crypt.Decrypt(key, string(data)))
		}

		err = json.Unmarshal(data, &backupData)
		if err != nil {
			return fmt.Errorf("Error unmarshalling backup file: %w", err)
		}

		fmt.Println("Restoring audit logs...")
		for _, auditLog := range backupData.AuditLogs {
			err := db.SaveAuditLog(auditLog)
			if err != nil {
				return fmt.Errorf("Error restoring audit log: %w", err)
			}
			fmt.Println("Restored audit log: ", auditLog.Event)
		}

		fmt.Println("Restoring configuration values...")
		for _, cfgValue := range backupData.CfgValues {
			err := db.SaveCfgValue(cfgValue)
			if err != nil {
				return fmt.Errorf("Error restoring configuration value: %w", err)
			}
			fmt.Println("Restored configuration value: ", cfgValue.Name)
		}

		fmt.Println("Restoring templates...")
		for _, template := range backupData.Templates {
			err := db.SaveTemplate(template, nil)
			if err != nil {
				return fmt.Errorf("Error restoring template: %w", err)
			}
			fmt.Println("Restored template: ", template.Name)
		}

		fmt.Println("Restoring template variables...")
		for _, variable := range backupData.TemplateVars {
			err := db.SaveTemplateVar(variable)
			if err != nil {
				return fmt.Errorf("Error restoring template variable: %w", err)
			}
			fmt.Println("Restored template variable: ", variable.Name)
		}

		fmt.Println("Restoring volumes...")
		for _, volume := range backupData.Volumes {
			err := db.SaveVolume(volume, nil)
			if err != nil {
				return fmt.Errorf("Error restoring volume: %w", err)
			}
			fmt.Println("Restored volume: ", volume.Name)
		}

		fmt.Println("Restoring groups...")
		for _, group := range backupData.Groups {
			err := db.SaveGroup(group)
			if err != nil {
				return fmt.Errorf("Error restoring group: %w", err)
			}
			fmt.Println("Restored group: ", group.Name)
		}

		fmt.Println("Restoring roles...")
		for _, role := range backupData.Roles {
			err := db.SaveRole(role)
			if err != nil {
				return fmt.Errorf("Error restoring role: %w", err)
			}
			fmt.Println("Restored role: ", role.Name)
		}

		fmt.Println("Restoring users...")
		for _, user := range backupData.Users {
			err := db.SaveUser(user.User, nil)
			if err != nil {
				return fmt.Errorf("Error restoring user: %w", err)
			}
			fmt.Println("Restored user: ", user.User.Username)

			fmt.Println("Restoring tokens for user: ", user.User.Username)
			for _, token := range user.Tokens {
				err = db.SaveToken(token)
				if err != nil {
					return fmt.Errorf("Error restoring token for user: %w", err)
				}
				fmt.Println("Restored token for user: ", user.User.Username, token.Name)
			}

			fmt.Println("Restoring spaces for user: ", user.User.Username)
			for _, space := range user.Spaces {

				if space.StartedAt.IsZero() {
					space.StartedAt = time.Now().UTC()
				}

				err := db.SaveSpace(space, nil)
				if err != nil {
					return fmt.Errorf("Error restoring space: %w", err)
				}
				fmt.Println("Restored space: ", space.Name)
			}
		}

		fmt.Println("Database restore completed successfully.")
		return nil
	},
}
View Source
var SetPasswordCmd = &cli.Command{
	Name:        "set-password",
	Usage:       "Reset a users password",
	Description: "Set a new password for the specified user.",
	Arguments: []cli.Argument{
		&cli.StringArg{
			Name:     "email-address",
			Usage:    "The email address of the user to reset the password for",
			Required: true,
		},
	},
	MaxArgs: cli.NoArgs,
	Run: func(ctx context.Context, cmd *cli.Command) error {
		email := cmd.GetStringArg("email-address")

		fmt.Println("Setting new password for user: ", email)

		fmt.Printf("Enter the new password: ")
		password, err := term.ReadPassword(int(syscall.Stdin))
		if err != nil {
			return fmt.Errorf("Failed to read password: %w", err)
		}
		fmt.Println()

		db := database.GetInstance()

		user, err := db.GetUserByEmail(email)
		if err != nil {
			return fmt.Errorf("Error getting user: %w", err)
		}

		user.SetPassword(string(password))
		user.UpdatedAt = hlc.Now()

		err = db.SaveUser(user, []string{"Password", "UpdatedAt"})
		if err != nil {
			return fmt.Errorf("Error saving user: %w", err)
		}

		fmt.Print("\nPassword set\n")
		return nil
	},
}

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

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