143 lines
3.6 KiB
Go
143 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"unicode"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/crypto/nacl/secretbox"
|
|
|
|
. "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
|
|
)
|
|
|
|
const EASYBRIDGE_SYSTEM_PROTOCOL string = "✯◡✯"
|
|
|
|
func ezbrMxId() string {
|
|
return fmt.Sprintf("@%s:%s", registration.SenderLocalpart, config.MatrixDomain)
|
|
}
|
|
|
|
func ezbrSystemRoom(user_mx_id string) (string, error) {
|
|
mx_room_id, err := dbGetMxPmRoom(EASYBRIDGE_SYSTEM_PROTOCOL, UserID("Easybridge"), ezbrMxId(), user_mx_id, "easybridge")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
widget_kv_key := "ezbr_widget_on:" + mx_room_id
|
|
if config.WebURL != "" && dbKvGet(widget_kv_key) != "yes" {
|
|
widget := map[string]interface{}{
|
|
"type": "m.easybridge",
|
|
"url": config.WebURL,
|
|
"name": "Easybridge account configuration dashboard",
|
|
}
|
|
err = mx.PutStateAs(mx_room_id, "im.vector.modular.widgets", "ezbr_widget", widget, ezbrMxId())
|
|
if err == nil {
|
|
dbKvPut(widget_kv_key, "yes")
|
|
}
|
|
}
|
|
|
|
return mx_room_id, nil
|
|
}
|
|
|
|
func ezbrSystemSend(user_mx_id string, msg string) {
|
|
mx_room_id, err := ezbrSystemRoom(user_mx_id)
|
|
if err == nil {
|
|
err = mx.SendMessageAs(mx_room_id, "m.text", msg, ezbrMxId())
|
|
}
|
|
if err != nil {
|
|
log.Warnf("(%s) %s", user_mx_id, msg)
|
|
}
|
|
}
|
|
|
|
func ezbrSystemSendf(user_mx_id string, format string, args ...interface{}) {
|
|
ezbrSystemSend(user_mx_id, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
// ----
|
|
|
|
func roomAlias(protocol string, id RoomID) string {
|
|
what := fmt.Sprintf("%s_%s", safeStringForId(string(id)), protocol)
|
|
return strings.Replace(config.NameFormat, "{}", what, 1)
|
|
}
|
|
|
|
func userMxId(protocol string, id UserID) string {
|
|
what := fmt.Sprintf("%s_%s", safeStringForId(string(id)), protocol)
|
|
return strings.Replace(config.NameFormat, "{}", what, 1)
|
|
}
|
|
|
|
func safeStringForId(in string) string {
|
|
id2 := ""
|
|
for _, c := range in {
|
|
if c == '@' {
|
|
id2 += "__"
|
|
} else if c == ':' {
|
|
id2 += "_"
|
|
} else if unicode.IsDigit(c) || unicode.IsLetter(c) || c == '.' || c == '-' || c == '_' {
|
|
id2 += string(c)
|
|
}
|
|
}
|
|
return id2
|
|
}
|
|
|
|
func isBridgedIdentifier(mxid string) bool {
|
|
if mxid[0] == '@' || mxid[0] == '#' {
|
|
return isBridgedIdentifier(mxid[1:])
|
|
}
|
|
|
|
if strings.Contains(mxid, ":") {
|
|
sp := strings.Split(mxid, ":")
|
|
return (sp[1] == config.MatrixDomain) && isBridgedIdentifier(sp[0])
|
|
}
|
|
|
|
nameformat_fixed_part := strings.Replace(config.NameFormat, "{}", "", 1)
|
|
if strings.HasPrefix(config.NameFormat, "{}") {
|
|
return strings.HasSuffix(mxid, nameformat_fixed_part)
|
|
} else if strings.HasSuffix(config.NameFormat, "{}") {
|
|
return strings.HasPrefix(mxid, nameformat_fixed_part)
|
|
} else {
|
|
// This is not supported
|
|
log.Fatalf("Invalid name format %s, please put {} at the beginning or at the end", config.NameFormat)
|
|
return false
|
|
}
|
|
}
|
|
|
|
// ---- Encoding and encryption of account config
|
|
|
|
func encryptAccountConfig(config map[string]string, key *[32]byte) string {
|
|
bytes, err := json.Marshal(config)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
var nonce [24]byte
|
|
_, err = rand.Read(nonce[:])
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
crypto := secretbox.Seal([]byte{}, bytes, &nonce, key)
|
|
all := append(nonce[:], crypto...)
|
|
return base64.StdEncoding.EncodeToString(all)
|
|
}
|
|
|
|
func decryptAccountConfig(data string, key *[32]byte) (map[string]string, error) {
|
|
bytes, err := base64.StdEncoding.DecodeString(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var nonce [24]byte
|
|
copy(nonce[:], bytes[:24])
|
|
|
|
decoded, ok := secretbox.Open([]byte{}, bytes[24:], &nonce, key)
|
|
if !ok {
|
|
return nil, fmt.Errorf("Invalid key")
|
|
}
|
|
|
|
var config map[string]string
|
|
err = json.Unmarshal(decoded, &config)
|
|
return config, err
|
|
}
|