Add monorepo structure for NexaVPN WireGuard control plane including: - .gitignore for node_modules, build artifacts, and environment files - README with project overview, monorepo layout, and quick start guide - Admin web UI with React, Vite, TypeScript, and nginx reverse proxy - API client with type definitions for users, devices, policies, gateways, and audit logs - Admin pages for dashboard, users, devices, policies, g
41 lines
951 B
Go
41 lines
951 B
Go
package auth
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/subtle"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/argon2"
|
|
)
|
|
|
|
func HashPassword(password string) (string, error) {
|
|
salt := make([]byte, 16)
|
|
if _, err := rand.Read(salt); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
hash := argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32)
|
|
return fmt.Sprintf("argon2id$%s$%s", base64.RawStdEncoding.EncodeToString(salt), base64.RawStdEncoding.EncodeToString(hash)), nil
|
|
}
|
|
|
|
func VerifyPassword(hashValue, password string) bool {
|
|
parts := strings.Split(hashValue, "$")
|
|
if len(parts) != 3 || parts[0] != "argon2id" {
|
|
return false
|
|
}
|
|
|
|
salt, err := base64.RawStdEncoding.DecodeString(parts[1])
|
|
if err != nil {
|
|
return false
|
|
}
|
|
expected, err := base64.RawStdEncoding.DecodeString(parts[2])
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
actual := argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32)
|
|
return subtle.ConstantTimeCompare(expected, actual) == 1
|
|
}
|