diff --git a/go.mod b/go.mod index 9b141f4..1b77b71 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/gotify/go-api-client/v2 v2.0.4 github.com/gregdel/pushover v0.0.0-20210216095829-2131362cb888 + github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 github.com/nikoksr/notify v0.17.2 github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sfreiberg/gotwilio v0.0.0-20201211181435-c426a3710ab5 diff --git a/go.sum b/go.sum index a414851..8a59346 100644 --- a/go.sum +++ b/go.sum @@ -52,29 +52,17 @@ github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwc github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/atc0005/go-teams-notify/v2 v2.5.0 h1:WKkrbYe2gfT76rltlWTjg8Eukvz0tvzAqs2jyC3pQe0= -github.com/atc0005/go-teams-notify/v2 v2.5.0/go.mod h1:BSlh1HBcgWcGoNM3Abm36WMPcj+k8Wf0ZLZx6lBx2qk= github.com/atc0005/go-teams-notify/v2 v2.6.0 h1:YegKDWbjlatR0fP2yHsQYXzTcUGNJXhm1/OiCgbyysc= github.com/atc0005/go-teams-notify/v2 v2.6.0/go.mod h1:xo6GejLDHn3tWBA181F8LrllIL0xC1uRsRxq7YNXaaY= -github.com/aws/aws-sdk-go-v2 v1.6.0/go.mod h1:tI4KhsR5VkzlUa2DZAdwx7wCAYGwkZZ1H31PYrBFx1w= github.com/aws/aws-sdk-go-v2 v1.7.0/go.mod h1:tb9wi5s61kTDA5qCkcDbt3KRVV74GGslQkl/DRdX/P4= -github.com/aws/aws-sdk-go-v2/config v1.3.0/go.mod h1:lOxzHWDt/k7MMidA/K8DgXL4+ynnZYsDq65Qhs/l3dg= github.com/aws/aws-sdk-go-v2/config v1.4.1/go.mod h1:HCDWZ/oeY59TPtXslxlbkCqLQBsVu6b09kiG43tdP+I= -github.com/aws/aws-sdk-go-v2/credentials v1.2.1/go.mod h1:Rfvim1eZTC9W5s8YJyYYtl1KMk6e8fHv+wMRQGO4Ru0= github.com/aws/aws-sdk-go-v2/credentials v1.3.0/go.mod h1:tOcv+qDZ0O+6Jk2beMl5JnZX6N0H7O8fw9UsD3bP7GI= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.1.1/go.mod h1:GTXAhrxHQOj9N+J5tYVjwt+rpRyy/42qLjlgw9pz1a0= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.2.0/go.mod h1:XvzoGzuS0kKPzCQtJCC22Xh/mMgVAzfGo/0V+mk/Cu0= -github.com/aws/aws-sdk-go-v2/internal/ini v1.0.0/go.mod h1:g3XMXuxvqSMUjnsXXp/960152w0wFS4CXVYgQaSVOHE= github.com/aws/aws-sdk-go-v2/internal/ini v1.1.0/go.mod h1:qGQ/9IfkZonRNSNLE99/yBJ7EPA/h8jlWEqtJCcaj+Q= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.1.1/go.mod h1:2+ehJPkdIdl46VCj67Emz/EH2hpebHZtaLdzqg+sWOI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.2.0/go.mod h1:a7XLWNKuVgOxjssEF019IiHPv35k8KHBaWv/wJAfi2A= -github.com/aws/aws-sdk-go-v2/service/ses v1.3.1/go.mod h1:6WbvZTnH6a1YzeMZDi/hSjTbPB3RekFw5aQKSwKTksk= github.com/aws/aws-sdk-go-v2/service/ses v1.4.0/go.mod h1:08bHuVAInVMMxrPBP0iNcWSv+XlN0T1tEjfDUJNKIRk= -github.com/aws/aws-sdk-go-v2/service/sso v1.2.1/go.mod h1:VimPFPltQ/920i1X0Sb0VJBROLIHkDg2MNP10D46OGs= github.com/aws/aws-sdk-go-v2/service/sso v1.3.0/go.mod h1:qWR+TUuvfji9udM79e4CPe87C5+SjMEb2TFXkZaI0Vc= -github.com/aws/aws-sdk-go-v2/service/sts v1.4.1/go.mod h1:G9osDWA52WQ38BDcj65VY1cNmcAQXAXTsE8IWH8j81w= github.com/aws/aws-sdk-go-v2/service/sts v1.5.0/go.mod h1:HjDKUmissf6Mlut+WzG2r35r6LeTKmLEDJ6p9NryzLg= -github.com/aws/smithy-go v1.4.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.5.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= @@ -245,10 +233,11 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/line/line-bot-sdk-go v7.8.0+incompatible h1:Uf9/OxV0zCVfqyvwZPH8CrdiHXXmMRa/L91G3btQblQ= github.com/line/line-bot-sdk-go v7.8.0+incompatible/go.mod h1:0RjLjJEAU/3GIcHkC3av6O4jInAbt25nnZVmOFUgDBg= -github.com/mailgun/mailgun-go/v4 v4.5.1/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40= github.com/mailgun/mailgun-go/v4 v4.5.2/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4= +github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -262,8 +251,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nikoksr/notify v0.17.0 h1:Pi5lXgbE8LIEda9mbPJb3GwSCVQL5lbyXkLaj3VvICE= -github.com/nikoksr/notify v0.17.0/go.mod h1:INe8kALt/rpdYhYzOuu/pQr3xdVA5Azr1IbiAvSIzPc= github.com/nikoksr/notify v0.17.2 h1:Aqg+TdITuyeyUvddDUE/u4Mh+eljh4IBP0yZ7g00sXE= github.com/nikoksr/notify v0.17.2/go.mod h1:yfth7HYk/5vxobRxvN6mD4NMCWX6N/v+43rCurntfdA= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -279,7 +266,6 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/plivo/plivo-go v5.5.2+incompatible/go.mod h1:OhnI9crdl6O+D94Lp1lvuwJoA3KUH39J6IM+j3HwCBE= github.com/plivo/plivo-go v5.6.0+incompatible/go.mod h1:OhnI9crdl6O+D94Lp1lvuwJoA3KUH39J6IM+j3HwCBE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -300,8 +286,6 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= -github.com/slack-go/slack v0.9.1 h1:pekQBs0RmrdAgoqzcMCzUCWSyIkhzUU3F83ExAdZrKo= -github.com/slack-go/slack v0.9.1/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ= github.com/slack-go/slack v0.9.2 h1:tjIrKKYUCOmWeEAktWShKW+3UjLTH/wmgmCkAGAf8wM= github.com/slack-go/slack v0.9.2/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ= github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= @@ -320,8 +304,6 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= -github.com/textmagic/textmagic-rest-go-v2/v2 v2.0.1696 h1:TOtsbwwWNeiCCN+EA66/Qr7zXbLSTfmtDeglgC/ZRM8= -github.com/textmagic/textmagic-rest-go-v2/v2 v2.0.1696/go.mod h1:PbP69y7uRiNdwtPE3/bVGDaPYA1sr4vuHaGLQAGzeW8= github.com/textmagic/textmagic-rest-go-v2/v2 v2.0.1781 h1:x7Ff7QDRBy7VDeHNx6/5LsVLJrLc1viDoKwPmEiWF5g= github.com/textmagic/textmagic-rest-go-v2/v2 v2.0.1781/go.mod h1:PbP69y7uRiNdwtPE3/bVGDaPYA1sr4vuHaGLQAGzeW8= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= diff --git a/main.go b/main.go index 6efc419..4c9f000 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "github.com/kha7iq/pingme/service/matrix" "log" "os" @@ -58,6 +59,7 @@ email address, Line, Gotify and Wechat.` wechat.Send(), gotify.Send(), textmagic.Send(), + matrix.Send(), } err := app.Run(os.Args) diff --git a/service/matrix/matrix.go b/service/matrix/matrix.go new file mode 100644 index 0000000..ff939bb --- /dev/null +++ b/service/matrix/matrix.go @@ -0,0 +1,222 @@ +package matrix + +import ( + "fmt" + "github.com/matrix-org/gomatrix" + "github.com/urfave/cli/v2" + "strings" + //"github.com/urfave/cli/v2" +) + +type matrixPingMe struct { + Username string + Password string + Token string + Url string + ServerName string + Room string + RoomID string + Domain string + Message string + AutoJoin bool +} + +func Send() *cli.Command { + var matrix matrixPingMe + return &cli.Command{ + Name: "matrix", + Usage: "Send message via matrix", + UsageText: "pingme matrix --token 'syt_YW...E2qD' --room 'LRovrjPJaRChcTKgoK:matrix.org' " + + "--url 'matrix-client.matrix.org' --autoJoin --message 'Hello, Matrix!'", + Flags: []cli.Flag{ + &cli.StringFlag{ + Destination: &matrix.Username, + Name: "username", + Aliases: []string{"u"}, + Usage: "Matrix username", + EnvVars: []string{"MATRIX_USERNAME"}, + }, + &cli.StringFlag{ + Destination: &matrix.Password, + Name: "password", + Aliases: []string{"p"}, + Usage: "Matrix password", + EnvVars: []string{"MATRIX_PASSWORD"}, + }, + &cli.StringFlag{ + Destination: &matrix.Token, + Name: "accessToken", + Aliases: []string{"t"}, + Usage: "Matrix access token. Can be used instead of username+password", + EnvVars: []string{"MATRIX_ACCESS_TOKEN"}, + }, + &cli.StringFlag{ + Destination: &matrix.Url, + Name: "url", + Usage: "Matrix server URL", + EnvVars: []string{"MATRIX_SERVER_URL"}, + }, + &cli.StringFlag{ + Destination: &matrix.ServerName, + Name: "serverName", + Usage: "Can be provided if requests should be routed via a particular server", + EnvVars: []string{"MATRIX_SERVER_NAME"}, + }, + &cli.StringFlag{ + Destination: &matrix.Room, + Name: "room", + Usage: "Matrix room to send the message to, in the format :", + EnvVars: []string{"MATRIX_ROOM"}, + }, + &cli.StringFlag{ + Destination: &matrix.RoomID, + Name: "roomId", + Usage: "Matrix room ID to send the message to. The exclamation mark at the beginning can be excluded.", + EnvVars: []string{"MATRIX_ROOM_ID"}, + }, + &cli.StringFlag{ + Destination: &matrix.Domain, + Name: "domain", + Usage: "Used in conjunction with room ID to get the desired room", + EnvVars: []string{"MATRIX_DOMAIN"}, + }, + &cli.StringFlag{ + Destination: &matrix.Message, + Name: "message", + Aliases: []string{"m"}, + Required: true, + Usage: "Message to send to matrix", + EnvVars: []string{"MATRIX_MESSAGE"}, + }, + &cli.BoolFlag{ + Destination: &matrix.AutoJoin, + Name: "autoJoin", + Usage: "If enabled, will automatically join the specified room if not already joined", + EnvVars: []string{"MATRIX_AUTO_JOIN"}, + }, + }, + Action: func(ctx *cli.Context) error { + // Login + client, err := matrix.login() + if err != nil { + return fmt.Errorf("failed to login to matrix: %v", err) + } + + // Parse and set variables + err = matrix.setupVars() + if err != nil { + return err + } + + // If necessary, join the given room + err = matrix.joinRoomIfNecessary(client) + if err != nil { + return err + } + + // Send the message + _, err = client.SendText(matrix.Room, matrix.Message) + if err != nil { + return fmt.Errorf("failed to send matrix text: %v", err) + } + return nil + }, + } +} + +/* +setupVars will ensure the room ID begins with an exclamation mark and set the room string if not +already set, using the room ID and domain. If the room string, room id and domain are not set, +an error will be thrown. +*/ +func (m *matrixPingMe) setupVars() error { + // Format the room ID + if !strings.HasPrefix(m.RoomID, "!") { + m.RoomID = "!" + m.RoomID + } + + // Create the matrix room string if not already provided + if m.Room == "" { + if m.RoomID == "" || m.Domain == "" { + return fmt.Errorf("matrix room, or room ID and domain must be provided") + } + + m.Room = fmt.Sprintf("%s:%s", m.RoomID, m.Domain) + } + return nil +} + +/* +joinRoomIfNecessary gets all the joined rooms and checks if the desired room is in the list. +If not, and autoJoin is set to true - will attempt to join the room. If autoJoin is set to +false, an error will be thrown +*/ +func (m *matrixPingMe) joinRoomIfNecessary(client *gomatrix.Client) error { + // Get already joined rooms + joined, err := client.JoinedRooms() + if err != nil { + return fmt.Errorf("failed to get joined rooms: %v", err) + } + + // Check if we've already joined the desired room + foundRoom := false + for _, room := range joined.JoinedRooms { + if room == m.Room { + foundRoom = true + break + } + } + + // If not, try auto join the room + if !foundRoom { + if !m.AutoJoin { + return fmt.Errorf("not joined room '%s' and --autoJoin is set to false", m.Room) + } + + _, err = client.JoinRoom(m.Room, m.ServerName, nil) + if err != nil { + return fmt.Errorf("failed to auto join room '%s': %v", m.Room, err) + } + } + return nil +} + +/* +login creates a gomatrix.Client instance, connecting to the given URL, using the provided login details +*/ +func (m *matrixPingMe) login() (*gomatrix.Client, error) { + // Create a client instance + client, err := gomatrix.NewClient(m.Url, "", "") + if err != nil { + return nil, fmt.Errorf("failed to create matrix client: %v", err) + } + + // Attempt to log in with whatever login details were provided. + // Or, throw an error if no login details were given + var resp *gomatrix.RespLogin + if m.Token != "" { + resp, err = client.Login(&gomatrix.ReqLogin{ + Type: "m.login.token", + Token: m.Token, + }) + if err != nil { + return nil, err + } + } else if m.Username != "" && m.Password != "" { + resp, err = client.Login(&gomatrix.ReqLogin{ + Type: "m.login.password", + User: m.Username, + Password: m.Password, + }) + if err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("no token, or username and password provided") + } + + // Set the access token for this session + client.SetCredentials(resp.UserID, resp.AccessToken) + m.Token = resp.AccessToken + return client, nil +}