forked from lug/matterbridge
		
	
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//Package matterhook provides interaction with mattermost incoming/outgoing webhooks
 | 
						|
package matterhook
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"crypto/tls"
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"io/ioutil"
 | 
						|
	"log"
 | 
						|
	"net"
 | 
						|
	"net/http"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/gorilla/schema"
 | 
						|
	"github.com/slack-go/slack"
 | 
						|
)
 | 
						|
 | 
						|
// OMessage for mattermost incoming webhook. (send to mattermost)
 | 
						|
type OMessage struct {
 | 
						|
	Channel     string                 `json:"channel,omitempty"`
 | 
						|
	IconURL     string                 `json:"icon_url,omitempty"`
 | 
						|
	IconEmoji   string                 `json:"icon_emoji,omitempty"`
 | 
						|
	UserName    string                 `json:"username,omitempty"`
 | 
						|
	Text        string                 `json:"text"`
 | 
						|
	Attachments []slack.Attachment     `json:"attachments,omitempty"`
 | 
						|
	Type        string                 `json:"type,omitempty"`
 | 
						|
	Props       map[string]interface{} `json:"props"`
 | 
						|
}
 | 
						|
 | 
						|
// IMessage for mattermost outgoing webhook. (received from mattermost)
 | 
						|
type IMessage struct {
 | 
						|
	BotID       string `schema:"bot_id"`
 | 
						|
	BotName     string `schema:"bot_name"`
 | 
						|
	Token       string `schema:"token"`
 | 
						|
	TeamID      string `schema:"team_id"`
 | 
						|
	TeamDomain  string `schema:"team_domain"`
 | 
						|
	ChannelID   string `schema:"channel_id"`
 | 
						|
	ChannelName string `schema:"channel_name"`
 | 
						|
	Timestamp   string `schema:"timestamp"`
 | 
						|
	UserID      string `schema:"user_id"`
 | 
						|
	UserName    string `schema:"user_name"`
 | 
						|
	PostId      string `schema:"post_id"` //nolint:golint
 | 
						|
	RawText     string `schema:"raw_text"`
 | 
						|
	ServiceId   string `schema:"service_id"` //nolint:golint
 | 
						|
	Text        string `schema:"text"`
 | 
						|
	TriggerWord string `schema:"trigger_word"`
 | 
						|
	FileIDs     string `schema:"file_ids"`
 | 
						|
}
 | 
						|
 | 
						|
// Client for Mattermost.
 | 
						|
type Client struct {
 | 
						|
	// URL for incoming webhooks on mattermost.
 | 
						|
	Url        string // nolint:golint
 | 
						|
	In         chan IMessage
 | 
						|
	Out        chan OMessage
 | 
						|
	httpclient *http.Client
 | 
						|
	Config
 | 
						|
}
 | 
						|
 | 
						|
// Config for client.
 | 
						|
type Config struct {
 | 
						|
	BindAddress        string // Address to listen on
 | 
						|
	Token              string // Only allow this token from Mattermost. (Allow everything when empty)
 | 
						|
	InsecureSkipVerify bool   // disable certificate checking
 | 
						|
	DisableServer      bool   // Do not start server for outgoing webhooks from Mattermost.
 | 
						|
}
 | 
						|
 | 
						|
// New Mattermost client.
 | 
						|
func New(url string, config Config) *Client {
 | 
						|
	c := &Client{Url: url, In: make(chan IMessage), Out: make(chan OMessage), Config: config}
 | 
						|
	tr := &http.Transport{
 | 
						|
		TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify}, //nolint:gosec
 | 
						|
	}
 | 
						|
	c.httpclient = &http.Client{Transport: tr}
 | 
						|
	if !c.DisableServer {
 | 
						|
		_, _, err := net.SplitHostPort(c.BindAddress)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatalf("incorrect bindaddress %s", c.BindAddress)
 | 
						|
		}
 | 
						|
		go c.StartServer()
 | 
						|
	}
 | 
						|
	return c
 | 
						|
}
 | 
						|
 | 
						|
// StartServer starts a webserver listening for incoming mattermost POSTS.
 | 
						|
func (c *Client) StartServer() {
 | 
						|
	mux := http.NewServeMux()
 | 
						|
	mux.Handle("/", c)
 | 
						|
	srv := &http.Server{
 | 
						|
		ReadTimeout:  5 * time.Second,
 | 
						|
		WriteTimeout: 10 * time.Second,
 | 
						|
		Handler:      mux,
 | 
						|
		Addr:         c.BindAddress,
 | 
						|
	}
 | 
						|
	log.Printf("Listening on http://%v...\n", c.BindAddress)
 | 
						|
	if err := srv.ListenAndServe(); err != nil {
 | 
						|
		log.Fatal(err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ServeHTTP implementation.
 | 
						|
func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
						|
	if r.Method != "POST" {
 | 
						|
		log.Println("invalid " + r.Method + " connection from " + r.RemoteAddr)
 | 
						|
		http.NotFound(w, r)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	msg := IMessage{}
 | 
						|
	err := r.ParseForm()
 | 
						|
	if err != nil {
 | 
						|
		log.Println(err)
 | 
						|
		http.NotFound(w, r)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	defer r.Body.Close()
 | 
						|
	decoder := schema.NewDecoder()
 | 
						|
	err = decoder.Decode(&msg, r.PostForm)
 | 
						|
	if err != nil {
 | 
						|
		log.Println(err)
 | 
						|
		http.NotFound(w, r)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if msg.Token == "" {
 | 
						|
		log.Println("no token from " + r.RemoteAddr)
 | 
						|
		http.NotFound(w, r)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if c.Token != "" {
 | 
						|
		if msg.Token != c.Token {
 | 
						|
			log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr)
 | 
						|
			http.NotFound(w, r)
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
	c.In <- msg
 | 
						|
}
 | 
						|
 | 
						|
// Receive returns an incoming message from mattermost outgoing webhooks URL.
 | 
						|
func (c *Client) Receive() IMessage {
 | 
						|
	var msg IMessage
 | 
						|
	for msg := range c.In {
 | 
						|
		return msg
 | 
						|
	}
 | 
						|
	return msg
 | 
						|
}
 | 
						|
 | 
						|
// Send sends a msg to mattermost incoming webhooks URL.
 | 
						|
func (c *Client) Send(msg OMessage) error {
 | 
						|
	buf, err := json.Marshal(msg)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	resp, err := c.httpclient.Post(c.Url, "application/json", bytes.NewReader(buf))
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer resp.Body.Close()
 | 
						|
 | 
						|
	// Read entire body to completion to re-use keep-alive connections.
 | 
						|
	io.Copy(ioutil.Discard, resp.Body)
 | 
						|
 | 
						|
	if resp.StatusCode != 200 {
 | 
						|
		return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 |