aboutsummaryrefslogtreecommitdiff
path: root/util.go
blob: 4e23bb165dcad26047b97fe9eb1fefb19fc2aa58 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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 != "" && dbKvTestAndSet(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, "")
		}
	}

	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.Fatal("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
}