code.gitea.io/gitea@v1.22.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  	"math/rand"
     8  	"net/http"
     9  	"os"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  var client = New(WithHTTP(&http.Client{
    18  	Timeout: time.Second * 2,
    19  }))
    20  
    21  func TestMain(m *testing.M) {
    22  	rand.Seed(time.Now().Unix())
    23  	os.Exit(m.Run())
    24  }
    25  
    26  func TestPassword(t *testing.T) {
    27  	// Check input error
    28  	_, err := client.CheckPassword("", false)
    29  	assert.ErrorIs(t, err, ErrEmptyPassword, "blank input should return ErrEmptyPassword")
    30  
    31  	// Should fail
    32  	fail := "password1234"
    33  	count, err := client.CheckPassword(fail, false)
    34  	assert.NotEmpty(t, count, "%s should fail as a password", fail)
    35  	assert.NoError(t, err)
    36  
    37  	// Should fail (with padding)
    38  	failPad := "administrator"
    39  	count, err = client.CheckPassword(failPad, true)
    40  	assert.NotEmpty(t, count, "%s should fail as a password", failPad)
    41  	assert.NoError(t, err)
    42  
    43  	// Checking for a "good" password isn't going to be perfect, but we can give it a good try
    44  	// with hopefully minimal error. Try five times?
    45  	assert.Condition(t, func() bool {
    46  		for i := 0; i <= 5; i++ {
    47  			count, err = client.CheckPassword(testPassword(), false)
    48  			assert.NoError(t, err)
    49  			if count == 0 {
    50  				return true
    51  			}
    52  		}
    53  		return false
    54  	}, "no generated passwords passed. there is a chance this is a fluke")
    55  
    56  	// Again, but with padded responses
    57  	assert.Condition(t, func() bool {
    58  		for i := 0; i <= 5; i++ {
    59  			count, err = client.CheckPassword(testPassword(), true)
    60  			assert.NoError(t, err)
    61  			if count == 0 {
    62  				return true
    63  			}
    64  		}
    65  		return false
    66  	}, "no generated passwords passed. there is a chance this is a fluke")
    67  }
    68  
    69  // Credit to https://golangbyexample.com/generate-random-password-golang/
    70  // DO NOT USE THIS FOR AN ACTUAL PASSWORD GENERATOR
    71  var (
    72  	lowerCharSet   = "abcdedfghijklmnopqrst"
    73  	upperCharSet   = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    74  	specialCharSet = "!@#$%&*"
    75  	numberSet      = "0123456789"
    76  	allCharSet     = lowerCharSet + upperCharSet + specialCharSet + numberSet
    77  )
    78  
    79  func testPassword() string {
    80  	var password strings.Builder
    81  
    82  	// Set special character
    83  	for i := 0; i < 5; i++ {
    84  		random := rand.Intn(len(specialCharSet))
    85  		password.WriteString(string(specialCharSet[random]))
    86  	}
    87  
    88  	// Set numeric
    89  	for i := 0; i < 5; i++ {
    90  		random := rand.Intn(len(numberSet))
    91  		password.WriteString(string(numberSet[random]))
    92  	}
    93  
    94  	// Set uppercase
    95  	for i := 0; i < 5; i++ {
    96  		random := rand.Intn(len(upperCharSet))
    97  		password.WriteString(string(upperCharSet[random]))
    98  	}
    99  
   100  	for i := 0; i < 5; i++ {
   101  		random := rand.Intn(len(allCharSet))
   102  		password.WriteString(string(allCharSet[random]))
   103  	}
   104  	inRune := []rune(password.String())
   105  	rand.Shuffle(len(inRune), func(i, j int) {
   106  		inRune[i], inRune[j] = inRune[j], inRune[i]
   107  	})
   108  	return string(inRune)
   109  }