Skip to content

Commit

Permalink
feat(strength): 添加用于验证密码强度的包
Browse files Browse the repository at this point in the history
  • Loading branch information
caixw committed Jan 20, 2025
1 parent 8a9196e commit d8e4650
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 102 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.23.0
require (
github.com/google/uuid v1.6.0
github.com/issue9/assert/v4 v4.3.1
github.com/issue9/rands/v3 v3.1.0
github.com/issue9/version v1.0.8
github.com/issue9/web v0.100.9
golang.org/x/text v0.21.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ github.com/issue9/mux/v9 v9.1.2 h1:Ng5uv8bwsduZV6w14gv0HR78ahBs8Fm0JWlc7Xjtbd4=
github.com/issue9/mux/v9 v9.1.2/go.mod h1:CLtV5ZfIrAmfaC/qxn07wXc3GALI45GYCsdE3c/h9CQ=
github.com/issue9/query/v3 v3.1.3 h1:Y6ETEYXxaKqhpM4lXPKCffhJ72VuKQbrAwgwHlacu0Y=
github.com/issue9/query/v3 v3.1.3/go.mod h1:a/W/+7iel9K+5rRT4AFAKR8+OJeV5axeF6tK9My4lNA=
github.com/issue9/rands/v3 v3.0.1 h1:EnX9WNushGgHCzoL/R5eBPaLfvjLO/c7CGHNgLK0JhY=
github.com/issue9/rands/v3 v3.0.1/go.mod h1:n4mM2ts7NCpuxHwS9zorPITJBWEUGksXg6cTOH6yqS0=
github.com/issue9/rands/v3 v3.1.0 h1:GC0884SAtAAWIA5J4pQ2BpaISD0xK2njnqVpeVXQoYQ=
github.com/issue9/rands/v3 v3.1.0/go.mod h1:cUBNpOf1rF2thj/OjErcj8c8JtkHC54eyFaDcB8kJo8=
github.com/issue9/scheduled v0.22.0 h1:qGk4+IbaxozIEaYX9mWEM1C//Zg/iI8DVT6tYIS/ibU=
github.com/issue9/scheduled v0.22.0/go.mod h1:wVGvPy6kxstLwkfQIYEfpORl+gNKTW68ydFA4d78fMQ=
github.com/issue9/sliceutil v0.17.0 h1:EtmVlldkAyGxS0O2TnxcAu3pgLJw74I5eh9DHT7TOZs=
Expand Down
50 changes: 0 additions & 50 deletions internal/strength/strength.go

This file was deleted.

46 changes: 0 additions & 46 deletions internal/strength/strength_test.go

This file was deleted.

104 changes: 104 additions & 0 deletions strength/strength.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-FileCopyrightText: 2022-2025 caixw
//
// SPDX-License-Identifier: MIT

package strength

import (
"unicode"

"github.com/issue9/rands/v3"
)

var chars = []byte("abcdefghijkmnprstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ1234567890!@#$%^&*()_+[]{};':\",./<>?")

func lower() []byte { return chars[0:23] }
func upper() []byte { return chars[23:47] }
func num() []byte { return chars[47:57] }
func punct() []byte { return chars[57:] }
func allChars() []byte { return chars }

// Strength 密码强度管理
type Strength struct {
Length int8 // 长度不能小于此值
Upper int8 // 大写字母的数量不能小于此值
Lower int8 // 小写字母的数量不能小于此值
Punct int8 // 符号的数量不能小于此值
Number int8 // 数值的数量不能小于此值
}

// Gen 生成符合要求的随机密码
func (s *Strength) Gen() []byte {
bs := rands.Bytes(int(s.Length), int(s.Length+1), allChars())
cnt := Strength{}
for _, b := range bs {
switch r := rune(b); {
case unicode.IsPunct(r) || unicode.IsSymbol(r):
cnt.Punct++
case unicode.IsUpper(r):
cnt.Upper++
case unicode.IsLower(r):
cnt.Lower++
case unicode.IsNumber(r):
cnt.Number++
}
}

if size := s.Punct - cnt.Punct; size > 0 {
bs = append(bs, rands.Bytes(int(size), int(size+3), punct())...)
}

if size := s.Upper - cnt.Upper; size > 0 {
bs = append(bs, rands.Bytes(int(size), int(size+3), upper())...)
}

if size := s.Lower - cnt.Lower; size > 0 {
bs = append(bs, rands.Bytes(int(size), int(size+3), lower())...)
}

if size := s.Number - cnt.Number; size > 0 {
bs = append(bs, rands.Bytes(int(size), int(size+3), num())...)
}

return bs
}

// Valid 验证密码是否符合要求
func (s *Strength) Valid(pass string) bool {
if s.Length == 0 && s.Upper == 0 && s.Lower == 0 && s.Punct == 0 {
return true
}

cnt := Strength{}
for _, r := range pass {
switch {
case unicode.IsPunct(r) || unicode.IsSymbol(r):
cnt.Punct++
case unicode.IsUpper(r):
cnt.Upper++
case unicode.IsLower(r):
cnt.Lower++
case unicode.IsNumber(r):
cnt.Number++
}
cnt.Length++
}

ok := true
if s.Length > 0 {
ok = cnt.Length >= s.Length
}
if ok && s.Lower > 0 {
ok = cnt.Lower >= s.Lower
}
if ok && s.Upper > 0 {
ok = cnt.Upper >= s.Upper
}
if ok && s.Punct > 0 {
ok = cnt.Punct >= s.Punct
}
if ok && s.Number > 0 {
ok = cnt.Number >= s.Number
}
return ok
}
64 changes: 64 additions & 0 deletions strength/strength_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: 2022-2025 caixw
//
// SPDX-License-Identifier: MIT

package strength

import (
"testing"

"github.com/issue9/assert/v4"
)

func TestStrength_Gen(t *testing.T) {
a := assert.New(t, false)
v := &Strength{Length: 5}
a.True(v.Valid(string(v.Gen())))

v = &Strength{Length: 5, Number: 5}
a.True(v.Valid(string(v.Gen())))

v = &Strength{Length: 5, Number: 5, Upper: 3}
a.True(v.Valid(string(v.Gen())))

v = &Strength{Length: 5, Number: 5, Lower: 3}
a.True(v.Valid(string(v.Gen())))

v = &Strength{Length: 5, Number: 5, Lower: 3, Punct: 3}
a.True(v.Valid(string(v.Gen())))
}

func TestStrength_Valid(t *testing.T) {
a := assert.New(t, false)

v := &Strength{}
a.True(v.Valid(""))
a.True(v.Valid("123"))

v = &Strength{Length: 3}
a.False(v.Valid(""))
a.False(v.Valid("12"))
a.True(v.Valid("123"))
a.True(v.Valid("Abcdef"))

v = &Strength{Length: 3, Upper: 2}
a.False(v.Valid(""))
a.False(v.Valid("12"))
a.False(v.Valid("123"))
a.False(v.Valid("123A"))
a.True(v.Valid("123AB"))
a.False(v.Valid("AB"))
a.True(v.Valid("ABc"))

v = &Strength{Upper: 2, Lower: 3, Punct: 1}
a.False(v.Valid(""))
a.False(v.Valid("12345678"))
a.True(v.Valid("ABcde>"))
a.True(v.Valid("ABcde123><"))

v = &Strength{Length: 4, Upper: 2, Punct: 1}
a.False(v.Valid(""))
a.False(v.Valid("12345678"))
a.False(v.Valid("AB>"))
a.True(v.Valid("AB=!>"))
}
11 changes: 7 additions & 4 deletions validator/string.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022-2024 caixw
// SPDX-FileCopyrightText: 2022-2025 caixw
//
// SPDX-License-Identifier: MIT

Expand All @@ -16,8 +16,8 @@ import (
"github.com/issue9/webfilter/gb11643"
"github.com/issue9/webfilter/gb32100"
"github.com/issue9/webfilter/internal/isbn"
"github.com/issue9/webfilter/internal/strength"
"github.com/issue9/webfilter/luhn"
"github.com/issue9/webfilter/strength"
)

// Strength 声明密码强度的验证对象
Expand All @@ -26,8 +26,11 @@ import (
// upper 对大写字符的最小要求;
// lower 对小写字符的最小要求;
// punct 对符号的最小要求;
func Strength(length, upper, lower, punct int) func(string) bool {
return strength.New(length, upper, lower, punct)
// num 对数字的最小要求
//
// 详细文档可参考 [strength.Strength]。
func Strength(length, upper, lower, punct, num int8) func(string) bool {
return (&strength.Strength{Length: length, Upper: upper, Lower: lower, Punct: punct, Number: num}).Valid
}

func URL(val string) bool {
Expand Down

0 comments on commit d8e4650

Please sign in to comment.