aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2020-02-26 20:21:32 +0100
committerAlex Auvolat <alex@adnab.me>2020-02-26 20:21:32 +0100
commitf675ba57e400d378088d29c08bd5d0bd9126c74b (patch)
treec5d54b55b9f8a1bbb5e12cafb3da846124a2f821
parentd1b66d30883c9e5fda0c4cace494dec74d7df024 (diff)
downloadeasybridge-f675ba57e400d378088d29c08bd5d0bd9126c74b.tar.gz
easybridge-f675ba57e400d378088d29c08bd5d0bd9126c74b.zip
Implement account configuration save/load from db
-rw-r--r--account.go7
-rw-r--r--db.go14
-rw-r--r--go.sum2
-rw-r--r--main.go30
-rw-r--r--util.go42
-rw-r--r--web.go64
6 files changed, 141 insertions, 18 deletions
diff --git a/account.go b/account.go
index 6be12e7..c17fb2f 100644
--- a/account.go
+++ b/account.go
@@ -14,6 +14,7 @@ type Account struct {
MatrixUser string
AccountName string
Protocol string
+ Config map[string]string
Conn Connector
JoinedRooms map[RoomID]bool
@@ -77,7 +78,7 @@ func (a *Account) ezbrMessagef(format string, args ...interface{}) {
ezbrSystemSend(a.MatrixUser, msg)
}
-func (a *Account) connect(config map[string]string, join_rooms []string) {
+func (a *Account) connect(config map[string]string) {
ezbrSystemSendf(a.MatrixUser, "Connecting to account %s (%s)", a.AccountName, a.Protocol)
err := a.Conn.Configure(config)
@@ -86,10 +87,6 @@ func (a *Account) connect(config map[string]string, join_rooms []string) {
return
}
- for _, room := range join_rooms {
- a.addAutojoin(RoomID(room))
- }
-
var autojoin []DbJoinedRoom
db.Where(&DbJoinedRoom{
MxUserID: a.MatrixUser,
diff --git a/db.go b/db.go
index 602bd1f..c5f74ef 100644
--- a/db.go
+++ b/db.go
@@ -25,6 +25,8 @@ func InitDb() error {
return err
}
+ db.AutoMigrate(&DbAccountConfig{})
+
db.AutoMigrate(&DbCache{})
db.AutoMigrate(&DbUserMap{})
@@ -42,6 +44,16 @@ func InitDb() error {
return nil
}
+// Account configuration
+type DbAccountConfig struct {
+ gorm.Model
+
+ MxUserID string `gorm:"index:account_mxuserid"`
+ Name string
+ Protocol string
+ Config string
+}
+
// Long-term cache entries
type DbCache struct {
gorm.Model
@@ -56,7 +68,7 @@ type DbUserMap struct {
Protocol string
UserID connector.UserID
- MxUserID string `gorm:"index:mxuserid"`
+ MxUserID string `gorm:"index:usermap_mxuserid"`
}
// Room mapping between Matrix rooms and outside rooms
diff --git a/go.sum b/go.sum
index 83d9db7..31d4c85 100644
--- a/go.sum
+++ b/go.sum
@@ -106,6 +106,7 @@ github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2/go.mod
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -274,6 +275,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
diff --git a/main.go b/main.go
index 1b3971e..a8a349c 100644
--- a/main.go
+++ b/main.go
@@ -24,7 +24,6 @@ import (
type ConfigAccount struct {
Protocol string `json:"protocol"`
- Rooms []string `json:"rooms"`
Config map[string]string `json:"config"`
}
@@ -176,27 +175,21 @@ func main() {
for user, accounts := range config.Accounts {
for name, params := range accounts {
- var conn connector.Connector
- switch params.Protocol {
- case "irc":
- conn = &irc.IRC{}
- case "xmpp":
- conn = &xmpp.XMPP{}
- case "mattermost":
- conn = &mattermost.Mattermost{}
- default:
- log.Fatalf("Invalid protocol %s", params.Protocol)
+ conn := createConnector(params.Protocol)
+ if conn == nil {
+ log.Fatalf("Could not create connector for protocol %s", params.Protocol)
}
account := &Account{
MatrixUser: fmt.Sprintf("@%s:%s", user, config.MatrixDomain),
AccountName: name,
Protocol: params.Protocol,
+ Config: params.Config,
Conn: conn,
JoinedRooms: map[connector.RoomID]bool{},
}
conn.SetHandler(account)
AddAccount(account)
- go account.connect(params.Config, params.Rooms)
+ go account.connect(params.Config)
}
}
@@ -205,3 +198,16 @@ func main() {
log.Fatal(err)
}
}
+
+func createConnector(protocol string) connector.Connector {
+ switch protocol {
+ case "irc":
+ return &irc.IRC{}
+ case "xmpp":
+ return &xmpp.XMPP{}
+ case "mattermost":
+ return &mattermost.Mattermost{}
+ default:
+ return nil
+ }
+}
diff --git a/util.go b/util.go
index c1da665..323f99d 100644
--- a/util.go
+++ b/util.go
@@ -1,10 +1,14 @@
package main
import (
+ "crypto/rand"
+ "encoding/base64"
+ "encoding/json"
"fmt"
"unicode"
log "github.com/sirupsen/logrus"
+ "golang.org/x/crypto/nacl/secretbox"
. "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
)
@@ -56,3 +60,41 @@ func safeStringForId(in string) string {
}
return id2
}
+
+// ---- 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
+}
diff --git a/web.go b/web.go
index dafb8b1..bff8acc 100644
--- a/web.go
+++ b/web.go
@@ -9,13 +9,16 @@ import (
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
+ "golang.org/x/crypto/argon2"
+ "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
)
const SESSION_NAME = "easybridge_session"
var sessionsStore sessions.Store = nil
+var userKeys = map[string]*[32]byte{}
func StartWeb() {
session_key := make([]byte, 32)
@@ -147,6 +150,12 @@ func handleLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
return nil
}
+ key := new([32]byte)
+ key_slice := argon2.IDKey([]byte(password), []byte("EZBRIDGE account store"), 3, 64*1024, 4, 32)
+ copy(key[:], key_slice[:])
+ userKeys[mxid] = key
+ syncDbAccounts(mxid, key)
+
// Successfully logged in, save it to session
session, err := sessionsStore.Get(r, SESSION_NAME)
if err != nil {
@@ -169,3 +178,58 @@ func handleLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
return nil
}
}
+
+func syncDbAccounts(mxid string, key *[32]byte) {
+ accountsLock.Lock()
+ defer accountsLock.Unlock()
+
+ // 1. Save all accounts that we have
+ var accounts map[string]*Account
+ if accts, ok := registeredAccounts[mxid]; ok {
+ accounts = accts
+ for name, acct := range accts {
+ var entry DbAccountConfig
+ db.Where(&DbAccountConfig{
+ MxUserID: mxid,
+ Name: name,
+ }).Assign(&DbAccountConfig{
+ Protocol: acct.Protocol,
+ Config: encryptAccountConfig(acct.Config, key),
+ }).FirstOrCreate(&entry)
+ }
+ } else {
+ accounts = make(map[string]*Account)
+ registeredAccounts[mxid] = accounts
+ }
+
+ // 2. Load and start missing accounts
+ var allAccounts []DbAccountConfig
+ db.Where(&DbAccountConfig{MxUserID: mxid}).Find(&allAccounts)
+ for _, acct := range allAccounts {
+ if _, ok := accounts[acct.Name]; !ok {
+ config, err := decryptAccountConfig(acct.Config, key)
+ if err != nil {
+ ezbrSystemSendf("Could not decrypt stored configuration for account %s", acct.Name)
+ continue
+ }
+ conn := createConnector(acct.Protocol)
+ if conn == nil {
+ ezbrSystemSendf("Could not create connector for protocol %s", acct.Protocol)
+ continue
+ }
+ account := &Account{
+ MatrixUser: mxid,
+ AccountName: acct.Name,
+ Protocol: acct.Protocol,
+ Config: config,
+ Conn: conn,
+ JoinedRooms: map[connector.RoomID]bool{},
+ }
+ conn.SetHandler(account)
+
+ accounts[acct.Name] = account
+
+ go account.connect(config)
+ }
+ }
+}