@@ -20,10 +20,10 @@ import (
2020 "context"
2121 "crypto/rand"
2222 _ "embed"
23- "encoding/hex"
2423 "encoding/json"
2524 "errors"
2625 "fmt"
26+ "math/big"
2727 "strings"
2828
2929 common_helper "github.com/openstack-k8s-operators/lib-common/modules/common/helper"
@@ -187,16 +187,46 @@ func getDeployment(ctx context.Context, h *common_helper.Helper, name string, na
187187 return deployment , nil
188188}
189189
190- // generateRandomString generates a random hex string of the given length.
190+ // generateRandomString generates a random alphanumeric string of the given length containing at
191+ // least one lowercase letter, one uppercase letter, and one digit. Minimum required secretLength
192+ // is 16.
191193func generateRandomString (secretLength int ) (string , error ) {
192- // Ceiling division: hex.EncodeToString doubles the byte count, so we need ceil(secretLength/2) bytes.
193- randDataLen := (secretLength + 1 ) / 2
194+ const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
195+ const charsetLen = len (charset )
196+ const minLength = 16
197+ const maxIterations = 1000
194198
195- b := make ([]byte , randDataLen )
196- if _ , err := rand .Read (b ); err != nil {
197- return "" , fmt .Errorf ("failed to generate secret: %w" , err )
199+ if secretLength < minLength {
200+ return "" , fmt .Errorf ("secret length must be at least %d" , minLength )
198201 }
199202
200- randString := hex .EncodeToString (b )
201- return randString [:secretLength ], nil
203+ for range maxIterations {
204+
205+ randPassword := make ([]byte , secretLength )
206+ var hasLowerCase , hasUpperCase , hasNumber bool
207+
208+ for passwdCharIdx := range secretLength {
209+ idx , err := rand .Int (rand .Reader , big .NewInt (int64 (charsetLen )))
210+ if err != nil {
211+ return "" , fmt .Errorf ("failed to generate secret: %w" , err )
212+ }
213+
214+ passwdChar := charset [idx .Int64 ()]
215+ if passwdChar >= 'a' && passwdChar <= 'z' {
216+ hasLowerCase = true
217+ } else if passwdChar >= 'A' && passwdChar <= 'Z' {
218+ hasUpperCase = true
219+ } else if passwdChar >= '0' && passwdChar <= '9' {
220+ hasNumber = true
221+ }
222+
223+ randPassword [passwdCharIdx ] = passwdChar
224+ }
225+
226+ if hasLowerCase && hasUpperCase && hasNumber {
227+ return string (randPassword ), nil
228+ }
229+ }
230+
231+ return "" , fmt .Errorf ("failed to generate secret: exceeded iterations - %d" , maxIterations )
202232}
0 commit comments