summaryrefslogtreecommitdiff
path: root/teleirc/matterbridge/matterhook/matterhook.go
diff options
context:
space:
mode:
Diffstat (limited to 'teleirc/matterbridge/matterhook/matterhook.go')
-rw-r--r--teleirc/matterbridge/matterhook/matterhook.go168
1 files changed, 168 insertions, 0 deletions
diff --git a/teleirc/matterbridge/matterhook/matterhook.go b/teleirc/matterbridge/matterhook/matterhook.go
new file mode 100644
index 0000000..6b03643
--- /dev/null
+++ b/teleirc/matterbridge/matterhook/matterhook.go
@@ -0,0 +1,168 @@
+//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
+}