This commit is contained in:
2023-07-05 22:07:10 +02:00
parent 0ba69b5496
commit b2e65a9df0
15 changed files with 645 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
package prosody
import (
"log"
"os"
"reflect"
"strings"
)
type account struct {
salt string `prosody:"salt"`
storedKey string `prosody:"stored_key"`
iterationCount int `prosody:"iteration_count"`
}
func (acc *account) unmarshal(data map[string]interface{}) {
valueOfPerson := reflect.ValueOf(acc).Elem()
typeOfPerson := valueOfPerson.Type()
for i := 0; i < valueOfPerson.NumField(); i++ {
field := valueOfPerson.Field(i)
tag := typeOfPerson.Field(i).Tag.Get("mytag")
if val, ok := data[tag]; ok {
field.Set(reflect.ValueOf(val))
}
}
}
// loadAccount read the user .dat file and retrieves the data store in it
func (p *Prosody) loadAccount(username string) (*account, error) {
var acc *account
data, err := os.ReadFile(p.accountsPath + username + ".dat")
if err != nil {
return nil, err
}
lines := strings.Split(string(data), "\n")
mapValues := make(map[string]interface{})
for _, line := range lines {
if strings.Contains(line, "=") {
parts := strings.Split(line, "=")
key := strings.Trim(strings.TrimSpace(parts[0]), "[]\"")
log.Println("key", key)
value := strings.TrimSpace(strings.Trim(parts[1], "\"; "))
mapValues[key] = value
}
}
acc.unmarshal(mapValues)
return acc, nil
}

View File

@@ -0,0 +1,53 @@
package prosody
import (
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"errors"
"fmt"
"log"
"os/exec"
"github.com/xdg-go/pbkdf2"
)
func (p *Prosody) ChangePassword(user string, currentPwd string, newPwd string) error {
acc, err := p.loadAccount(user)
if err != nil {
return fmt.Errorf("p.loadAccount %w", err)
}
storedKey, err := hashPassword(currentPwd, acc.salt, acc.iterationCount)
if err != nil {
return fmt.Errorf("hashPassword: %w", err)
}
// Compare the hashes
if storedKey != acc.storedKey {
return errors.New("password is incorrect")
}
result, err := exec.Command("/usr/bin/prosodyctl", "-c", "passwd -s 12 -scny 1").Output()
if err != nil {
return fmt.Errorf("prosodcytl: %w", err)
}
log.Println("string(result)", string(result))
return nil
}
func hashPassword(password, salt string, iterationCount int) (string, error) {
// Hash the password using the SCRAM mechanism
saltedPassword := pbkdf2.Key([]byte(password), []byte(salt), iterationCount, 20, sha1.New)
clientKey := hmacSha1(saltedPassword, []byte("Client Key"))
storedKey := sha1.Sum(clientKey)
return hex.EncodeToString(storedKey[:]), nil
}
func hmacSha1(key, data []byte) []byte {
mac := hmac.New(sha1.New, key)
mac.Write(data)
return mac.Sum(nil)
}

View File

@@ -0,0 +1,19 @@
package prosody
type Prosody struct {
binPath string
accountsPath string
}
// /var/lib/prosody/xmpp%%2eurkob%%2ecom/accounts/
func NewProsody(domain string) *Prosody {
return &Prosody{
binPath: "/usr/bin/prosodyctl",
accountsPath: "/var/lib/prosody/" + domain + "/accounts/",
}
}
func (p *Prosody) WithBinPath(binPath string) *Prosody {
p.binPath = binPath
return p
}