Allow _ezbr_ to be put in suffix of usernames/room aliases instead of prefix
This commit is contained in:
parent
38a3f1bdb1
commit
2649e41c85
6 changed files with 92 additions and 27 deletions
19
README.md
19
README.md
|
@ -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
23
db.go
|
@ -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
26
main.go
|
@ -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{},
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
29
util.go
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue