wisski-cloud-distillery/pkg/password/common.go
2023-01-10 11:10:38 +01:00

96 lines
2 KiB
Go

package password
import (
"bufio"
"embed"
"fmt"
"io/fs"
"strings"
)
// CommonPasswordError
type CommonPasswordError struct {
CommonPassword
}
func (cpe CommonPasswordError) Error() string {
return fmt.Sprintf("%q from %q", cpe.Password, cpe.Source)
}
type CommonPassword struct {
Password string
Source string
}
//go:embed common
var commonEmbed embed.FS
// CommonPasswords returns a channel that contains all passwords.
// The caller must drain the channel.
func CommonPasswords() <-chan CommonPassword {
pChan := make(chan CommonPassword, 10)
go func() {
defer close(pChan)
fs.WalkDir(commonEmbed, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
// get the full path
if d.IsDir() || !strings.HasSuffix(path, ".txt") {
return nil
}
// open it
file, err := commonEmbed.Open(path)
if err != nil {
return err
}
defer file.Close()
// scan it line by line
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "//") {
continue
}
pChan <- CommonPassword{
Password: line,
Source: path,
}
}
return scanner.Err()
})
}()
return pChan
}
// CheckCommonPassword checks if a password is a common password.
//
// check is called with each candidate password to perform the check.
// check should return a boolean indicating if the password in question corresponds to the candidate.
//
// CheckCommonPassword returns one of three error values.
//
// - a CommonPasswordError (when a password matches a common password)
// - an error returned by check (assuming some check went wrong)
// - or nil (when a password is not a common password
func CheckCommonPassword(check func(candidate string) (bool, error)) error {
for commmon := range CommonPasswords() {
ok, err := check(commmon.Password)
if err != nil {
return err
}
// password validation passed
if ok {
return CommonPasswordError{
CommonPassword: commmon,
}
}
}
return nil
}