From 4bc4f3a4cfc1dbb1feaaa4109c9777f658a89507 Mon Sep 17 00:00:00 2001 From: Nikos Filippakis Date: Wed, 17 Jun 2020 18:50:40 +0200 Subject: [PATCH] Replace mautrix.Client usage with BotClient for all services to use the e2ee-enabled client Signed-off-by: Nikos Filippakis --- api/handlers/service.go | 3 +- clients/bot_client.go | 23 +++++++-------- clients/clients.go | 34 +++++++++++----------- clients/clients_test.go | 4 +-- go.mod | 4 +-- go.sum | 6 ++++ services/alertmanager/alertmanager.go | 8 ++--- services/alertmanager/alertmanager_test.go | 2 +- services/echo/echo.go | 3 +- services/giphy/giphy.go | 5 ++-- services/github/github.go | 7 ++--- services/github/github_webhook.go | 7 ++--- services/google/google.go | 6 ++-- services/guggy/guggy.go | 5 ++-- services/imgur/imgur.go | 5 ++-- services/jira/jira.go | 9 +++--- services/rssbot/rssbot.go | 10 +++---- services/slackapi/slackapi.go | 6 ++-- services/travisci/travisci.go | 8 ++--- services/wikipedia/wikipedia.go | 5 ++-- types/service.go | 30 +++++++++++++------ 21 files changed, 94 insertions(+), 96 deletions(-) diff --git a/api/handlers/service.go b/api/handlers/service.go index d2450d9..cedcaef 100644 --- a/api/handlers/service.go +++ b/api/handlers/service.go @@ -16,7 +16,6 @@ import ( "github.com/matrix-org/go-neb/types" "github.com/matrix-org/util" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" ) // ConfigureService represents an HTTP handler which can process /admin/configureService requests. @@ -225,7 +224,7 @@ func (h *GetService) OnIncomingRequest(req *http.Request) util.JSONResponse { } } -func checkClientForService(service types.Service, client *mautrix.Client) error { +func checkClientForService(service types.Service, client *clients.BotClient) error { // If there are any commands or expansions for this Service then the service user ID // MUST be a syncing client or else the Service will never get the incoming command/expansion! cmds := service.Commands(client) diff --git a/clients/bot_client.go b/clients/bot_client.go index 0226a18..74a6202 100644 --- a/clients/bot_client.go +++ b/clients/bot_client.go @@ -14,8 +14,8 @@ import ( // It can be used for sending messages and retrieving information about the rooms that // the client has joined. type BotClient struct { + *mautrix.Client config api.ClientConfig - client *mautrix.Client olmMachine *crypto.OlmMachine stateStore *NebStateStore } @@ -68,34 +68,31 @@ func (botClient *BotClient) DecryptMegolmEvent(evt *mevt.Event) (*mevt.Event, er // SendMessageEvent sends the given content to the given room ID using this BotClient as a message event. // If the target room has enabled encryption, a megolm session is created if one doesn't already exist // and the message is sent after being encrypted. -func (botClient *BotClient) SendMessageEvent(content interface{}, roomID id.RoomID) error { - evtType := mevt.EventMessage +func (botClient *BotClient) SendMessageEvent(roomID id.RoomID, evtType mevt.Type, content interface{}, + extra ...mautrix.ReqSendEvent) (*mautrix.RespSendEvent, error) { + olmMachine := botClient.olmMachine if olmMachine.StateStore.IsEncrypted(roomID) { // Check if there is already a megolm session if sess, err := olmMachine.CryptoStore.GetOutboundGroupSession(roomID); err != nil { - return err + return nil, err } else if sess == nil || sess.Expired() || !sess.Shared { // No error but valid, shared session does not exist memberIDs, err := botClient.stateStore.GetJoinedMembers(roomID) if err != nil { - return err + return nil, err } // Share group session with room members if err = olmMachine.ShareGroupSession(roomID, memberIDs); err != nil { - return err + return nil, err } } - msgContent := mevt.Content{Parsed: content} - enc, err := olmMachine.EncryptMegolmEvent(roomID, mevt.EventMessage, msgContent) + enc, err := olmMachine.EncryptMegolmEvent(roomID, mevt.EventMessage, content) if err != nil { - return err + return nil, err } content = enc evtType = mevt.EventEncrypted } - if _, err := botClient.client.SendMessageEvent(roomID, evtType, content); err != nil { - return err - } - return nil + return botClient.Client.SendMessageEvent(roomID, evtType, content, extra...) } diff --git a/clients/clients.go b/clients/clients.go index e29e0c5..b638dbe 100644 --- a/clients/clients.go +++ b/clients/clients.go @@ -40,13 +40,13 @@ func New(db database.Storer, cli *http.Client) *Clients { } // Client gets a client for the userID -func (c *Clients) Client(userID id.UserID) (*mautrix.Client, error) { +func (c *Clients) Client(userID id.UserID) (*BotClient, error) { entry := c.getClient(userID) - if entry.client != nil { - return entry.client, nil + if entry.Client != nil { + return &entry, nil } entry, err := c.loadClientFromDB(userID) - return entry.client, err + return &entry, err } // Update updates the config for a matrix client @@ -88,7 +88,7 @@ func (c *Clients) loadClientFromDB(userID id.UserID) (entry BotClient, err error defer c.dbMutex.Unlock() entry = c.getClient(userID) - if entry.client != nil { + if entry.Client != nil { return } @@ -112,7 +112,7 @@ func (c *Clients) updateClientInDB(newConfig api.ClientConfig) (new, old BotClie defer c.dbMutex.Unlock() old = c.getClient(newConfig.UserID) - if old.client != nil && old.config == newConfig { + if old.Client != nil && old.config == newConfig { // Already have a client with that config. new = old return @@ -126,7 +126,7 @@ func (c *Clients) updateClientInDB(newConfig api.ClientConfig) (new, old BotClie // set the new display name if they differ if old.config.DisplayName != new.config.DisplayName { - if err := new.client.SetDisplayName(new.config.DisplayName); err != nil { + if err := new.SetDisplayName(new.config.DisplayName); err != nil { // whine about it but don't stop: this isn't fatal. log.WithFields(log.Fields{ log.ErrorKey: err, @@ -137,12 +137,12 @@ func (c *Clients) updateClientInDB(newConfig api.ClientConfig) (new, old BotClie } if old.config, err = c.db.StoreMatrixClientConfig(new.config); err != nil { - new.client.StopSync() + new.StopSync() return } - if old.client != nil { - old.client.StopSync() + if old.Client != nil { + old.Client.StopSync() return } @@ -151,12 +151,12 @@ func (c *Clients) updateClientInDB(newConfig api.ClientConfig) (new, old BotClie } func (c *Clients) onMessageEvent(botClient *BotClient, event *mevt.Event) { - services, err := c.db.LoadServicesForUser(botClient.client.UserID) + services, err := c.db.LoadServicesForUser(botClient.UserID) if err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": event.RoomID, - "service_user_id": botClient.client.UserID, + "service_user_id": botClient.UserID, }).Warn("Error loading services") } @@ -191,17 +191,17 @@ func (c *Clients) onMessageEvent(botClient *BotClient, event *mevt.Event) { args = strings.Split(body[1:], " ") } - if response := runCommandForService(service.Commands(botClient.client), event, args); response != nil { + if response := runCommandForService(service.Commands(botClient), event, args); response != nil { responses = append(responses, response) } } else { // message isn't a command, it might need expanding - expansions := runExpansionsForService(service.Expansions(botClient.client), event, body) + expansions := runExpansionsForService(service.Expansions(botClient), event, body) responses = append(responses, expansions...) } } for _, content := range responses { - if err := botClient.SendMessageEvent(content, event.RoomID); err != nil { + if _, err := botClient.SendMessageEvent(event.RoomID, mevt.EventMessage, content); err != nil { log.WithFields(log.Fields{ "room_id": event.RoomID, "content": content, @@ -344,7 +344,7 @@ func (c *Clients) initClient(botClient *BotClient) error { client.Client = c.httpClient client.DeviceID = config.DeviceID - botClient.client = client + botClient.Client = client syncer := client.Syncer.(*mautrix.DefaultSyncer) @@ -369,7 +369,7 @@ func (c *Clients) initClient(botClient *BotClient) error { }) syncer.OnEventType(mevt.Type{Type: "m.room.bot.options", Class: mevt.UnknownEventType}, func(_ mautrix.EventSource, event *mevt.Event) { - c.onBotOptionsEvent(botClient.client, event) + c.onBotOptionsEvent(botClient.Client, event) }) if config.AutoJoinRooms { diff --git a/clients/clients_test.go b/clients/clients_test.go index dd04c2a..d133fe8 100644 --- a/clients/clients_test.go +++ b/clients/clients_test.go @@ -30,7 +30,7 @@ type MockService struct { commands []types.Command } -func (s *MockService) Commands(cli *mautrix.Client) []types.Command { +func (s *MockService) Commands(cli types.MatrixClient) []types.Command { return s.commands } @@ -76,7 +76,7 @@ func TestCommandParsing(t *testing.T) { clients := New(&store, cli) mxCli, _ := mautrix.NewClient("https://someplace.somewhere", "@service:user", "token") mxCli.Client = cli - botClient := BotClient{client: mxCli} + botClient := BotClient{Client: mxCli} for _, input := range commandParseTests { executedCmdArgs = []string{} diff --git a/go.mod b/go.mod index e5796a2..6ef508e 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/json-iterator/go v1.1.9 // indirect github.com/julienschmidt/httprouter v1.2.0 // indirect github.com/kr/pretty v0.1.0 // indirect - github.com/lib/pq v1.3.0 + github.com/lib/pq v1.7.0 github.com/matrix-org/dugong v0.0.0-20180820122854-51a565b5666b github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7 github.com/mattn/go-shellwords v1.0.10 @@ -51,5 +51,5 @@ require ( gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v2 v2.3.0 - maunium.net/go/mautrix v0.5.0-rc.1 + maunium.net/go/mautrix v0.5.5 ) diff --git a/go.sum b/go.sum index d285f74..d896bb6 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kyokomi/emoji v2.2.2+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY= +github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lithammer/fuzzysearch v1.1.0/go.mod h1:Bqx4wo8lTOFcJr3ckpY6HA9lEIOO0H5HrkJ5CsN56HQ= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/matrix-org/dugong v0.0.0-20180820122854-51a565b5666b h1:xpcmnpfUImRC4O2SAS/dmTcJENDXvGmLUzey76V1R3Q= @@ -94,6 +96,7 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw= github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c= +github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -208,6 +211,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200505041828-1ed23360d12c h1:zJ0mtu4jCalhKg6Oaukv6iIkb+cOvDrajDH9DH46Q4M= golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= @@ -264,5 +268,7 @@ maunium.net/go/mautrix v0.4.7 h1:jpclbeGcuiHPIWZFZhQJoxgZKP9f+9OLBPtcDNMFV/o= maunium.net/go/mautrix v0.4.7/go.mod h1:8Y+NqmROJyWYvvP4yPfX9tLM59VCfgE/kcQ0SeX68ho= maunium.net/go/mautrix v0.5.0-rc.1 h1:Ux2rwQfgf044lXjzCXmaY6VVJPcLioNzdN3okbOVIlg= maunium.net/go/mautrix v0.5.0-rc.1/go.mod h1:LnkFnB1yjCbb8V+upoEHDGvI/F38NHSTWYCe2RRJgSY= +maunium.net/go/mautrix v0.5.5 h1:e0Pql1FdxoNUudx2oXo1gZHMrqIh5MC72cdXEPIrYLA= +maunium.net/go/mautrix v0.5.5/go.mod h1:FLbMANzwqlsX2Fgm7SDe+E4I3wSa4UxJRKqS5wGkCwA= maunium.net/go/mauview v0.1.1/go.mod h1:3QBUiuLct9moP1LgDhCGIg0Ovxn38Bd2sGndnUOuj4o= maunium.net/go/tcell v0.2.0/go.mod h1:9Apcb3lNNS6C6lCqKT9UFp7BTRzHXfWE+/tgufsAMho= diff --git a/services/alertmanager/alertmanager.go b/services/alertmanager/alertmanager.go index a02e969..9f12fe5 100644 --- a/services/alertmanager/alertmanager.go +++ b/services/alertmanager/alertmanager.go @@ -13,7 +13,6 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -78,7 +77,7 @@ type WebhookNotification struct { } // OnReceiveWebhook receives requests from Alertmanager and sends requests to Matrix as a result. -func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { +func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli types.MatrixClient) { decoder := json.NewDecoder(req.Body) var notif WebhookNotification if err := decoder.Decode(¬if); err != nil { @@ -144,7 +143,7 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli } // Register makes sure the Config information supplied is valid. -func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { +func (s *Service) Register(oldService types.Service, client types.MatrixClient) error { s.WebhookURL = s.webhookEndpointURL for _, templates := range s.Rooms { // validate that we have at least a plain text template @@ -191,13 +190,12 @@ func (s *Service) PostRegister(oldService types.Service) { } } -func (s *Service) joinRooms(client *mautrix.Client) { +func (s *Service) joinRooms(client types.MatrixClient) { for roomID := range s.Rooms { if _, err := client.JoinRoom(roomID.String(), "", nil); err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": roomID, - "user_id": client.UserID, }).Error("Failed to join room") } } diff --git a/services/alertmanager/alertmanager_test.go b/services/alertmanager/alertmanager_test.go index e752144..d0a9983 100644 --- a/services/alertmanager/alertmanager_test.go +++ b/services/alertmanager/alertmanager_test.go @@ -93,7 +93,7 @@ func TestNotify(t *testing.T) { } } -func buildTestClient(msgs *[]mevt.MessageEventContent) *mautrix.Client { +func buildTestClient(msgs *[]mevt.MessageEventContent) types.MatrixClient { matrixTrans := struct{ testutils.MockTransport }{} matrixTrans.RT = func(req *http.Request) (*http.Response, error) { if !strings.Contains(req.URL.String(), "/send/m.room.message") { diff --git a/services/echo/echo.go b/services/echo/echo.go index f10de5a..daf45f6 100644 --- a/services/echo/echo.go +++ b/services/echo/echo.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/matrix-org/go-neb/types" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -21,7 +20,7 @@ type Service struct { // Commands supported: // !echo some message // Responds with a notice of "some message". -func (e *Service) Commands(cli *mautrix.Client) []types.Command { +func (e *Service) Commands(cli types.MatrixClient) []types.Command { return []types.Command{ { Path: []string{"echo"}, diff --git a/services/giphy/giphy.go b/services/giphy/giphy.go index 0fd58ce..583b0fb 100644 --- a/services/giphy/giphy.go +++ b/services/giphy/giphy.go @@ -11,7 +11,6 @@ import ( "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" "maunium.net/go/mautrix/event" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -61,7 +60,7 @@ type Service struct { // Commands supported: // !giphy some search query without quotes // Responds with a suitable GIF into the same room as the command. -func (s *Service) Commands(client *mautrix.Client) []types.Command { +func (s *Service) Commands(client types.MatrixClient) []types.Command { return []types.Command{ types.Command{ Path: []string{"giphy"}, @@ -72,7 +71,7 @@ func (s *Service) Commands(client *mautrix.Client) []types.Command { } } -func (s *Service) cmdGiphy(client *mautrix.Client, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { +func (s *Service) cmdGiphy(client types.MatrixClient, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { // only 1 arg which is the text to search for. query := strings.Join(args, " ") gifResult, err := s.searchGiphy(query) diff --git a/services/github/github.go b/services/github/github.go index 702eda6..91b1515 100644 --- a/services/github/github.go +++ b/services/github/github.go @@ -22,7 +22,6 @@ import ( "github.com/matrix-org/go-neb/services/github/client" "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -563,7 +562,7 @@ func (s *Service) expandCommit(roomID id.RoomID, userID id.UserID, owner, repo, // Responds with the outcome of the issue comment creation request. This command requires // a Github account to be linked to the Matrix user ID issuing the command. If there // is no link, it will return a Starter Link instead. -func (s *Service) Commands(cli *mautrix.Client) []types.Command { +func (s *Service) Commands(cli types.MatrixClient) []types.Command { return []types.Command{ { Path: []string{"github", "search"}, @@ -632,7 +631,7 @@ func (s *Service) Commands(cli *mautrix.Client) []types.Command { // it will also expand strings of the form: // #12 // using the default repository. -func (s *Service) Expansions(cli *mautrix.Client) []types.Expansion { +func (s *Service) Expansions(cli types.MatrixClient) []types.Expansion { return []types.Expansion{ types.Expansion{ Regexp: ownerRepoIssueRegex, @@ -718,7 +717,7 @@ func (s *Service) Expansions(cli *mautrix.Client) []types.Expansion { } // Register makes sure that the given realm ID maps to a github realm. -func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { +func (s *Service) Register(oldService types.Service, client types.MatrixClient) error { if s.RealmID == "" { return fmt.Errorf("RealmID is required") } diff --git a/services/github/github_webhook.go b/services/github/github_webhook.go index 4c54d2e..6e43b00 100644 --- a/services/github/github_webhook.go +++ b/services/github/github_webhook.go @@ -13,7 +13,6 @@ import ( "github.com/matrix-org/go-neb/services/github/webhook" "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -82,7 +81,7 @@ type WebhookService struct { // // If the "owner/repo" string doesn't exist in this Service config, then the webhook will be deleted from // Github. -func (s *WebhookService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { +func (s *WebhookService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli types.MatrixClient) { evType, repo, msg, err := webhook.OnReceiveRequest(req, s.SecretToken) if err != nil { w.WriteHeader(err.Code) @@ -146,7 +145,7 @@ func (s *WebhookService) OnReceiveWebhook(w http.ResponseWriter, req *http.Reque // // Hooks can get out of sync if a user manually deletes a hook in the Github UI. In this case, toggling the repo configuration will // force NEB to recreate the hook. -func (s *WebhookService) Register(oldService types.Service, client *mautrix.Client) error { +func (s *WebhookService) Register(oldService types.Service, client types.MatrixClient) error { if s.RealmID == "" || s.ClientUserID == "" { return fmt.Errorf("RealmID and ClientUserID is required") } @@ -252,7 +251,7 @@ func (s *WebhookService) PostRegister(oldService types.Service) { } } -func (s *WebhookService) joinWebhookRooms(client *mautrix.Client) error { +func (s *WebhookService) joinWebhookRooms(client types.MatrixClient) error { for roomID := range s.Rooms { if _, err := client.JoinRoom(roomID.String(), "", nil); err != nil { // TODO: Leave the rooms we successfully joined? diff --git a/services/google/google.go b/services/google/google.go index 6d456f2..64719b9 100644 --- a/services/google/google.go +++ b/services/google/google.go @@ -13,7 +13,6 @@ import ( "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -70,7 +69,7 @@ type Service struct { // Commands supported: // !google image some_search_query_without_quotes // Responds with a suitable image into the same room as the command. -func (s *Service) Commands(client *mautrix.Client) []types.Command { +func (s *Service) Commands(client types.MatrixClient) []types.Command { return []types.Command{ { Path: []string{"google", "image"}, @@ -101,7 +100,8 @@ func usageMessage() *mevt.MessageEventContent { } } -func (s *Service) cmdGoogleImgSearch(client *mautrix.Client, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { +func (s *Service) cmdGoogleImgSearch(client types.MatrixClient, roomID id.RoomID, userID id.UserID, + args []string) (interface{}, error) { if len(args) < 1 { return usageMessage(), nil diff --git a/services/guggy/guggy.go b/services/guggy/guggy.go index 33b8020..6c1b9c7 100644 --- a/services/guggy/guggy.go +++ b/services/guggy/guggy.go @@ -12,7 +12,6 @@ import ( "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -51,7 +50,7 @@ type Service struct { // Commands supported: // !guggy some search query without quotes // Responds with a suitable GIF into the same room as the command. -func (s *Service) Commands(client *mautrix.Client) []types.Command { +func (s *Service) Commands(client types.MatrixClient) []types.Command { return []types.Command{ { Path: []string{"guggy"}, @@ -61,7 +60,7 @@ func (s *Service) Commands(client *mautrix.Client) []types.Command { }, } } -func (s *Service) cmdGuggy(client *mautrix.Client, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { +func (s *Service) cmdGuggy(client types.MatrixClient, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { // only 1 arg which is the text to search for. querySentence := strings.Join(args, " ") gifResult, err := s.text2gifGuggy(querySentence) diff --git a/services/imgur/imgur.go b/services/imgur/imgur.go index 4193cdb..af3dc71 100644 --- a/services/imgur/imgur.go +++ b/services/imgur/imgur.go @@ -12,7 +12,6 @@ import ( "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -116,7 +115,7 @@ type Service struct { // Commands supported: // !imgur some_search_query_without_quotes // Responds with a suitable image into the same room as the command. -func (s *Service) Commands(client *mautrix.Client) []types.Command { +func (s *Service) Commands(client types.MatrixClient) []types.Command { return []types.Command{ { Path: []string{"imgur", "help"}, @@ -142,7 +141,7 @@ func usageMessage() *mevt.MessageEventContent { } // Search Imgur for a relevant image and upload it to matrix -func (s *Service) cmdImgSearch(client *mautrix.Client, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { +func (s *Service) cmdImgSearch(client types.MatrixClient, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { // Check for query text if len(args) < 1 { return usageMessage(), nil diff --git a/services/jira/jira.go b/services/jira/jira.go index 9b9bf4a..91e3400 100644 --- a/services/jira/jira.go +++ b/services/jira/jira.go @@ -21,7 +21,6 @@ import ( "github.com/matrix-org/go-neb/services/utils" "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -76,7 +75,7 @@ type Service struct { // Register ensures that the given realm IDs are valid JIRA realms and registers webhooks // with those JIRA endpoints. -func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { +func (s *Service) Register(oldService types.Service, client types.MatrixClient) error { // We only ever make 1 JIRA webhook which listens for all projects and then filter // on receive. So we simply need to know if we need to make a webhook or not. We // need to do this for each unique realm. @@ -242,7 +241,7 @@ func (s *Service) expandIssue(roomID id.RoomID, userID id.UserID, issueKeyGroups // same project key, which project is chosen is undefined. If there // is no JIRA account linked to the Matrix user ID, it will return a Starter Link // if there is a known public project with that project key. -func (s *Service) Commands(cli *mautrix.Client) []types.Command { +func (s *Service) Commands(cli types.MatrixClient) []types.Command { return []types.Command{ types.Command{ Path: []string{"jira", "create"}, @@ -259,7 +258,7 @@ func (s *Service) Commands(cli *mautrix.Client) []types.Command { // to map the project key to a realm, and subsequently the JIRA endpoint to hit. // If there are multiple projects with the same project key in the Service Config, one will // be chosen arbitrarily. -func (s *Service) Expansions(cli *mautrix.Client) []types.Expansion { +func (s *Service) Expansions(cli types.MatrixClient) []types.Expansion { return []types.Expansion{ { Regexp: issueKeyRegex, @@ -271,7 +270,7 @@ func (s *Service) Expansions(cli *mautrix.Client) []types.Expansion { } // OnReceiveWebhook receives requests from JIRA and possibly sends requests to Matrix as a result. -func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { +func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli types.MatrixClient) { eventProjectKey, event, httpErr := webhook.OnReceiveRequest(req) if httpErr != nil { log.Print("Failed to handle JIRA webhook") diff --git a/services/rssbot/rssbot.go b/services/rssbot/rssbot.go index 251c282..c339975 100644 --- a/services/rssbot/rssbot.go +++ b/services/rssbot/rssbot.go @@ -19,7 +19,6 @@ import ( "github.com/mmcdole/gofeed" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -102,7 +101,7 @@ type Service struct { } // Register will check the liveness of each RSS feed given. If all feeds check out okay, no error is returned. -func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { +func (s *Service) Register(oldService types.Service, client types.MatrixClient) error { if len(s.Feeds) == 0 { // this is an error UNLESS the old service had some feeds in which case they are deleting us :( var numOldFeeds int @@ -131,7 +130,7 @@ func (s *Service) Register(oldService types.Service, client *mautrix.Client) err return nil } -func (s *Service) joinRooms(client *mautrix.Client) { +func (s *Service) joinRooms(client types.MatrixClient) { roomSet := make(map[id.RoomID]bool) for _, feedInfo := range s.Feeds { for _, roomID := range feedInfo.Rooms { @@ -144,7 +143,6 @@ func (s *Service) joinRooms(client *mautrix.Client) { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": roomID, - "user_id": client.UserID, }).Error("Failed to join room") } } @@ -175,7 +173,7 @@ func (s *Service) PostRegister(oldService types.Service) { // - Else if there is a Title field, use it as the GUID. // // Returns a timestamp representing when this Service should have OnPoll called again. -func (s *Service) OnPoll(cli *mautrix.Client) time.Time { +func (s *Service) OnPoll(cli types.MatrixClient) time.Time { logger := log.WithFields(log.Fields{ "service_id": s.ServiceID(), "service_type": s.ServiceType(), @@ -408,7 +406,7 @@ func (s *Service) newItems(feedURL string, allItems []*gofeed.Item) (items []gof return } -func (s *Service) sendToRooms(cli *mautrix.Client, feedURL string, feed *gofeed.Feed, item gofeed.Item) error { +func (s *Service) sendToRooms(cli types.MatrixClient, feedURL string, feed *gofeed.Feed, item gofeed.Item) error { logger := log.WithFields(log.Fields{ "feed_url": feedURL, "title": item.Title, diff --git a/services/slackapi/slackapi.go b/services/slackapi/slackapi.go index 327d4ad..75eb3b7 100644 --- a/services/slackapi/slackapi.go +++ b/services/slackapi/slackapi.go @@ -6,7 +6,6 @@ import ( "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -37,7 +36,7 @@ type Service struct { // to Matrix as a result. // // This requires that the WebhookURL is given to an outgoing slack webhook (see https://api.slack.com/outgoing-webhooks) -func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { +func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli types.MatrixClient) { segments := strings.Split(req.URL.Path, "/") if len(segments) < 2 { @@ -72,13 +71,12 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli } // Register joins the configured room and sets the public WebhookURL -func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { +func (s *Service) Register(oldService types.Service, client types.MatrixClient) error { s.WebhookURL = s.webhookEndpointURL if _, err := client.JoinRoom(s.RoomID.String(), "", nil); err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": s.RoomID, - "user_id": client.UserID, }).Error("Failed to join room") } return nil diff --git a/services/travisci/travisci.go b/services/travisci/travisci.go index 837389c..b6b7b24 100644 --- a/services/travisci/travisci.go +++ b/services/travisci/travisci.go @@ -13,7 +13,6 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -180,7 +179,7 @@ func outputForTemplate(travisTmpl string, tmpl map[string]string) (out string) { // webhooks: http://go-neb-endpoint.com/notifications // // See https://docs.travis-ci.com/user/notifications#Webhook-notifications for more information. -func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { +func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli types.MatrixClient) { if err := req.ParseForm(); err != nil { log.WithError(err).Error("Failed to read incoming Travis-CI webhook form") w.WriteHeader(400) @@ -243,7 +242,7 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli } // Register makes sure the Config information supplied is valid. -func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { +func (s *Service) Register(oldService types.Service, client types.MatrixClient) error { s.WebhookURL = s.webhookEndpointURL for _, roomData := range s.Rooms { for repo := range roomData.Repos { @@ -275,13 +274,12 @@ func (s *Service) PostRegister(oldService types.Service) { } } -func (s *Service) joinRooms(client *mautrix.Client) { +func (s *Service) joinRooms(client types.MatrixClient) { for roomID := range s.Rooms { if _, err := client.JoinRoom(roomID.String(), "", nil); err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": roomID, - "user_id": client.UserID, }).Error("Failed to join room") } } diff --git a/services/wikipedia/wikipedia.go b/services/wikipedia/wikipedia.go index ae3fa2f..b99138b 100644 --- a/services/wikipedia/wikipedia.go +++ b/services/wikipedia/wikipedia.go @@ -12,7 +12,6 @@ import ( "github.com/jaytaylor/html2text" "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" - "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -51,7 +50,7 @@ type Service struct { // Commands supported: // !wikipedia some_search_query_without_quotes // Responds with a suitable article extract and link to the referenced page into the same room as the command. -func (s *Service) Commands(client *mautrix.Client) []types.Command { +func (s *Service) Commands(client types.MatrixClient) []types.Command { return []types.Command{ { Path: []string{"wikipedia"}, @@ -70,7 +69,7 @@ func usageMessage() *mevt.MessageEventContent { } } -func (s *Service) cmdWikipediaSearch(client *mautrix.Client, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { +func (s *Service) cmdWikipediaSearch(client types.MatrixClient, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { // Check for query text if len(args) < 1 { return usageMessage(), nil diff --git a/types/service.go b/types/service.go index a4e1105..5f208d0 100644 --- a/types/service.go +++ b/types/service.go @@ -9,6 +9,7 @@ import ( "time" "maunium.net/go/mautrix" + "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -24,7 +25,18 @@ type BotOptions struct { type Poller interface { // OnPoll is called when the poller should poll. Return the timestamp when you want to be polled again. // Return 0 to never be polled again. - OnPoll(client *mautrix.Client) time.Time + OnPoll(client MatrixClient) time.Time +} + +// MatrixClient represents an object that can communicate with a Matrix server in certain ways that services require. +type MatrixClient interface { + // Join a room by ID or alias. Content can optionally specify the request body. + JoinRoom(roomIDorAlias, serverName string, content interface{}) (resp *mautrix.RespJoinRoom, err error) + // Send a message event to a room. + SendMessageEvent(roomID id.RoomID, eventType event.Type, contentJSON interface{}, + extra ...mautrix.ReqSendEvent) (resp *mautrix.RespSendEvent, err error) + // Upload an HTTP URL. + UploadLink(link string) (*mautrix.RespMediaUpload, error) } // A Service is the configuration for a bot service. @@ -35,14 +47,14 @@ type Service interface { ServiceID() string // Return the type of service. This string MUST NOT change. ServiceType() string - Commands(cli *mautrix.Client) []Command - Expansions(cli *mautrix.Client) []Expansion - OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) + Commands(cli MatrixClient) []Command + Expansions(cli MatrixClient) []Expansion + OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli MatrixClient) // A lifecycle function which is invoked when the service is being registered. The old service, if one exists, is provided, // along with a Client instance for ServiceUserID(). If this function returns an error, the service will not be registered // or persisted to the database, and the user's request will fail. This can be useful if you depend on external factors // such as registering webhooks. - Register(oldService Service, client *mautrix.Client) error + Register(oldService Service, client MatrixClient) error // A lifecycle function which is invoked after the service has been successfully registered and persisted to the database. // This function is invoked within the critical section for configuring services, guaranteeing that there will not be // concurrent modifications to this service whilst this function executes. This lifecycle hook should be used to clean @@ -83,23 +95,23 @@ func (s *DefaultService) ServiceType() string { } // Commands returns no commands. -func (s *DefaultService) Commands(cli *mautrix.Client) []Command { +func (s *DefaultService) Commands(cli MatrixClient) []Command { return []Command{} } // Expansions returns no expansions. -func (s *DefaultService) Expansions(cli *mautrix.Client) []Expansion { +func (s *DefaultService) Expansions(cli MatrixClient) []Expansion { return []Expansion{} } // Register does nothing and returns no error. -func (s *DefaultService) Register(oldService Service, client *mautrix.Client) error { return nil } +func (s *DefaultService) Register(oldService Service, cli MatrixClient) error { return nil } // PostRegister does nothing. func (s *DefaultService) PostRegister(oldService Service) {} // OnReceiveWebhook does nothing but 200 OK the request. -func (s *DefaultService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { +func (s *DefaultService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli MatrixClient) { w.WriteHeader(200) // Do nothing }