diff --git a/.travis.yml b/.travis.yml index 723b9b8..5f53f5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,11 @@ +os: linux +dist: bionic language: go go: - 1.14 install: + - sudo apt-get update + - sudo apt-get -y install libolm2 libolm-dev - go get golang.org/x/lint/golint - go get github.com/fzipp/gocyclo diff --git a/Dockerfile b/Dockerfile index bcd1c58..df72004 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,11 @@ # Build go-neb FROM golang:1.14-alpine as builder -RUN apk add --no-cache -t build-deps git gcc musl-dev go +RUN apk add --no-cache -t build-deps git gcc musl-dev go make g++ + +RUN git clone https://gitlab.matrix.org/matrix-org/olm.git /tmp/libolm \ + && cd /tmp/libolm \ + && make install COPY . /tmp/go-neb WORKDIR /tmp/go-neb @@ -22,7 +26,11 @@ ENV BIND_ADDRESS=:4050 \ GID=1337 COPY --from=builder /tmp/go-neb/go-neb /usr/local/bin/go-neb +# Copy libolm.so +COPY --from=builder /usr/local/lib/* /usr/local/lib/ + RUN apk add --no-cache \ + libstdc++ \ ca-certificates \ su-exec \ s6 diff --git a/README.md b/README.md index 242393a..154e2ee 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,10 @@ Before submitting pull requests, please read the [Matrix.org contribution guidel # Developing +This project depends on `libolm` for the end-to-end encryption. Therefore, +you need to install `libolm2` and `libolm-dev` on Ubuntu / `libolm-devel` on +CentOS to be able to build and run it. + There's a bunch more tools this project uses when developing in order to do things like linting. Some of them are bundled with go (fmt and vet) but some are not. You should install the ones which are not: diff --git a/api/api.go b/api/api.go index 183dfd1..01ca8c1 100644 --- a/api/api.go +++ b/api/api.go @@ -12,6 +12,8 @@ import ( "encoding/json" "errors" "net/url" + + "maunium.net/go/mautrix/id" ) // ConfigureAuthRealmRequest is a request to /configureAuthRealm @@ -32,7 +34,7 @@ type RequestAuthSessionRequest struct { RealmID string // The Matrix user ID requesting the auth session. If the auth is successful, // this user ID will be associated with the third-party credentials obtained. - UserID string + UserID id.UserID // AuthRealm specific config information. See the docs for the auth realm you're interested in. Config json.RawMessage } @@ -47,7 +49,7 @@ type ConfigureServiceRequest struct { Type string // The user ID of the configured client that this service will use to communicate with Matrix. // The user MUST already be configured. - UserID string + UserID id.UserID // Service-specific config information. See the docs for the service you're interested in. Config json.RawMessage } @@ -56,7 +58,7 @@ type ConfigureServiceRequest struct { // Go-NEB can drive it. It forms the HTTP body to /configureClient requests. type ClientConfig struct { // The matrix User ID to connect with. E.g. @alice:matrix.org - UserID string + UserID id.UserID // A URL with the host and port of the matrix server. E.g. https://matrix.org:8448 HomeserverURL string // The matrix access token to authenticate the requests with. @@ -81,7 +83,7 @@ type ClientConfig struct { type Session struct { SessionID string RealmID string - UserID string + UserID id.UserID Config json.RawMessage } diff --git a/api/handlers/auth.go b/api/handlers/auth.go index 0f6d220..d6835d9 100644 --- a/api/handlers/auth.go +++ b/api/handlers/auth.go @@ -13,6 +13,7 @@ import ( "github.com/matrix-org/go-neb/types" "github.com/matrix-org/util" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix/id" ) // RequestAuthSession represents an HTTP handler capable of processing /admin/requestAuthSession requests. @@ -104,7 +105,7 @@ func (h *RemoveAuthSession) OnIncomingRequest(req *http.Request) util.JSONRespon } var body struct { RealmID string - UserID string + UserID id.UserID } if err := json.NewDecoder(req.Body).Decode(&body); err != nil { return util.MessageResponse(400, "Error parsing request JSON") @@ -276,7 +277,7 @@ func (h *GetSession) OnIncomingRequest(req *http.Request) util.JSONResponse { } var body struct { RealmID string - UserID string + UserID id.UserID } if err := json.NewDecoder(req.Body).Decode(&body); err != nil { return util.MessageResponse(400, "Error parsing request JSON") diff --git a/api/handlers/service.go b/api/handlers/service.go index 73e9a8c..d2450d9 100644 --- a/api/handlers/service.go +++ b/api/handlers/service.go @@ -14,9 +14,9 @@ import ( "github.com/matrix-org/go-neb/metrics" "github.com/matrix-org/go-neb/polling" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" "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 +225,7 @@ func (h *GetService) OnIncomingRequest(req *http.Request) util.JSONResponse { } } -func checkClientForService(service types.Service, client *gomatrix.Client) error { +func checkClientForService(service types.Service, client *mautrix.Client) 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/clients.go b/clients/clients.go index fe75914..fc2c285 100644 --- a/clients/clients.go +++ b/clients/clients.go @@ -13,9 +13,11 @@ import ( "github.com/matrix-org/go-neb/matrix" "github.com/matrix-org/go-neb/metrics" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" shellwords "github.com/mattn/go-shellwords" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // A Clients is a collection of clients used for bot services. @@ -24,7 +26,7 @@ type Clients struct { httpClient *http.Client dbMutex sync.Mutex mapMutex sync.Mutex - clients map[string]clientEntry + clients map[id.UserID]clientEntry } // New makes a new collection of matrix clients @@ -32,13 +34,13 @@ func New(db database.Storer, cli *http.Client) *Clients { clients := &Clients{ db: db, httpClient: cli, - clients: make(map[string]clientEntry), // user_id => clientEntry + clients: make(map[id.UserID]clientEntry), // user_id => clientEntry } return clients } // Client gets a client for the userID -func (c *Clients) Client(userID string) (*gomatrix.Client, error) { +func (c *Clients) Client(userID id.UserID) (*mautrix.Client, error) { entry := c.getClient(userID) if entry.client != nil { return entry.client, nil @@ -71,10 +73,10 @@ func (c *Clients) Start() error { type clientEntry struct { config api.ClientConfig - client *gomatrix.Client + client *mautrix.Client } -func (c *Clients) getClient(userID string) clientEntry { +func (c *Clients) getClient(userID id.UserID) clientEntry { c.mapMutex.Lock() defer c.mapMutex.Unlock() return c.clients[userID] @@ -86,7 +88,7 @@ func (c *Clients) setClient(client clientEntry) { c.clients[client.config.UserID] = client } -func (c *Clients) loadClientFromDB(userID string) (entry clientEntry, err error) { +func (c *Clients) loadClientFromDB(userID id.UserID) (entry clientEntry, err error) { c.dbMutex.Lock() defer c.dbMutex.Unlock() @@ -153,7 +155,7 @@ func (c *Clients) updateClientInDB(newConfig api.ClientConfig) (new clientEntry, return } -func (c *Clients) onMessageEvent(client *gomatrix.Client, event *gomatrix.Event) { +func (c *Clients) onMessageEvent(client *mautrix.Client, event *mevt.Event) { services, err := c.db.LoadServicesForUser(client.UserID) if err != nil { log.WithFields(log.Fields{ @@ -163,13 +165,19 @@ func (c *Clients) onMessageEvent(client *gomatrix.Client, event *gomatrix.Event) }).Warn("Error loading services") } - body, ok := event.Body() - if !ok || body == "" { + if err := event.Content.ParseRaw(mevt.EventMessage); err != nil { + return + } + + message := event.Content.AsMessage() + body := message.Body + + if body == "" { return } // filter m.notice to prevent loops - if msgtype, ok := event.MessageType(); !ok || msgtype == "m.notice" { + if message.MsgType == mevt.MsgNotice { return } @@ -198,7 +206,7 @@ func (c *Clients) onMessageEvent(client *gomatrix.Client, event *gomatrix.Event) } for _, content := range responses { - if _, err := client.SendMessageEvent(event.RoomID, "m.room.message", content); err != nil { + if _, err := client.SendMessageEvent(event.RoomID, mevt.EventMessage, content); err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": event.RoomID, @@ -213,7 +221,7 @@ func (c *Clients) onMessageEvent(client *gomatrix.Client, event *gomatrix.Event) // the matching command with the longest path. Returns the JSON encodable // content of a single matrix message event to use as a response or nil if no // response is appropriate. -func runCommandForService(cmds []types.Command, event *gomatrix.Event, arguments []string) interface{} { +func runCommandForService(cmds []types.Command, event *mevt.Event, arguments []string) interface{} { var bestMatch *types.Command for i, command := range cmds { matches := command.Matches(arguments) @@ -245,7 +253,10 @@ func runCommandForService(cmds []types.Command, event *gomatrix.Event, arguments }).Warn("Command returned both error and content.") } metrics.IncrementCommand(bestMatch.Path[0], metrics.StatusFailure) - content = gomatrix.TextMessage{"m.notice", err.Error()} + content = mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: err.Error(), + } } else { metrics.IncrementCommand(bestMatch.Path[0], metrics.StatusSuccess) } @@ -254,7 +265,7 @@ func runCommandForService(cmds []types.Command, event *gomatrix.Event, arguments } // run the expansions for a matrix event. -func runExpansionsForService(expans []types.Expansion, event *gomatrix.Event, body string) []interface{} { +func runExpansionsForService(expans []types.Expansion, event *mevt.Event, body string) []interface{} { var responses []interface{} for _, expansion := range expans { @@ -275,10 +286,13 @@ func runExpansionsForService(expans []types.Expansion, event *gomatrix.Event, bo return responses } -func (c *Clients) onBotOptionsEvent(client *gomatrix.Client, event *gomatrix.Event) { +func (c *Clients) onBotOptionsEvent(client *mautrix.Client, event *mevt.Event) { // see if these options are for us. The state key is the user ID with a leading _ // to get around restrictions in the HS about having user IDs as state keys. - targetUserID := strings.TrimPrefix(*event.StateKey, "_") + if event.StateKey == nil { + return + } + targetUserID := id.UserID(strings.TrimPrefix(*event.StateKey, "_")) if targetUserID != client.UserID { return } @@ -287,7 +301,7 @@ func (c *Clients) onBotOptionsEvent(client *gomatrix.Client, event *gomatrix.Eve UserID: client.UserID, RoomID: event.RoomID, SetByUserID: event.Sender, - Options: event.Content, + Options: event.Content.Raw, } if _, err := c.db.StoreBotOptions(opts); err != nil { log.WithFields(log.Fields{ @@ -299,15 +313,14 @@ func (c *Clients) onBotOptionsEvent(client *gomatrix.Client, event *gomatrix.Eve } } -func (c *Clients) onRoomMemberEvent(client *gomatrix.Client, event *gomatrix.Event) { - if *event.StateKey != client.UserID { - return // not our member event - } - m := event.Content["membership"] - membership, ok := m.(string) - if !ok { +func (c *Clients) onRoomMemberEvent(client *mautrix.Client, event *mevt.Event) { + if err := event.Content.ParseRaw(mevt.StateMember); err != nil { return } + if event.StateKey == nil || *event.StateKey != client.UserID.String() { + return // not our member event + } + membership := event.Content.AsMember().Membership if membership == "invite" { logger := log.WithFields(log.Fields{ "room_id": event.RoomID, @@ -317,10 +330,10 @@ func (c *Clients) onRoomMemberEvent(client *gomatrix.Client, event *gomatrix.Eve logger.Print("Accepting invite from user") content := struct { - Inviter string `json:"inviter"` + Inviter id.UserID `json:"inviter"` }{event.Sender} - if _, err := client.JoinRoom(event.RoomID, "", content); err != nil { + if _, err := client.JoinRoom(event.RoomID.String(), "", content); err != nil { logger.WithError(err).Print("Failed to join room") } else { logger.Print("Joined room") @@ -328,15 +341,15 @@ func (c *Clients) onRoomMemberEvent(client *gomatrix.Client, event *gomatrix.Eve } } -func (c *Clients) newClient(config api.ClientConfig) (*gomatrix.Client, error) { - client, err := gomatrix.NewClient(config.HomeserverURL, config.UserID, config.AccessToken) +func (c *Clients) newClient(config api.ClientConfig) (*mautrix.Client, error) { + client, err := mautrix.NewClient(config.HomeserverURL, config.UserID, config.AccessToken) if err != nil { return nil, err } client.Client = c.httpClient - syncer := client.Syncer.(*gomatrix.DefaultSyncer) + syncer := client.Syncer.(*mautrix.DefaultSyncer) nebStore := &matrix.NEBStore{ - InMemoryStore: *gomatrix.NewInMemoryStore(), + InMemoryStore: *mautrix.NewInMemoryStore(), Database: c.db, ClientConfig: config, } @@ -346,16 +359,16 @@ func (c *Clients) newClient(config api.ClientConfig) (*gomatrix.Client, error) { // TODO: Check that the access token is valid for the userID by peforming // a request against the server. - syncer.OnEventType("m.room.message", func(event *gomatrix.Event) { + syncer.OnEventType(mevt.EventMessage, func(event *mevt.Event) { c.onMessageEvent(client, event) }) - syncer.OnEventType("m.room.bot.options", func(event *gomatrix.Event) { + syncer.OnEventType(mevt.Type{Type: "m.room.bot.options", Class: mevt.UnknownEventType}, func(event *mevt.Event) { c.onBotOptionsEvent(client, event) }) if config.AutoJoinRooms { - syncer.OnEventType("m.room.member", func(event *gomatrix.Event) { + syncer.OnEventType(mevt.StateMember, func(event *mevt.Event) { c.onRoomMemberEvent(client, event) }) } diff --git a/clients/clients_test.go b/clients/clients_test.go index 2fcc613..d000f4e 100644 --- a/clients/clients_test.go +++ b/clients/clients_test.go @@ -8,7 +8,9 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) var commandParseTests = []struct { @@ -28,7 +30,7 @@ type MockService struct { commands []types.Command } -func (s *MockService) Commands(cli *gomatrix.Client) []types.Command { +func (s *MockService) Commands(cli *mautrix.Client) []types.Command { return s.commands } @@ -37,7 +39,7 @@ type MockStore struct { service types.Service } -func (d *MockStore) LoadServicesForUser(userID string) ([]types.Service, error) { +func (d *MockStore) LoadServicesForUser(userID id.UserID) ([]types.Service, error) { return []types.Service{d.service}, nil } @@ -54,7 +56,7 @@ func TestCommandParsing(t *testing.T) { cmds := []types.Command{ types.Command{ Path: []string{"test"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { executedCmdArgs = args return nil, nil }, @@ -72,19 +74,25 @@ func TestCommandParsing(t *testing.T) { Transport: trans, } clients := New(&store, cli) - mxCli, _ := gomatrix.NewClient("https://someplace.somewhere", "@service:user", "token") + mxCli, _ := mautrix.NewClient("https://someplace.somewhere", "@service:user", "token") mxCli.Client = cli for _, input := range commandParseTests { executedCmdArgs = []string{} - event := gomatrix.Event{ - Type: "m.room.message", - Sender: "@someone:somewhere", - RoomID: "!foo:bar", - Content: map[string]interface{}{ - "body": input.body, - "msgtype": "m.text", - }, + content := mevt.Content{Raw: map[string]interface{}{ + "body": input.body, + "msgtype": "m.text", + }} + if veryRaw, err := content.MarshalJSON(); err != nil { + t.Errorf("Error marshalling JSON: %s", err) + } else { + content.VeryRaw = veryRaw + } + event := mevt.Event{ + Type: mevt.EventMessage, + Sender: "@someone:somewhere", + RoomID: "!foo:bar", + Content: content, } clients.onMessageEvent(mxCli, &event) if !reflect.DeepEqual(executedCmdArgs, input.expectArgs) { diff --git a/database/db.go b/database/db.go index 87380ad..6551650 100644 --- a/database/db.go +++ b/database/db.go @@ -4,9 +4,11 @@ import ( "database/sql" "encoding/json" "fmt" + "time" + "github.com/matrix-org/go-neb/api" "github.com/matrix-org/go-neb/types" - "time" + "maunium.net/go/mautrix/id" ) // A ServiceDB stores the configuration for the services @@ -75,7 +77,7 @@ func (d *ServiceDB) LoadMatrixClientConfigs() (configs []api.ClientConfig, err e // LoadMatrixClientConfig loads a Matrix client config from the database. // Returns sql.ErrNoRows if the client isn't in the database. -func (d *ServiceDB) LoadMatrixClientConfig(userID string) (config api.ClientConfig, err error) { +func (d *ServiceDB) LoadMatrixClientConfig(userID id.UserID) (config api.ClientConfig, err error) { err = runTransaction(d.db, func(txn *sql.Tx) error { config, err = selectMatrixClientConfigTxn(txn, userID) return err @@ -84,7 +86,7 @@ func (d *ServiceDB) LoadMatrixClientConfig(userID string) (config api.ClientConf } // UpdateNextBatch updates the next_batch token for the given user. -func (d *ServiceDB) UpdateNextBatch(userID, nextBatch string) (err error) { +func (d *ServiceDB) UpdateNextBatch(userID id.UserID, nextBatch string) (err error) { err = runTransaction(d.db, func(txn *sql.Tx) error { return updateNextBatchTxn(txn, userID, nextBatch) }) @@ -92,7 +94,7 @@ func (d *ServiceDB) UpdateNextBatch(userID, nextBatch string) (err error) { } // LoadNextBatch loads the next_batch token for the given user. -func (d *ServiceDB) LoadNextBatch(userID string) (nextBatch string, err error) { +func (d *ServiceDB) LoadNextBatch(userID id.UserID) (nextBatch string, err error) { err = runTransaction(d.db, func(txn *sql.Tx) error { nextBatch, err = selectNextBatchTxn(txn, userID) return err @@ -120,7 +122,7 @@ func (d *ServiceDB) DeleteService(serviceID string) (err error) { // LoadServicesForUser loads all the bot services configured for a given user. // Returns an empty list if there aren't any services configured. -func (d *ServiceDB) LoadServicesForUser(serviceUserID string) (services []types.Service, err error) { +func (d *ServiceDB) LoadServicesForUser(serviceUserID id.UserID) (services []types.Service, err error) { err = runTransaction(d.db, func(txn *sql.Tx) error { services, err = selectServicesForUserTxn(txn, serviceUserID) if err != nil { @@ -218,7 +220,7 @@ func (d *ServiceDB) StoreAuthSession(session types.AuthSession) (old types.AuthS // RemoveAuthSession removes the auth session for the given user on the given realm. // No error is returned if the session did not exist in the first place. -func (d *ServiceDB) RemoveAuthSession(realmID, userID string) error { +func (d *ServiceDB) RemoveAuthSession(realmID string, userID id.UserID) error { return runTransaction(d.db, func(txn *sql.Tx) error { return deleteAuthSessionTxn(txn, realmID, userID) }) @@ -227,7 +229,7 @@ func (d *ServiceDB) RemoveAuthSession(realmID, userID string) error { // LoadAuthSessionByUser loads an AuthSession from the database based on the given // realm and user ID. // Returns sql.ErrNoRows if the session isn't in the database. -func (d *ServiceDB) LoadAuthSessionByUser(realmID, userID string) (session types.AuthSession, err error) { +func (d *ServiceDB) LoadAuthSessionByUser(realmID string, userID id.UserID) (session types.AuthSession, err error) { err = runTransaction(d.db, func(txn *sql.Tx) error { session, err = selectAuthSessionByUserTxn(txn, realmID, userID) return err @@ -248,7 +250,7 @@ func (d *ServiceDB) LoadAuthSessionByID(realmID, sessionID string) (session type // LoadBotOptions loads bot options from the database. // Returns sql.ErrNoRows if the bot options isn't in the database. -func (d *ServiceDB) LoadBotOptions(userID, roomID string) (opts types.BotOptions, err error) { +func (d *ServiceDB) LoadBotOptions(userID id.UserID, roomID id.RoomID) (opts types.BotOptions, err error) { err = runTransaction(d.db, func(txn *sql.Tx) error { opts, err = selectBotOptionsTxn(txn, userID, roomID) return err diff --git a/database/interface.go b/database/interface.go index 684f9da..6a0532f 100644 --- a/database/interface.go +++ b/database/interface.go @@ -3,20 +3,21 @@ package database import ( "github.com/matrix-org/go-neb/api" "github.com/matrix-org/go-neb/types" + "maunium.net/go/mautrix/id" ) // Storer is the interface which needs to be conformed to in order to persist Go-NEB data type Storer interface { StoreMatrixClientConfig(config api.ClientConfig) (oldConfig api.ClientConfig, err error) LoadMatrixClientConfigs() (configs []api.ClientConfig, err error) - LoadMatrixClientConfig(userID string) (config api.ClientConfig, err error) + LoadMatrixClientConfig(userID id.UserID) (config api.ClientConfig, err error) - UpdateNextBatch(userID, nextBatch string) (err error) - LoadNextBatch(userID string) (nextBatch string, err error) + UpdateNextBatch(userID id.UserID, nextBatch string) (err error) + LoadNextBatch(userID id.UserID) (nextBatch string, err error) LoadService(serviceID string) (service types.Service, err error) DeleteService(serviceID string) (err error) - LoadServicesForUser(serviceUserID string) (services []types.Service, err error) + LoadServicesForUser(serviceUserID id.UserID) (services []types.Service, err error) LoadServicesByType(serviceType string) (services []types.Service, err error) StoreService(service types.Service) (oldService types.Service, err error) @@ -25,11 +26,11 @@ type Storer interface { StoreAuthRealm(realm types.AuthRealm) (old types.AuthRealm, err error) StoreAuthSession(session types.AuthSession) (old types.AuthSession, err error) - LoadAuthSessionByUser(realmID, userID string) (session types.AuthSession, err error) + LoadAuthSessionByUser(realmID string, userID id.UserID) (session types.AuthSession, err error) LoadAuthSessionByID(realmID, sessionID string) (session types.AuthSession, err error) - RemoveAuthSession(realmID, userID string) error + RemoveAuthSession(realmID string, userID id.UserID) error - LoadBotOptions(userID, roomID string) (opts types.BotOptions, err error) + LoadBotOptions(userID id.UserID, roomID id.RoomID) (opts types.BotOptions, err error) StoreBotOptions(opts types.BotOptions) (oldOpts types.BotOptions, err error) InsertFromConfig(cfg *api.ConfigFile) error @@ -50,17 +51,17 @@ func (s *NopStorage) LoadMatrixClientConfigs() (configs []api.ClientConfig, err } // LoadMatrixClientConfig NOP -func (s *NopStorage) LoadMatrixClientConfig(userID string) (config api.ClientConfig, err error) { +func (s *NopStorage) LoadMatrixClientConfig(userID id.UserID) (config api.ClientConfig, err error) { return } // UpdateNextBatch NOP -func (s *NopStorage) UpdateNextBatch(userID, nextBatch string) (err error) { +func (s *NopStorage) UpdateNextBatch(userID id.UserID, nextBatch string) (err error) { return } // LoadNextBatch NOP -func (s *NopStorage) LoadNextBatch(userID string) (nextBatch string, err error) { +func (s *NopStorage) LoadNextBatch(userID id.UserID) (nextBatch string, err error) { return } @@ -75,7 +76,7 @@ func (s *NopStorage) DeleteService(serviceID string) (err error) { } // LoadServicesForUser NOP -func (s *NopStorage) LoadServicesForUser(serviceUserID string) (services []types.Service, err error) { +func (s *NopStorage) LoadServicesForUser(serviceUserID id.UserID) (services []types.Service, err error) { return } @@ -110,7 +111,7 @@ func (s *NopStorage) StoreAuthSession(session types.AuthSession) (old types.Auth } // LoadAuthSessionByUser NOP -func (s *NopStorage) LoadAuthSessionByUser(realmID, userID string) (session types.AuthSession, err error) { +func (s *NopStorage) LoadAuthSessionByUser(realmID string, userID id.UserID) (session types.AuthSession, err error) { return } @@ -120,12 +121,12 @@ func (s *NopStorage) LoadAuthSessionByID(realmID, sessionID string) (session typ } // RemoveAuthSession NOP -func (s *NopStorage) RemoveAuthSession(realmID, userID string) error { +func (s *NopStorage) RemoveAuthSession(realmID string, userID id.UserID) error { return nil } // LoadBotOptions NOP -func (s *NopStorage) LoadBotOptions(userID, roomID string) (opts types.BotOptions, err error) { +func (s *NopStorage) LoadBotOptions(userID id.UserID, roomID id.RoomID) (opts types.BotOptions, err error) { return } diff --git a/database/schema.go b/database/schema.go index 9a9fc51..d218c8c 100644 --- a/database/schema.go +++ b/database/schema.go @@ -8,6 +8,7 @@ import ( "github.com/matrix-org/go-neb/api" "github.com/matrix-org/go-neb/types" + "maunium.net/go/mautrix/id" ) const schemaSQL = ` @@ -66,7 +67,7 @@ const selectMatrixClientConfigSQL = ` SELECT client_json FROM matrix_clients WHERE user_id = $1 ` -func selectMatrixClientConfigTxn(txn *sql.Tx, userID string) (config api.ClientConfig, err error) { +func selectMatrixClientConfigTxn(txn *sql.Tx, userID id.UserID) (config api.ClientConfig, err error) { var configJSON []byte err = txn.QueryRow(selectMatrixClientConfigSQL, userID).Scan(&configJSON) if err != nil { @@ -135,7 +136,7 @@ const updateNextBatchSQL = ` UPDATE matrix_clients SET next_batch = $1 WHERE user_id = $2 ` -func updateNextBatchTxn(txn *sql.Tx, userID, nextBatch string) error { +func updateNextBatchTxn(txn *sql.Tx, userID id.UserID, nextBatch string) error { _, err := txn.Exec(updateNextBatchSQL, nextBatch, userID) return err } @@ -144,7 +145,7 @@ const selectNextBatchSQL = ` SELECT next_batch FROM matrix_clients WHERE user_id = $1 ` -func selectNextBatchTxn(txn *sql.Tx, userID string) (string, error) { +func selectNextBatchTxn(txn *sql.Tx, userID id.UserID) (string, error) { var nextBatch string row := txn.QueryRow(selectNextBatchSQL, userID) if err := row.Scan(&nextBatch); err != nil { @@ -160,7 +161,7 @@ SELECT service_type, service_user_id, service_json FROM services func selectServiceTxn(txn *sql.Tx, serviceID string) (types.Service, error) { var serviceType string - var serviceUserID string + var serviceUserID id.UserID var serviceJSON []byte row := txn.QueryRow(selectServiceSQL, serviceID) if err := row.Scan(&serviceType, &serviceUserID, &serviceJSON); err != nil { @@ -210,7 +211,7 @@ const selectServicesForUserSQL = ` SELECT service_id, service_type, service_json FROM services WHERE service_user_id=$1 ORDER BY service_id ` -func selectServicesForUserTxn(txn *sql.Tx, userID string) (srvs []types.Service, err error) { +func selectServicesForUserTxn(txn *sql.Tx, userID id.UserID) (srvs []types.Service, err error) { rows, err := txn.Query(selectServicesForUserSQL, userID) if err != nil { return @@ -246,7 +247,7 @@ func selectServicesByTypeTxn(txn *sql.Tx, serviceType string) (srvs []types.Serv for rows.Next() { var s types.Service var serviceID string - var serviceUserID string + var serviceUserID id.UserID var serviceJSON []byte if err = rows.Scan(&serviceID, &serviceUserID, &serviceJSON); err != nil { return @@ -369,7 +370,7 @@ const deleteAuthSessionSQL = ` DELETE FROM auth_sessions WHERE realm_id=$1 AND user_id=$2 ` -func deleteAuthSessionTxn(txn *sql.Tx, realmID, userID string) error { +func deleteAuthSessionTxn(txn *sql.Tx, realmID string, userID id.UserID) error { _, err := txn.Exec(deleteAuthSessionSQL, realmID, userID) return err } @@ -380,7 +381,7 @@ SELECT session_id, realm_type, realm_json, session_json FROM auth_sessions WHERE auth_sessions.realm_id = $1 AND auth_sessions.user_id = $2 ` -func selectAuthSessionByUserTxn(txn *sql.Tx, realmID, userID string) (types.AuthSession, error) { +func selectAuthSessionByUserTxn(txn *sql.Tx, realmID string, userID id.UserID) (types.AuthSession, error) { var id string var realmType string var realmJSON []byte @@ -409,12 +410,12 @@ SELECT user_id, realm_type, realm_json, session_json FROM auth_sessions WHERE auth_sessions.realm_id = $1 AND auth_sessions.session_id = $2 ` -func selectAuthSessionByIDTxn(txn *sql.Tx, realmID, id string) (types.AuthSession, error) { - var userID string +func selectAuthSessionByIDTxn(txn *sql.Tx, realmID, sid string) (types.AuthSession, error) { + var userID id.UserID var realmType string var realmJSON []byte var sessionJSON []byte - row := txn.QueryRow(selectAuthSessionByIDSQL, realmID, id) + row := txn.QueryRow(selectAuthSessionByIDSQL, realmID, sid) if err := row.Scan(&userID, &realmType, &realmJSON, &sessionJSON); err != nil { return nil, err } @@ -422,7 +423,7 @@ func selectAuthSessionByIDTxn(txn *sql.Tx, realmID, id string) (types.AuthSessio if err != nil { return nil, err } - session := realm.AuthSession(id, userID, realmID) + session := realm.AuthSession(sid, userID, realmID) if session == nil { return nil, fmt.Errorf("Cannot create session for given realm") } @@ -454,7 +455,7 @@ const selectBotOptionsSQL = ` SELECT bot_options_json, set_by_user_id FROM bot_options WHERE user_id = $1 AND room_id = $2 ` -func selectBotOptionsTxn(txn *sql.Tx, userID, roomID string) (opts types.BotOptions, err error) { +func selectBotOptionsTxn(txn *sql.Tx, userID id.UserID, roomID id.RoomID) (opts types.BotOptions, err error) { var optionsJSON []byte err = txn.QueryRow(selectBotOptionsSQL, userID, roomID).Scan(&optionsJSON, &opts.SetByUserID) if err != nil { diff --git a/go.mod b/go.mod index 8ed4e68..24d8f26 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/gogo/protobuf v1.1.1 // indirect github.com/golang/protobuf v1.3.2 // indirect github.com/google/go-cmp v0.4.0 // indirect - github.com/google/go-github v2.0.1-0.20160719063544-b5e5babef39c+incompatible + github.com/google/go-github v17.0.0+incompatible github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 github.com/jaytaylor/html2text v0.0.0-20200220170450-61d9dc4d7195 github.com/json-iterator/go v1.1.9 // indirect @@ -25,7 +25,6 @@ require ( github.com/kr/pretty v0.1.0 // indirect github.com/lib/pq v1.3.0 github.com/matrix-org/dugong v0.0.0-20180820122854-51a565b5666b - github.com/matrix-org/gomatrix v0.0.0-20200128155335-9e7906b6766d github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7 github.com/mattn/go-shellwords v1.0.10 github.com/mattn/go-sqlite3 v2.0.3+incompatible @@ -36,21 +35,22 @@ require ( github.com/modern-go/reflect2 v1.0.1 // indirect github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 // indirect github.com/olekukonko/tablewriter v0.0.4 // indirect - github.com/pkg/errors v0.8.1 // indirect + github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v0.8.1-0.20160916180340-5636dc67ae77 github.com/prometheus/client_model v0.0.0-20150212101744-fa8ad6fec335 // indirect github.com/prometheus/common v0.0.0-20161002210234-85637ea67b04 // indirect github.com/prometheus/procfs v0.0.0-20160411190841-abf152e5f3e9 // indirect github.com/russross/blackfriday v1.5.2 + github.com/sasha-s/go-deadlock v0.2.0 github.com/sirupsen/logrus v1.4.2 github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect - github.com/stretchr/testify v1.4.0 // indirect - golang.org/x/net v0.0.0-20200301022130-244492dfa37a + golang.org/dl v0.0.0-20200601221412-a954fa24b3e5 // indirect + golang.org/x/net v0.0.0-20200505041828-1ed23360d12c golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d - golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect - golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 // indirect golang.org/x/tools v0.0.0-20200311090712-aafaee8bce8c // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v2 v2.2.8 + maunium.net/go/gomuks v0.1.0 + maunium.net/go/mautrix v0.4.7 ) diff --git a/go.sum b/go.sum index 2e6f284..982e162 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,11 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= +github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= +github.com/alecthomas/chroma v0.7.2/go.mod h1:fv5SzZPFJbwp2NXJWpFIX7DZS4HgV1K4ew4Pc2OZD9s= +github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= +github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= +github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -17,7 +22,9 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dghubble/oauth1 v0.6.0 h1:m1yC01Ohc/eF38jwZ8JUjL1a+XHHXtGQgK+MxQbmSx0= github.com/dghubble/oauth1 v0.6.0/go.mod h1:8pFdfPkv/jr8mkChVbNVuJ0suiHe278BtWI4Tk1ujxk= @@ -25,8 +32,11 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/die-net/lrucache v0.0.0-20190707192454-883874fe3947 h1:U/5Sq2nJQ0XDyks+8ATghtHSuquIGq7JYrqSrvtR2dg= github.com/die-net/lrucache v0.0.0-20190707192454-883874fe3947/go.mod h1:KsMcjmY1UCGl7ozPbdVPDOvLaFeXnptSvtNRczhxNto= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= +github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/fatih/structs v1.0.0 h1:BrX964Rv5uQ3wwS+KRUAJCBBw5PQmgJfJ6v4yly5QwU= github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -39,6 +49,7 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v2.0.1-0.20160719063544-b5e5babef39c+incompatible h1:9bbdREkf94ZqDMJ3Nsy5cJYNswJW2Xiirp+YuuuGAKM= github.com/google/go-github v2.0.1-0.20160719063544-b5e5babef39c+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= @@ -49,6 +60,7 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/jaytaylor/html2text v0.0.0-20200220170450-61d9dc4d7195 h1:j0UEFmS7wSjAwKEIkgKBn8PRDfjcuggzr93R9wk53nQ= @@ -59,19 +71,26 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V 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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/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= github.com/matrix-org/dugong v0.0.0-20180820122854-51a565b5666b/go.mod h1:NgPCr+UavRGH6n5jmdX8DuqFZ4JiCWIJoZiuhTRLSUg= -github.com/matrix-org/gomatrix v0.0.0-20200128155335-9e7906b6766d h1:Vf/EQgAfg8/CBUQv9te7UJreZ9iKKouB2gb8UIRM4jQ= -github.com/matrix-org/gomatrix v0.0.0-20200128155335-9e7906b6766d/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0= github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7 h1:ntrLa/8xVzeSs8vHFHK25k0C+NV74sYMJnNSg5NoSRo= github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 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= @@ -79,6 +98,7 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK 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= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mmcdole/gofeed v1.0.0-beta2 h1:CjQ0ADhAwNSb08zknAkGOEYqr8zfZKfrzgk9BxpWP2E= github.com/mmcdole/gofeed v1.0.0-beta2/go.mod h1:/BF9JneEL2/flujm8XHoxUcghdTV6vvb3xx/vKyChFU= github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf h1:sWGE2v+hO0Nd4yFU/S/mDBM5plIU8v/Qhfz41hkDIAI= @@ -90,9 +110,14 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.1-0.20160916180340-5636dc67ae77 h1:YXoHPWLq9PIcMoZg7znMmEzqYHBszdXSemwGQRJoiSk= github.com/prometheus/client_golang v0.8.1-0.20160916180340-5636dc67ae77/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -127,8 +152,14 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y= +github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -138,13 +169,32 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= +github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.1 h1:WE4RBSZ1x6McVVC8S/Md+Qse8YUv6HRObAx6ke00NY8= +github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.1.1 h1:7h1vk049Jnd5EH9NyzNiEuwYW4b5qgreBbqRC19AS3U= +github.com/tidwall/sjson v1.1.1/go.mod h1:yvVuSnpEQv5cYIrO+AT6kw4QVfd5SDZoGIS7/5+fZFs= github.com/trivago/tgo v1.0.1 h1:bxatjJIXNIpV18bucU4Uk/LaoxvxuOlp/oowRHyncLQ= github.com/trivago/tgo v1.0.1/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc= +github.com/zyedidia/clipboard v0.0.0-20200421031010-7c45b8673834/go.mod h1:zykFnZUXX0ErxqvYLUFEq7QDJKId8rmh2FgD0/Y8cjA= +github.com/zyedidia/poller v1.0.1/go.mod h1:vZXJOHGDcuK08GXhF6IAY0ZFd2WcgOR5DOTp84Uk5eE= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +golang.org/dl v0.0.0-20200601221412-a954fa24b3e5 h1:LrG45X3Uq6Sb+SuDP5WXq1jUhjYbqOyqw92r+E8Q7n0= +golang.org/dl v0.0.0-20200601221412-a954fa24b3e5/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -157,6 +207,8 @@ 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-20200505041828-1ed23360d12c h1:zJ0mtu4jCalhKg6Oaukv6iIkb+cOvDrajDH9DH46Q4M= +golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -165,13 +217,21 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3rzIsrrXfAQBWnYfn+w= +golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200311090712-aafaee8bce8c h1:9WR4YuzLDuQMqEmLQrG0DiMmE2/HvX1dlrujzjmNVFg= golang.org/x/tools v0.0.0-20200311090712-aafaee8bce8c/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= @@ -182,10 +242,20 @@ google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO50 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2/go.mod h1:s1Sn2yZos05Qfs7NKt867Xe18emOmtsO3eAKbDaon0o= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +maunium.net/go/gomuks v0.1.0 h1:Ra0But5Cr3UfCSzd456x8MzV6jXLisZG0gW7RZY1xnk= +maunium.net/go/gomuks v0.1.0/go.mod h1:UWB7mC4OcKINQ2+ygalRSsSvnROoiwdSxdVLrWTeco4= +maunium.net/go/maulogger/v2 v2.1.1/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A= +maunium.net/go/mautrix v0.4.2/go.mod h1:8Y+NqmROJyWYvvP4yPfX9tLM59VCfgE/kcQ0SeX68ho= +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/mauview v0.1.1/go.mod h1:3QBUiuLct9moP1LgDhCGIg0Ovxn38Bd2sGndnUOuj4o= +maunium.net/go/tcell v0.2.0/go.mod h1:9Apcb3lNNS6C6lCqKT9UFp7BTRzHXfWE+/tgufsAMho= diff --git a/goneb.go b/goneb.go index e1df87c..ed3ea67 100644 --- a/goneb.go +++ b/goneb.go @@ -19,13 +19,16 @@ import ( "github.com/matrix-org/go-neb/polling" _ "github.com/matrix-org/go-neb/realms/github" _ "github.com/matrix-org/go-neb/realms/jira" + _ "github.com/matrix-org/go-neb/services/alertmanager" _ "github.com/matrix-org/go-neb/services/echo" _ "github.com/matrix-org/go-neb/services/giphy" _ "github.com/matrix-org/go-neb/services/github" + _ "github.com/matrix-org/go-neb/services/google" _ "github.com/matrix-org/go-neb/services/guggy" _ "github.com/matrix-org/go-neb/services/imgur" + _ "github.com/matrix-org/go-neb/services/jira" _ "github.com/matrix-org/go-neb/services/rssbot" _ "github.com/matrix-org/go-neb/services/slackapi" diff --git a/matrix/matrix.go b/matrix/matrix.go index e35368c..ec8cb76 100644 --- a/matrix/matrix.go +++ b/matrix/matrix.go @@ -5,21 +5,22 @@ import ( "github.com/matrix-org/go-neb/api" "github.com/matrix-org/go-neb/database" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + "maunium.net/go/mautrix/id" ) -// NEBStore implements the gomatrix.Storer interface. +// NEBStore implements the mautrix.Storer interface. // // It persists the next batch token in the database, and includes a ClientConfig for the client. type NEBStore struct { - gomatrix.InMemoryStore + mautrix.InMemoryStore Database database.Storer ClientConfig api.ClientConfig } // SaveNextBatch saves to the database. -func (s *NEBStore) SaveNextBatch(userID, nextBatch string) { +func (s *NEBStore) SaveNextBatch(userID id.UserID, nextBatch string) { if err := s.Database.UpdateNextBatch(userID, nextBatch); err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, @@ -30,7 +31,7 @@ func (s *NEBStore) SaveNextBatch(userID, nextBatch string) { } // LoadNextBatch loads from the database. -func (s *NEBStore) LoadNextBatch(userID string) string { +func (s *NEBStore) LoadNextBatch(userID id.UserID) string { token, err := s.Database.LoadNextBatch(userID) if err != nil { log.WithFields(log.Fields{ diff --git a/realms/github/github.go b/realms/github/github.go index ab28a71..70eebd6 100644 --- a/realms/github/github.go +++ b/realms/github/github.go @@ -2,6 +2,7 @@ package github import ( + "context" "crypto/rand" "encoding/hex" "encoding/json" @@ -14,6 +15,7 @@ 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/id" ) // RealmType of the Github Realm @@ -41,7 +43,7 @@ type Realm struct { // Session represents an authenticated github session type Session struct { id string - userID string + userID id.UserID realmID string // AccessToken is the github access token for the user @@ -86,7 +88,7 @@ func (s *Session) Info() interface{} { } for { // query for a list of possible projects - rs, resp, err := cli.Repositories.List("", opts) + rs, resp, err := cli.Repositories.List(context.Background(), "", opts) if err != nil { logger.WithError(err).Print("Failed to query github projects on github.com") return nil @@ -110,7 +112,7 @@ func (s *Session) Info() interface{} { } // UserID returns the user_id who authorised with Github -func (s *Session) UserID() string { +func (s *Session) UserID() id.UserID { return s.userID } @@ -156,7 +158,7 @@ func (r *Realm) Register() error { // { // "URL": "https://github.com/login/oauth/authorize?client_id=abcdef&client_secret=acascacac...." // } -func (r *Realm) RequestAuthSession(userID string, req json.RawMessage) interface{} { +func (r *Realm) RequestAuthSession(userID id.UserID, req json.RawMessage) interface{} { state, err := randomString(10) if err != nil { log.WithError(err).Print("Failed to generate state param") @@ -259,7 +261,7 @@ func (r *Realm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request) { return } r.redirectOr( - w, 200, "You have successfully linked your Github account to "+ghSession.UserID(), logger, ghSession, + w, 200, "You have successfully linked your Github account to "+ghSession.UserID().String(), logger, ghSession, ) } @@ -275,7 +277,7 @@ func (r *Realm) redirectOr(w http.ResponseWriter, code int, msg string, logger * } // AuthSession returns a Github Session for this user -func (r *Realm) AuthSession(id, userID, realmID string) types.AuthSession { +func (r *Realm) AuthSession(id string, userID id.UserID, realmID string) types.AuthSession { return &Session{ id: id, userID: userID, diff --git a/realms/jira/jira.go b/realms/jira/jira.go index 6081e66..74f15b6 100644 --- a/realms/jira/jira.go +++ b/realms/jira/jira.go @@ -19,6 +19,7 @@ import ( "github.com/matrix-org/go-neb/types" log "github.com/sirupsen/logrus" "golang.org/x/net/context" + "maunium.net/go/mautrix/id" ) // RealmType of the JIRA realm @@ -83,7 +84,7 @@ type Realm struct { // The endpoint is dictated by the realm ID. type Session struct { id string // request token - userID string + userID id.UserID realmID string // Configuration fields @@ -121,7 +122,7 @@ func (s *Session) Info() interface{} { } // UserID returns the ID of the user performing the authentication. -func (s *Session) UserID() string { +func (s *Session) UserID() id.UserID { return s.userID } @@ -203,7 +204,7 @@ func (r *Realm) Register() error { // { // "URL": "https://jira.somewhere.com/plugins/servlet/oauth/authorize?oauth_token=7yeuierbgweguiegrTbOT" // } -func (r *Realm) RequestAuthSession(userID string, req json.RawMessage) interface{} { +func (r *Realm) RequestAuthSession(userID id.UserID, req json.RawMessage) interface{} { logger := log.WithField("jira_url", r.JIRAEndpoint) // check if they supplied a redirect URL @@ -298,7 +299,7 @@ func (r *Realm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request) { } // AuthSession returns a JIRASession with the given parameters -func (r *Realm) AuthSession(id, userID, realmID string) types.AuthSession { +func (r *Realm) AuthSession(id string, userID id.UserID, realmID string) types.AuthSession { return &Session{ id: id, userID: userID, @@ -310,7 +311,7 @@ func (r *Realm) AuthSession(id, userID, realmID string) types.AuthSession { // An authenticated client for userID will be used if one exists, else an // unauthenticated client will be used, which may not be able to see the complete list // of projects. -func (r *Realm) ProjectKeyExists(userID, projectKey string) (bool, error) { +func (r *Realm) ProjectKeyExists(userID id.UserID, projectKey string) (bool, error) { cli, err := r.JIRAClient(userID, true) if err != nil { return false, err @@ -344,7 +345,7 @@ func (r *Realm) ProjectKeyExists(userID, projectKey string) (bool, error) { // JIRAClient returns an authenticated jira.Client for the given userID. Returns an unauthenticated // client if allowUnauth is true and no authenticated session is found, else returns an error. -func (r *Realm) JIRAClient(userID string, allowUnauth bool) (*jira.Client, error) { +func (r *Realm) JIRAClient(userID id.UserID, allowUnauth bool) (*jira.Client, error) { // Check if user has an auth session. session, err := database.GetServiceDB().LoadAuthSessionByUser(r.id, userID) if err != nil { @@ -367,7 +368,7 @@ func (r *Realm) JIRAClient(userID string, allowUnauth bool) (*jira.Client, error // make an unauthenticated client return jira.NewClient(nil, r.JIRAEndpoint) } - return nil, errors.New("No authenticated session found for " + userID) + return nil, errors.New("No authenticated session found for " + userID.String()) } // make an authenticated client auth := r.oauth1Config(r.JIRAEndpoint) diff --git a/services/alertmanager/alertmanager.go b/services/alertmanager/alertmanager.go index 1bdfe37..a02e969 100644 --- a/services/alertmanager/alertmanager.go +++ b/services/alertmanager/alertmanager.go @@ -5,14 +5,17 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/matrix-org/go-neb/database" - "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" - log "github.com/sirupsen/logrus" html "html/template" "net/http" "strings" text "text/template" + + "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" ) // ServiceType of the Alertmanager service. @@ -46,10 +49,10 @@ type Service struct { // The URL which should be added to alertmanagers config - Populated by Go-NEB after Service registration. WebhookURL string `json:"webhook_url"` // A map of matrix rooms to templates - Rooms map[string]struct { - TextTemplate string `json:"text_template"` - HTMLTemplate string `json:"html_template"` - MsgType string `json:"msg_type"` + Rooms map[id.RoomID]struct { + TextTemplate string `json:"text_template"` + HTMLTemplate string `json:"html_template"` + MsgType mevt.MessageType `json:"msg_type"` } `json:"rooms"` } @@ -75,7 +78,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 *gomatrix.Client) { +func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { decoder := json.NewDecoder(req.Body) var notif WebhookNotification if err := decoder.Decode(¬if); err != nil { @@ -115,14 +118,14 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli w.WriteHeader(500) return } - msg = gomatrix.HTMLMessage{ + msg = mevt.MessageEventContent{ Body: bodyBuffer.String(), MsgType: templates.MsgType, - Format: "org.matrix.custom.html", + Format: mevt.FormatHTML, FormattedBody: formattedBodyBuffer.String(), } } else { - msg = gomatrix.TextMessage{ + msg = mevt.MessageEventContent{ Body: bodyBuffer.String(), MsgType: templates.MsgType, } @@ -132,7 +135,7 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli "message": msg, "room_id": roomID, }).Print("Sending Alertmanager notification to room") - if _, e := cli.SendMessageEvent(roomID, "m.room.message", msg); e != nil { + if _, e := cli.SendMessageEvent(roomID, mevt.EventMessage, msg); e != nil { log.WithError(e).WithField("room_id", roomID).Print( "Failed to send Alertmanager notification to room.") } @@ -141,7 +144,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 *gomatrix.Client) error { +func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { s.WebhookURL = s.webhookEndpointURL for _, templates := range s.Rooms { // validate that we have at least a plain text template @@ -188,9 +191,9 @@ func (s *Service) PostRegister(oldService types.Service) { } } -func (s *Service) joinRooms(client *gomatrix.Client) { +func (s *Service) joinRooms(client *mautrix.Client) { for roomID := range s.Rooms { - if _, err := client.JoinRoom(roomID, "", nil); err != nil { + if _, err := client.JoinRoom(roomID.String(), "", nil); err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": roomID, @@ -201,7 +204,7 @@ func (s *Service) joinRooms(client *gomatrix.Client) { } func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), webhookEndpointURL: webhookEndpointURL, diff --git a/services/alertmanager/alertmanager_test.go b/services/alertmanager/alertmanager_test.go index a498863..e752144 100644 --- a/services/alertmanager/alertmanager_test.go +++ b/services/alertmanager/alertmanager_test.go @@ -4,10 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/matrix-org/go-neb/database" - "github.com/matrix-org/go-neb/testutils" - "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" "io/ioutil" "net/http" "net/http/httptest" @@ -15,13 +11,19 @@ import ( "regexp" "strings" "testing" + + "github.com/matrix-org/go-neb/database" + "github.com/matrix-org/go-neb/testutils" + "github.com/matrix-org/go-neb/types" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" ) func TestNotify(t *testing.T) { database.SetServiceDB(&database.NopStorage{}) // Intercept message sending to Matrix and mock responses - msgs := []gomatrix.HTMLMessage{} + msgs := []mevt.MessageEventContent{} matrixCli := buildTestClient(&msgs) // create the service @@ -91,13 +93,13 @@ func TestNotify(t *testing.T) { } } -func buildTestClient(msgs *[]gomatrix.HTMLMessage) *gomatrix.Client { +func buildTestClient(msgs *[]mevt.MessageEventContent) *mautrix.Client { matrixTrans := struct{ testutils.MockTransport }{} matrixTrans.RT = func(req *http.Request) (*http.Response, error) { if !strings.Contains(req.URL.String(), "/send/m.room.message") { return nil, fmt.Errorf("Unhandled URL: %s", req.URL.String()) } - var msg gomatrix.HTMLMessage + var msg mevt.MessageEventContent if err := json.NewDecoder(req.Body).Decode(&msg); err != nil { return nil, fmt.Errorf("Failed to decode request JSON: %s", err) } @@ -107,7 +109,7 @@ func buildTestClient(msgs *[]gomatrix.HTMLMessage) *gomatrix.Client { Body: ioutil.NopCloser(bytes.NewBufferString(`{"event_id":"$yup:event"}`)), }, nil } - matrixCli, _ := gomatrix.NewClient("https://hs", "@neb:hs", "its_a_secret") + matrixCli, _ := mautrix.NewClient("https://hs", "@neb:hs", "its_a_secret") matrixCli.Client = &http.Client{Transport: matrixTrans} return matrixCli } diff --git a/services/echo/echo.go b/services/echo/echo.go index 32ae181..ca9b3a0 100644 --- a/services/echo/echo.go +++ b/services/echo/echo.go @@ -5,7 +5,9 @@ import ( "strings" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // ServiceType of the Echo service @@ -19,19 +21,22 @@ type Service struct { // Commands supported: // !echo some message // Responds with a notice of "some message". -func (e *Service) Commands(cli *gomatrix.Client) []types.Command { +func (e *Service) Commands(cli *mautrix.Client) []types.Command { return []types.Command{ types.Command{ Path: []string{"echo"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { - return &gomatrix.TextMessage{"m.notice", strings.Join(args, " ")}, nil + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: strings.Join(args, " "), + }, nil }, }, } } func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), } diff --git a/services/giphy/giphy.go b/services/giphy/giphy.go index 1c92231..0fd58ce 100644 --- a/services/giphy/giphy.go +++ b/services/giphy/giphy.go @@ -10,8 +10,11 @@ import ( "strings" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" 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" ) // ServiceType of the Giphy service. @@ -58,18 +61,18 @@ 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 *gomatrix.Client) []types.Command { +func (s *Service) Commands(client *mautrix.Client) []types.Command { return []types.Command{ types.Command{ Path: []string{"giphy"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGiphy(client, roomID, userID, args) }, }, } } -func (s *Service) cmdGiphy(client *gomatrix.Client, roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGiphy(client *mautrix.Client, 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) @@ -90,14 +93,14 @@ func (s *Service) cmdGiphy(client *gomatrix.Client, roomID, userID string, args return nil, err } - return gomatrix.ImageMessage{ - MsgType: "m.image", + return mevt.MessageEventContent{ + MsgType: event.MsgImage, Body: gifResult.Slug, - URL: resUpload.ContentURI, - Info: gomatrix.ImageInfo{ + URL: resUpload.ContentURI.CUString(), + Info: &mevt.FileInfo{ Height: asInt(image.Height), Width: asInt(image.Width), - Mimetype: "image/gif", + MimeType: "image/gif", Size: asInt(image.Size), }, }, nil @@ -130,16 +133,16 @@ func (s *Service) searchGiphy(query string) (*result, error) { return &search.Data, nil } -func asInt(strInt string) uint { - u64, err := strconv.ParseUint(strInt, 10, 32) +func asInt(strInt string) int { + i64, err := strconv.ParseInt(strInt, 10, 32) if err != nil { return 0 // default to 0 since these are all just hints to the client } - return uint(u64) + return int(i64) } func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), } diff --git a/services/github/github.go b/services/github/github.go index 7cbd413..702eda6 100644 --- a/services/github/github.go +++ b/services/github/github.go @@ -5,6 +5,7 @@ package github import ( + "context" "database/sql" "fmt" "regexp" @@ -12,15 +13,18 @@ import ( "strings" "bytes" + "html" + gogithub "github.com/google/go-github/github" "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/matrix" "github.com/matrix-org/go-neb/realms/github" "github.com/matrix-org/go-neb/services/github/client" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" - "html" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // ServiceType of the Github service @@ -69,7 +73,7 @@ type Service struct { RealmID string } -func (s *Service) requireGithubClientFor(userID string) (cli *gogithub.Client, resp interface{}, err error) { +func (s *Service) requireGithubClientFor(userID id.UserID) (cli *gogithub.Client, resp interface{}, err error) { cli = s.githubClientFor(userID, false) if cli == nil { var r types.AuthRealm @@ -91,14 +95,17 @@ func (s *Service) requireGithubClientFor(userID string) (cli *gogithub.Client, r const numberGithubSearchSummaries = 3 const cmdGithubSearchUsage = `!github search "search query"` -func (s *Service) cmdGithubSearch(roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGithubSearch(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { cli := s.githubClientFor(userID, true) if len(args) < 2 { - return &gomatrix.TextMessage{"m.notice", "Usage: " + cmdGithubSearchUsage}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Usage: " + cmdGithubSearchUsage, + }, nil } query := strings.Join(args, " ") - searchResult, res, err := cli.Search.Issues(query, nil) + searchResult, res, err := cli.Search.Issues(context.Background(), query, nil) if err != nil { log.WithField("err", err).Print("Failed to search") @@ -109,7 +116,10 @@ func (s *Service) cmdGithubSearch(roomID, userID string, args []string) (interfa } if searchResult.Total == nil || *searchResult.Total == 0 { - return &gomatrix.TextMessage{"m.notice", "No results found for your search query!"}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "No results found for your search query!", + }, nil } numResults := *searchResult.Total @@ -130,9 +140,9 @@ func (s *Service) cmdGithubSearch(roomID, userID string, args []string) (interfa } htmlBuffer.WriteString("") - return &gomatrix.HTMLMessage{ + return &mevt.MessageEventContent{ Body: plainBuffer.String(), - MsgType: "m.notice", + MsgType: mevt.MsgNotice, Format: "org.matrix.custom.html", FormattedBody: htmlBuffer.String(), }, nil @@ -140,13 +150,16 @@ func (s *Service) cmdGithubSearch(roomID, userID string, args []string) (interfa const cmdGithubCreateUsage = `!github create [owner/repo] "issue title" "description"` -func (s *Service) cmdGithubCreate(roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGithubCreate(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { cli, resp, err := s.requireGithubClientFor(userID) if cli == nil { return resp, err } if len(args) == 0 { - return &gomatrix.TextMessage{"m.notice", "Usage: " + cmdGithubCreateUsage}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Usage: " + cmdGithubCreateUsage, + }, nil } // We expect the args to look like: @@ -159,12 +172,16 @@ func (s *Service) cmdGithubCreate(roomID, userID string, args []string) (interfa // look for a default repo defaultRepo := s.defaultRepo(roomID) if defaultRepo == "" { - return &gomatrix.TextMessage{"m.notice", "Need to specify repo. Usage: " + cmdGithubCreateUsage}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Need to specify repo. Usage: " + cmdGithubCreateUsage, + }, nil } // default repo should pass the regexp ownerRepoGroups = ownerRepoRegex.FindStringSubmatch(defaultRepo) if len(ownerRepoGroups) == 0 { - return &gomatrix.TextMessage{"m.notice", "Malformed default repo. Usage: " + cmdGithubCreateUsage}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, Body: "Malformed default repo. Usage: " + cmdGithubCreateUsage}, nil } // insert the default as the first arg to reuse the same indices @@ -187,7 +204,7 @@ func (s *Service) cmdGithubCreate(roomID, userID string, args []string) (interfa title = &joinedTitle } - issue, res, err := cli.Issues.Create(ownerRepoGroups[1], ownerRepoGroups[2], &gogithub.IssueRequest{ + issue, res, err := cli.Issues.Create(context.Background(), ownerRepoGroups[1], ownerRepoGroups[2], &gogithub.IssueRequest{ Title: title, Body: desc, }) @@ -199,7 +216,8 @@ func (s *Service) cmdGithubCreate(roomID, userID string, args []string) (interfa return nil, fmt.Errorf("Failed to create issue. HTTP %d", res.StatusCode) } - return gomatrix.TextMessage{"m.notice", fmt.Sprintf("Created issue: %s", *issue.HTMLURL)}, nil + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, Body: fmt.Sprintf("Created issue: %s", *issue.HTMLURL)}, nil } var cmdGithubReactAliases = map[string]string{ @@ -235,18 +253,23 @@ var cmdGithubReactAliases = map[string]string{ const cmdGithubReactUsage = `!github react [owner/repo]#issue (+1|👍|-1|:-1:|laugh|:smile:|confused|uncertain|heart|❤|hooray|:tada:)` -func (s *Service) cmdGithubReact(roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGithubReact(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { cli, resp, err := s.requireGithubClientFor(userID) if cli == nil { return resp, err } if len(args) < 2 { - return &gomatrix.TextMessage{"m.notice", "Usage: " + cmdGithubReactUsage}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, Body: "Usage: " + cmdGithubReactUsage, + }, nil } reaction, ok := cmdGithubReactAliases[args[1]] if !ok { - return &gomatrix.TextMessage{"m.notice", "Invalid reaction. Usage: " + cmdGithubReactUsage}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Invalid reaction. Usage: " + cmdGithubReactUsage, + }, nil } // get owner,repo,issue,resp out of args[0] @@ -255,7 +278,7 @@ func (s *Service) cmdGithubReact(roomID, userID string, args []string) (interfac return resp, nil } - _, res, err := cli.Reactions.CreateIssueReaction(owner, repo, issueNum, reaction) + _, res, err := cli.Reactions.CreateIssueReaction(context.Background(), owner, repo, issueNum, reaction) if err != nil { log.WithField("err", err).Print("Failed to react to issue") @@ -265,18 +288,24 @@ func (s *Service) cmdGithubReact(roomID, userID string, args []string) (interfac return nil, fmt.Errorf("Failed to react to issue. HTTP %d", res.StatusCode) } - return gomatrix.TextMessage{"m.notice", fmt.Sprintf("Reacted to issue with: %s", args[1])}, nil + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: fmt.Sprintf("Reacted to issue with: %s", args[1]), + }, nil } const cmdGithubCommentUsage = `!github comment [owner/repo]#issue "comment text"` -func (s *Service) cmdGithubComment(roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGithubComment(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { cli, resp, err := s.requireGithubClientFor(userID) if cli == nil { return resp, err } if len(args) == 0 { - return &gomatrix.TextMessage{"m.notice", "Usage: " + cmdGithubCommentUsage}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Usage: " + cmdGithubCommentUsage, + }, nil } // get owner,repo,issue,resp out of args[0] @@ -294,7 +323,7 @@ func (s *Service) cmdGithubComment(roomID, userID string, args []string) (interf comment = &joinedComment } - issueComment, res, err := cli.Issues.CreateComment(owner, repo, issueNum, &gogithub.IssueComment{ + issueComment, res, err := cli.Issues.CreateComment(context.Background(), owner, repo, issueNum, &gogithub.IssueComment{ Body: comment, }) @@ -306,20 +335,29 @@ func (s *Service) cmdGithubComment(roomID, userID string, args []string) (interf return nil, fmt.Errorf("Failed to create issue comment. HTTP %d", res.StatusCode) } - return gomatrix.TextMessage{"m.notice", fmt.Sprintf("Commented on issue: %s", *issueComment.HTMLURL)}, nil + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: fmt.Sprintf("Commented on issue: %s", *issueComment.HTMLURL), + }, nil } const cmdGithubAssignUsage = `!github assign [owner/repo]#issue username [username] [...]` -func (s *Service) cmdGithubAssign(roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGithubAssign(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { cli, resp, err := s.requireGithubClientFor(userID) if cli == nil { return resp, err } if len(args) < 1 { - return &gomatrix.TextMessage{"m.notice", "Usage: " + cmdGithubAssignUsage}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Usage: " + cmdGithubAssignUsage, + }, nil } else if len(args) < 2 { - return &gomatrix.TextMessage{"m.notice", "Needs at least one username. Usage: " + cmdGithubAssignUsage}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Needs at least one username. Usage: " + cmdGithubAssignUsage, + }, nil } // get owner,repo,issue,resp out of args[0] @@ -328,7 +366,7 @@ func (s *Service) cmdGithubAssign(roomID, userID string, args []string) (interfa return resp, nil } - issue, res, err := cli.Issues.AddAssignees(owner, repo, issueNum, args[1:]) + issue, res, err := cli.Issues.AddAssignees(context.Background(), owner, repo, issueNum, args[1:]) if err != nil { log.WithField("err", err).Print("Failed to add issue assignees") @@ -338,16 +376,22 @@ func (s *Service) cmdGithubAssign(roomID, userID string, args []string) (interfa return nil, fmt.Errorf("Failed to add issue assignees. HTTP %d", res.StatusCode) } - return gomatrix.TextMessage{"m.notice", fmt.Sprintf("Added assignees to issue: %s", *issue.HTMLURL)}, nil + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: fmt.Sprintf("Added assignees to issue: %s", *issue.HTMLURL), + }, nil } -func (s *Service) githubIssueCloseReopen(roomID, userID string, args []string, state, verb, help string) (interface{}, error) { +func (s *Service) githubIssueCloseReopen(roomID id.RoomID, userID id.UserID, args []string, state, verb, help string) (interface{}, error) { cli, resp, err := s.requireGithubClientFor(userID) if cli == nil { return resp, err } if len(args) == 0 { - return &gomatrix.TextMessage{"m.notice", "Usage: " + help}, nil + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Usage: " + help, + }, nil } // get owner,repo,issue,resp out of args[0] @@ -356,7 +400,7 @@ func (s *Service) githubIssueCloseReopen(roomID, userID string, args []string, s return resp, nil } - issueComment, res, err := cli.Issues.Edit(owner, repo, issueNum, &gogithub.IssueRequest{ + issueComment, res, err := cli.Issues.Edit(context.Background(), owner, repo, issueNum, &gogithub.IssueRequest{ State: &state, }) @@ -368,22 +412,25 @@ func (s *Service) githubIssueCloseReopen(roomID, userID string, args []string, s return nil, fmt.Errorf("Failed to %s issue. HTTP %d", verb, res.StatusCode) } - return gomatrix.TextMessage{"m.notice", fmt.Sprintf("Closed issue: %s", *issueComment.HTMLURL)}, nil + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: fmt.Sprintf("Closed issue: %s", *issueComment.HTMLURL), + }, nil } const cmdGithubCloseUsage = `!github close [owner/repo]#issue` -func (s *Service) cmdGithubClose(roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGithubClose(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.githubIssueCloseReopen(roomID, userID, args, "closed", "close", cmdGithubCloseUsage) } const cmdGithubReopenUsage = `!github reopen [owner/repo]#issue` -func (s *Service) cmdGithubReopen(roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGithubReopen(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.githubIssueCloseReopen(roomID, userID, args, "open", "open", cmdGithubCloseUsage) } -func (s *Service) getIssueDetailsFor(input, roomID, usage string) (owner, repo string, issueNum int, resp interface{}) { +func (s *Service) getIssueDetailsFor(input string, roomID id.RoomID, usage string) (owner, repo string, issueNum int, resp interface{}) { // We expect the input to look like: // "[owner/repo]#issue" // They can omit the owner/repo if there is a default one set. @@ -391,7 +438,10 @@ func (s *Service) getIssueDetailsFor(input, roomID, usage string) (owner, repo s ownerRepoIssueGroups := ownerRepoIssueRegexAnchored.FindStringSubmatch(input) if len(ownerRepoIssueGroups) != 5 { - resp = &gomatrix.TextMessage{"m.notice", "Usage: " + usage} + resp = &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Usage: " + usage, + } return } @@ -400,7 +450,10 @@ func (s *Service) getIssueDetailsFor(input, roomID, usage string) (owner, repo s var err error if issueNum, err = strconv.Atoi(ownerRepoIssueGroups[4]); err != nil { - resp = &gomatrix.TextMessage{"m.notice", "Malformed issue number. Usage: " + usage} + resp = &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Malformed issue number. Usage: " + usage, + } return } @@ -408,13 +461,19 @@ func (s *Service) getIssueDetailsFor(input, roomID, usage string) (owner, repo s // issue only match, this only works if there is a default repo defaultRepo := s.defaultRepo(roomID) if defaultRepo == "" { - resp = &gomatrix.TextMessage{"m.notice", "Need to specify repo. Usage: " + usage} + resp = &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Need to specify repo. Usage: " + usage, + } return } segs := strings.Split(defaultRepo, "/") if len(segs) != 2 { - resp = &gomatrix.TextMessage{"m.notice", "Malformed default repo. Usage: " + usage} + resp = &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Malformed default repo. Usage: " + usage, + } return } @@ -424,10 +483,10 @@ func (s *Service) getIssueDetailsFor(input, roomID, usage string) (owner, repo s return } -func (s *Service) expandIssue(roomID, userID, owner, repo string, issueNum int) interface{} { +func (s *Service) expandIssue(roomID id.RoomID, userID id.UserID, owner, repo string, issueNum int) interface{} { cli := s.githubClientFor(userID, true) - i, _, err := cli.Issues.Get(owner, repo, issueNum) + i, _, err := cli.Issues.Get(context.Background(), owner, repo, issueNum) if err != nil { log.WithError(err).WithFields(log.Fields{ "owner": owner, @@ -437,16 +496,16 @@ func (s *Service) expandIssue(roomID, userID, owner, repo string, issueNum int) return nil } - return &gomatrix.TextMessage{ - "m.notice", - fmt.Sprintf("%s : %s", *i.HTMLURL, *i.Title), + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: fmt.Sprintf("%s : %s", *i.HTMLURL, *i.Title), } } -func (s *Service) expandCommit(roomID, userID, owner, repo, sha string) interface{} { +func (s *Service) expandCommit(roomID id.RoomID, userID id.UserID, owner, repo, sha string) interface{} { cli := s.githubClientFor(userID, true) - c, _, err := cli.Repositories.GetCommit(owner, repo, sha) + c, _, err := cli.Repositories.GetCommit(context.Background(), owner, repo, sha) if err != nil { log.WithError(err).WithFields(log.Fields{ "owner": owner, @@ -487,10 +546,10 @@ func (s *Service) expandCommit(roomID, userID, owner, repo, sha string) interfac plainBuffer.WriteString(segs[0]) } - return &gomatrix.HTMLMessage{ + return &mevt.MessageEventContent{ Body: plainBuffer.String(), - MsgType: "m.notice", - Format: "org.matrix.custom.html", + MsgType: mevt.MsgNotice, + Format: mevt.FormatHTML, FormattedBody: htmlBuffer.String(), } } @@ -504,56 +563,56 @@ func (s *Service) expandCommit(roomID, userID, owner, repo, sha string) interfac // 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 *gomatrix.Client) []types.Command { +func (s *Service) Commands(cli *mautrix.Client) []types.Command { return []types.Command{ - types.Command{ + { Path: []string{"github", "search"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGithubSearch(roomID, userID, args) }, }, - types.Command{ + { Path: []string{"github", "create"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGithubCreate(roomID, userID, args) }, }, - types.Command{ + { Path: []string{"github", "react"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGithubReact(roomID, userID, args) }, }, - types.Command{ + { Path: []string{"github", "comment"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGithubComment(roomID, userID, args) }, }, - types.Command{ + { Path: []string{"github", "assign"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGithubAssign(roomID, userID, args) }, }, - types.Command{ + { Path: []string{"github", "close"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGithubClose(roomID, userID, args) }, }, - types.Command{ + { Path: []string{"github", "reopen"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGithubReopen(roomID, userID, args) }, }, - types.Command{ + { Path: []string{"github", "help"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { - return &gomatrix.TextMessage{ - "m.notice", - strings.Join([]string{ + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: strings.Join([]string{ cmdGithubCreateUsage, cmdGithubReactUsage, cmdGithubCommentUsage, @@ -573,11 +632,11 @@ func (s *Service) Commands(cli *gomatrix.Client) []types.Command { // it will also expand strings of the form: // #12 // using the default repository. -func (s *Service) Expansions(cli *gomatrix.Client) []types.Expansion { +func (s *Service) Expansions(cli *mautrix.Client) []types.Expansion { return []types.Expansion{ types.Expansion{ Regexp: ownerRepoIssueRegex, - Expand: func(roomID, userID string, matchingGroups []string) interface{} { + Expand: func(roomID id.RoomID, userID id.UserID, matchingGroups []string) interface{} { // There's an optional group in the regex so matchingGroups can look like: // [foo/bar#55 foo bar 55] // [#55 55] @@ -619,7 +678,7 @@ func (s *Service) Expansions(cli *gomatrix.Client) []types.Expansion { }, types.Expansion{ Regexp: ownerRepoCommitRegex, - Expand: func(roomID, userID string, matchingGroups []string) interface{} { + Expand: func(roomID id.RoomID, userID id.UserID, matchingGroups []string) interface{} { // There's an optional group in the regex so matchingGroups can look like: // [foo/bar@a123 foo bar a123] // [@a123 a123] @@ -659,7 +718,7 @@ func (s *Service) Expansions(cli *gomatrix.Client) []types.Expansion { } // Register makes sure that the given realm ID maps to a github realm. -func (s *Service) Register(oldService types.Service, client *gomatrix.Client) error { +func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { if s.RealmID == "" { return fmt.Errorf("RealmID is required") } @@ -678,7 +737,7 @@ func (s *Service) Register(oldService types.Service, client *gomatrix.Client) er } // defaultRepo returns the default repo for the given room, or an empty string. -func (s *Service) defaultRepo(roomID string) string { +func (s *Service) defaultRepo(roomID id.RoomID) string { logger := log.WithFields(log.Fields{ "room_id": roomID, "bot_user_id": s.ServiceUserID(), @@ -707,7 +766,7 @@ func (s *Service) defaultRepo(roomID string) string { return defaultRepo } -func (s *Service) githubClientFor(userID string, allowUnauth bool) *gogithub.Client { +func (s *Service) githubClientFor(userID id.UserID, allowUnauth bool) *gogithub.Client { token, err := getTokenForUser(s.RealmID, userID) if err != nil { log.WithFields(log.Fields{ @@ -725,7 +784,7 @@ func (s *Service) githubClientFor(userID string, allowUnauth bool) *gogithub.Cli } } -func getTokenForUser(realmID, userID string) (string, error) { +func getTokenForUser(realmID string, userID id.UserID) (string, error) { realm, err := database.GetServiceDB().LoadAuthRealm(realmID) if err != nil { return "", err @@ -750,7 +809,7 @@ func getTokenForUser(realmID, userID string) (string, error) { } func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), } diff --git a/services/github/github_webhook.go b/services/github/github_webhook.go index f8bcea9..4c54d2e 100644 --- a/services/github/github_webhook.go +++ b/services/github/github_webhook.go @@ -1,6 +1,7 @@ package github import ( + "context" "fmt" "net/http" "sort" @@ -11,8 +12,10 @@ import ( "github.com/matrix-org/go-neb/services/github/client" "github.com/matrix-org/go-neb/services/github/webhook" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // WebhookServiceType of the Github Webhook service. @@ -45,12 +48,12 @@ type WebhookService struct { types.DefaultService webhookEndpointURL string // The user ID to create/delete webhooks as. - ClientUserID string + ClientUserID id.UserID // The ID of an existing "github" realm. This realm will be used to obtain // the Github credentials of the ClientUserID. RealmID string // A map from Matrix room ID to Github "owner/repo"-style repositories. - Rooms map[string]struct { + Rooms map[id.RoomID]struct { // A map of "owner/repo"-style repositories to the events to listen for. Repos map[string]struct { // owner/repo => { events: ["push","issue","pull_request"] } // The webhook events to listen for. Currently supported: @@ -79,7 +82,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 *gomatrix.Client) { +func (s *WebhookService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { evType, repo, msg, err := webhook.OnReceiveRequest(req, s.SecretToken) if err != nil { w.WriteHeader(err.Code) @@ -108,7 +111,7 @@ func (s *WebhookService) OnReceiveWebhook(w http.ResponseWriter, req *http.Reque "message": msg, "room_id": roomID, }).Print("Sending notification to room") - if _, e := cli.SendMessageEvent(roomID, "m.room.message", msg); e != nil { + if _, e := cli.SendMessageEvent(roomID, event.EventMessage, msg); e != nil { logger.WithError(e).WithField("room_id", roomID).Print( "Failed to send notification to room.") } @@ -143,7 +146,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 *gomatrix.Client) error { +func (s *WebhookService) Register(oldService types.Service, client *mautrix.Client) error { if s.RealmID == "" || s.ClientUserID == "" { return fmt.Errorf("RealmID and ClientUserID is required") } @@ -249,9 +252,9 @@ func (s *WebhookService) PostRegister(oldService types.Service) { } } -func (s *WebhookService) joinWebhookRooms(client *gomatrix.Client) error { +func (s *WebhookService) joinWebhookRooms(client *mautrix.Client) error { for roomID := range s.Rooms { - if _, err := client.JoinRoom(roomID, "", nil); err != nil { + if _, err := client.JoinRoom(roomID.String(), "", nil); err != nil { // TODO: Leave the rooms we successfully joined? return err } @@ -300,7 +303,7 @@ func (s *WebhookService) createHook(cli *gogithub.Client, ownerRepo string) erro cfg["secret"] = s.SecretToken } events := []string{"push", "pull_request", "issues", "issue_comment", "pull_request_review_comment"} - _, res, err := cli.Repositories.CreateHook(owner, repo, &gogithub.Hook{ + _, res, err := cli.Repositories.CreateHook(context.Background(), owner, repo, &gogithub.Hook{ Name: &name, Config: cfg, Events: events, @@ -338,7 +341,7 @@ func (s *WebhookService) deleteHook(owner, repo string) error { // Get a list of webhooks for this owner/repo and find the one which has the // same endpoint URL which is what github uses to determine equivalence. - hooks, _, err := cli.Repositories.ListHooks(owner, repo, nil) + hooks, _, err := cli.Repositories.ListHooks(context.Background(), owner, repo, nil) if err != nil { return err } @@ -362,7 +365,7 @@ func (s *WebhookService) deleteHook(owner, repo string) error { return fmt.Errorf("Failed to find hook with endpoint: %s", s.webhookEndpointURL) } - _, err = cli.Repositories.DeleteHook(owner, repo, *hook.ID) + _, err = cli.Repositories.DeleteHook(context.Background(), owner, repo, *hook.ID) return err } @@ -427,7 +430,7 @@ func difference(a, b []string) (onlyA, onlyB []string) { } } -func (s *WebhookService) githubClientFor(userID string, allowUnauth bool) *gogithub.Client { +func (s *WebhookService) githubClientFor(userID id.UserID, allowUnauth bool) *gogithub.Client { token, err := getTokenForUser(s.RealmID, userID) if err != nil { log.WithFields(log.Fields{ @@ -462,7 +465,7 @@ func (s *WebhookService) loadRealm() (types.AuthRealm, error) { } func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &WebhookService{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, WebhookServiceType), webhookEndpointURL: webhookEndpointURL, diff --git a/services/github/github_webhook_test.go b/services/github/github_webhook_test.go index b73c083..2d9d3d5 100644 --- a/services/github/github_webhook_test.go +++ b/services/github/github_webhook_test.go @@ -13,7 +13,8 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/testutils" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" ) var roomID = "!testroom:id" @@ -22,13 +23,13 @@ func TestGithubWebhook(t *testing.T) { database.SetServiceDB(&database.NopStorage{}) // Intercept message sending to Matrix and mock responses - msgs := []gomatrix.TextMessage{} + msgs := []mevt.MessageEventContent{} matrixTrans := struct{ testutils.MockTransport }{} matrixTrans.RT = func(req *http.Request) (*http.Response, error) { if !strings.Contains(req.URL.String(), "/send/m.room.message") { return nil, fmt.Errorf("Unhandled URL: %s", req.URL.String()) } - var msg gomatrix.TextMessage + var msg mevt.MessageEventContent if err := json.NewDecoder(req.Body).Decode(&msg); err != nil { return nil, fmt.Errorf("Failed to decode request JSON: %s", err) } @@ -38,7 +39,7 @@ func TestGithubWebhook(t *testing.T) { Body: ioutil.NopCloser(bytes.NewBufferString(`{"event_id":"$yup:event"}`)), }, nil } - matrixCli, _ := gomatrix.NewClient("https://hyrule", "@ghwebhook:hyrule", "its_a_secret") + matrixCli, _ := mautrix.NewClient("https://hyrule", "@ghwebhook:hyrule", "its_a_secret") matrixCli.Client = &http.Client{Transport: matrixTrans} // create the service diff --git a/services/github/webhook/webhook.go b/services/github/webhook/webhook.go index bfa8720..d639ab7 100644 --- a/services/github/webhook/webhook.go +++ b/services/github/webhook/webhook.go @@ -12,16 +12,17 @@ import ( "strings" "github.com/google/go-github/github" - "github.com/matrix-org/gomatrix" + "github.com/matrix-org/go-neb/services/utils" "github.com/matrix-org/util" log "github.com/sirupsen/logrus" + mevt "maunium.net/go/mautrix/event" ) // OnReceiveRequest processes incoming github webhook requests and returns a // matrix message to send, along with parsed repo information. // The secretToken, if supplied, will be used to verify the request is from // Github. If it isn't, an error is returned. -func OnReceiveRequest(r *http.Request, secretToken string) (string, *github.Repository, *gomatrix.HTMLMessage, *util.JSONResponse) { +func OnReceiveRequest(r *http.Request, secretToken string) (string, *github.Repository, *mevt.MessageEventContent, *util.JSONResponse) { // Verify the HMAC signature if NEB was configured with a secret token eventType := r.Header.Get("X-GitHub-Event") signatureSHA1 := r.Header.Get("X-Hub-Signature") @@ -72,7 +73,7 @@ func OnReceiveRequest(r *http.Request, secretToken string) (string, *github.Repo return "", nil, nil, &resErr } - msg := gomatrix.GetHTMLMessage("m.notice", htmlStr) + msg := utils.StrippedHTMLMessage(mevt.MsgNotice, htmlStr) return refinedType, repo, &msg, nil } diff --git a/services/google/google.go b/services/google/google.go index 430af61..6d456f2 100644 --- a/services/google/google.go +++ b/services/google/google.go @@ -12,8 +12,10 @@ import ( "strings" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // ServiceType of the Google service @@ -68,23 +70,23 @@ 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 *gomatrix.Client) []types.Command { +func (s *Service) Commands(client *mautrix.Client) []types.Command { return []types.Command{ - types.Command{ + { Path: []string{"google", "image"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGoogleImgSearch(client, roomID, userID, args) }, }, - types.Command{ + { Path: []string{"google", "help"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return usageMessage(), nil }, }, - types.Command{ + { Path: []string{"google"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return usageMessage(), nil }, }, @@ -92,12 +94,14 @@ func (s *Service) Commands(client *gomatrix.Client) []types.Command { } // usageMessage returns a matrix TextMessage representation of the service usage -func usageMessage() *gomatrix.TextMessage { - return &gomatrix.TextMessage{"m.notice", - `Usage: !google image image_search_text`} +func usageMessage() *mevt.MessageEventContent { + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: `Usage: !google image image_search_text`, + } } -func (s *Service) cmdGoogleImgSearch(client *gomatrix.Client, roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGoogleImgSearch(client *mautrix.Client, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { if len(args) < 1 { return usageMessage(), nil @@ -114,8 +118,8 @@ func (s *Service) cmdGoogleImgSearch(client *gomatrix.Client, roomID, userID str var imgURL = searchResult.Link if imgURL == "" { - return gomatrix.TextMessage{ - MsgType: "m.notice", + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, Body: "No image found!", }, nil } @@ -126,14 +130,14 @@ func (s *Service) cmdGoogleImgSearch(client *gomatrix.Client, roomID, userID str return nil, fmt.Errorf("Failed to upload Google image at URL %s (content type %s) to matrix: %s", imgURL, searchResult.Mime, err.Error()) } - return gomatrix.ImageMessage{ - MsgType: "m.image", + return mevt.MessageEventContent{ + MsgType: mevt.MsgImage, Body: querySentence, - URL: resUpload.ContentURI, - Info: gomatrix.ImageInfo{ - Height: uint(math.Floor(searchResult.Image.Height)), - Width: uint(math.Floor(searchResult.Image.Width)), - Mimetype: searchResult.Mime, + URL: resUpload.ContentURI.CUString(), + Info: &mevt.FileInfo{ + Height: int(math.Floor(searchResult.Image.Height)), + Width: int(math.Floor(searchResult.Image.Width)), + MimeType: searchResult.Mime, }, }, nil } @@ -195,7 +199,7 @@ func response2String(res *http.Response) string { // Initialise the service func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), } diff --git a/services/google/google_test.go b/services/google/google_test.go index d3a5cf7..f60ba07 100644 --- a/services/google/google_test.go +++ b/services/google/google_test.go @@ -12,7 +12,7 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/testutils" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" ) // TODO: It would be nice to tabularise this test so we can try failing different combinations of responses to make @@ -101,7 +101,7 @@ func TestCommand(t *testing.T) { } return nil, fmt.Errorf("Unknown URL: %s", req.URL.String()) } - matrixCli, _ := gomatrix.NewClient("https://hyrule", "@googlebot:hyrule", "its_a_secret") + matrixCli, _ := mautrix.NewClient("https://hyrule", "@googlebot:hyrule", "its_a_secret") matrixCli.Client = &http.Client{Transport: matrixTrans} // Execute the matrix !command diff --git a/services/guggy/guggy.go b/services/guggy/guggy.go index 329c13f..33b8020 100644 --- a/services/guggy/guggy.go +++ b/services/guggy/guggy.go @@ -11,8 +11,10 @@ import ( "strings" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // ServiceType of the Guggy service @@ -49,17 +51,17 @@ 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 *gomatrix.Client) []types.Command { +func (s *Service) Commands(client *mautrix.Client) []types.Command { return []types.Command{ - types.Command{ + { Path: []string{"guggy"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdGuggy(client, roomID, userID, args) }, }, } } -func (s *Service) cmdGuggy(client *gomatrix.Client, roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdGuggy(client *mautrix.Client, 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) @@ -68,8 +70,8 @@ func (s *Service) cmdGuggy(client *gomatrix.Client, roomID, userID string, args } if gifResult.GIF == "" { - return gomatrix.TextMessage{ - MsgType: "m.notice", + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, Body: "No GIF found!", }, nil } @@ -79,14 +81,14 @@ func (s *Service) cmdGuggy(client *gomatrix.Client, roomID, userID string, args return nil, fmt.Errorf("Failed to upload Guggy image to matrix: %s", err.Error()) } - return gomatrix.ImageMessage{ + return mevt.MessageEventContent{ MsgType: "m.image", Body: querySentence, - URL: resUpload.ContentURI, - Info: gomatrix.ImageInfo{ - Height: uint(math.Floor(gifResult.Height)), - Width: uint(math.Floor(gifResult.Width)), - Mimetype: "image/gif", + URL: resUpload.ContentURI.CUString(), + Info: &mevt.FileInfo{ + Height: int(math.Floor(gifResult.Height)), + Width: int(math.Floor(gifResult.Width)), + MimeType: "image/gif", }, }, nil } @@ -142,7 +144,7 @@ func (s *Service) text2gifGuggy(querySentence string) (*guggyGifResult, error) { } func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), } diff --git a/services/guggy/guggy_test.go b/services/guggy/guggy_test.go index 9451a84..ae8d097 100644 --- a/services/guggy/guggy_test.go +++ b/services/guggy/guggy_test.go @@ -12,7 +12,7 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/testutils" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" ) // TODO: It would be nice to tabularise this test so we can try failing different combinations of responses to make @@ -86,7 +86,7 @@ func TestCommand(t *testing.T) { } return nil, fmt.Errorf("Unknown URL: %s", req.URL.String()) } - matrixCli, _ := gomatrix.NewClient("https://hyrule", "@guggybot:hyrule", "its_a_secret") + matrixCli, _ := mautrix.NewClient("https://hyrule", "@guggybot:hyrule", "its_a_secret") matrixCli.Client = &http.Client{Transport: matrixTrans} // Execute the matrix !command diff --git a/services/imgur/imgur.go b/services/imgur/imgur.go index a2ccbb9..4193cdb 100644 --- a/services/imgur/imgur.go +++ b/services/imgur/imgur.go @@ -11,8 +11,10 @@ import ( "strings" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // ServiceType of the Imgur service @@ -114,17 +116,17 @@ 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 *gomatrix.Client) []types.Command { +func (s *Service) Commands(client *mautrix.Client) []types.Command { return []types.Command{ - types.Command{ + { Path: []string{"imgur", "help"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return usageMessage(), nil }, }, - types.Command{ + { Path: []string{"imgur"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdImgSearch(client, roomID, userID, args) }, }, @@ -132,13 +134,15 @@ func (s *Service) Commands(client *gomatrix.Client) []types.Command { } // usageMessage returns a matrix TextMessage representation of the service usage -func usageMessage() *gomatrix.TextMessage { - return &gomatrix.TextMessage{"m.notice", - `Usage: !imgur image_search_text`} +func usageMessage() *mevt.MessageEventContent { + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Usage: !imgur image_search_text", + } } // Search Imgur for a relevant image and upload it to matrix -func (s *Service) cmdImgSearch(client *gomatrix.Client, roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdImgSearch(client *mautrix.Client, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { // Check for query text if len(args) < 1 { return usageMessage(), nil @@ -155,8 +159,8 @@ func (s *Service) cmdImgSearch(client *gomatrix.Client, roomID, userID string, a if searchResultImage != nil { var imgURL = searchResultImage.Link if imgURL == "" { - return gomatrix.TextMessage{ - MsgType: "m.notice", + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, Body: "No image found!", }, nil } @@ -168,24 +172,24 @@ func (s *Service) cmdImgSearch(client *gomatrix.Client, roomID, userID string, a } // Return image message - return gomatrix.ImageMessage{ + return mevt.MessageEventContent{ MsgType: "m.image", Body: querySentence, - URL: resUpload.ContentURI, - Info: gomatrix.ImageInfo{ - Height: uint(searchResultImage.Height), - Width: uint(searchResultImage.Width), - Mimetype: searchResultImage.Type, + URL: resUpload.ContentURI.CUString(), + Info: &mevt.FileInfo{ + Height: searchResultImage.Height, + Width: searchResultImage.Width, + MimeType: searchResultImage.Type, }, }, nil } else if searchResultAlbum != nil { - return gomatrix.TextMessage{ - MsgType: "m.notice", + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, Body: "Search returned an album - Not currently supported", }, nil } else { - return gomatrix.TextMessage{ - MsgType: "m.notice", + return mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, Body: "No image found!", }, nil } @@ -280,7 +284,7 @@ func response2String(res *http.Response) string { // Initialise the service func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), } diff --git a/services/imgur/imgur_test.go b/services/imgur/imgur_test.go index 2ebe548..9b3a676 100644 --- a/services/imgur/imgur_test.go +++ b/services/imgur/imgur_test.go @@ -12,7 +12,7 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/testutils" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" ) func TestCommand(t *testing.T) { @@ -106,7 +106,7 @@ func TestCommand(t *testing.T) { } return nil, fmt.Errorf("Unknown URL: %s", req.URL.String()) } - matrixCli, _ := gomatrix.NewClient("https://hyrule", "@imgurbot:hyrule", "its_a_secret") + matrixCli, _ := mautrix.NewClient("https://hyrule", "@imgurbot:hyrule", "its_a_secret") matrixCli.Client = &http.Client{Transport: matrixTrans} // Execute the matrix !command diff --git a/services/jira/jira.go b/services/jira/jira.go index 212b09a..9d1b0f6 100644 --- a/services/jira/jira.go +++ b/services/jira/jira.go @@ -18,9 +18,12 @@ import ( "github.com/matrix-org/go-neb/realms/jira" "github.com/matrix-org/go-neb/realms/jira/urls" "github.com/matrix-org/go-neb/services/jira/webhook" + "github.com/matrix-org/go-neb/services/utils" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // ServiceType of the JIRA Service @@ -54,9 +57,9 @@ type Service struct { webhookEndpointURL string // The user ID to create issues as, or to create/delete webhooks as. This user // is also used to look up issues for expansions. - ClientUserID string + ClientUserID id.UserID // A map from Matrix room ID to JIRA realms and project keys. - Rooms map[string]struct { + Rooms map[id.RoomID]struct { // A map of realm IDs to project keys. The realm IDs determine the JIRA // endpoint used. Realms map[string]struct { @@ -73,7 +76,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 *gomatrix.Client) error { +func (s *Service) Register(oldService types.Service, client *mautrix.Client) 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. @@ -94,7 +97,7 @@ func (s *Service) Register(oldService types.Service, client *gomatrix.Client) er return nil } -func (s *Service) cmdJiraCreate(roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdJiraCreate(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { // E.g jira create PROJ "Issue title" "Issue desc" if len(args) <= 1 { return nil, errors.New("Missing project key (e.g 'ABC') and/or title") @@ -164,13 +167,13 @@ func (s *Service) cmdJiraCreate(roomID, userID string, args []string) (interface return nil, fmt.Errorf("Failed to create issue: JIRA returned %d", res.StatusCode) } - return &gomatrix.TextMessage{ - "m.notice", - fmt.Sprintf("Created issue: %sbrowse/%s", r.JIRAEndpoint, i.Key), + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: fmt.Sprintf("Created issue: %sbrowse/%s", r.JIRAEndpoint, i.Key), }, nil } -func (s *Service) expandIssue(roomID, userID string, issueKeyGroups []string) interface{} { +func (s *Service) expandIssue(roomID id.RoomID, userID id.UserID, issueKeyGroups []string) interface{} { // issueKeyGroups => ["SYN-123", "SYN", "123"] if len(issueKeyGroups) != 3 { log.WithField("groups", issueKeyGroups).Error("Bad number of groups") @@ -221,8 +224,8 @@ func (s *Service) expandIssue(roomID, userID string, issueKeyGroups []string) in logger.WithError(err).Print("Failed to GET issue") return err } - return gomatrix.GetHTMLMessage( - "m.notice", + return utils.StrippedHTMLMessage( + mevt.MsgNotice, fmt.Sprintf( "%sbrowse/%s : %s", jrealm.JIRAEndpoint, issueKey, htmlSummaryForIssue(issue), @@ -239,11 +242,11 @@ func (s *Service) expandIssue(roomID, userID string, issueKeyGroups []string) in // 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 *gomatrix.Client) []types.Command { +func (s *Service) Commands(cli *mautrix.Client) []types.Command { return []types.Command{ types.Command{ Path: []string{"jira", "create"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdJiraCreate(roomID, userID, args) }, }, @@ -256,11 +259,11 @@ func (s *Service) Commands(cli *gomatrix.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 *gomatrix.Client) []types.Expansion { +func (s *Service) Expansions(cli *mautrix.Client) []types.Expansion { return []types.Expansion{ types.Expansion{ Regexp: issueKeyRegex, - Expand: func(roomID, userID string, issueKeyGroups []string) interface{} { + Expand: func(roomID id.RoomID, userID id.UserID, issueKeyGroups []string) interface{} { return s.expandIssue(roomID, userID, issueKeyGroups) }, }, @@ -268,7 +271,7 @@ func (s *Service) Expansions(cli *gomatrix.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 *gomatrix.Client) { +func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { eventProjectKey, event, httpErr := webhook.OnReceiveRequest(req) if httpErr != nil { log.Print("Failed to handle JIRA webhook") @@ -297,7 +300,7 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli continue } _, msgErr := cli.SendMessageEvent( - roomID, "m.room.message", gomatrix.GetHTMLMessage("m.notice", htmlText), + roomID, mevt.EventMessage, utils.StrippedHTMLMessage(mevt.MsgNotice, htmlText), ) if msgErr != nil { log.WithFields(log.Fields{ @@ -312,7 +315,7 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli w.WriteHeader(200) } -func (s *Service) realmIDForProject(roomID, projectKey string) string { +func (s *Service) realmIDForProject(roomID id.RoomID, projectKey string) string { // TODO: Multiple realms with the same pkey will be randomly chosen. for r, realmConfig := range s.Rooms[roomID].Realms { for pkey, projectConfig := range realmConfig.Projects { @@ -324,7 +327,7 @@ func (s *Service) realmIDForProject(roomID, projectKey string) string { return "" } -func (s *Service) projectToRealm(userID, pkey string) (*jira.Realm, error) { +func (s *Service) projectToRealm(userID id.UserID, pkey string) (*jira.Realm, error) { // We don't know which JIRA installation this project maps to, so: // - Get all known JIRA realms and f.e query their endpoints with the // given user ID's credentials (so if it is a private project they @@ -447,7 +450,7 @@ func htmlForEvent(whe *webhook.Event, jiraBaseURL string) string { } func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), webhookEndpointURL: webhookEndpointURL, diff --git a/services/jira/webhook/webhook.go b/services/jira/webhook/webhook.go index ea6a509..fc18c7b 100644 --- a/services/jira/webhook/webhook.go +++ b/services/jira/webhook/webhook.go @@ -11,6 +11,7 @@ import ( "github.com/matrix-org/go-neb/realms/jira" "github.com/matrix-org/util" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix/id" ) type jiraWebhook struct { @@ -32,7 +33,7 @@ type Event struct { } // RegisterHook checks to see if this user is allowed to track the given projects and then tracks them. -func RegisterHook(jrealm *jira.Realm, projects []string, userID, webhookEndpointURL string) error { +func RegisterHook(jrealm *jira.Realm, projects []string, userID id.UserID, webhookEndpointURL string) error { // Tracking means that a webhook may need to be created on the remote JIRA installation. // We need to make sure that the user has permission to do this. If they don't, it may still be okay if // there is an existing webhook set up for this installation by someone else, *PROVIDED* that the projects @@ -120,7 +121,7 @@ func OnReceiveRequest(req *http.Request) (string, *Event, *util.JSONResponse) { return projKey, &whe, nil } -func createWebhook(jrealm *jira.Realm, webhookEndpointURL, userID string) error { +func createWebhook(jrealm *jira.Realm, webhookEndpointURL string, userID id.UserID) error { cli, err := jrealm.JIRAClient(userID, false) if err != nil { return err @@ -182,7 +183,7 @@ func getWebhook(cli *gojira.Client, webhookEndpointURL string) (*jiraWebhook, bo return nebWH, false, nil } -func checkProjectsArePublic(jrealm *jira.Realm, projects []string, userID string) error { +func checkProjectsArePublic(jrealm *jira.Realm, projects []string, userID id.UserID) error { publicCli, err := jrealm.JIRAClient("", true) if err != nil { return fmt.Errorf("Cannot create public JIRA client") diff --git a/services/rssbot/rssbot.go b/services/rssbot/rssbot.go index ff759cd..251c282 100644 --- a/services/rssbot/rssbot.go +++ b/services/rssbot/rssbot.go @@ -16,10 +16,12 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/polling" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" "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" ) // ServiceType of the RSS Bot service @@ -81,7 +83,7 @@ type Service struct { // Optional. The time to wait between polls. If this is less than minPollingIntervalSeconds, it is ignored. PollIntervalMins int `json:"poll_interval_mins"` // The list of rooms to send feed updates into. This cannot be empty. - Rooms []string `json:"rooms"` + Rooms []id.RoomID `json:"rooms"` // True if rss bot is unable to poll this feed. This is populated by Go-NEB. Use /getService to // retrieve this value. IsFailing bool `json:"is_failing"` @@ -100,7 +102,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 *gomatrix.Client) error { +func (s *Service) Register(oldService types.Service, client *mautrix.Client) 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 @@ -129,8 +131,8 @@ func (s *Service) Register(oldService types.Service, client *gomatrix.Client) er return nil } -func (s *Service) joinRooms(client *gomatrix.Client) { - roomSet := make(map[string]bool) +func (s *Service) joinRooms(client *mautrix.Client) { + roomSet := make(map[id.RoomID]bool) for _, feedInfo := range s.Feeds { for _, roomID := range feedInfo.Rooms { roomSet[roomID] = true @@ -138,7 +140,7 @@ func (s *Service) joinRooms(client *gomatrix.Client) { } for roomID := range roomSet { - if _, err := client.JoinRoom(roomID, "", nil); err != nil { + if _, err := client.JoinRoom(roomID.String(), "", nil); err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": roomID, @@ -173,7 +175,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 *gomatrix.Client) time.Time { +func (s *Service) OnPoll(cli *mautrix.Client) time.Time { logger := log.WithFields(log.Fields{ "service_id": s.ServiceID(), "service_type": s.ServiceType(), @@ -406,7 +408,7 @@ func (s *Service) newItems(feedURL string, allItems []*gofeed.Item) (items []gof return } -func (s *Service) sendToRooms(cli *gomatrix.Client, feedURL string, feed *gofeed.Feed, item gofeed.Item) error { +func (s *Service) sendToRooms(cli *mautrix.Client, feedURL string, feed *gofeed.Feed, item gofeed.Item) error { logger := log.WithFields(log.Fields{ "feed_url": feedURL, "title": item.Title, @@ -414,14 +416,14 @@ func (s *Service) sendToRooms(cli *gomatrix.Client, feedURL string, feed *gofeed }) logger.Info("Sending new feed item") for _, roomID := range s.Feeds[feedURL].Rooms { - if _, err := cli.SendMessageEvent(roomID, "m.room.message", itemToHTML(feed, item)); err != nil { + if _, err := cli.SendMessageEvent(roomID, mevt.EventMessage, itemToHTML(feed, item)); err != nil { logger.WithError(err).WithField("room_id", roomID).Error("Failed to send to room") } } return nil } -func itemToHTML(feed *gofeed.Feed, item gofeed.Item) gomatrix.HTMLMessage { +func itemToHTML(feed *gofeed.Feed, item gofeed.Item) mevt.MessageEventContent { // If an item does not have a title, try using the feed's title instead // Create a new variable instead of mutating that which is passed in itemTitle := item.Title @@ -442,11 +444,11 @@ func itemToHTML(feed *gofeed.Feed, item gofeed.Item) gomatrix.HTMLMessage { html.EscapeString(item.Author.Email)) } } - return gomatrix.HTMLMessage{ + return mevt.MessageEventContent{ Body: fmt.Sprintf("%s: %s ( %s )", html.EscapeString(feed.Title), html.EscapeString(itemTitle), html.EscapeString(item.Link)), MsgType: "m.notice", - Format: "org.matrix.custom.html", + Format: mevt.FormatHTML, FormattedBody: fmtBody, // FeedTitle: //
@@ -532,7 +534,7 @@ func init() { cachingClient = &http.Client{ Transport: userAgentRoundTripper{httpcache.NewTransport(lruCache)}, } - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { r := &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), } diff --git a/services/rssbot/rssbot_test.go b/services/rssbot/rssbot_test.go index b3253dd..3ba9917 100644 --- a/services/rssbot/rssbot_test.go +++ b/services/rssbot/rssbot_test.go @@ -14,7 +14,9 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/testutils" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) const rssFeedXML = ` @@ -65,7 +67,7 @@ func createRSSClient(t *testing.T, feedURL string) *Service { // Configure the service to force OnPoll to query the RSS feed and attempt to send results // to the right room. f := rssbot.Feeds[feedURL] - f.Rooms = []string{"!linksroom:hyrule"} + f.Rooms = []id.RoomID{"!linksroom:hyrule"} f.NextPollTimestampSecs = time.Now().Unix() rssbot.Feeds[feedURL] = f @@ -84,7 +86,7 @@ func TestHTMLEntities(t *testing.T) { matrixTrans.RT = func(req *http.Request) (*http.Response, error) { if strings.HasPrefix(req.URL.Path, "/_matrix/client/r0/rooms/!linksroom:hyrule/send/m.room.message") { // Check content body to make sure it is decoded - var msg gomatrix.HTMLMessage + var msg mevt.MessageEventContent if err := json.NewDecoder(req.Body).Decode(&msg); err != nil { t.Fatal("Failed to decode request JSON: ", err) return nil, errors.New("Error handling matrix client test request") @@ -104,7 +106,7 @@ func TestHTMLEntities(t *testing.T) { } return nil, errors.New("Unhandled matrix client test request") } - matrixClient, _ := gomatrix.NewClient("https://hyrule", "@happy_mask_salesman:hyrule", "its_a_secret") + matrixClient, _ := mautrix.NewClient("https://hyrule", "@happy_mask_salesman:hyrule", "its_a_secret") matrixClient.Client = &http.Client{Transport: matrixTrans} // Invoke OnPoll to trigger the RSS feed update diff --git a/services/slackapi/message.go b/services/slackapi/message.go index c24325b..54099bf 100644 --- a/services/slackapi/message.go +++ b/services/slackapi/message.go @@ -12,9 +12,9 @@ import ( "regexp" "time" - "github.com/matrix-org/gomatrix" "github.com/russross/blackfriday" log "github.com/sirupsen/logrus" + mevt "maunium.net/go/mautrix/event" ) type slackAttachment struct { @@ -195,7 +195,7 @@ func renderSlackAttachment(attachment *slackAttachment) { } } -func slackMessageToHTMLMessage(message slackMessage) (html gomatrix.HTMLMessage, err error) { +func slackMessageToHTMLMessage(message slackMessage) (html mevt.MessageEventContent, err error) { text := linkifyString(message.Text) if message.Mrkdwn == nil || *message.Mrkdwn == true { message.TextRendered = template.HTML(blackfriday.MarkdownBasic([]byte(text))) diff --git a/services/slackapi/slackapi.go b/services/slackapi/slackapi.go index fd0d75d..327d4ad 100644 --- a/services/slackapi/slackapi.go +++ b/services/slackapi/slackapi.go @@ -5,8 +5,10 @@ import ( "strings" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // ServiceType of the Slack API service @@ -26,16 +28,16 @@ type Service struct { types.DefaultService webhookEndpointURL string // The URL which should be given to an outgoing slack webhook - Populated by Go-NEB after Service registration. - WebhookURL string `json:"webhook_url"` - RoomID string `json:"room_id"` - MessageType string `json:"message_type"` + WebhookURL string `json:"webhook_url"` + RoomID id.RoomID `json:"room_id"` + MessageType event.MessageType `json:"message_type"` } // OnReceiveWebhook receives requests from a slack outgoing webhook and possibly sends requests // 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 *gomatrix.Client) { +func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { segments := strings.Split(req.URL.Path, "/") if len(segments) < 2 { @@ -45,7 +47,7 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli messageType := s.MessageType if messageType == "" { - messageType = "m.text" + messageType = event.MsgText } roomID := s.RoomID @@ -64,15 +66,15 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli } htmlMessage.MsgType = messageType cli.SendMessageEvent( - roomID, "m.room.message", htmlMessage, + roomID, event.EventMessage, htmlMessage, ) w.WriteHeader(200) } // Register joins the configured room and sets the public WebhookURL -func (s *Service) Register(oldService types.Service, client *gomatrix.Client) error { +func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { s.WebhookURL = s.webhookEndpointURL - if _, err := client.JoinRoom(s.RoomID, "", nil); err != nil { + if _, err := client.JoinRoom(s.RoomID.String(), "", nil); err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": s.RoomID, @@ -83,7 +85,7 @@ func (s *Service) Register(oldService types.Service, client *gomatrix.Client) er } func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), webhookEndpointURL: webhookEndpointURL, diff --git a/services/travisci/travisci.go b/services/travisci/travisci.go index d1953bf..837389c 100644 --- a/services/travisci/travisci.go +++ b/services/travisci/travisci.go @@ -12,8 +12,10 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // ServiceType of the Travis-CI service. @@ -54,7 +56,7 @@ type Service struct { // The URL which should be added to .travis.yml - Populated by Go-NEB after Service registration. WebhookURL string `json:"webhook_url"` // A map from Matrix room ID to Github-style owner/repo repositories. - Rooms map[string]struct { + Rooms map[id.RoomID]struct { // A map of "owner/repo" to configuration information Repos map[string]struct { // The template string to use when creating notifications. @@ -178,7 +180,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 *gomatrix.Client) { +func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { if err := req.ParseForm(); err != nil { log.WithError(err).Error("Failed to read incoming Travis-CI webhook form") w.WriteHeader(400) @@ -222,7 +224,7 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli if ownerRepo != whForRepo { continue } - msg := gomatrix.TextMessage{ + msg := mevt.MessageEventContent{ Body: outputForTemplate(repoData.Template, tmplData), MsgType: "m.notice", } @@ -231,7 +233,7 @@ func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli "message": msg, "room_id": roomID, }).Print("Sending Travis-CI notification to room") - if _, e := cli.SendMessageEvent(roomID, "m.room.message", msg); e != nil { + if _, e := cli.SendMessageEvent(roomID, mevt.EventMessage, msg); e != nil { logger.WithError(e).WithField("room_id", roomID).Print( "Failed to send Travis-CI notification to room.") } @@ -241,7 +243,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 *gomatrix.Client) error { +func (s *Service) Register(oldService types.Service, client *mautrix.Client) error { s.WebhookURL = s.webhookEndpointURL for _, roomData := range s.Rooms { for repo := range roomData.Repos { @@ -273,9 +275,9 @@ func (s *Service) PostRegister(oldService types.Service) { } } -func (s *Service) joinRooms(client *gomatrix.Client) { +func (s *Service) joinRooms(client *mautrix.Client) { for roomID := range s.Rooms { - if _, err := client.JoinRoom(roomID, "", nil); err != nil { + if _, err := client.JoinRoom(roomID.String(), "", nil); err != nil { log.WithFields(log.Fields{ log.ErrorKey: err, "room_id": roomID, @@ -286,7 +288,7 @@ func (s *Service) joinRooms(client *gomatrix.Client) { } func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), webhookEndpointURL: webhookEndpointURL, diff --git a/services/travisci/travisci_test.go b/services/travisci/travisci_test.go index 7bcbf61..91a0091 100644 --- a/services/travisci/travisci_test.go +++ b/services/travisci/travisci_test.go @@ -13,7 +13,8 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/testutils" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" ) const travisOrgPEMPublicKey = (`-----BEGIN PUBLIC KEY----- @@ -114,13 +115,13 @@ func TestTravisCI(t *testing.T) { httpClient = &http.Client{Transport: travisTransport} // Intercept message sending to Matrix and mock responses - msgs := []gomatrix.TextMessage{} + msgs := []mevt.MessageEventContent{} matrixTrans := struct{ testutils.MockTransport }{} matrixTrans.RT = func(req *http.Request) (*http.Response, error) { if !strings.Contains(req.URL.String(), "/send/m.room.message") { return nil, fmt.Errorf("Unhandled URL: %s", req.URL.String()) } - var msg gomatrix.TextMessage + var msg mevt.MessageEventContent if err := json.NewDecoder(req.Body).Decode(&msg); err != nil { return nil, fmt.Errorf("Failed to decode request JSON: %s", err) } @@ -130,13 +131,13 @@ func TestTravisCI(t *testing.T) { Body: ioutil.NopCloser(bytes.NewBufferString(`{"event_id":"$yup:event"}`)), }, nil } - matrixCli, _ := gomatrix.NewClient("https://hyrule", "@travisci:hyrule", "its_a_secret") + matrixCli, _ := mautrix.NewClient("https://hyrule", "@travisci:hyrule", "its_a_secret") matrixCli.Client = &http.Client{Transport: matrixTrans} // BEGIN running the Travis-CI table tests // --------------------------------------- for _, test := range travisTests { - msgs = []gomatrix.TextMessage{} // reset sent messages + msgs = []mevt.MessageEventContent{} // reset sent messages mockWriter := httptest.NewRecorder() travis := makeService(t, test.Template) if travis == nil { @@ -172,7 +173,7 @@ func TestTravisCI(t *testing.T) { } } -func assertResponse(t *testing.T, w *httptest.ResponseRecorder, msgs []gomatrix.TextMessage, expectCode int, expectMsgLength int) bool { +func assertResponse(t *testing.T, w *httptest.ResponseRecorder, msgs []mevt.MessageEventContent, expectCode int, expectMsgLength int) bool { if w.Code != expectCode { t.Errorf("TestTravisCI OnReceiveWebhook want HTTP code %d, got %d", expectCode, w.Code) return false diff --git a/services/utils/utils.go b/services/utils/utils.go new file mode 100644 index 0000000..4a991b2 --- /dev/null +++ b/services/utils/utils.go @@ -0,0 +1,21 @@ +package utils + +import ( + "html" + "regexp" + + mevt "maunium.net/go/mautrix/event" +) + +var htmlRegex = regexp.MustCompile("<[^<]+?>") + +// StrippedHTMLMessage returns a MessageEventContent with the body set to a stripped version of the provided HTML, +// in addition to the provided HTML. +func StrippedHTMLMessage(msgtype mevt.MessageType, htmlText string) mevt.MessageEventContent { + return mevt.MessageEventContent{ + Body: html.UnescapeString(htmlRegex.ReplaceAllLiteralString(htmlText, "")), + MsgType: msgtype, + Format: mevt.FormatHTML, + FormattedBody: htmlText, + } +} diff --git a/services/utils/utils_test.go b/services/utils/utils_test.go new file mode 100644 index 0000000..0c418a1 --- /dev/null +++ b/services/utils/utils_test.go @@ -0,0 +1,19 @@ +package utils + +import ( + "testing" + + mevt "maunium.net/go/mautrix/event" +) + +func TestHTMLStrip(t *testing.T) { + msg := `before <during> after` + stripped := StrippedHTMLMessage(mevt.MsgNotice, msg) + if stripped.MsgType != mevt.MsgNotice { + t.Fatalf("Expected MsgType %v, got %v", mevt.MsgNotice, stripped.MsgType) + } + expected := "before after" + if stripped.Body != expected { + t.Fatalf(`Expected Body "%v", got "%v"`, expected, stripped.Body) + } +} diff --git a/services/wikipedia/wikipedia.go b/services/wikipedia/wikipedia.go index 6d395b3..ae3fa2f 100644 --- a/services/wikipedia/wikipedia.go +++ b/services/wikipedia/wikipedia.go @@ -11,8 +11,10 @@ import ( "github.com/jaytaylor/html2text" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" log "github.com/sirupsen/logrus" + "maunium.net/go/mautrix" + mevt "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) // ServiceType of the Wikipedia service @@ -49,11 +51,11 @@ 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 *gomatrix.Client) []types.Command { +func (s *Service) Commands(client *mautrix.Client) []types.Command { return []types.Command{ - types.Command{ + { Path: []string{"wikipedia"}, - Command: func(roomID, userID string, args []string) (interface{}, error) { + Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { return s.cmdWikipediaSearch(client, roomID, userID, args) }, }, @@ -61,12 +63,14 @@ func (s *Service) Commands(client *gomatrix.Client) []types.Command { } // usageMessage returns a matrix TextMessage representation of the service usage -func usageMessage() *gomatrix.TextMessage { - return &gomatrix.TextMessage{"m.notice", - `Usage: !wikipedia search_text`} +func usageMessage() *mevt.MessageEventContent { + return &mevt.MessageEventContent{ + MsgType: mevt.MsgNotice, + Body: "Usage: !wikipedia search_text", + } } -func (s *Service) cmdWikipediaSearch(client *gomatrix.Client, roomID, userID string, args []string) (interface{}, error) { +func (s *Service) cmdWikipediaSearch(client *mautrix.Client, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { // Check for query text if len(args) < 1 { return usageMessage(), nil @@ -81,7 +85,7 @@ func (s *Service) cmdWikipediaSearch(client *gomatrix.Client, roomID, userID str // No article extracts if searchResultPage == nil || searchResultPage.Extract == "" { - return gomatrix.TextMessage{ + return mevt.MessageEventContent{ MsgType: "m.notice", Body: "No results", }, nil @@ -90,7 +94,7 @@ func (s *Service) cmdWikipediaSearch(client *gomatrix.Client, roomID, userID str // Convert article HTML to text extractText, err := html2text.FromString(searchResultPage.Extract) if err != nil { - return gomatrix.TextMessage{ + return mevt.MessageEventContent{ MsgType: "m.notice", Body: "Failed to convert extract to plain text - " + err.Error(), }, nil @@ -105,7 +109,7 @@ func (s *Service) cmdWikipediaSearch(client *gomatrix.Client, roomID, userID str extractText += fmt.Sprintf("\nhttp://en.wikipedia.org/?curid=%d", searchResultPage.PageID) // Return article extract - return gomatrix.TextMessage{ + return mevt.MessageEventContent{ MsgType: "m.notice", Body: extractText, }, nil @@ -175,7 +179,7 @@ func response2String(res *http.Response) string { // Initialise the service func init() { - types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { + types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), } diff --git a/services/wikipedia/wikipedia_test.go b/services/wikipedia/wikipedia_test.go index d60b8da..00c3019 100644 --- a/services/wikipedia/wikipedia_test.go +++ b/services/wikipedia/wikipedia_test.go @@ -12,7 +12,7 @@ import ( "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/testutils" "github.com/matrix-org/go-neb/types" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" ) // TODO: It would be nice to tabularise this test so we can try failing different combinations of responses to make @@ -83,7 +83,7 @@ func TestCommand(t *testing.T) { matrixTrans.RT = func(req *http.Request) (*http.Response, error) { return nil, fmt.Errorf("Unknown URL: %s", req.URL.String()) } - matrixCli, _ := gomatrix.NewClient("https://hyrule", "@wikipediabot:hyrule", "its_a_secret") + matrixCli, _ := mautrix.NewClient("https://hyrule", "@wikipediabot:hyrule", "its_a_secret") matrixCli.Client = &http.Client{Transport: matrixTrans} // Execute the matrix !command diff --git a/testutil_test.go b/testutil_test.go index c3d63aa..d74f08b 100644 --- a/testutil_test.go +++ b/testutil_test.go @@ -5,6 +5,8 @@ import ( "fmt" "io/ioutil" "net/http" + + "maunium.net/go/mautrix/id" ) // newResponse creates a new HTTP response with the given data. @@ -46,8 +48,8 @@ func (rt *matrixTripper) Handle(method, path string, handler func(req *http.Requ rt.handlers[key] = handler } -func (rt *matrixTripper) HandlePOSTFilter(userID string) { - rt.Handle("POST", "/_matrix/client/r0/user/"+userID+"/filter", +func (rt *matrixTripper) HandlePOSTFilter(userID id.UserID) { + rt.Handle("POST", "/_matrix/client/r0/user/"+userID.String()+"/filter", func(req *http.Request) (*http.Response, error) { return newResponse(200, `{ "filter_id":"abcdef" diff --git a/types/actions.go b/types/actions.go index dbe9e7d..dadcfc5 100644 --- a/types/actions.go +++ b/types/actions.go @@ -3,6 +3,8 @@ package types import ( "regexp" "strings" + + "maunium.net/go/mautrix/id" ) // A Command is something that a user invokes by sending a message starting with '!' @@ -13,7 +15,7 @@ type Command struct { Path []string Arguments []string Help string - Command func(roomID, userID string, arguments []string) (content interface{}, err error) + Command func(roomID id.RoomID, userID id.UserID, arguments []string) (content interface{}, err error) } // An Expansion is something that actives when the user sends any message @@ -22,7 +24,7 @@ type Command struct { // the appropriate RFC. type Expansion struct { Regexp *regexp.Regexp - Expand func(roomID, userID string, matchingGroups []string) interface{} + Expand func(roomID id.RoomID, userID id.UserID, matchingGroups []string) interface{} } // Matches if the arguments start with the path of the command. diff --git a/types/auth.go b/types/auth.go index 27acda0..f29043e 100644 --- a/types/auth.go +++ b/types/auth.go @@ -5,6 +5,8 @@ import ( "encoding/json" "errors" "net/http" + + "maunium.net/go/mautrix/id" ) // AuthRealm represents a place where a user can authenticate themselves. @@ -15,8 +17,8 @@ type AuthRealm interface { Init() error Register() error OnReceiveRedirect(w http.ResponseWriter, req *http.Request) - AuthSession(id, userID, realmID string) AuthSession - RequestAuthSession(userID string, config json.RawMessage) interface{} + AuthSession(id string, userID id.UserID, realmID string) AuthSession + RequestAuthSession(userID id.UserID, config json.RawMessage) interface{} } var realmsByType = map[string]func(string, string) AuthRealm{} @@ -49,7 +51,7 @@ func CreateAuthRealm(realmID, realmType string, realmJSON []byte) (AuthRealm, er // an auth realm. type AuthSession interface { ID() string - UserID() string + UserID() id.UserID RealmID() string Authenticated() bool Info() interface{} diff --git a/types/service.go b/types/service.go index 832f7d6..a4e1105 100644 --- a/types/service.go +++ b/types/service.go @@ -8,14 +8,15 @@ import ( "strings" "time" - "github.com/matrix-org/gomatrix" + "maunium.net/go/mautrix" + "maunium.net/go/mautrix/id" ) // BotOptions for a given bot user in a given room type BotOptions struct { - RoomID string - UserID string - SetByUserID string + RoomID id.RoomID + UserID id.UserID + SetByUserID id.UserID Options map[string]interface{} } @@ -23,25 +24,25 @@ 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 *gomatrix.Client) time.Time + OnPoll(client *mautrix.Client) time.Time } // A Service is the configuration for a bot service. type Service interface { // Return the user ID of this service. - ServiceUserID() string + ServiceUserID() id.UserID // Return an opaque ID used to identify this service. ServiceID() string // Return the type of service. This string MUST NOT change. ServiceType() string - Commands(cli *gomatrix.Client) []Command - Expansions(cli *gomatrix.Client) []Expansion - OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *gomatrix.Client) + Commands(cli *mautrix.Client) []Command + Expansions(cli *mautrix.Client) []Expansion + OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) // 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 *gomatrix.Client) error + Register(oldService Service, client *mautrix.Client) 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 @@ -52,12 +53,12 @@ type Service interface { // DefaultService NO-OPs the implementation of optional Service interface methods. Feel free to override them. type DefaultService struct { id string - serviceUserID string + serviceUserID id.UserID serviceType string } // NewDefaultService creates a new service with implementations for ServiceID(), ServiceType() and ServiceUserID() -func NewDefaultService(serviceID, serviceUserID, serviceType string) DefaultService { +func NewDefaultService(serviceID string, serviceUserID id.UserID, serviceType string) DefaultService { return DefaultService{serviceID, serviceUserID, serviceType} } @@ -70,7 +71,7 @@ func (s *DefaultService) ServiceID() string { // ServiceUserID returns the user ID that the service sends events as. In order for this to return the // service user ID, DefaultService MUST have been initialised by NewDefaultService, the zero-initialiser // is NOT enough. -func (s *DefaultService) ServiceUserID() string { +func (s *DefaultService) ServiceUserID() id.UserID { return s.serviceUserID } @@ -82,23 +83,23 @@ func (s *DefaultService) ServiceType() string { } // Commands returns no commands. -func (s *DefaultService) Commands(cli *gomatrix.Client) []Command { +func (s *DefaultService) Commands(cli *mautrix.Client) []Command { return []Command{} } // Expansions returns no expansions. -func (s *DefaultService) Expansions(cli *gomatrix.Client) []Expansion { +func (s *DefaultService) Expansions(cli *mautrix.Client) []Expansion { return []Expansion{} } // Register does nothing and returns no error. -func (s *DefaultService) Register(oldService Service, client *gomatrix.Client) error { return nil } +func (s *DefaultService) Register(oldService Service, client *mautrix.Client) 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 *gomatrix.Client) { +func (s *DefaultService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *mautrix.Client) { w.WriteHeader(200) // Do nothing } @@ -120,11 +121,11 @@ func BaseURL(u string) error { return nil } -var servicesByType = map[string]func(string, string, string) Service{} +var servicesByType = map[string]func(string, id.UserID, string) Service{} var serviceTypesWhichPoll = map[string]bool{} // RegisterService registers a factory for creating Service instances. -func RegisterService(factory func(string, string, string) Service) { +func RegisterService(factory func(string, id.UserID, string) Service) { s := factory("", "", "") servicesByType[s.ServiceType()] = factory @@ -143,7 +144,7 @@ func PollingServiceTypes() (types []string) { // CreateService creates a Service of the given type and serviceID. // Returns an error if the Service couldn't be created. -func CreateService(serviceID, serviceType, serviceUserID string, serviceJSON []byte) (Service, error) { +func CreateService(serviceID, serviceType string, serviceUserID id.UserID, serviceJSON []byte) (Service, error) { f := servicesByType[serviceType] if f == nil { return nil, errors.New("Unknown service type: " + serviceType)