diff --git a/bank_transactions/absa_bank_password.go b/bank_transactions/absa_bank_password.go new file mode 100644 index 0000000000000000000000000000000000000000..ae032b5ade62f69aeec7103c9abf6ca9cf34bd38 --- /dev/null +++ b/bank_transactions/absa_bank_password.go @@ -0,0 +1,174 @@ +package bank_transactions + +import ( + "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors" + "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/secrets_manager" + "math/rand" + "strings" + "time" +) + +func ChangeAbsaPassword(loginInfo AbsaLoginInfo) error { + + client, err := setupAbsaClient(loginInfo.AbsaSecretName, loginInfo.IsDebug) + if err != nil { + return err + } + + defer logoff(client) + + // Get password + credentials, err := getAbsaSecret(loginInfo.AbsaSecretName, loginInfo.IsDebug) + if err != nil { + return err + } + + username := credentials["username"] + currentPassword := credentials["password"] + + // Get Initial session ID + _, err = client.R(). + SetDoNotParseResponse(true). + Get("https://bionline.absa.co.za/businessintegrator/login_new.jsp") + if err != nil { + return err + } + time.Sleep(sleepTime) + + // Navigate to change password page + _, err = client.R(). + SetDoNotParseResponse(true). + SetFormData(map[string]string{ + "lastpage": "login", + "buttonClicked": "changepassword", + "hasCert": "Y", + "certExpired": "false", + "certExpiry": loginInfo.CertExpiry, + "displayIgnoreButton": "true", + "system_Message": "", + "system_Available": "true", + "partialNo": loginInfo.PartialNo, + "universalTracker": "8f5f303d-152f-4e38-b783-52b7879782012e049546-d52e-446d-92c1-0c1279a97a1e", + "deviceFingerprint": loginInfo.DeviceFingerprint, + "certSerialNo": loginInfo.CertSerialNumber, + "UserID": username, + "password_one": "", + "message": "", + }). + Post("https://bionline.absa.co.za/businessintegrator/SignOn") + if err != nil { + return err + } + time.Sleep(sleepTime) + + // Generate new password + var newPassword string + for { + newPassword = GenerateRandomPassword() + if isValidPassword(newPassword) { + println("Generated password:", newPassword) + break + } + } + + // Change password + response, err := client.R(). + SetDoNotParseResponse(true). + SetFormData(map[string]string{ + "buttonClicked": "proceed", + "lastpage": "changepassword", + "UserID": username, + "error_code": "null", + "password_one": currentPassword, + "password_one_new": newPassword, + "password_one_confirm": newPassword, + "ErrorText": "", + }). + Post("https://bionline.absa.co.za/businessintegrator/SignOn") + if err != nil { + return err + } + time.Sleep(sleepTime) + + // Success, update secret + if response.IsSuccess() { + credentials["password"] = newPassword + err := secrets_manager.UpdateSecret(loginInfo.AbsaSecretName, credentials, loginInfo.IsDebug) + if err != nil { + return err + } + + return nil + } + + return errors.Error("Failed to update Absa CIB password") +} + +// ================================================================================ +// Generate password +// ================================================================================ + +// The password must: +// • Be between 8 and 16 characters +// • Contain one uppercase character +// • Contain one lowercase character +// • Contain one of the following nine special characters: &+-().,/; +// • Contain one numeral +// • May not contain three identical consecutive characters + +var ( + upperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + lowerCase = "abcdefghijklmnopqrstuvwxyz" + numerals = "0123456789" + specialChars = "&+-().,;/" +) + +func GenerateRandomPassword() string { + // Define password length between 8 and 16 characters + length := rand.Intn(9) + 8 + + // Ensure at least one character from each set is included + password := []byte{ + upperCase[rand.Intn(len(upperCase))], + lowerCase[rand.Intn(len(lowerCase))], + numerals[rand.Intn(len(numerals))], + specialChars[rand.Intn(len(specialChars))], + } + + // Fill the rest of the password length with random characters from all sets + allChars := upperCase + lowerCase + numerals + specialChars + for i := 4; i < length; i++ { + password = append(password, allChars[rand.Intn(len(allChars))]) + } + + // Shuffle the password to avoid predictable sequences + rand.Shuffle(len(password), func(i, j int) { + password[i], password[j] = password[j], password[i] + }) + + return string(password) +} + +func isValidPassword(password string) bool { + // Check the length + if len(password) < 8 || len(password) > 16 { + return false + } + + // Check for at least one uppercase, one lowercase, one numeral, and one special character + if !strings.ContainsAny(password, upperCase) || + !strings.ContainsAny(password, lowerCase) || + !strings.ContainsAny(password, numerals) || + !strings.ContainsAny(password, specialChars) { + return false + } + + // Check for three identical consecutive characters + for i := 0; i < len(password)-2; i++ { + if password[i] == password[i+1] && password[i+1] == password[i+2] { + return false + } + } + + return true +} diff --git a/bank_transactions/absa_bank_password_test.go b/bank_transactions/absa_bank_password_test.go new file mode 100644 index 0000000000000000000000000000000000000000..2af95dd663f7360e3de8920d4af6dc7e4c3423bd --- /dev/null +++ b/bank_transactions/absa_bank_password_test.go @@ -0,0 +1,11 @@ +package bank_transactions + +import ( + "fmt" + "testing" +) + +func TestUpdateSecret(t *testing.T) { + password := GenerateRandomPassword() + fmt.Print(password) +} diff --git a/secrets_manager/secrets_manager.go b/secrets_manager/secrets_manager.go index 3fc3e24a034485f537aa2eab3c9ee7dc9f70c763..85f4bdaedcc12191cb60d6c393fe0a13515618a3 100644 --- a/secrets_manager/secrets_manager.go +++ b/secrets_manager/secrets_manager.go @@ -195,3 +195,32 @@ func DeleteSecret(secretID string, forceWithoutRecovery bool, isDebug bool) erro return nil } + +// UpdateSecret Updates an exising secret +func UpdateSecret(secretID string, secret any, isDebug bool) error { + // Create a Secrets Manager client + err := getSecretManagerSession(isDebug) + if err != nil { + logs.Info("Could not create client: %+v", err) + return err + } + + // Create the secret - marshaling "any" into a JSON string + secretStr, err := json.Marshal(secret) + if err != nil { + logs.Info("Could not marshal secret: %+v", err) + return err + } + input := &secretsmanager.UpdateSecretInput{ + SecretId: aws.String(secretID), + SecretString: aws.String(string(secretStr)), + } + + _, err = secretManagerSession.UpdateSecret(input) + if err != nil { + logError(err) + return err + } + + return nil +}