htpasswd: refactor and add Passwd methods
Signed-off-by: Nagy Károly Gábriel <k@jpi.io>
This commit is contained in:
+186
-147
@@ -79,24 +79,6 @@ func ParseHtpasswd(htpasswdBytes []byte) (Passwds, error) {
|
|||||||
return passwords, err
|
return passwords, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func validLine(parts []string, lineNumber int, line string) (bool, error) {
|
|
||||||
var err error
|
|
||||||
if len(parts) != 2 {
|
|
||||||
err = errors.New(fmt.Sprintln("invalid line", lineNumber+1,
|
|
||||||
"unexpected number of parts split by", ":", len(parts),
|
|
||||||
"instead of 2 in\"", line, "\""))
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func trimParts(parts []string) []string {
|
|
||||||
for i, part := range parts {
|
|
||||||
parts[i] = strings.Trim(part, " ")
|
|
||||||
}
|
|
||||||
return parts
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateUser creates a record in the named file with
|
// CreateUser creates a record in the named file with
|
||||||
// the named password and hash algorithm
|
// the named password and hash algorithm
|
||||||
func CreateUser(file, user, passwd string, algo HashAlgorithm) error {
|
func CreateUser(file, user, passwd string, algo HashAlgorithm) error {
|
||||||
@@ -104,15 +86,25 @@ func CreateUser(file, user, passwd string, algo HashAlgorithm) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, exists := pp[user]; exists {
|
newpp, err := pp.CreateUser(user, passwd, algo)
|
||||||
return fmt.Errorf("user %s already exists", user)
|
|
||||||
}
|
|
||||||
h, err := createHash(passwd, algo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return newpp.Write(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateUser will create a new user in the given Passwd object
|
||||||
|
// using the given name, password and hashing algorithm
|
||||||
|
func (pp Passwds) CreateUser(user, passwd string, algo HashAlgorithm) (Passwds, error) {
|
||||||
|
if _, exists := pp[user]; exists {
|
||||||
|
return nil, fmt.Errorf("user %s already exists", user)
|
||||||
|
}
|
||||||
|
h, err := createHash(passwd, algo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
pp[user] = h
|
pp[user] = h
|
||||||
return os.WriteFile(file, pp.toByte(), os.ModePerm)
|
return pp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUser will update the password for the named user
|
// UpdateUser will update the password for the named user
|
||||||
@@ -122,15 +114,25 @@ func UpdateUser(file, user, passwd string, algo HashAlgorithm) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, exists := pp[user]; !exists {
|
newpp, err := pp.UpdateUser(user, passwd, algo)
|
||||||
return fmt.Errorf("user %s does not exist", user)
|
|
||||||
}
|
|
||||||
h, err := createHash(passwd, algo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return newpp.Write(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUser will update the password for the named user
|
||||||
|
// using the given name, password and hashing algorithm
|
||||||
|
func (pp Passwds) UpdateUser(user, passwd string, algo HashAlgorithm) (Passwds, error) {
|
||||||
|
if _, exists := pp[user]; !exists {
|
||||||
|
return nil, fmt.Errorf("user %s does not exist", user)
|
||||||
|
}
|
||||||
|
h, err := createHash(passwd, algo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
pp[user] = h
|
pp[user] = h
|
||||||
return os.WriteFile(file, pp.toByte(), os.ModePerm)
|
return pp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser deletes the named user from the named file
|
// DeleteUser deletes the named user from the named file
|
||||||
@@ -139,12 +141,22 @@ func DeleteUser(file, user string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
newpp, err := pp.DeleteUser(user)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newpp.Write(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUser deletes the named user from the named file
|
||||||
|
func (pp Passwds) DeleteUser(user string) (Passwds, error) {
|
||||||
if _, exists := pp[user]; !exists {
|
if _, exists := pp[user]; !exists {
|
||||||
return fmt.Errorf("user %s does not exist", user)
|
return nil, fmt.Errorf("user %s does not exist", user)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(pp, user)
|
delete(pp, user)
|
||||||
return os.WriteFile(file, pp.toByte(), os.ModePerm)
|
return pp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyUser will check if the given user and password are matching
|
// VerifyUser will check if the given user and password are matching
|
||||||
@@ -154,12 +166,12 @@ func VerifyUser(file, user, passwd string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return pp.Verify(user, passwd)
|
return pp.VerifyUser(user, passwd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify will check if the given user and password are matching
|
// VerifyUser will check if the given user and password are matching
|
||||||
// with the given Passwd object content
|
// with the given Passwd object
|
||||||
func (pp Passwds) Verify(user, passwd string) error {
|
func (pp Passwds) VerifyUser(user, passwd string) error {
|
||||||
if _, ok := pp[user]; !ok {
|
if _, ok := pp[user]; !ok {
|
||||||
return fmt.Errorf("user %s does not exist", user)
|
return fmt.Errorf("user %s does not exist", user)
|
||||||
}
|
}
|
||||||
@@ -170,6 +182,49 @@ func (pp Passwds) Verify(user, passwd string) error {
|
|||||||
return verifyPass(passwd, pp[user], alg)
|
return verifyPass(passwd, pp[user], alg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write will cwrite the Passwd object to the given file
|
||||||
|
func (pp Passwds) Write(file string) error {
|
||||||
|
return os.WriteFile(file, pp.Byte(), os.ModePerm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte will return the Passwd as a byte slice
|
||||||
|
func (pp Passwds) Byte() []byte {
|
||||||
|
pass := []byte{}
|
||||||
|
for name, hash := range pp {
|
||||||
|
pass = append(pass, []byte(name+":"+hash+"\n")...)
|
||||||
|
}
|
||||||
|
return pass
|
||||||
|
}
|
||||||
|
|
||||||
|
func createHash(passwd string, algo HashAlgorithm) (string, error) {
|
||||||
|
hash := ""
|
||||||
|
prefix := ""
|
||||||
|
var err error
|
||||||
|
switch algo {
|
||||||
|
case HashAPR1:
|
||||||
|
hash, err = hashApr1(passwd)
|
||||||
|
case HashBCrypt:
|
||||||
|
hash, err = hashBcrypt(passwd)
|
||||||
|
case HashSHA:
|
||||||
|
prefix = "{SHA}"
|
||||||
|
hash, err = hashSha(passwd)
|
||||||
|
case HashSSHA:
|
||||||
|
prefix = "{SSHA}"
|
||||||
|
hash, err = hashSSha(passwd)
|
||||||
|
case HashSHA256:
|
||||||
|
prefix = "$5$"
|
||||||
|
hash, err = hashSha256(passwd)
|
||||||
|
case HashSHA512:
|
||||||
|
prefix = "$6$"
|
||||||
|
hash, err = hashSha512(passwd)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefix + hash, nil
|
||||||
|
}
|
||||||
|
|
||||||
func verifyPass(pass, hash string, alg HashAlgorithm) error {
|
func verifyPass(pass, hash string, alg HashAlgorithm) error {
|
||||||
switch alg {
|
switch alg {
|
||||||
case HashAPR1:
|
case HashAPR1:
|
||||||
@@ -188,10 +243,55 @@ func verifyPass(pass, hash string, alg HashAlgorithm) error {
|
|||||||
return fmt.Errorf("unsupported hash algorithm %v", alg)
|
return fmt.Errorf("unsupported hash algorithm %v", alg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func identifyHash(h string) (HashAlgorithm, error) {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(h, "$2a$"), strings.HasPrefix(h, "$2y$"),
|
||||||
|
strings.HasPrefix(h, "$2x$"), strings.HasPrefix(h, "$2b$"):
|
||||||
|
return HashBCrypt, nil
|
||||||
|
case strings.HasPrefix(h, "$apr1$"):
|
||||||
|
return HashAPR1, nil
|
||||||
|
case strings.HasPrefix(h, "{SHA}"):
|
||||||
|
return HashSHA, nil
|
||||||
|
case strings.HasPrefix(h, "{SSHA}"):
|
||||||
|
return HashSSHA, nil
|
||||||
|
case strings.HasPrefix(h, "$5$"):
|
||||||
|
return HashSHA256, nil
|
||||||
|
case strings.HasPrefix(h, "$6$"):
|
||||||
|
return HashSHA512, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("unsupported hash algorithm")
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashApr1(passwd string) (string, error) {
|
||||||
|
return apr1_crypt.New().Generate([]byte(passwd), nil)
|
||||||
|
}
|
||||||
|
|
||||||
func verifyAPR1(password, hashedPassword string) error {
|
func verifyAPR1(password, hashedPassword string) error {
|
||||||
return apr1_crypt.New().Verify(hashedPassword, []byte(password))
|
return apr1_crypt.New().Verify(hashedPassword, []byte(password))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hashBcrypt(passwd string) (string, error) {
|
||||||
|
passwordBytes, err := bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(passwordBytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// func verifyBcrypt does not exist as its place
|
||||||
|
// is taken by `bcrypt.CompareHashAndPassword`
|
||||||
|
|
||||||
|
func hashSha(passwd string) (string, error) {
|
||||||
|
s := sha1.New()
|
||||||
|
_, err := s.Write([]byte(passwd))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
passwordSum := []byte(s.Sum(nil))
|
||||||
|
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
||||||
|
}
|
||||||
|
|
||||||
func verifySHA(password, hashedPassword string) error {
|
func verifySHA(password, hashedPassword string) error {
|
||||||
eppS := hashedPassword[5:]
|
eppS := hashedPassword[5:]
|
||||||
hash, err := base64.StdEncoding.DecodeString(eppS)
|
hash, err := base64.StdEncoding.DecodeString(eppS)
|
||||||
@@ -215,6 +315,26 @@ func verifySHA(password, hashedPassword string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hashSSha(passwd string) (string, error) {
|
||||||
|
s := sha1.New()
|
||||||
|
_, err := s.Write([]byte(passwd))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
salt := make([]byte, 4)
|
||||||
|
_, err = rand.Read(salt)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
_, err = s.Write([]byte(salt))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
passwordSum := []byte(s.Sum(nil))
|
||||||
|
ret := append(passwordSum, salt...)
|
||||||
|
return base64.StdEncoding.EncodeToString(ret), nil
|
||||||
|
}
|
||||||
|
|
||||||
func verifySSHA(password, hashedPassword string) error {
|
func verifySSHA(password, hashedPassword string) error {
|
||||||
eppS := hashedPassword[6:]
|
eppS := hashedPassword[6:]
|
||||||
hash, err := base64.StdEncoding.DecodeString(eppS)
|
hash, err := base64.StdEncoding.DecodeString(eppS)
|
||||||
@@ -246,6 +366,16 @@ func verifySSHA(password, hashedPassword string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hashSha256(passwd string) (string, error) {
|
||||||
|
s := sha256.New()
|
||||||
|
_, err := s.Write([]byte(passwd))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
passwordSum := []byte(s.Sum(nil))
|
||||||
|
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
||||||
|
}
|
||||||
|
|
||||||
func verifySHA256(password, hashedPassword string) error {
|
func verifySHA256(password, hashedPassword string) error {
|
||||||
eppS := hashedPassword[3:]
|
eppS := hashedPassword[3:]
|
||||||
hash, err := base64.StdEncoding.DecodeString(eppS)
|
hash, err := base64.StdEncoding.DecodeString(eppS)
|
||||||
@@ -269,6 +399,16 @@ func verifySHA256(password, hashedPassword string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hashSha512(passwd string) (string, error) {
|
||||||
|
s := sha512.New()
|
||||||
|
_, err := s.Write([]byte(passwd))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
passwordSum := []byte(s.Sum(nil))
|
||||||
|
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
||||||
|
}
|
||||||
|
|
||||||
func verifySHA512(password, hashedPassword string) error {
|
func verifySHA512(password, hashedPassword string) error {
|
||||||
eppS := hashedPassword[3:]
|
eppS := hashedPassword[3:]
|
||||||
hash, err := base64.StdEncoding.DecodeString(eppS)
|
hash, err := base64.StdEncoding.DecodeString(eppS)
|
||||||
@@ -292,121 +432,20 @@ func verifySHA512(password, hashedPassword string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp Passwds) toByte() []byte {
|
func validLine(parts []string, lineNumber int, line string) (bool, error) {
|
||||||
pass := []byte{}
|
|
||||||
for name, hash := range pp {
|
|
||||||
pass = append(pass, []byte(name+":"+hash+"\n")...)
|
|
||||||
}
|
|
||||||
return pass
|
|
||||||
}
|
|
||||||
|
|
||||||
func identifyHash(h string) (HashAlgorithm, error) {
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(h, "$2a$"), strings.HasPrefix(h, "$2y$"),
|
|
||||||
strings.HasPrefix(h, "$2x$"), strings.HasPrefix(h, "$2b$"):
|
|
||||||
return HashBCrypt, nil
|
|
||||||
case strings.HasPrefix(h, "$apr1$"):
|
|
||||||
return HashAPR1, nil
|
|
||||||
case strings.HasPrefix(h, "{SHA}"):
|
|
||||||
return HashSHA, nil
|
|
||||||
case strings.HasPrefix(h, "{SSHA}"):
|
|
||||||
return HashSSHA, nil
|
|
||||||
case strings.HasPrefix(h, "$5$"):
|
|
||||||
return HashSHA256, nil
|
|
||||||
case strings.HasPrefix(h, "$6$"):
|
|
||||||
return HashSHA512, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", fmt.Errorf("unsupported hash algorithm")
|
|
||||||
}
|
|
||||||
|
|
||||||
func createHash(passwd string, algo HashAlgorithm) (string, error) {
|
|
||||||
hash := ""
|
|
||||||
prefix := ""
|
|
||||||
var err error
|
var err error
|
||||||
switch algo {
|
if len(parts) != 2 {
|
||||||
case HashAPR1:
|
err = errors.New(fmt.Sprintln("invalid line", lineNumber+1,
|
||||||
hash, err = hashApr1(passwd)
|
"unexpected number of parts split by", ":", len(parts),
|
||||||
case HashBCrypt:
|
"instead of 2 in\"", line, "\""))
|
||||||
hash, err = hashBcrypt(passwd)
|
return false, err
|
||||||
case HashSHA:
|
|
||||||
prefix = "{SHA}"
|
|
||||||
hash, err = hashSha(passwd)
|
|
||||||
case HashSSHA:
|
|
||||||
prefix = "{SSHA}"
|
|
||||||
hash, err = hashSSha(passwd)
|
|
||||||
case HashSHA256:
|
|
||||||
prefix = "$5$"
|
|
||||||
hash, err = hashSha256(passwd)
|
|
||||||
case HashSHA512:
|
|
||||||
prefix = "$6$"
|
|
||||||
hash, err = hashSha512(passwd)
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
return true, nil
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefix + hash, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashApr1(passwd string) (string, error) {
|
func trimParts(parts []string) []string {
|
||||||
return apr1_crypt.New().Generate([]byte(passwd), nil)
|
for i, part := range parts {
|
||||||
}
|
parts[i] = strings.Trim(part, " ")
|
||||||
|
}
|
||||||
func hashBcrypt(passwd string) (string, error) {
|
return parts
|
||||||
passwordBytes, err := bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(passwordBytes), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashSha(passwd string) (string, error) {
|
|
||||||
s := sha1.New()
|
|
||||||
_, err := s.Write([]byte(passwd))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
passwordSum := []byte(s.Sum(nil))
|
|
||||||
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashSha256(passwd string) (string, error) {
|
|
||||||
s := sha256.New()
|
|
||||||
_, err := s.Write([]byte(passwd))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
passwordSum := []byte(s.Sum(nil))
|
|
||||||
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashSha512(passwd string) (string, error) {
|
|
||||||
s := sha512.New()
|
|
||||||
_, err := s.Write([]byte(passwd))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
passwordSum := []byte(s.Sum(nil))
|
|
||||||
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashSSha(passwd string) (string, error) {
|
|
||||||
s := sha1.New()
|
|
||||||
_, err := s.Write([]byte(passwd))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
salt := make([]byte, 4)
|
|
||||||
_, err = rand.Read(salt)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
_, err = s.Write([]byte(salt))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
passwordSum := []byte(s.Sum(nil))
|
|
||||||
ret := append(passwordSum, salt...)
|
|
||||||
return base64.StdEncoding.EncodeToString(ret), nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseHtpassd(t *testing.T) {
|
func TestParseHtpasswd(t *testing.T) {
|
||||||
passwords, err := ParseHtpasswd([]byte("sha:{SHA}IRRjboXT92QSYXm8lpGPCZUvU1E=\n"))
|
passwords, err := ParseHtpasswd([]byte("sha:{SHA}IRRjboXT92QSYXm8lpGPCZUvU1E=\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -77,7 +77,7 @@ func TestVerifyPassword(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVerify(t *testing.T) {
|
func TestVerifyUser(t *testing.T) {
|
||||||
f, err := os.Stat("htpasswd_testdata")
|
f, err := os.Stat("htpasswd_testdata")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
TestCreateUser(t)
|
TestCreateUser(t)
|
||||||
@@ -87,8 +87,23 @@ func TestVerify(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = pp.Verify("bcrypt", "123456@")
|
testCases := []struct {
|
||||||
if err != nil {
|
user, password string
|
||||||
t.Fatalf(err.Error())
|
expected error
|
||||||
|
}{
|
||||||
|
{"apr1", "123456@", nil},
|
||||||
|
{"bcrypt", "123456@", nil},
|
||||||
|
{"ssha", "123456@", nil},
|
||||||
|
{"sha", "123456@", nil},
|
||||||
|
{"sha256", "123456@", nil},
|
||||||
|
{"sha512", "123456@", nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
err := pp.VerifyUser(tc.user, tc.password)
|
||||||
|
if err != tc.expected {
|
||||||
|
t.Errorf("VerifyUser(%s, %s) = %v; want %v",
|
||||||
|
tc.user, tc.password, err, tc.expected)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
apr1:$apr1$v0FnbGJM$b2P3y1ltZYHakDaHrWx3N1
|
|
||||||
bcrypt:$2a$10$pBSUext6NDsFYrm8GviW.OFe6SczH91INRC3YmsfE3HJp/fPmRaee
|
|
||||||
ssha:{SSHA}LoTRQgCdeGIeJ3nxDQMCmQSWdnMEsLqj
|
|
||||||
sha512:$6$78RjySv19bx/knbdL6q1cpoV8WblZwc3x+wmPGQUvrSycxc4liKbksvDr9HZj76hgRuZZCyEngP+WEJmePArCQ==
|
|
||||||
sha:{SHA}YEn9/RmoXLdbyB9TEDJ0OqWoPy8=
|
|
||||||
sha256:$5$ufJ2S16IOhB6XLTGrVLqGQBKv/odjE3rypxnUDLqaS0=
|
sha256:$5$ufJ2S16IOhB6XLTGrVLqGQBKv/odjE3rypxnUDLqaS0=
|
||||||
|
apr1:$apr1$paiD.yqE$4lKqGF77KuaaEDY.bBpnv0
|
||||||
|
bcrypt:$2a$10$imLJRfdHQkOg4/cleE31Re5Xp73DQctfXtlqeZc2Mcs2I9YdjXUl2
|
||||||
|
ssha:{SSHA}m2iNELVYJhxKppu7FZHXXkGcKSlUkA/t
|
||||||
|
sha:{SHA}YEn9/RmoXLdbyB9TEDJ0OqWoPy8=
|
||||||
|
sha512:$6$78RjySv19bx/knbdL6q1cpoV8WblZwc3x+wmPGQUvrSycxc4liKbksvDr9HZj76hgRuZZCyEngP+WEJmePArCQ==
|
||||||
|
|||||||
Reference in New Issue
Block a user