You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pingme/service/matrix/matrix.go

222 lines
5.9 KiB

package matrix
import (
"fmt"
"github.com/matrix-org/gomatrix"
"github.com/urfave/cli/v2"
"strings"
)
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 --msg 'Hello, Matrix!'",
Flags: []cli.Flag{
&cli.StringFlag{
Destination: &matrix.Username,
Name: "username",
Aliases: []string{"u"},
Usage: "Matrix username",
EnvVars: []string{"MATRIX_USER"},
},
&cli.StringFlag{
Destination: &matrix.Password,
Name: "password",
Aliases: []string{"p"},
Usage: "Matrix password",
EnvVars: []string{"MATRIX_PASSWORD"},
},
&cli.StringFlag{
Destination: &matrix.Token,
Name: "token",
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 <roomId>:<domain>",
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: "msg",
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
}