mirror of
https://github.com/42wim/matterbridge.git
synced 2024-12-04 08:22:03 -08:00
259 lines
5.4 KiB
Go
259 lines
5.4 KiB
Go
|
package slackevents
|
||
|
|
||
|
import (
|
||
|
"crypto/subtle"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
|
||
|
"github.com/slack-go/slack"
|
||
|
)
|
||
|
|
||
|
// eventsMap checks both slack.EventsMapping and
|
||
|
// and slackevents.EventsAPIInnerEventMapping. If the event
|
||
|
// exists, returns the the unmarshalled struct instance of
|
||
|
// target for the matching event type.
|
||
|
// TODO: Consider moving all events into its own package?
|
||
|
func eventsMap(t string) (interface{}, bool) {
|
||
|
// Must parse EventsAPI FIRST as both RTM and EventsAPI
|
||
|
// have a type: "Message" event.
|
||
|
// TODO: Handle these cases more explicitly.
|
||
|
v, exists := EventsAPIInnerEventMapping[t]
|
||
|
if exists {
|
||
|
return v, exists
|
||
|
}
|
||
|
v, exists = slack.EventMapping[t]
|
||
|
if exists {
|
||
|
return v, exists
|
||
|
}
|
||
|
return v, exists
|
||
|
}
|
||
|
|
||
|
func parseOuterEvent(rawE json.RawMessage) (EventsAPIEvent, error) {
|
||
|
e := &EventsAPIEvent{}
|
||
|
err := json.Unmarshal(rawE, e)
|
||
|
if err != nil {
|
||
|
return EventsAPIEvent{
|
||
|
"",
|
||
|
"",
|
||
|
"unmarshalling_error",
|
||
|
"",
|
||
|
"",
|
||
|
&slack.UnmarshallingErrorEvent{ErrorObj: err},
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, err
|
||
|
}
|
||
|
if e.Type == CallbackEvent {
|
||
|
cbEvent := &EventsAPICallbackEvent{}
|
||
|
err = json.Unmarshal(rawE, cbEvent)
|
||
|
if err != nil {
|
||
|
return EventsAPIEvent{
|
||
|
"",
|
||
|
"",
|
||
|
"unmarshalling_error",
|
||
|
"",
|
||
|
"",
|
||
|
&slack.UnmarshallingErrorEvent{ErrorObj: err},
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, err
|
||
|
}
|
||
|
return EventsAPIEvent{
|
||
|
e.Token,
|
||
|
e.TeamID,
|
||
|
e.Type,
|
||
|
e.APIAppID,
|
||
|
e.EnterpriseID,
|
||
|
cbEvent,
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, nil
|
||
|
}
|
||
|
urlVE := &EventsAPIURLVerificationEvent{}
|
||
|
err = json.Unmarshal(rawE, urlVE)
|
||
|
if err != nil {
|
||
|
return EventsAPIEvent{
|
||
|
"",
|
||
|
"",
|
||
|
"unmarshalling_error",
|
||
|
"",
|
||
|
"",
|
||
|
&slack.UnmarshallingErrorEvent{ErrorObj: err},
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, err
|
||
|
}
|
||
|
return EventsAPIEvent{
|
||
|
e.Token,
|
||
|
e.TeamID,
|
||
|
e.Type,
|
||
|
e.APIAppID,
|
||
|
e.EnterpriseID,
|
||
|
urlVE,
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func parseInnerEvent(e *EventsAPICallbackEvent) (EventsAPIEvent, error) {
|
||
|
iE := &slack.Event{}
|
||
|
rawInnerJSON := e.InnerEvent
|
||
|
err := json.Unmarshal(*rawInnerJSON, iE)
|
||
|
if err != nil {
|
||
|
return EventsAPIEvent{
|
||
|
e.Token,
|
||
|
e.TeamID,
|
||
|
"unmarshalling_error",
|
||
|
e.APIAppID,
|
||
|
"",
|
||
|
&slack.UnmarshallingErrorEvent{ErrorObj: err},
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, err
|
||
|
}
|
||
|
v, exists := eventsMap(iE.Type)
|
||
|
if !exists {
|
||
|
return EventsAPIEvent{
|
||
|
e.Token,
|
||
|
e.TeamID,
|
||
|
iE.Type,
|
||
|
e.APIAppID,
|
||
|
"",
|
||
|
nil,
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, fmt.Errorf("Inner Event does not exist! %s", iE.Type)
|
||
|
}
|
||
|
t := reflect.TypeOf(v)
|
||
|
recvEvent := reflect.New(t).Interface()
|
||
|
err = json.Unmarshal(*rawInnerJSON, recvEvent)
|
||
|
if err != nil {
|
||
|
return EventsAPIEvent{
|
||
|
e.Token,
|
||
|
e.TeamID,
|
||
|
"unmarshalling_error",
|
||
|
e.APIAppID,
|
||
|
"",
|
||
|
&slack.UnmarshallingErrorEvent{ErrorObj: err},
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, err
|
||
|
}
|
||
|
return EventsAPIEvent{
|
||
|
e.Token,
|
||
|
e.TeamID,
|
||
|
e.Type,
|
||
|
e.APIAppID,
|
||
|
"",
|
||
|
e,
|
||
|
EventsAPIInnerEvent{iE.Type, recvEvent},
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
type Config struct {
|
||
|
VerificationToken string
|
||
|
TokenVerified bool
|
||
|
}
|
||
|
|
||
|
type Option func(cfg *Config)
|
||
|
|
||
|
type verifier interface {
|
||
|
Verify(token string) bool
|
||
|
}
|
||
|
|
||
|
func OptionVerifyToken(v verifier) Option {
|
||
|
return func(cfg *Config) {
|
||
|
cfg.TokenVerified = v.Verify(cfg.VerificationToken)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// OptionNoVerifyToken skips the check of the Slack verification token
|
||
|
func OptionNoVerifyToken() Option {
|
||
|
return func(cfg *Config) {
|
||
|
cfg.TokenVerified = true
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type TokenComparator struct {
|
||
|
VerificationToken string
|
||
|
}
|
||
|
|
||
|
func (c TokenComparator) Verify(t string) bool {
|
||
|
return subtle.ConstantTimeCompare([]byte(c.VerificationToken), []byte(t)) == 1
|
||
|
}
|
||
|
|
||
|
// ParseEvent parses the outter and inner events (if applicable) of an events
|
||
|
// api event returning a EventsAPIEvent type. If the event is a url_verification event,
|
||
|
// the inner event is empty.
|
||
|
func ParseEvent(rawEvent json.RawMessage, opts ...Option) (EventsAPIEvent, error) {
|
||
|
e, err := parseOuterEvent(rawEvent)
|
||
|
if err != nil {
|
||
|
return EventsAPIEvent{}, err
|
||
|
}
|
||
|
|
||
|
cfg := &Config{}
|
||
|
cfg.VerificationToken = e.Token
|
||
|
for _, opt := range opts {
|
||
|
opt(cfg)
|
||
|
}
|
||
|
|
||
|
if !cfg.TokenVerified {
|
||
|
return EventsAPIEvent{}, errors.New("Invalid verification token")
|
||
|
}
|
||
|
|
||
|
if e.Type == CallbackEvent {
|
||
|
cbEvent := e.Data.(*EventsAPICallbackEvent)
|
||
|
innerEvent, err := parseInnerEvent(cbEvent)
|
||
|
if err != nil {
|
||
|
err := fmt.Errorf("EventsAPI Error parsing inner event: %s, %s", innerEvent.Type, err)
|
||
|
return EventsAPIEvent{
|
||
|
"",
|
||
|
"",
|
||
|
"unmarshalling_error",
|
||
|
"",
|
||
|
"",
|
||
|
&slack.UnmarshallingErrorEvent{ErrorObj: err},
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, err
|
||
|
}
|
||
|
return innerEvent, nil
|
||
|
}
|
||
|
urlVerificationEvent := &EventsAPIURLVerificationEvent{}
|
||
|
err = json.Unmarshal(rawEvent, urlVerificationEvent)
|
||
|
if err != nil {
|
||
|
return EventsAPIEvent{
|
||
|
"",
|
||
|
"",
|
||
|
"unmarshalling_error",
|
||
|
"",
|
||
|
"",
|
||
|
&slack.UnmarshallingErrorEvent{ErrorObj: err},
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, err
|
||
|
}
|
||
|
return EventsAPIEvent{
|
||
|
e.Token,
|
||
|
e.TeamID,
|
||
|
e.Type,
|
||
|
e.APIAppID,
|
||
|
e.EnterpriseID,
|
||
|
urlVerificationEvent,
|
||
|
EventsAPIInnerEvent{},
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func ParseActionEvent(payloadString string, opts ...Option) (MessageAction, error) {
|
||
|
byteString := []byte(payloadString)
|
||
|
action := MessageAction{}
|
||
|
err := json.Unmarshal(byteString, &action)
|
||
|
if err != nil {
|
||
|
return MessageAction{}, errors.New("MessageAction unmarshalling failed")
|
||
|
}
|
||
|
|
||
|
cfg := &Config{}
|
||
|
cfg.VerificationToken = action.Token
|
||
|
for _, opt := range opts {
|
||
|
opt(cfg)
|
||
|
}
|
||
|
|
||
|
if !cfg.TokenVerified {
|
||
|
return MessageAction{}, errors.New("invalid verification token")
|
||
|
} else {
|
||
|
return action, nil
|
||
|
}
|
||
|
}
|