Allow _ezbr_ to be put in suffix of usernames/room aliases instead of prefix

This commit is contained in:
Alex 2020-02-29 10:51:09 +01:00
parent 38a3f1bdb1
commit 2649e41c85
6 changed files with 92 additions and 27 deletions

View file

@ -48,11 +48,22 @@ Easybridge is configured using a single JSON configuration file, which contains
a dictionnary whose keys are the following: a dictionnary whose keys are the following:
- `log_level`: what log level Easybridge runs with (trace, debug, info, warn, error, fatal, panic). **Warning:** in `trace` level, the content of all calls to the Matrix API and some other information will be dumped, exposing user's credentials and messages. In `debug` level, room join/leave information will be exposed. The `info` level (default) does not expose any user's private information. - `log_level`: what log level Easybridge runs with (trace, debug, info, warn, error, fatal, panic). **Warning:** in `trace` level, the content of all calls to the Matrix API and some other information will be dumped, exposing user's credentials and messages. In `debug` level, room join/leave information will be exposed. The `info` level (default) does not expose any user's private information.
- `easybridge_avatar`: path to the image that Easybridge uses as an avatar on Matrix
### Matrix configuration
- `registration`: path to the YAML appservice registration file
- `appservice_bind_addr`: on what IP/port to bind as a Matrix app service (HTTP only, no HTTPS) - `appservice_bind_addr`: on what IP/port to bind as a Matrix app service (HTTP only, no HTTPS)
- `homeserver_url`: HTTP address of the Matrix homeserver
- `matrix_domain`: the domain name of the Matrix homeserver (i.e. the domain used in user identifiers, room identifiers, etc)
- `name_format`: the format of identifiers that are created on Matrix for users and room aliases. `{}` is replaced by the concatenation of user/room identifier and protocol. Typically you want either `_ezbr_{}` or `{}_ezbr`, the latter having the advantage that the briged user's names are then used as prefixes for the created identifiers.
### Web interface configuration
- `web_bind_addr`: on what IP/port to bind for the web interface that allows adding and configuring accounts (HTTP only, no HTTPS, use a reverse proxy for that) - `web_bind_addr`: on what IP/port to bind for the web interface that allows adding and configuring accounts (HTTP only, no HTTPS, use a reverse proxy for that)
- `web_url`: the outside HTTP/HTTPS address at which the web interface is made available. If set, a widget will be added in the Easybridge room so that users can configure the bridge without leaving the Riot client. - `web_url`: the outside HTTP/HTTPS address at which the web interface is made available. If set, a widget will be added in the Easybridge room so that users can configure the bridge without leaving the Riot client.
- `registration`: path to the YAML appservice registration file
- `homeserver_url`: HTTP address of the Matrix homeserver
- `matrix_domain`: the dmoain name of the Matrix homeserver (i.e. the domain used in user identifiers, room identifiers, etc)
- `db_type` and `db_path`: the database backend and path to use (see the [Gorm documentation](http://gorm.io/docs/connecting_to_the_database.html))
- `session_key`: a key with which session cookies are encrypted for the web interface - `session_key`: a key with which session cookies are encrypted for the web interface
### Storage configuration
- `db_type` and `db_path`: the database backend and path to use (see the [Gorm documentation](http://gorm.io/docs/connecting_to_the_database.html))

23
db.go
View file

@ -213,18 +213,21 @@ func dbGetMxRoom(protocol string, roomId connector.RoomID) (string, error) {
if must_create { if must_create {
alias := roomAlias(protocol, roomId) alias := roomAlias(protocol, roomId)
// Lookup alias
mx_room_id, err := mx.DirectoryRoom(fmt.Sprintf("#%s:%s", alias, config.MatrixDomain))
// If no alias found, create room // Delete previous alias if it existed
prev_full_alias := fmt.Sprintf("#%s:%s", alias, config.MatrixDomain)
mx_room_id, err := mx.DirectoryRoom(prev_full_alias)
if err == nil {
mx.DirectoryDeleteRoom(prev_full_alias)
}
// Create room
name := fmt.Sprintf("%s (%s)", roomId, protocol)
mx_room_id, err = mx.CreateRoom(name, alias, []string{})
if err != nil { if err != nil {
name := fmt.Sprintf("%s (%s)", roomId, protocol) log.Warnf("Could not create room for %s: %s", name, err)
return "", err
mx_room_id, err = mx.CreateRoom(name, alias, []string{})
if err != nil {
log.Warnf("Could not create room for %s: %s", name, err)
return "", err
}
} }
room = DbRoomMap{ room = DbRoomMap{

26
main.go
View file

@ -15,17 +15,22 @@ import (
) )
type ConfigFile struct { type ConfigFile struct {
LogLevel string `json:"log_level"` LogLevel string `json:"log_level"`
ASBindAddr string `json:"appservice_bind_addr"`
WebBindAddr string `json:"web_bind_addr"`
WebURL string `json:"web_url"`
Registration string `json:"registration"` Registration string `json:"registration"`
ASBindAddr string `json:"appservice_bind_addr"`
Server string `json:"homeserver_url"` Server string `json:"homeserver_url"`
DbType string `json:"db_type"`
DbPath string `json:"db_path"`
MatrixDomain string `json:"matrix_domain"` MatrixDomain string `json:"matrix_domain"`
SessionKey string `json:"web_session_key"` NameFormat string `json:"name_format"`
AvatarFile string `json:"easybridge_avatar"`
WebBindAddr string `json:"web_bind_addr"`
WebURL string `json:"web_url"`
SessionKey string `json:"web_session_key"`
DbType string `json:"db_type"`
DbPath string `json:"db_path"`
AvatarFile string `json:"easybridge_avatar"`
} }
var configFlag = flag.String("config", "./config.json", "Configuration file path") var configFlag = flag.String("config", "./config.json", "Configuration file path")
@ -43,6 +48,7 @@ func readConfig() ConfigFile {
WebBindAddr: "0.0.0.0:8281", WebBindAddr: "0.0.0.0:8281",
Registration: "./registration.yaml", Registration: "./registration.yaml",
Server: "http://localhost:8008", Server: "http://localhost:8008",
NameFormat: "{}_ezbr_",
DbType: "sqlite3", DbType: "sqlite3",
DbPath: "easybridge.db", DbPath: "easybridge.db",
AvatarFile: "./easybridge.jpg", AvatarFile: "./easybridge.jpg",
@ -102,13 +108,13 @@ func readRegistration(file string) mxlib.Registration {
Users: []mxlib.RegistrationNamespace{ Users: []mxlib.RegistrationNamespace{
mxlib.RegistrationNamespace{ mxlib.RegistrationNamespace{
Exclusive: true, Exclusive: true,
Regex: "@_ezbr_.*", Regex: "@.*_ezbr_",
}, },
}, },
Aliases: []mxlib.RegistrationNamespace{ Aliases: []mxlib.RegistrationNamespace{
mxlib.RegistrationNamespace{ mxlib.RegistrationNamespace{
Exclusive: true, Exclusive: true,
Regex: "#_ezbr_.*", Regex: "#.*_ezbr_",
}, },
}, },
Rooms: []mxlib.RegistrationNamespace{}, Rooms: []mxlib.RegistrationNamespace{},

View file

@ -78,6 +78,17 @@ func (mx *Client) PostApiCall(endpoint string, data interface{}, response interf
return mx.DoAndParse(req, response) return mx.DoAndParse(req, response)
} }
func (mx *Client) DeleteApiCall(endpoint string, response interface{}) error {
log.Debugf("Matrix DELETE request: %s\n", endpoint)
req, err := http.NewRequest("DELETE", mx.Server+endpoint, nil)
if err != nil {
return err
}
return mx.DoAndParse(req, response)
}
func (mx *Client) DoAndParse(req *http.Request, response interface{}) error { func (mx *Client) DoAndParse(req *http.Request, response interface{}) error {
if mx.Token != "" { if mx.Token != "" {
req.Header.Add("Authorization", "Bearer "+mx.Token) req.Header.Add("Authorization", "Bearer "+mx.Token)
@ -181,6 +192,15 @@ func (mx *Client) DirectoryRoom(alias string) (string, error) {
return rep.RoomId, nil return rep.RoomId, nil
} }
func (mx *Client) DirectoryDeleteRoom(alias string) error {
var rep struct{}
err := mx.DeleteApiCall("/_matrix/client/r0/directory/room/"+url.QueryEscape(alias), &rep)
if err != nil {
return err
}
return nil
}
func (mx *Client) CreateRoom(name string, alias string, invite []string) (string, error) { func (mx *Client) CreateRoom(name string, alias string, invite []string) (string, error) {
rq := CreateRoomRequest{ rq := CreateRoomRequest{
Preset: "private_chat", Preset: "private_chat",

View file

@ -102,7 +102,7 @@ func handleTxn(w http.ResponseWriter, r *http.Request) {
for i := range txn.Events { for i := range txn.Events {
ev := &txn.Events[i] ev := &txn.Events[i]
if strings.HasPrefix(ev.Sender, "@"+registration.SenderLocalpart) { if isBridgedIdentifier(ev.Sender) {
// Don't do anything with ezbr events that come back to us // Don't do anything with ezbr events that come back to us
continue continue
} }

29
util.go
View file

@ -5,6 +5,7 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings"
"unicode" "unicode"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -58,11 +59,13 @@ func ezbrSystemSendf(user_mx_id string, format string, args ...interface{}) {
// ---- // ----
func roomAlias(protocol string, id RoomID) string { func roomAlias(protocol string, id RoomID) string {
return fmt.Sprintf("%s_%s__%s", registration.SenderLocalpart, safeStringForId(string(id)), protocol) what := fmt.Sprintf("%s_%s", safeStringForId(string(id)), protocol)
return strings.Replace(config.NameFormat, "{}", what, 1)
} }
func userMxId(protocol string, id UserID) string { func userMxId(protocol string, id UserID) string {
return fmt.Sprintf("%s_%s__%s", registration.SenderLocalpart, safeStringForId(string(id)), protocol) what := fmt.Sprintf("%s_%s", safeStringForId(string(id)), protocol)
return strings.Replace(config.NameFormat, "{}", what, 1)
} }
func safeStringForId(in string) string { func safeStringForId(in string) string {
@ -79,6 +82,28 @@ func safeStringForId(in string) string {
return id2 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 // ---- Encoding and encryption of account config
func encryptAccountConfig(config map[string]string, key *[32]byte) string { func encryptAccountConfig(config map[string]string, key *[32]byte) string {