2026-03-11 22:06:44 +01:00
|
|
|
// Copyright (C) 2026 saces@c-base.org
|
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
2026-01-31 08:13:53 +01:00
|
|
|
package mxapi
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2026-03-17 18:16:21 +01:00
|
|
|
"crypto/rand"
|
2026-01-31 08:13:53 +01:00
|
|
|
"encoding/json"
|
2026-03-17 18:16:21 +01:00
|
|
|
"errors"
|
2026-01-31 08:13:53 +01:00
|
|
|
"fmt"
|
2026-03-17 18:16:21 +01:00
|
|
|
"os"
|
2026-01-31 08:13:53 +01:00
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"maunium.net/go/mautrix"
|
|
|
|
|
"maunium.net/go/mautrix/id"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type login_data struct {
|
2026-03-17 18:16:21 +01:00
|
|
|
Homeserver string `json:"homeserver"`
|
|
|
|
|
Mxid string `json:"mxid"`
|
|
|
|
|
Loginname string `json:"loginname"`
|
|
|
|
|
Password string `json:"password"`
|
|
|
|
|
DeviceID string `json:"deviceid"`
|
|
|
|
|
DeviceName string `json:"devicename"`
|
|
|
|
|
MXPassFile string `json:"mxpassfile"`
|
|
|
|
|
MakeMasterKey bool `json:"make_master_key"`
|
|
|
|
|
MakeRecoveryKey bool `json:"make_recovery_key"`
|
2026-01-31 08:13:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Login(data string) (string, error) {
|
|
|
|
|
var ld login_data
|
|
|
|
|
err := json.Unmarshal([]byte(data), &ld)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-17 18:16:21 +01:00
|
|
|
if ld.MXPassFile != "" {
|
|
|
|
|
if _, err := os.Stat(ld.MXPassFile); err == nil {
|
|
|
|
|
return "", fmt.Errorf("mxpassfile '%s' already exists", ld.MXPassFile)
|
|
|
|
|
} else if !errors.Is(err, os.ErrNotExist) {
|
|
|
|
|
return "", fmt.Errorf("error while checking mxpassfile: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 08:13:53 +01:00
|
|
|
mauclient, err := mautrix.NewClient(ld.Homeserver, id.UserID(ld.Mxid), "")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-17 18:16:21 +01:00
|
|
|
now := time.Now()
|
|
|
|
|
if ld.DeviceID == "" {
|
|
|
|
|
ld.DeviceID = fmt.Sprintf("libmxclient-%d", now.Unix())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ld.DeviceName == "" {
|
|
|
|
|
ld.DeviceName = fmt.Sprintf("libmxclient-%s", now.Format(time.RFC3339))
|
|
|
|
|
}
|
2026-01-31 08:13:53 +01:00
|
|
|
|
|
|
|
|
resp, err := mauclient.Login(context.Background(), &mautrix.ReqLogin{
|
|
|
|
|
Type: "m.login.password",
|
|
|
|
|
Identifier: mautrix.UserIdentifier{
|
|
|
|
|
Type: "m.id.user",
|
|
|
|
|
User: ld.Loginname,
|
|
|
|
|
},
|
|
|
|
|
Password: ld.Password,
|
2026-03-17 18:16:21 +01:00
|
|
|
DeviceID: id.DeviceID(ld.DeviceID),
|
|
|
|
|
InitialDeviceDisplayName: ld.DeviceName,
|
2026-01-31 08:13:53 +01:00
|
|
|
StoreCredentials: false,
|
|
|
|
|
StoreHomeserverURL: false,
|
|
|
|
|
RefreshToken: false,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-17 18:16:21 +01:00
|
|
|
res := fmt.Sprintf("%s | %s | %s | %s\n", ld.Homeserver, ld.Loginname, id.UserID(ld.Mxid).Homeserver(), resp.AccessToken)
|
|
|
|
|
|
|
|
|
|
if ld.MakeMasterKey {
|
|
|
|
|
masterkey := make([]byte, 32)
|
|
|
|
|
rand.Read(masterkey)
|
|
|
|
|
res = fmt.Sprintf("%smaster | | | %x\n", res, masterkey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ld.MakeRecoveryKey {
|
|
|
|
|
recoverykey := make([]byte, 32)
|
|
|
|
|
rand.Read(recoverykey)
|
|
|
|
|
res = fmt.Sprintf("%srecovery | | | %x\n", res, recoverykey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ld.MXPassFile != "" {
|
|
|
|
|
err := os.WriteFile(ld.MXPassFile, []byte(res), 0600)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", fmt.Errorf("unable to write file: %w", err)
|
|
|
|
|
}
|
|
|
|
|
return "SUCCESS.", nil
|
|
|
|
|
}
|
2026-01-31 08:13:53 +01:00
|
|
|
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|