jamesread 4 недель назад
Родитель
Сommit
0541210c60
2 измененных файлов с 146 добавлено и 116 удалено
  1. 82 57
      service/cmd/config-tool/main.go
  2. 64 59
      service/main.go

+ 82 - 57
service/cmd/config-tool/main.go

@@ -82,75 +82,100 @@ func backupOriginalConfig(configPath string) {
 	log.Infof("Original config backed up to %s", originalConfigPath)
 }
 
-func resetAllPasswords(k *koanf.Koanf, cfg *config.Config) {
-	if !cfg.AuthLocalUsers.Enabled || len(cfg.AuthLocalUsers.Users) == 0 {
-		log.Info("No local users found, skipping password reset")
-		return
+func passwordHashPreview(password string) string {
+	if len(password) > 20 {
+		return password[:20]
 	}
 
-	hashedPassword, err := api.CreateHash("password")
-	if err != nil {
-		log.Fatalf("Error creating password hash: %v", err)
+	return password
+}
+
+func userDisplayName(username string, index int) string {
+	if username == "" {
+		return fmt.Sprintf("user[%d]", index)
 	}
 
-	usersSlice := k.Get("authLocalUsers.users")
-	usersSliceTyped, ok := usersSlice.([]interface{})
+	return username
+}
 
-	if ok && len(usersSliceTyped) > 0 {
-		newUsersSlice := make([]interface{}, len(usersSliceTyped))
-		for index, userValue := range usersSliceTyped {
-			userMap, ok := userValue.(map[string]interface{})
-			if !ok {
-				log.Warnf("User entry at index %d is not a map, skipping", index)
-				newUsersSlice[index] = userValue
-				continue
-			}
-
-			oldPassword, _ := userMap["password"].(string)
-			username, _ := userMap["username"].(string)
-			if username == "" {
-				username = fmt.Sprintf("user[%d]", index)
-			}
-
-			newUserMap := make(map[string]interface{})
-			for k, v := range userMap {
-				newUserMap[k] = v
-			}
-			newUserMap["password"] = hashedPassword
-			newUsersSlice[index] = newUserMap
-
-			oldHashPreview := oldPassword
-			if len(oldPassword) > 20 {
-				oldHashPreview = oldPassword[:20]
-			}
-			log.Infof("Reset password for user '%s' (old hash: %s...)", username, oldHashPreview)
-		}
-		err = k.Set("authLocalUsers.users", newUsersSlice)
+func copyUserMapWithPassword(userMap map[string]interface{}, hashedPassword string) map[string]interface{} {
+	newUserMap := make(map[string]interface{}, len(userMap)+1)
+	for key, value := range userMap {
+		newUserMap[key] = value
+	}
+	newUserMap["password"] = hashedPassword
+
+	return newUserMap
+}
+
+func resetPasswordInUserMap(userValue interface{}, index int, hashedPassword string) interface{} {
+	userMap, ok := userValue.(map[string]interface{})
+	if !ok {
+		log.Warnf("User entry at index %d is not a map, skipping", index)
+		return userValue
+	}
+
+	oldPassword, _ := userMap["password"].(string)
+	username, _ := userMap["username"].(string)
+	log.Infof("Reset password for user '%s' (old hash: %s...)", userDisplayName(username, index), passwordHashPreview(oldPassword))
+
+	return copyUserMapWithPassword(userMap, hashedPassword)
+}
+
+func resetPasswordsFromSlice(k *koanf.Koanf, usersSliceTyped []interface{}, hashedPassword string) {
+	newUsersSlice := make([]interface{}, len(usersSliceTyped))
+	for index, userValue := range usersSliceTyped {
+		newUsersSlice[index] = resetPasswordInUserMap(userValue, index, hashedPassword)
+	}
+
+	err := k.Set("authLocalUsers.users", newUsersSlice)
+	if err != nil {
+		log.WithFields(log.Fields{
+			"error": err,
+		}).Fatalf("Error setting users")
+	}
+}
 
+func resetPasswordsFromConfig(k *koanf.Koanf, cfg *config.Config, hashedPassword string) {
+	for index, user := range cfg.AuthLocalUsers.Users {
+		key := "authLocalUsers.users." + strconv.Itoa(index) + ".password"
+		err := k.Set(key, hashedPassword)
 		if err != nil {
 			log.WithFields(log.Fields{
 				"error": err,
-			}).Fatalf("Error setting users")
-		}
-	} else {
-		for index, user := range cfg.AuthLocalUsers.Users {
-			key := "authLocalUsers.users." + strconv.Itoa(index) + ".password"
-			err = k.Set(key, hashedPassword)
-
-			if err != nil {
-				log.WithFields(log.Fields{
-					"error": err,
-				}).Fatalf("Error setting user password")
-			}
-
-			oldHashPreview := user.Password
-			if len(oldHashPreview) > 20 {
-				oldHashPreview = oldHashPreview[:20]
-			}
-			log.Infof("Reset password for user '%s' (old hash: %s...)", user.Username, oldHashPreview)
+			}).Fatalf("Error setting user password")
 		}
+
+		log.Infof("Reset password for user '%s' (old hash: %s...)", user.Username, passwordHashPreview(user.Password))
+	}
+}
+
+func hasLocalUsers(cfg *config.Config) bool {
+	return cfg.AuthLocalUsers.Enabled && len(cfg.AuthLocalUsers.Users) > 0
+}
+
+func applyPasswordResets(k *koanf.Koanf, cfg *config.Config, hashedPassword string) {
+	usersSliceTyped, ok := k.Get("authLocalUsers.users").([]interface{})
+	if ok && len(usersSliceTyped) > 0 {
+		resetPasswordsFromSlice(k, usersSliceTyped, hashedPassword)
+		return
+	}
+
+	resetPasswordsFromConfig(k, cfg, hashedPassword)
+}
+
+func resetAllPasswords(k *koanf.Koanf, cfg *config.Config) {
+	if !hasLocalUsers(cfg) {
+		log.Info("No local users found, skipping password reset")
+		return
+	}
+
+	hashedPassword, err := api.CreateHash("password")
+	if err != nil {
+		log.Fatalf("Error creating password hash: %v", err)
 	}
 
+	applyPasswordResets(k, cfg, hashedPassword)
 	log.Infof("Reset %d password(s) to 'password'", len(cfg.AuthLocalUsers.Users))
 }
 

+ 64 - 59
service/main.go

@@ -129,92 +129,97 @@ func getConfigPath(directory string) string {
 	return configPath
 }
 
-func initConfig(configDir string) {
-	k := koanf.New(".")
-	err := k.Load(env.Provider(".", ".", nil), nil)
-
-	if err != nil {
-		log.WithFields(log.Fields{
-			"error": err,
-		}).Fatalf("Error loading environment variables")
-	}
-
-	directories := []string{
-		configDir,
-	}
+func configSearchDirectories(configDir string) []string {
+	directories := []string{configDir}
 
 	// Only load additional configs if not in integration test mode
 	absConfigDir, _ := filepath.Abs(configDir)
-	if !strings.Contains(absConfigDir, "integration-tests") {
-		directories = append(directories,
-			servicehost.GetConfigFilePath(),
-			"/config", // For containers.
-			"/etc/OliveTin/",
-		)
+	if strings.Contains(absConfigDir, "integration-tests") {
+		return directories
 	}
 
-	var baseConfigPath string
+	return append(directories,
+		servicehost.GetConfigFilePath(),
+		"/config", // For containers.
+		"/etc/OliveTin/",
+	)
+}
 
-	for _, directory := range directories {
-		configPath := getConfigPath(directory)
+func configPathExists(configPath string) bool {
+	_, err := os.Stat(configPath)
+	found := err == nil
 
-		found := true
-		if _, err := os.Stat(configPath); err != nil {
-			found = false
-		}
+	log.WithFields(log.Fields{
+		"configPath": configPath,
+		"found":      found,
+	}).Debug("Checking base config path")
 
-		log.WithFields(log.Fields{
-			"configPath": configPath,
-			"found":      found,
-		}).Debug("Checking base config path")
+	return found
+}
 
-		if !found {
-			continue
-		}
+func watchConfigFile(k *koanf.Koanf, f *file.File, configPath string) {
+	err := f.Watch(func(evt interface{}, err error) {
+		log.Infof("config file changed: %v", evt)
 
-		if baseConfigPath == "" {
-			baseConfigPath = configPath
+		errLoad := k.Load(f, yaml.Parser())
+		if errLoad != nil {
+			log.WithFields(log.Fields{
+				"error": errLoad,
+			}).Fatalf("Error loading config file")
 		}
 
+		config.AppendSource(cfg, k, configPath)
+	})
+
+	if err != nil {
 		log.WithFields(log.Fields{
-			"configPath": configPath,
-		}).Info("Loading config from path")
+			"error": err,
+		}).Fatalf("Error watching config file")
+	}
+}
 
-		f := file.Provider(configPath)
+func loadAndWatchConfig(k *koanf.Koanf, configPath string) {
+	log.WithFields(log.Fields{
+		"configPath": configPath,
+	}).Info("Loading config from path")
 
-		if err := k.Load(f, yaml.Parser()); err != nil {
-			log.Fatalf("error loading config from %s: %v", configPath, err)
-			os.Exit(1)
-		}
+	f := file.Provider(configPath)
 
-		err := f.Watch(func(evt interface{}, err error) {
-			log.Infof("config file changed: %v", evt)
+	if err := k.Load(f, yaml.Parser()); err != nil {
+		log.Fatalf("error loading config from %s: %v", configPath, err)
+	}
 
-			errLoad := k.Load(f, yaml.Parser())
+	watchConfigFile(k, f, configPath)
+}
 
-			if errLoad != nil {
-				log.WithFields(log.Fields{
-					"error": errLoad,
-				}).Fatalf("Error loading config file")
-			}
+func findAndLoadBaseConfig(k *koanf.Koanf, directories []string) string {
+	for _, directory := range directories {
+		configPath := getConfigPath(directory)
+		if !configPathExists(configPath) {
+			continue
+		}
 
-			config.AppendSource(cfg, k, configPath)
-		})
+		loadAndWatchConfig(k, configPath)
+		return configPath
+	}
 
-		if err != nil {
-			log.WithFields(log.Fields{
-				"error": err,
-			}).Fatalf("Error watching config file")
-		}
+	return ""
+}
 
-		break
+func initConfig(configDir string) {
+	k := koanf.New(".")
+	err := k.Load(env.Provider(".", ".", nil), nil)
+	if err != nil {
+		log.WithFields(log.Fields{
+			"error": err,
+		}).Fatalf("Error loading environment variables")
 	}
 
+	baseConfigPath := findAndLoadBaseConfig(k, configSearchDirectories(configDir))
 	cfg = config.DefaultConfigWithBasePort(getBasePort())
 
 	if baseConfigPath == "" {
 		log.Fatalf("No base config file found")
-		os.Exit(1)
 	}
 
 	config.AppendSource(cfg, k, baseConfigPath)