matterbridge/vendor/github.com/slack-go/slack/slackevents/parsers.go
2022-03-15 13:01:41 +03:00

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
}
}