Compare commits
5 Commits
geoip/v1.1
...
v1.1.16
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
713975e7f1 | ||
|
|
2ab920982a | ||
|
|
3153ff149f | ||
|
|
578cf26ee8 | ||
|
|
ef08927a50 |
@@ -1,17 +1,55 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// DefaultCost 最小值=4 最大值=31 默认值=10
|
||||
var DefaultCost = 10
|
||||
|
||||
// HashPassword 加密密码
|
||||
func HashPassword(password string) (string, error) {
|
||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 10)
|
||||
// Prefix + Cost + Salt + Hashed Text
|
||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), DefaultCost)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
// CheckPasswordHash 校验密码
|
||||
func CheckPasswordHash(password, hash string) bool {
|
||||
// HashPasswordWithSalt 对密码进行加盐哈希处理
|
||||
func HashPasswordWithSalt(password, salt string) (string, error) {
|
||||
// 将密码和盐组合
|
||||
combined := []byte(password + salt)
|
||||
|
||||
// 计算哈希值
|
||||
hash := sha256.Sum256(combined)
|
||||
|
||||
// 将哈希值转换为十六进制字符串
|
||||
return hex.EncodeToString(hash[:]), nil
|
||||
}
|
||||
|
||||
// VerifyPassword 验证密码是否正确
|
||||
func VerifyPassword(password, hash string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// VerifyPasswordWithSalt 验证密码是否正确
|
||||
func VerifyPasswordWithSalt(password, salt, hashedPassword string) bool {
|
||||
// 对输入的密码和盐进行哈希处理
|
||||
newHash, _ := HashPasswordWithSalt(password, salt)
|
||||
// 比较哈希值是否相同
|
||||
return newHash == hashedPassword
|
||||
}
|
||||
|
||||
// GenerateSalt 生成指定长度的盐
|
||||
func GenerateSalt(length int) (string, error) {
|
||||
salt := make([]byte, length)
|
||||
_, err := rand.Read(salt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(salt), nil
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@ package crypto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestHashPassword(t *testing.T) {
|
||||
@@ -13,13 +14,15 @@ func TestHashPassword(t *testing.T) {
|
||||
fmt.Println(hash)
|
||||
}
|
||||
|
||||
func TestCheckPasswordHash(t *testing.T) {
|
||||
func TestVerifyPassword(t *testing.T) {
|
||||
text := "123456"
|
||||
|
||||
// Prefix + Cost + Salt + Hashed Text
|
||||
hash3 := "$2a$10$ygWrRwHCzg2GUpz0UK40kuWAGva121VkScpcdMNsDCih2U/bL2qYy"
|
||||
bMatched := CheckPasswordHash(text, hash3)
|
||||
bMatched := VerifyPassword(text, hash3)
|
||||
assert.True(t, bMatched)
|
||||
|
||||
bMatched = CheckPasswordHash(text, hash3)
|
||||
bMatched = VerifyPassword(text, hash3)
|
||||
assert.True(t, bMatched)
|
||||
}
|
||||
|
||||
|
||||
10
rand/rand.go
10
rand/rand.go
@@ -1,16 +1,16 @@
|
||||
package rand
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/tx7do/go-utils/math"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
var rnd = rand.New(rand.NewSource(Seed(UnixNanoSeed)))
|
||||
|
||||
func init() {
|
||||
rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
if rnd != nil {
|
||||
rnd = rand.New(rand.NewSource(Seed(UnixNanoSeed)))
|
||||
}
|
||||
}
|
||||
|
||||
func Float32() float32 {
|
||||
|
||||
179
rand/randomizer.go
Normal file
179
rand/randomizer.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package rand
|
||||
|
||||
import (
|
||||
"github.com/tx7do/go-utils/math"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
type Randomizer struct {
|
||||
rnd *rand.Rand
|
||||
}
|
||||
|
||||
func NewRandomizer(seedType SeedType) *Randomizer {
|
||||
return &Randomizer{
|
||||
rnd: rand.New(rand.NewSource(Seed(seedType))),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Randomizer) Float32() float32 {
|
||||
return r.rnd.Float32()
|
||||
}
|
||||
|
||||
func (r *Randomizer) Float64() float64 {
|
||||
return r.rnd.Float64()
|
||||
}
|
||||
|
||||
func (r *Randomizer) Int() int {
|
||||
return r.rnd.Int()
|
||||
}
|
||||
|
||||
func (r *Randomizer) Int31() int32 {
|
||||
return r.rnd.Int31()
|
||||
}
|
||||
|
||||
func (r *Randomizer) Int63() int64 {
|
||||
return r.rnd.Int63()
|
||||
}
|
||||
|
||||
func (r *Randomizer) Uint32() uint32 {
|
||||
return r.rnd.Uint32()
|
||||
}
|
||||
|
||||
func (r *Randomizer) Uint64() uint64 {
|
||||
return r.rnd.Uint64()
|
||||
}
|
||||
|
||||
func (r *Randomizer) Intn(n int) int {
|
||||
return r.rnd.Intn(n)
|
||||
}
|
||||
|
||||
func (r *Randomizer) Int31n(n int32) int32 {
|
||||
return r.rnd.Int31n(n)
|
||||
}
|
||||
|
||||
func (r *Randomizer) Int63n(n int64) int64 {
|
||||
return r.rnd.Int63n(n)
|
||||
}
|
||||
|
||||
// RangeInt 根据区间产生随机数
|
||||
func (r *Randomizer) RangeInt(min, max int) int {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return min + r.Intn(max-min+1)
|
||||
}
|
||||
|
||||
// RangeInt32 根据区间产生随机数
|
||||
func (r *Randomizer) RangeInt32(min, max int32) int32 {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return min + r.Int31n(max-min+1)
|
||||
}
|
||||
|
||||
// RangeInt64 根据区间产生随机数
|
||||
func (r *Randomizer) RangeInt64(min, max int64) int64 {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return min + r.Int63n(max-min+1)
|
||||
}
|
||||
|
||||
// RangeUint 根据区间产生随机数
|
||||
func (r *Randomizer) RangeUint(min, max uint) uint {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return min + uint(r.Intn(int(max-min+1)))
|
||||
}
|
||||
|
||||
// RangeUint32 根据区间产生随机数
|
||||
func (r *Randomizer) RangeUint32(min, max uint32) uint32 {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return min + uint32(r.Int31n(int32(max-min+1)))
|
||||
}
|
||||
|
||||
// RangeUint64 根据区间产生随机数
|
||||
func (r *Randomizer) RangeUint64(min, max uint64) uint64 {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return min + uint64(r.Int63n(int64(max-min+1)))
|
||||
}
|
||||
|
||||
// RangeFloat32 根据区间产生随机数
|
||||
func (r *Randomizer) RangeFloat32(min, max float32) float32 {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return min + r.Float32()*(max-min)
|
||||
}
|
||||
|
||||
// RangeFloat64 根据区间产生随机数
|
||||
func (r *Randomizer) RangeFloat64(min, max float64) float64 {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return min + r.Float64()*(max-min)
|
||||
}
|
||||
|
||||
// RandomString 随机字符串,包含大小写字母和数字
|
||||
func (r *Randomizer) RandomString(l int) string {
|
||||
bytes := make([]byte, l)
|
||||
for i := 0; i < l; i++ {
|
||||
x := r.Intn(3)
|
||||
switch x {
|
||||
case 0:
|
||||
bytes[i] = byte(r.RangeInt(65, 90)) //大写字母
|
||||
case 1:
|
||||
bytes[i] = byte(r.RangeInt(97, 122))
|
||||
case 2:
|
||||
bytes[i] = byte(r.Intn(10))
|
||||
}
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// WeightedChoice 根据权重随机,返回对应选项的索引,O(n)
|
||||
func (r *Randomizer) WeightedChoice(weightArray []int) int {
|
||||
if weightArray == nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
total := math.SumInt(weightArray)
|
||||
rv := r.Int63n(total)
|
||||
for i, v := range weightArray {
|
||||
if rv < int64(v) {
|
||||
return i
|
||||
}
|
||||
rv -= int64(v)
|
||||
}
|
||||
|
||||
return len(weightArray) - 1
|
||||
}
|
||||
|
||||
// NonWeightedChoice 根据权重随机,返回对应选项的索引,O(n). 权重大于等于0
|
||||
func (r *Randomizer) NonWeightedChoice(weightArray []int) int {
|
||||
if weightArray == nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
for i, weight := range weightArray {
|
||||
if weight < 0 {
|
||||
weightArray[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
total := math.SumInt(weightArray)
|
||||
rv := r.Int63n(total)
|
||||
for i, v := range weightArray {
|
||||
if rv < int64(v) {
|
||||
return i
|
||||
}
|
||||
rv -= int64(v)
|
||||
}
|
||||
|
||||
return len(weightArray) - 1
|
||||
}
|
||||
86
rand/randomizer_test.go
Normal file
86
rand/randomizer_test.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package rand
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRandomizer_RangeUint32_MinEqualsMax(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
result := r.RangeUint32(5, 5)
|
||||
assert.Equal(t, uint32(5), result)
|
||||
}
|
||||
|
||||
func TestRandomizer_RangeUint32_MinGreaterThanMax(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
result := r.RangeUint32(10, 5)
|
||||
assert.Equal(t, uint32(5), result)
|
||||
}
|
||||
|
||||
func TestRandomizer_RangeUint32_PositiveRange(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
for i := 0; i < 1000; i++ {
|
||||
result := r.RangeUint32(1, 10)
|
||||
assert.True(t, result >= 1)
|
||||
assert.True(t, result <= 10)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomizer_RangeUint64_MinEqualsMax(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
result := r.RangeUint64(5, 5)
|
||||
assert.Equal(t, uint64(5), result)
|
||||
}
|
||||
|
||||
func TestRandomizer_RangeUint64_MinGreaterThanMax(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
result := r.RangeUint64(10, 5)
|
||||
assert.Equal(t, uint64(5), result)
|
||||
}
|
||||
|
||||
func TestRandomizer_RangeUint64_PositiveRange(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
for i := 0; i < 1000; i++ {
|
||||
result := r.RangeUint64(1, 10)
|
||||
assert.True(t, result >= 1)
|
||||
assert.True(t, result <= 10)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomizer_WeightedChoice_EmptyArray(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
result := r.WeightedChoice([]int{})
|
||||
assert.Equal(t, -1, result)
|
||||
}
|
||||
|
||||
func TestRandomizer_WeightedChoice_AllZeroWeights(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
result := r.WeightedChoice([]int{0, 0, 0})
|
||||
assert.Equal(t, 2, result)
|
||||
}
|
||||
|
||||
func TestRandomizer_WeightedChoice_MixedWeights(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
weightArray := []int{1, 0, 3, 0, 2}
|
||||
counts := make([]int, len(weightArray))
|
||||
for i := 0; i < 1000; i++ {
|
||||
choice := r.WeightedChoice(weightArray)
|
||||
counts[choice]++
|
||||
}
|
||||
assert.Greater(t, counts[0], 0)
|
||||
assert.Greater(t, counts[2], 0)
|
||||
assert.Greater(t, counts[4], 0)
|
||||
}
|
||||
|
||||
func TestRandomizer_RandomString_LengthZero(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
result := r.RandomString(0)
|
||||
assert.Equal(t, "", result)
|
||||
}
|
||||
|
||||
func TestRandomizer_RandomString_CorrectLength(t *testing.T) {
|
||||
r := NewRandomizer(UnixNanoSeed)
|
||||
length := 50
|
||||
result := r.RandomString(length)
|
||||
assert.Equal(t, length, len(result))
|
||||
}
|
||||
99
rand/seeder.go
Normal file
99
rand/seeder.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package rand
|
||||
|
||||
import (
|
||||
cryptoRand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"golang.org/x/exp/rand"
|
||||
"hash/maphash"
|
||||
mathRand "math/rand"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SeedType string
|
||||
|
||||
const (
|
||||
UnixNanoSeed SeedType = "UnixNano"
|
||||
MapHashSeed SeedType = "MapHash"
|
||||
CryptoRandSeed SeedType = "CryptoRand"
|
||||
RandomStringSeed SeedType = "RandomString"
|
||||
)
|
||||
|
||||
type Seeder struct {
|
||||
seedType SeedType
|
||||
}
|
||||
|
||||
func NewSeeder(seedType SeedType) *Seeder {
|
||||
return &Seeder{
|
||||
seedType: seedType,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Seeder) UnixNano() int64 {
|
||||
// 获取当前时间戳
|
||||
timestamp := time.Now().UnixNano()
|
||||
|
||||
// 生成一个随机数
|
||||
var randomBytes [8]byte
|
||||
_, err := rand.Read(randomBytes[:])
|
||||
if err != nil {
|
||||
panic("failed to generate random bytes")
|
||||
}
|
||||
randomPart := int64(binary.LittleEndian.Uint64(randomBytes[:]))
|
||||
|
||||
// 获取 Goroutine ID(或其他唯一标识)
|
||||
goroutineID := int64(runtime.NumGoroutine())
|
||||
|
||||
// 结合时间戳、随机数和 Goroutine ID
|
||||
seed := timestamp ^ randomPart ^ goroutineID
|
||||
|
||||
return seed
|
||||
}
|
||||
|
||||
func (r *Seeder) MapHash() int64 {
|
||||
return int64(new(maphash.Hash).Sum64())
|
||||
}
|
||||
|
||||
func (r *Seeder) CryptoRand() int64 {
|
||||
var b [8]byte
|
||||
_, err := cryptoRand.Read(b[:])
|
||||
if err != nil {
|
||||
panic("cannot seed math/rand package with cryptographically secure random number generator")
|
||||
}
|
||||
seed := int64(binary.LittleEndian.Uint64(b[:]))
|
||||
return seed
|
||||
}
|
||||
|
||||
var Alpha = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"
|
||||
|
||||
func (r *Seeder) RandomString() int64 {
|
||||
const size = 8
|
||||
buf := make([]byte, size)
|
||||
for i := 0; i < size; i++ {
|
||||
buf[i] = Alpha[mathRand.Intn(len(Alpha))]
|
||||
}
|
||||
seed := int64(binary.LittleEndian.Uint64(buf[:]))
|
||||
|
||||
return seed
|
||||
}
|
||||
|
||||
func (r *Seeder) Seed() int64 {
|
||||
switch r.seedType {
|
||||
default:
|
||||
fallthrough
|
||||
case UnixNanoSeed:
|
||||
return r.UnixNano()
|
||||
case MapHashSeed:
|
||||
return r.MapHash()
|
||||
case CryptoRandSeed:
|
||||
return r.CryptoRand()
|
||||
case RandomStringSeed:
|
||||
return r.RandomString()
|
||||
}
|
||||
}
|
||||
|
||||
// Seed generates a seed based on the specified SeedType.
|
||||
func Seed(seedType SeedType) int64 {
|
||||
randomizer := NewSeeder(seedType)
|
||||
return randomizer.Seed()
|
||||
}
|
||||
80
rand/seeder_test.go
Normal file
80
rand/seeder_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package rand
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnixNanoSeed(t *testing.T) {
|
||||
seeder := NewSeeder(UnixNanoSeed)
|
||||
|
||||
var seeds = make(map[int64]bool)
|
||||
for i := 0; i < 100000; i++ {
|
||||
seed := seeder.Seed()
|
||||
seeds[seed] = true
|
||||
}
|
||||
fmt.Println("UnixNano Seed", len(seeds))
|
||||
}
|
||||
|
||||
func TestMapHashSeed(t *testing.T) {
|
||||
seeder := NewSeeder(MapHashSeed)
|
||||
|
||||
var seeds = make(map[int64]bool)
|
||||
for i := 0; i < 100000; i++ {
|
||||
seed := seeder.Seed()
|
||||
seeds[seed] = true
|
||||
}
|
||||
fmt.Println("MapHash Seed", len(seeds))
|
||||
}
|
||||
|
||||
func TestCryptoRandSeed(t *testing.T) {
|
||||
seeder := NewSeeder(CryptoRandSeed)
|
||||
|
||||
var seeds = make(map[int64]bool)
|
||||
for i := 0; i < 100000; i++ {
|
||||
seed := seeder.Seed()
|
||||
seeds[seed] = true
|
||||
}
|
||||
fmt.Println("CryptoRand Seed", len(seeds))
|
||||
}
|
||||
|
||||
func TestRandomStringSeed(t *testing.T) {
|
||||
seeder := NewSeeder(RandomStringSeed)
|
||||
|
||||
var seeds = make(map[int64]bool)
|
||||
for i := 0; i < 100000; i++ {
|
||||
seed := seeder.Seed()
|
||||
seeds[seed] = true
|
||||
}
|
||||
fmt.Println("RandomString Seed", len(seeds))
|
||||
}
|
||||
|
||||
func TestSeed(t *testing.T) {
|
||||
var seeds = make(map[int64]bool)
|
||||
for i := 0; i < 100000; i++ {
|
||||
seed := Seed(UnixNanoSeed)
|
||||
seeds[seed] = true
|
||||
}
|
||||
fmt.Println("UnixNano Seed", len(seeds))
|
||||
|
||||
seeds = make(map[int64]bool)
|
||||
for i := 0; i < 100000; i++ {
|
||||
seed := Seed(MapHashSeed)
|
||||
seeds[seed] = true
|
||||
}
|
||||
fmt.Println("MapHash Seed", len(seeds))
|
||||
|
||||
seeds = make(map[int64]bool)
|
||||
for i := 0; i < 100000; i++ {
|
||||
seed := Seed(CryptoRandSeed)
|
||||
seeds[seed] = true
|
||||
}
|
||||
fmt.Println("CryptoRand Seed", len(seeds))
|
||||
|
||||
seeds = make(map[int64]bool)
|
||||
for i := 0; i < 100000; i++ {
|
||||
seed := Seed(RandomStringSeed)
|
||||
seeds[seed] = true
|
||||
}
|
||||
fmt.Println("RandomString Seed", len(seeds))
|
||||
}
|
||||
2
tag.bat
2
tag.bat
@@ -1,4 +1,4 @@
|
||||
git tag v1.1.14
|
||||
git tag v1.1.16
|
||||
|
||||
git tag bank_card/v1.1.4
|
||||
git tag geoip/v1.1.4
|
||||
|
||||
@@ -165,3 +165,18 @@ func DurationpbToNumber[T int | int8 | int16 | int32 | int64 | uint | uint8 | ui
|
||||
secondsWithPrecision := T(seconds / timePrecision.Seconds())
|
||||
return &secondsWithPrecision
|
||||
}
|
||||
|
||||
func DurationToDurationpb(duration *time.Duration) *durationpb.Duration {
|
||||
if duration == nil {
|
||||
return nil
|
||||
}
|
||||
return durationpb.New(*duration)
|
||||
}
|
||||
|
||||
func DurationpbToDuration(duration *durationpb.Duration) *time.Duration {
|
||||
if duration == nil {
|
||||
return nil
|
||||
}
|
||||
d := duration.AsDuration()
|
||||
return &d
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user