code.gitea.io/gitea@v1.19.3/modules/auth/password/pwn/pwn_test.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package pwn 5 6 import ( 7 "errors" 8 "math/rand" 9 "net/http" 10 "os" 11 "strings" 12 "testing" 13 "time" 14 ) 15 16 var client = New(WithHTTP(&http.Client{ 17 Timeout: time.Second * 2, 18 })) 19 20 func TestMain(m *testing.M) { 21 rand.Seed(time.Now().Unix()) 22 os.Exit(m.Run()) 23 } 24 25 func TestPassword(t *testing.T) { 26 // Check input error 27 _, err := client.CheckPassword("", false) 28 if err == nil { 29 t.Log("blank input should return an error") 30 t.Fail() 31 } 32 if !errors.Is(err, ErrEmptyPassword) { 33 t.Log("blank input should return ErrEmptyPassword") 34 t.Fail() 35 } 36 37 // Should fail 38 fail := "password1234" 39 count, err := client.CheckPassword(fail, false) 40 if err != nil { 41 t.Log(err) 42 t.Fail() 43 } 44 if count == 0 { 45 t.Logf("%s should fail as a password\n", fail) 46 t.Fail() 47 } 48 49 // Should fail (with padding) 50 failPad := "administrator" 51 count, err = client.CheckPassword(failPad, true) 52 if err != nil { 53 t.Log(err) 54 t.Fail() 55 } 56 if count == 0 { 57 t.Logf("%s should fail as a password\n", failPad) 58 t.Fail() 59 } 60 61 // Checking for a "good" password isn't going to be perfect, but we can give it a good try 62 // with hopefully minimal error. Try five times? 63 var good bool 64 var pw string 65 for idx := 0; idx <= 5; idx++ { 66 pw = testPassword() 67 count, err = client.CheckPassword(pw, false) 68 if err != nil { 69 t.Log(err) 70 t.Fail() 71 } 72 if count == 0 { 73 good = true 74 break 75 } 76 } 77 if !good { 78 t.Log("no generated passwords passed. there is a chance this is a fluke") 79 t.Fail() 80 } 81 82 // Again, but with padded responses 83 good = false 84 for idx := 0; idx <= 5; idx++ { 85 pw = testPassword() 86 count, err = client.CheckPassword(pw, true) 87 if err != nil { 88 t.Log(err) 89 t.Fail() 90 } 91 if count == 0 { 92 good = true 93 break 94 } 95 } 96 if !good { 97 t.Log("no generated passwords passed. there is a chance this is a fluke") 98 t.Fail() 99 } 100 } 101 102 // Credit to https://golangbyexample.com/generate-random-password-golang/ 103 // DO NOT USE THIS FOR AN ACTUAL PASSWORD GENERATOR 104 var ( 105 lowerCharSet = "abcdedfghijklmnopqrst" 106 upperCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 107 specialCharSet = "!@#$%&*" 108 numberSet = "0123456789" 109 allCharSet = lowerCharSet + upperCharSet + specialCharSet + numberSet 110 ) 111 112 func testPassword() string { 113 var password strings.Builder 114 115 // Set special character 116 for i := 0; i < 5; i++ { 117 random := rand.Intn(len(specialCharSet)) 118 password.WriteString(string(specialCharSet[random])) 119 } 120 121 // Set numeric 122 for i := 0; i < 5; i++ { 123 random := rand.Intn(len(numberSet)) 124 password.WriteString(string(numberSet[random])) 125 } 126 127 // Set uppercase 128 for i := 0; i < 5; i++ { 129 random := rand.Intn(len(upperCharSet)) 130 password.WriteString(string(upperCharSet[random])) 131 } 132 133 for i := 0; i < 5; i++ { 134 random := rand.Intn(len(allCharSet)) 135 password.WriteString(string(allCharSet[random])) 136 } 137 inRune := []rune(password.String()) 138 rand.Shuffle(len(inRune), func(i, j int) { 139 inRune[i], inRune[j] = inRune[j], inRune[i] 140 }) 141 return string(inRune) 142 }