diff options
Diffstat (limited to 'vendor/github.com')
62 files changed, 1004 insertions, 554 deletions
diff --git a/vendor/github.com/d5/tengo/v2/compiler.go b/vendor/github.com/d5/tengo/v2/compiler.go index cb1c8f30..1937a1d6 100644 --- a/vendor/github.com/d5/tengo/v2/compiler.go +++ b/vendor/github.com/d5/tengo/v2/compiler.go @@ -506,7 +506,11 @@ func (c *Compiler) Compile(node parser.Node) error { return err } } - c.emit(node, parser.OpCall, len(node.Args)) + ellipsis := 0 + if node.Ellipsis.IsValid() { + ellipsis = 1 + } + c.emit(node, parser.OpCall, len(node.Args), ellipsis) case *parser.ImportExpr: if node.ModuleName == "" { return c.errorf(node, "empty module name") @@ -526,7 +530,7 @@ func (c *Compiler) Compile(node parser.Node) error { return err } c.emit(node, parser.OpConstant, c.addConstant(compiled)) - c.emit(node, parser.OpCall, 0) + c.emit(node, parser.OpCall, 0, 0) case Object: // builtin module c.emit(node, parser.OpConstant, c.addConstant(v)) default: @@ -556,7 +560,7 @@ func (c *Compiler) Compile(node parser.Node) error { return err } c.emit(node, parser.OpConstant, c.addConstant(compiled)) - c.emit(node, parser.OpCall, 0) + c.emit(node, parser.OpCall, 0, 0) } else { return c.errorf(node, "module '%s' not found", node.ModuleName) } diff --git a/vendor/github.com/d5/tengo/v2/objects.go b/vendor/github.com/d5/tengo/v2/objects.go index 27c1d493..30913db5 100644 --- a/vendor/github.com/d5/tengo/v2/objects.go +++ b/vendor/github.com/d5/tengo/v2/objects.go @@ -1342,6 +1342,38 @@ func (o *String) BinaryOp(op token.Token, rhs Object) (Object, error) { } return &String{Value: o.Value + rhsStr}, nil } + case token.Less: + switch rhs := rhs.(type) { + case *String: + if o.Value < rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + } + case token.LessEq: + switch rhs := rhs.(type) { + case *String: + if o.Value <= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + } + case token.Greater: + switch rhs := rhs.(type) { + case *String: + if o.Value > rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + } + case token.GreaterEq: + switch rhs := rhs.(type) { + case *String: + if o.Value >= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + } } return nil, ErrInvalidOperator } diff --git a/vendor/github.com/d5/tengo/v2/parser/expr.go b/vendor/github.com/d5/tengo/v2/parser/expr.go index 71e5155b..b6b6c62b 100644 --- a/vendor/github.com/d5/tengo/v2/parser/expr.go +++ b/vendor/github.com/d5/tengo/v2/parser/expr.go @@ -111,10 +111,11 @@ func (e *BoolLit) String() string { // CallExpr represents a function call expression. type CallExpr struct { - Func Expr - LParen Pos - Args []Expr - RParen Pos + Func Expr + LParen Pos + Args []Expr + Ellipsis Pos + RParen Pos } func (e *CallExpr) exprNode() {} @@ -134,6 +135,9 @@ func (e *CallExpr) String() string { for _, e := range e.Args { args = append(args, e.String()) } + if len(args) > 0 && e.Ellipsis.IsValid() { + args[len(args)-1] = args[len(args)-1] + "..." + } return e.Func.String() + "(" + strings.Join(args, ", ") + ")" } diff --git a/vendor/github.com/d5/tengo/v2/parser/opcodes.go b/vendor/github.com/d5/tengo/v2/parser/opcodes.go index a4fbfbaf..d97f4896 100644 --- a/vendor/github.com/d5/tengo/v2/parser/opcodes.go +++ b/vendor/github.com/d5/tengo/v2/parser/opcodes.go @@ -120,7 +120,7 @@ var OpcodeOperands = [...][]int{ OpImmutable: {}, OpIndex: {}, OpSliceIndex: {}, - OpCall: {1}, + OpCall: {1, 1}, OpReturn: {1}, OpGetLocal: {1}, OpSetLocal: {1}, diff --git a/vendor/github.com/d5/tengo/v2/parser/parser.go b/vendor/github.com/d5/tengo/v2/parser/parser.go index 501a9106..fd20423b 100644 --- a/vendor/github.com/d5/tengo/v2/parser/parser.go +++ b/vendor/github.com/d5/tengo/v2/parser/parser.go @@ -270,9 +270,13 @@ func (p *Parser) parseCall(x Expr) *CallExpr { p.exprLevel++ var list []Expr - for p.token != token.RParen && p.token != token.EOF { + var ellipsis Pos + for p.token != token.RParen && p.token != token.EOF && !ellipsis.IsValid() { list = append(list, p.parseExpr()) - + if p.token == token.Ellipsis { + ellipsis = p.pos + p.next() + } if !p.expectComma(token.RParen, "call argument") { break } @@ -281,10 +285,11 @@ func (p *Parser) parseCall(x Expr) *CallExpr { p.exprLevel-- rparen := p.expect(token.RParen) return &CallExpr{ - Func: x, - LParen: lparen, - RParen: rparen, - Args: list, + Func: x, + LParen: lparen, + RParen: rparen, + Ellipsis: ellipsis, + Args: list, } } diff --git a/vendor/github.com/d5/tengo/v2/vm.go b/vendor/github.com/d5/tengo/v2/vm.go index af8783f0..811ecef9 100644 --- a/vendor/github.com/d5/tengo/v2/vm.go +++ b/vendor/github.com/d5/tengo/v2/vm.go @@ -537,12 +537,36 @@ func (v *VM) run() { } case parser.OpCall: numArgs := int(v.curInsts[v.ip+1]) - v.ip++ + spread := int(v.curInsts[v.ip+2]) + v.ip += 2 + value := v.stack[v.sp-1-numArgs] if !value.CanCall() { v.err = fmt.Errorf("not callable: %s", value.TypeName()) return } + + if spread == 1 { + v.sp-- + switch arr := v.stack[v.sp].(type) { + case *Array: + for _, item := range arr.Value { + v.stack[v.sp] = item + v.sp++ + } + numArgs += len(arr.Value) - 1 + case *ImmutableArray: + for _, item := range arr.Value { + v.stack[v.sp] = item + v.sp++ + } + numArgs += len(arr.Value) - 1 + default: + v.err = fmt.Errorf("not an array: %s", arr.TypeName()) + return + } + } + if callee, ok := value.(*CompiledFunction); ok { if callee.VarArgs { // if the closure is variadic, diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml index 5769aa14..51865c84 100644 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml +++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml @@ -3,4 +3,6 @@ language: go go: - '1.10' - '1.11' + - '1.12' + - '1.13' - tip diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/README.md b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/README.md index 93250611..43b33ed8 100644 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/README.md +++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/README.md @@ -3,7 +3,7 @@ [![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) [![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api) -All methods are fairly self explanatory, and reading the godoc page should +All methods are fairly self explanatory, and reading the [godoc](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) page should explain everything. If something isn't clear, open an issue or submit a pull request. @@ -63,7 +63,7 @@ func main() { ``` There are more examples on the [wiki](https://github.com/go-telegram-bot-api/telegram-bot-api/wiki) -with detailed information on how to do many differen kinds of things. +with detailed information on how to do many different kinds of things. It's a great place to get started on using keyboards, commands, or other kinds of reply markup. diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go index 85e16c19..e6c2cc83 100644 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go +++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go @@ -19,34 +19,50 @@ import ( "github.com/technoweenie/multipartstreamer" ) +type HttpClient interface { + Do(req *http.Request) (*http.Response, error) +} + // BotAPI allows you to interact with the Telegram Bot API. type BotAPI struct { Token string `json:"token"` Debug bool `json:"debug"` Buffer int `json:"buffer"` - Self User `json:"-"` - Client *http.Client `json:"-"` + Self User `json:"-"` + Client HttpClient `json:"-"` shutdownChannel chan interface{} + + apiEndpoint string } // NewBotAPI creates a new BotAPI instance. // // It requires a token, provided by @BotFather on Telegram. func NewBotAPI(token string) (*BotAPI, error) { - return NewBotAPIWithClient(token, &http.Client{}) + return NewBotAPIWithClient(token, APIEndpoint, &http.Client{}) +} + +// NewBotAPIWithAPIEndpoint creates a new BotAPI instance +// and allows you to pass API endpoint. +// +// It requires a token, provided by @BotFather on Telegram and API endpoint. +func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) { + return NewBotAPIWithClient(token, apiEndpoint, &http.Client{}) } // NewBotAPIWithClient creates a new BotAPI instance // and allows you to pass a http.Client. // -// It requires a token, provided by @BotFather on Telegram. -func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) { +// It requires a token, provided by @BotFather on Telegram and API endpoint. +func NewBotAPIWithClient(token, apiEndpoint string, client HttpClient) (*BotAPI, error) { bot := &BotAPI{ - Token: token, - Client: client, - Buffer: 100, + Token: token, + Client: client, + Buffer: 100, shutdownChannel: make(chan interface{}), + + apiEndpoint: apiEndpoint, } self, err := bot.GetMe() @@ -59,11 +75,21 @@ func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) { return bot, nil } +func (b *BotAPI) SetAPIEndpoint(apiEndpoint string) { + b.apiEndpoint = apiEndpoint +} + // MakeRequest makes a request to a specific endpoint with our token. func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) { - method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint) + method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) - resp, err := bot.Client.PostForm(method, params) + req, err := http.NewRequest("POST", method, strings.NewReader(params.Encode())) + if err != nil { + return APIResponse{}, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + resp, err := bot.Client.Do(req) if err != nil { return APIResponse{}, err } @@ -84,7 +110,7 @@ func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, if apiResp.Parameters != nil { parameters = *apiResp.Parameters } - return apiResp, Error{apiResp.Description, parameters} + return apiResp, &Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters} } return apiResp, nil @@ -186,7 +212,7 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna return APIResponse{}, errors.New(ErrBadFileType) } - method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint) + method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) req, err := http.NewRequest("POST", method, nil) if err != nil { @@ -430,7 +456,7 @@ func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) { // RemoveWebhook unsets the webhook. func (bot *BotAPI) RemoveWebhook() (APIResponse, error) { - return bot.MakeRequest("setWebhook", url.Values{}) + return bot.MakeRequest("deleteWebhook", url.Values{}) } // SetWebhook sets a webhook. @@ -487,10 +513,11 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) { for { select { case <-bot.shutdownChannel: + close(ch) return default: } - + updates, err := bot.GetUpdates(config) if err != nil { log.Println(err) @@ -966,3 +993,22 @@ func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, e return bot.MakeRequest(config.method(), v) } + +// GetStickerSet get a sticker set. +func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) { + v, err := config.values() + if err != nil { + return StickerSet{}, err + } + bot.debugLog(config.method(), v, nil) + res, err := bot.MakeRequest(config.method(), v) + if err != nil { + return StickerSet{}, err + } + stickerSet := StickerSet{} + err = json.Unmarshal(res.Result, &stickerSet) + if err != nil { + return StickerSet{}, err + } + return stickerSet, nil +} diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go index 181d4e43..a7052ddc 100644 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go +++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go @@ -1262,3 +1262,18 @@ func (config DeleteChatPhotoConfig) values() (url.Values, error) { return v, nil } + +// GetStickerSetConfig contains information for get sticker set. +type GetStickerSetConfig struct { + Name string +} + +func (config GetStickerSetConfig) method() string { + return "getStickerSet" +} + +func (config GetStickerSetConfig) values() (url.Values, error) { + v := url.Values{} + v.Add("name", config.Name) + return v, nil +} diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/go.mod b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/go.mod new file mode 100644 index 00000000..7df46f4b --- /dev/null +++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/go.mod @@ -0,0 +1,5 @@ +module github.com/go-telegram-bot-api/telegram-bot-api + +go 1.12 + +require github.com/technoweenie/multipartstreamer v1.0.1 diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/go.sum b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/go.sum new file mode 100644 index 00000000..86606006 --- /dev/null +++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/go.sum @@ -0,0 +1,2 @@ +github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= +github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/helpers.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/helpers.go index 3dabe11e..d2fb165a 100644 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/helpers.go +++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/helpers.go @@ -29,7 +29,8 @@ func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig { // NewMessageToChannel creates a new Message that is sent to a channel // by username. // -// username is the username of the channel, text is the message text. +// username is the username of the channel, text is the message text, +// and the username should be in the form of `@username`. func NewMessageToChannel(username string, text string) MessageConfig { return MessageConfig{ BaseChat: BaseChat{ @@ -604,6 +605,18 @@ func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) } } +// NewInlineQueryResultVenue creates a new inline query venue. +func NewInlineQueryResultVenue(id, title, address string, latitude, longitude float64) InlineQueryResultVenue { + return InlineQueryResultVenue{ + Type: "venue", + ID: id, + Title: title, + Address: address, + Latitude: latitude, + Longitude: longitude, + } +} + // NewEditMessageText allows you to edit the text of a message. func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig { return EditMessageTextConfig{ @@ -622,7 +635,7 @@ func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMess ChatID: chatID, MessageID: messageID, }, - Caption: caption, + Caption: caption, } } diff --git a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go index c6cd642f..6e295cab 100644 --- a/vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go +++ b/vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go @@ -64,6 +64,9 @@ type User struct { // It is normally a user's username, but falls back to a first/last // name as available. func (u *User) String() string { + if u == nil { + return "" + } if u.UserName != "" { return u.UserName } @@ -100,6 +103,7 @@ type Chat struct { Photo *ChatPhoto `json:"photo"` Description string `json:"description,omitempty"` // optional InviteLink string `json:"invite_link,omitempty"` // optional + PinnedMessage *Message `json:"pinned_message"` // optional } // IsPrivate returns if the Chat is a private conversation. @@ -142,6 +146,7 @@ type Message struct { EditDate int `json:"edit_date"` // optional Text string `json:"text"` // optional Entities *[]MessageEntity `json:"entities"` // optional + CaptionEntities *[]MessageEntity `json:"caption_entities"` // optional Audio *Audio `json:"audio"` // optional Document *Document `json:"document"` // optional Animation *ChatAnimation `json:"animation"` // optional @@ -183,7 +188,7 @@ func (m *Message) IsCommand() bool { } entity := (*m.Entities)[0] - return entity.Offset == 0 && entity.Type == "bot_command" + return entity.Offset == 0 && entity.IsCommand() } // Command checks if the message was a command and if it was, returns the @@ -249,12 +254,62 @@ type MessageEntity struct { } // ParseURL attempts to parse a URL contained within a MessageEntity. -func (entity MessageEntity) ParseURL() (*url.URL, error) { - if entity.URL == "" { +func (e MessageEntity) ParseURL() (*url.URL, error) { + if e.URL == "" { return nil, errors.New(ErrBadURL) } - return url.Parse(entity.URL) + return url.Parse(e.URL) +} + +// IsMention returns true if the type of the message entity is "mention" (@username). +func (e MessageEntity) IsMention() bool { + return e.Type == "mention" +} + +// IsHashtag returns true if the type of the message entity is "hashtag". +func (e MessageEntity) IsHashtag() bool { + return e.Type == "hashtag" +} + +// IsCommand returns true if the type of the message entity is "bot_command". +func (e MessageEntity) IsCommand() bool { + return e.Type == "bot_command" +} + +// IsUrl returns true if the type of the message entity is "url". +func (e MessageEntity) IsUrl() bool { + return e.Type == "url" +} + +// IsEmail returns true if the type of the message entity is "email". +func (e MessageEntity) IsEmail() bool { + return e.Type == "email" +} + +// IsBold returns true if the type of the message entity is "bold" (bold text). +func (e MessageEntity) IsBold() bool { + return e.Type == "bold" +} + +// IsItalic returns true if the type of the message entity is "italic" (italic text). +func (e MessageEntity) IsItalic() bool { + return e.Type == "italic" +} + +// IsCode returns true if the type of the message entity is "code" (monowidth string). +func (e MessageEntity) IsCode() bool { + return e.Type == "code" +} + +// IsPre returns true if the type of the message entity is "pre" (monowidth block). +func (e MessageEntity) IsPre() bool { + return e.Type == "pre" +} + +// IsTextLink returns true if the type of the message entity is "text_link" (clickable text URL). +func (e MessageEntity) IsTextLink() bool { + return e.Type == "text_link" } // PhotoSize contains information about photos. @@ -286,13 +341,23 @@ type Document struct { // Sticker contains information about a sticker. type Sticker struct { - FileID string `json:"file_id"` - Width int `json:"width"` - Height int `json:"height"` - Thumbnail *PhotoSize `json:"thumb"` // optional - Emoji string `json:"emoji"` // optional - FileSize int `json:"file_size"` // optional - SetName string `json:"set_name"` // optional + FileUniqueID string `json:"file_unique_id"` + FileID string `json:"file_id"` + Width int `json:"width"` + Height int `json:"height"` + Thumbnail *PhotoSize `json:"thumb"` // optional + Emoji string `json:"emoji"` // optional + FileSize int `json:"file_size"` // optional + SetName string `json:"set_name"` // optional + IsAnimated bool `json:"is_animated"` // optional +} + +type StickerSet struct { + Name string `json:"name"` + Title string `json:"title"` + IsAnimated bool `json:"is_animated"` + ContainsMasks bool `json:"contains_masks"` + Stickers []Sticker `json:"stickers"` } // ChatAnimation contains information about an animation. @@ -582,6 +647,7 @@ type InlineQueryResultPhoto struct { Title string `json:"title"` Description string `json:"description"` Caption string `json:"caption"` + ParseMode string `json:"parse_mode"` ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` InputMessageContent interface{} `json:"input_message_content,omitempty"` } @@ -601,15 +667,15 @@ type InlineQueryResultCachedPhoto struct { // InlineQueryResultGIF is an inline query response GIF. type InlineQueryResultGIF struct { - Type string `json:"type"` // required - ID string `json:"id"` // required - URL string `json:"gif_url"` // required - Width int `json:"gif_width"` - Height int `json:"gif_height"` - Duration int `json:"gif_duration"` - ThumbURL string `json:"thumb_url"` - Title string `json:"title"` - Caption string `json:"caption"` + Type string `json:"type"` // required + ID string `json:"id"` // required + URL string `json:"gif_url"` // required + ThumbURL string `json:"thumb_url"` // required + Width int `json:"gif_width,omitempty"` + Height int `json:"gif_height,omitempty"` + Duration int `json:"gif_duration,omitempty"` + Title string `json:"title,omitempty"` + Caption string `json:"caption,omitempty"` ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` InputMessageContent interface{} `json:"input_message_content,omitempty"` } @@ -775,6 +841,23 @@ type InlineQueryResultLocation struct { ThumbHeight int `json:"thumb_height"` } +// InlineQueryResultVenue is an inline query response venue. +type InlineQueryResultVenue struct { + Type string `json:"type"` // required + ID string `json:"id"` // required + Latitude float64 `json:"latitude"` // required + Longitude float64 `json:"longitude"` // required + Title string `json:"title"` // required + Address string `json:"address"` // required + FoursquareID string `json:"foursquare_id"` + FoursquareType string `json:"foursquare_type"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + InputMessageContent interface{} `json:"input_message_content,omitempty"` + ThumbURL string `json:"thumb_url"` + ThumbWidth int `json:"thumb_width"` + ThumbHeight int `json:"thumb_height"` +} + // InlineQueryResultGame is an inline query response game. type InlineQueryResultGame struct { Type string `json:"type"` @@ -897,6 +980,7 @@ type PreCheckoutQuery struct { // Error is an error containing extra information returned by the Telegram API. type Error struct { + Code int Message string ResponseParameters } diff --git a/vendor/github.com/gomarkdown/markdown/html/renderer.go b/vendor/github.com/gomarkdown/markdown/html/renderer.go index f0e10a7f..01e0deec 100644 --- a/vendor/github.com/gomarkdown/markdown/html/renderer.go +++ b/vendor/github.com/gomarkdown/markdown/html/renderer.go @@ -28,6 +28,7 @@ const ( Safelink // Only link to trusted protocols NofollowLinks // Only link with rel="nofollow" NoreferrerLinks // Only link with rel="noreferrer" + NoopenerLinks // Only link with rel="noopener" HrefTargetBlank // Add a blank target CompletePage // Generate a complete HTML page UseXHTML // Generate XHTML output instead of HTML @@ -295,6 +296,9 @@ func appendLinkAttrs(attrs []string, flags Flags, link []byte) []string { if flags&NoreferrerLinks != 0 { val = append(val, "noreferrer") } + if flags&NoopenerLinks != 0 { + val = append(val, "noopener") + } if flags&HrefTargetBlank != 0 { attrs = append(attrs, `target="_blank"`) } @@ -1110,7 +1114,9 @@ func (r *Renderer) writeTOC(w io.Writer, doc ast.Node) { buf.WriteString("</a>") return ast.GoToNext } - nodeData.HeadingID = fmt.Sprintf("toc_%d", headingCount) + if nodeData.HeadingID == "" { + nodeData.HeadingID = fmt.Sprintf("toc_%d", headingCount) + } if nodeData.Level == tocLevel { buf.WriteString("</li>\n\n<li>") } else if nodeData.Level < tocLevel { @@ -1126,7 +1132,7 @@ func (r *Renderer) writeTOC(w io.Writer, doc ast.Node) { } } - fmt.Fprintf(&buf, `<a href="#toc_%d">`, headingCount) + fmt.Fprintf(&buf, `<a href="#%s">`, nodeData.HeadingID) headingCount++ return ast.GoToNext } diff --git a/vendor/github.com/gomarkdown/markdown/parser/inline.go b/vendor/github.com/gomarkdown/markdown/parser/inline.go index 2a8ac77c..9bb5b30b 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/inline.go +++ b/vendor/github.com/gomarkdown/markdown/parser/inline.go @@ -326,6 +326,7 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) { i = skipSpace(data, i) linkB := i + brace := 0 // look for link end: ' " ) findlinkend: @@ -334,7 +335,18 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) { case data[i] == '\\': i += 2 - case data[i] == ')' || data[i] == '\'' || data[i] == '"': + case data[i] == '(': + brace++ + i++ + + case data[i] == ')': + if brace <= 0 { + break findlinkend + } + brace-- + i++ + + case data[i] == '\'' || data[i] == '"': break findlinkend default: @@ -352,19 +364,21 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) { if data[i] == '\'' || data[i] == '"' { i++ titleB = i + titleEndCharFound := false findtitleend: for i < len(data) { switch { case data[i] == '\\': - i += 2 + i++ - case data[i] == ')': - break findtitleend + case data[i] == data[titleB-1]: // matching title delimiter + titleEndCharFound = true - default: - i++ + case titleEndCharFound && data[i] == ')': + break findtitleend } + i++ } if i >= len(data) { diff --git a/vendor/github.com/google/gops/agent/agent.go b/vendor/github.com/google/gops/agent/agent.go index 24c0b896..bb2bbf09 100644 --- a/vendor/github.com/google/gops/agent/agent.go +++ b/vendor/github.com/google/gops/agent/agent.go @@ -20,12 +20,13 @@ import ( "runtime/pprof" "runtime/trace" "strconv" + "strings" "sync" + "syscall" "time" "github.com/google/gops/internal" "github.com/google/gops/signal" - "github.com/kardianos/osext" ) const defaultAddr = "127.0.0.1:0" @@ -116,18 +117,21 @@ func listen() { for { fd, err := listener.Accept() if err != nil { - fmt.Fprintf(os.Stderr, "gops: %v", err) + // No great way to check for this, see https://golang.org/issues/4373. + if !strings.Contains(err.Error(), "use of closed network connection") { + fmt.Fprintf(os.Stderr, "gops: %v\n", err) + } if netErr, ok := err.(net.Error); ok && !netErr.Temporary() { break } continue } if _, err := fd.Read(buf); err != nil { - fmt.Fprintf(os.Stderr, "gops: %v", err) + fmt.Fprintf(os.Stderr, "gops: %v\n", err) continue } if err := handle(fd, buf); err != nil { - fmt.Fprintf(os.Stderr, "gops: %v", err) + fmt.Fprintf(os.Stderr, "gops: %v\n", err) continue } fd.Close() @@ -136,12 +140,16 @@ func listen() { func gracefulShutdown() { c := make(chan os.Signal, 1) - gosignal.Notify(c, os.Interrupt) + gosignal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) go func() { // cleanup the socket on shutdown. - <-c + sig := <-c Close() - os.Exit(1) + ret := 1 + if sig == syscall.SIGTERM { + ret = 0 + } + os.Exit(ret) }() } @@ -220,7 +228,7 @@ func handle(conn io.ReadWriter, msg []byte) error { case signal.Version: fmt.Fprintf(conn, "%v\n", runtime.Version()) case signal.HeapProfile: - pprof.WriteHeapProfile(conn) + return pprof.WriteHeapProfile(conn) case signal.CPUProfile: if err := pprof.StartCPUProfile(conn); err != nil { return err @@ -233,7 +241,7 @@ func handle(conn io.ReadWriter, msg []byte) error { fmt.Fprintf(conn, "GOMAXPROCS: %v\n", runtime.GOMAXPROCS(0)) fmt.Fprintf(conn, "num CPU: %v\n", runtime.NumCPU()) case signal.BinaryDump: - path, err := osext.Executable() + path, err := os.Executable() if err != nil { return err } @@ -246,7 +254,9 @@ func handle(conn io.ReadWriter, msg []byte) error { _, err = bufio.NewReader(f).WriteTo(conn) return err case signal.Trace: - trace.Start(conn) + if err := trace.Start(conn); err != nil { + return err + } time.Sleep(5 * time.Second) trace.Stop() case signal.SetGCPercent: diff --git a/vendor/github.com/google/gops/internal/internal.go b/vendor/github.com/google/gops/internal/internal.go index 80eac63f..ec63f918 100644 --- a/vendor/github.com/google/gops/internal/internal.go +++ b/vendor/github.com/google/gops/internal/internal.go @@ -6,12 +6,12 @@ package internal import ( "errors" - "fmt" "io/ioutil" "os" "os/user" "path/filepath" "runtime" + "strconv" "strings" ) @@ -22,9 +22,18 @@ func ConfigDir() (string, error) { return configDir, nil } + if osUserConfigDir := getOSUserConfigDir(); osUserConfigDir != "" { + return filepath.Join(osUserConfigDir, "gops"), nil + } + if runtime.GOOS == "windows" { return filepath.Join(os.Getenv("APPDATA"), "gops"), nil } + + if xdgConfigDir := os.Getenv("XDG_CONFIG_HOME"); xdgConfigDir != "" { + return filepath.Join(xdgConfigDir, "gops"), nil + } + homeDir := guessUnixHomeDir() if homeDir == "" { return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty") @@ -45,7 +54,7 @@ func PIDFile(pid int) (string, error) { if err != nil { return "", err } - return fmt.Sprintf("%s/%d", gopsdir, pid), nil + return filepath.Join(gopsdir, strconv.Itoa(pid)), nil } func GetPort(pid int) (string, error) { diff --git a/vendor/github.com/google/gops/internal/internal_go1_13.go b/vendor/github.com/google/gops/internal/internal_go1_13.go new file mode 100644 index 00000000..6e823138 --- /dev/null +++ b/vendor/github.com/google/gops/internal/internal_go1_13.go @@ -0,0 +1,19 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.13 + +package internal + +import ( + "os" +) + +func getOSUserConfigDir() string { + configDir, err := os.UserConfigDir() + if err != nil { + return "" + } + return configDir +} diff --git a/vendor/github.com/google/gops/internal/internal_lt_go1_13.go b/vendor/github.com/google/gops/internal/internal_lt_go1_13.go new file mode 100644 index 00000000..8506cf5f --- /dev/null +++ b/vendor/github.com/google/gops/internal/internal_lt_go1_13.go @@ -0,0 +1,11 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.13 + +package internal + +func getOSUserConfigDir() string { + return "" +} diff --git a/vendor/github.com/kardianos/osext/LICENSE b/vendor/github.com/kardianos/osext/LICENSE deleted file mode 100644 index 74487567..00000000 --- a/vendor/github.com/kardianos/osext/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/kardianos/osext/README.md b/vendor/github.com/kardianos/osext/README.md deleted file mode 100644 index 15cbc3d9..00000000 --- a/vendor/github.com/kardianos/osext/README.md +++ /dev/null @@ -1,21 +0,0 @@ -### Extensions to the "os" package. - -[![GoDoc](https://godoc.org/github.com/kardianos/osext?status.svg)](https://godoc.org/github.com/kardianos/osext) - -## Find the current Executable and ExecutableFolder. - -As of go1.8 the Executable function may be found in `os`. The Executable function -in the std lib `os` package is used if available. - -There is sometimes utility in finding the current executable file -that is running. This can be used for upgrading the current executable -or finding resources located relative to the executable file. Both -working directory and the os.Args[0] value are arbitrary and cannot -be relied on; os.Args[0] can be "faked". - -Multi-platform and supports: - * Linux - * OS X - * Windows - * Plan 9 - * BSDs. diff --git a/vendor/github.com/kardianos/osext/osext.go b/vendor/github.com/kardianos/osext/osext.go deleted file mode 100644 index 17f380f0..00000000 --- a/vendor/github.com/kardianos/osext/osext.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Extensions to the standard "os" package. -package osext // import "github.com/kardianos/osext" - -import "path/filepath" - -var cx, ce = executableClean() - -func executableClean() (string, error) { - p, err := executable() - return filepath.Clean(p), err -} - -// Executable returns an absolute path that can be used to -// re-invoke the current program. -// It may not be valid after the current program exits. -func Executable() (string, error) { - return cx, ce -} - -// Returns same path as Executable, returns just the folder -// path. Excludes the executable name and any trailing slash. -func ExecutableFolder() (string, error) { - p, err := Executable() - if err != nil { - return "", err - } - - return filepath.Dir(p), nil -} diff --git a/vendor/github.com/kardianos/osext/osext_go18.go b/vendor/github.com/kardianos/osext/osext_go18.go deleted file mode 100644 index 009d8a92..00000000 --- a/vendor/github.com/kardianos/osext/osext_go18.go +++ /dev/null @@ -1,9 +0,0 @@ -//+build go1.8,!openbsd - -package osext - -import "os" - -func executable() (string, error) { - return os.Executable() -} diff --git a/vendor/github.com/kardianos/osext/osext_plan9.go b/vendor/github.com/kardianos/osext/osext_plan9.go deleted file mode 100644 index 95e23713..00000000 --- a/vendor/github.com/kardianos/osext/osext_plan9.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//+build !go1.8 - -package osext - -import ( - "os" - "strconv" - "syscall" -) - -func executable() (string, error) { - f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text") - if err != nil { - return "", err - } - defer f.Close() - return syscall.Fd2path(int(f.Fd())) -} diff --git a/vendor/github.com/kardianos/osext/osext_procfs.go b/vendor/github.com/kardianos/osext/osext_procfs.go deleted file mode 100644 index e1f16f88..00000000 --- a/vendor/github.com/kardianos/osext/osext_procfs.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.8,android !go1.8,linux !go1.8,netbsd !go1.8,solaris !go1.8,dragonfly - -package osext - -import ( - "errors" - "fmt" - "os" - "runtime" - "strings" -) - -func executable() (string, error) { - switch runtime.GOOS { - case "linux", "android": - const deletedTag = " (deleted)" - execpath, err := os.Readlink("/proc/self/exe") - if err != nil { - return execpath, err - } - execpath = strings.TrimSuffix(execpath, deletedTag) - execpath = strings.TrimPrefix(execpath, deletedTag) - return execpath, nil - case "netbsd": - return os.Readlink("/proc/curproc/exe") - case "dragonfly": - return os.Readlink("/proc/curproc/file") - case "solaris": - return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid())) - } - return "", errors.New("ExecPath not implemented for " + runtime.GOOS) -} diff --git a/vendor/github.com/kardianos/osext/osext_sysctl.go b/vendor/github.com/kardianos/osext/osext_sysctl.go deleted file mode 100644 index 33cee252..00000000 --- a/vendor/github.com/kardianos/osext/osext_sysctl.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.8,darwin !go1.8,freebsd openbsd - -package osext - -import ( - "os" - "os/exec" - "path/filepath" - "runtime" - "syscall" - "unsafe" -) - -var initCwd, initCwdErr = os.Getwd() - -func executable() (string, error) { - var mib [4]int32 - switch runtime.GOOS { - case "freebsd": - mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1} - case "darwin": - mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1} - case "openbsd": - mib = [4]int32{1 /* CTL_KERN */, 55 /* KERN_PROC_ARGS */, int32(os.Getpid()), 1 /* KERN_PROC_ARGV */} - } - - n := uintptr(0) - // Get length. - _, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0) - if errNum != 0 { - return "", errNum - } - if n == 0 { // This shouldn't happen. - return "", nil - } - buf := make([]byte, n) - _, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0) - if errNum != 0 { - return "", errNum - } - if n == 0 { // This shouldn't happen. - return "", nil - } - - var execPath string - switch runtime.GOOS { - case "openbsd": - // buf now contains **argv, with pointers to each of the C-style - // NULL terminated arguments. - var args []string - argv := uintptr(unsafe.Pointer(&buf[0])) - Loop: - for { - argp := *(**[1 << 20]byte)(unsafe.Pointer(argv)) - if argp == nil { - break - } - for i := 0; uintptr(i) < n; i++ { - // we don't want the full arguments list - if string(argp[i]) == " " { - break Loop - } - if argp[i] != 0 { - continue - } - args = append(args, string(argp[:i])) - n -= uintptr(i) - break - } - if n < unsafe.Sizeof(argv) { - break - } - argv += unsafe.Sizeof(argv) - n -= unsafe.Sizeof(argv) - } - execPath = args[0] - // There is no canonical way to get an executable path on - // OpenBSD, so check PATH in case we are called directly - if execPath[0] != '/' && execPath[0] != '.' { - execIsInPath, err := exec.LookPath(execPath) - if err == nil { - execPath = execIsInPath - } - } - default: - for i, v := range buf { - if v == 0 { - buf = buf[:i] - break - } - } - execPath = string(buf) - } - - var err error - // execPath will not be empty due to above checks. - // Try to get the absolute path if the execPath is not rooted. - if execPath[0] != '/' { - execPath, err = getAbs(execPath) - if err != nil { - return execPath, err - } - } - // For darwin KERN_PROCARGS may return the path to a symlink rather than the - // actual executable. - if runtime.GOOS == "darwin" { - if execPath, err = filepath.EvalSymlinks(execPath); err != nil { - return execPath, err - } - } - return execPath, nil -} - -func getAbs(execPath string) (string, error) { - if initCwdErr != nil { - return execPath, initCwdErr - } - // The execPath may begin with a "../" or a "./" so clean it first. - // Join the two paths, trailing and starting slashes undetermined, so use - // the generic Join function. - return filepath.Join(initCwd, filepath.Clean(execPath)), nil -} diff --git a/vendor/github.com/kardianos/osext/osext_windows.go b/vendor/github.com/kardianos/osext/osext_windows.go deleted file mode 100644 index 074b3b38..00000000 --- a/vendor/github.com/kardianos/osext/osext_windows.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//+build !go1.8 - -package osext - -import ( - "syscall" - "unicode/utf16" - "unsafe" -) - -var ( - kernel = syscall.MustLoadDLL("kernel32.dll") - getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW") -) - -// GetModuleFileName() with hModule = NULL -func executable() (exePath string, err error) { - return getModuleFileName() -} - -func getModuleFileName() (string, error) { - var n uint32 - b := make([]uint16, syscall.MAX_PATH) - size := uint32(len(b)) - - r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size)) - n = uint32(r0) - if n == 0 { - return "", e1 - } - return string(utf16.Decode(b[0:n])), nil -} diff --git a/vendor/github.com/matterbridge/discordgo/.gitignore b/vendor/github.com/matterbridge/discordgo/.gitignore new file mode 100644 index 00000000..34d2efa5 --- /dev/null +++ b/vendor/github.com/matterbridge/discordgo/.gitignore @@ -0,0 +1,2 @@ +# IDE-specific metadata +.idea/ diff --git a/vendor/github.com/matterbridge/discordgo/.travis.yml b/vendor/github.com/matterbridge/discordgo/.travis.yml index 2656ae53..b88f11ee 100644 --- a/vendor/github.com/matterbridge/discordgo/.travis.yml +++ b/vendor/github.com/matterbridge/discordgo/.travis.yml @@ -1,8 +1,9 @@ language: go go: - - 1.9.x - 1.10.x - 1.11.x + - 1.12.x + - 1.13.x install: - go get github.com/bwmarrin/discordgo - go get -v . diff --git a/vendor/github.com/matterbridge/discordgo/README.md b/vendor/github.com/matterbridge/discordgo/README.md index 7a83b9e2..4410d1e1 100644 --- a/vendor/github.com/matterbridge/discordgo/README.md +++ b/vendor/github.com/matterbridge/discordgo/README.md @@ -1,16 +1,16 @@ # DiscordGo -[![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo) [![Go report](http://goreportcard.com/badge/bwmarrin/discordgo)](http://goreportcard.com/report/bwmarrin/discordgo) [![Build Status](https://travis-ci.org/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.org/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/0f1SbxBZjYoCtNPP) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discordapp.com/invite/discord-api) +[![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo) [![Go report](http://goreportcard.com/badge/bwmarrin/discordgo)](http://goreportcard.com/report/bwmarrin/discordgo) [![Build Status](https://travis-ci.org/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.org/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/0f1SbxBZjYoCtNPP) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discord.com/invite/discord-api) <img align="right" src="http://bwmarrin.github.io/discordgo/img/discordgo.png"> DiscordGo is a [Go](https://golang.org/) package that provides low level -bindings to the [Discord](https://discordapp.com/) chat client API. DiscordGo +bindings to the [Discord](https://discord.com/) chat client API. DiscordGo has nearly complete support for all of the Discord API endpoints, websocket interface, and voice interface. If you would like to help the DiscordGo package please use -[this link](https://discordapp.com/oauth2/authorize?client_id=173113690092994561&scope=bot) +[this link](https://discord.com/oauth2/authorize?client_id=173113690092994561&scope=bot) to add the official DiscordGo test bot **dgo** to your server. This provides indispensable help to this project. diff --git a/vendor/github.com/matterbridge/discordgo/discord.go b/vendor/github.com/matterbridge/discordgo/discord.go index 3bcbe8b8..c8395080 100644 --- a/vendor/github.com/matterbridge/discordgo/discord.go +++ b/vendor/github.com/matterbridge/discordgo/discord.go @@ -17,11 +17,12 @@ import ( "errors" "fmt" "net/http" + "runtime" "time" ) // VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/) -const VERSION = "0.20.2" +const VERSION = "0.21.1" // ErrMFA will be risen by New when the user has 2FA. var ErrMFA = errors.New("account has 2FA enabled") @@ -30,10 +31,13 @@ var ErrMFA = errors.New("account has 2FA enabled") // tasks if given enough information to do so. Currently you can pass zero // arguments and it will return an empty Discord session. // There are 3 ways to call New: -// With a single auth token - All requests will use the token blindly, +// With a single auth token - All requests will use the token blindly +// (just tossing it into the HTTP Authorization header); // no verification of the token will be done and requests may fail. // IF THE TOKEN IS FOR A BOT, IT MUST BE PREFIXED WITH `BOT ` // eg: `"Bot <token>"` +// IF IT IS AN OAUTH2 ACCESS TOKEN, IT MUST BE PREFIXED WITH `Bearer ` +// eg: `"Bearer <token>"` // With an email and password - Discord will sign in with the provided // credentials. // With an email, password and auth token - Discord will verify the auth @@ -63,6 +67,15 @@ func New(args ...interface{}) (s *Session, err error) { LastHeartbeatAck: time.Now().UTC(), } + // Initilize the Identify Package with defaults + // These can be modified prior to calling Open() + s.Identify.Compress = true + s.Identify.LargeThreshold = 250 + s.Identify.GuildSubscriptions = true + s.Identify.Properties.OS = runtime.GOOS + s.Identify.Properties.Browser = "DiscordGo v" + VERSION + s.Identify.Intents = MakeIntent(IntentsAllWithoutPrivileged) + // If no arguments are passed return the empty Session interface. if args == nil { return @@ -94,7 +107,8 @@ func New(args ...interface{}) (s *Session, err error) { // If third string exists, it must be an auth token. if len(v) > 2 { - s.Token = v[2] + s.Identify.Token = v[2] + s.Token = v[2] // TODO: Remove, Deprecated - Kept for backwards compatibility. } case string: @@ -107,7 +121,8 @@ func New(args ...interface{}) (s *Session, err error) { } else if pass == "" { pass = v } else if s.Token == "" { - s.Token = v + s.Identify.Token = v + s.Token = v // TODO: Remove, Deprecated - Kept for backwards compatibility. } else { err = fmt.Errorf("too many string parameters provided") return @@ -127,10 +142,12 @@ func New(args ...interface{}) (s *Session, err error) { // Discord will verify it for free, or log the user in if it is // invalid. if pass == "" { - s.Token = auth + s.Identify.Token = auth + s.Token = auth // TODO: Remove, Deprecated - Kept for backwards compatibility. } else { err = s.Login(auth, pass) - if err != nil || s.Token == "" { + // TODO: Remove last s.Token part, Deprecated - Kept for backwards compatibility. + if err != nil || s.Identify.Token == "" || s.Token == "" { if s.MFA { err = ErrMFA } else { @@ -140,8 +157,5 @@ func New(args ...interface{}) (s *Session, err error) { } } - // The Session is now able to have RestAPI methods called on it. - // It is recommended that you now call Open() so that events will trigger. - return } diff --git a/vendor/github.com/matterbridge/discordgo/endpoints.go b/vendor/github.com/matterbridge/discordgo/endpoints.go index 6f86b67f..3d0c614a 100644 --- a/vendor/github.com/matterbridge/discordgo/endpoints.go +++ b/vendor/github.com/matterbridge/discordgo/endpoints.go @@ -18,12 +18,12 @@ var APIVersion = "6" // Known Discord API Endpoints. var ( - EndpointStatus = "https://status.discordapp.com/api/v2/" + EndpointStatus = "https://status.discord.com/api/v2/" EndpointSm = EndpointStatus + "scheduled-maintenances/" EndpointSmActive = EndpointSm + "active.json" EndpointSmUpcoming = EndpointSm + "upcoming.json" - EndpointDiscord = "https://discordapp.com/" + EndpointDiscord = "https://discord.com/" EndpointAPI = EndpointDiscord + "api/v" + APIVersion + "/" EndpointGuilds = EndpointAPI + "guilds/" EndpointChannels = EndpointAPI + "channels/" diff --git a/vendor/github.com/matterbridge/discordgo/event.go b/vendor/github.com/matterbridge/discordgo/event.go index 97cc00a2..67c5f7dd 100644 --- a/vendor/github.com/matterbridge/discordgo/event.go +++ b/vendor/github.com/matterbridge/discordgo/event.go @@ -110,7 +110,7 @@ func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() { // }) // // List of events can be found at this page, with corresponding names in the -// library for each event: https://discordapp.com/developers/docs/topics/gateway#event-names +// library for each event: https://discord.com/developers/docs/topics/gateway#event-names // There are also synthetic events fired by the library internally which are // available for handling, like Connect, Disconnect, and RateLimit. // events.go contains all of the Discord WSAPI and synthetic events that can be handled. diff --git a/vendor/github.com/matterbridge/discordgo/events.go b/vendor/github.com/matterbridge/discordgo/events.go index c416813c..99099c90 100644 --- a/vendor/github.com/matterbridge/discordgo/events.go +++ b/vendor/github.com/matterbridge/discordgo/events.go @@ -139,8 +139,11 @@ type GuildEmojisUpdate struct { // A GuildMembersChunk is the data for a GuildMembersChunk event. type GuildMembersChunk struct { - GuildID string `json:"guild_id"` - Members []*Member `json:"members"` + GuildID string `json:"guild_id"` + Members []*Member `json:"members"` + ChunkIndex int `json:"chunk_index"` + ChunkCount int `json:"chunk_count"` + Presences []*Presence `json:"presences,omitempty"` } // GuildIntegrationsUpdate is the data for a GuildIntegrationsUpdate event. @@ -169,6 +172,7 @@ type MessageUpdate struct { // MessageDelete is the data for a MessageDelete event. type MessageDelete struct { *Message + BeforeDelete *Message `json:"-"` } // MessageReactionAdd is the data for a MessageReactionAdd event. diff --git a/vendor/github.com/matterbridge/discordgo/go.mod b/vendor/github.com/matterbridge/discordgo/go.mod index 484bd32d..51ee8504 100644 --- a/vendor/github.com/matterbridge/discordgo/go.mod +++ b/vendor/github.com/matterbridge/discordgo/go.mod @@ -1,6 +1,8 @@ module github.com/matterbridge/discordgo require ( - github.com/gorilla/websocket v1.4.0 - golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 + github.com/gorilla/websocket v1.4.2 + golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 ) + +go 1.10 diff --git a/vendor/github.com/matterbridge/discordgo/go.sum b/vendor/github.com/matterbridge/discordgo/go.sum index a86b0501..e0aa38e3 100644 --- a/vendor/github.com/matterbridge/discordgo/go.sum +++ b/vendor/github.com/matterbridge/discordgo/go.sum @@ -1,4 +1,10 @@ -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA= -golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/matterbridge/discordgo/logging.go b/vendor/github.com/matterbridge/discordgo/logging.go index 6460b35b..41f0481f 100644 --- a/vendor/github.com/matterbridge/discordgo/logging.go +++ b/vendor/github.com/matterbridge/discordgo/logging.go @@ -37,7 +37,7 @@ const ( // Logger can be used to replace the standard logging for discordgo var Logger func(msgL, caller int, format string, a ...interface{}) -// msglog provides package wide logging consistancy for discordgo +// msglog provides package wide logging consistency for discordgo // the format, a... portion this command follows that of fmt.Printf // msgL : LogLevel of the message // caller : 1 + the number of callers away from the message source diff --git a/vendor/github.com/matterbridge/discordgo/message.go b/vendor/github.com/matterbridge/discordgo/message.go index cc874295..00b8112b 100644 --- a/vendor/github.com/matterbridge/discordgo/message.go +++ b/vendor/github.com/matterbridge/discordgo/message.go @@ -63,7 +63,7 @@ type Message struct { MentionRoles []string `json:"mention_roles"` // Whether the message is text-to-speech. - Tts bool `json:"tts"` + TTS bool `json:"tts"` // Whether the message mentions everyone. MentionEveryone bool `json:"mention_everyone"` @@ -129,10 +129,11 @@ type File struct { // MessageSend stores all parameters you can send with ChannelMessageSendComplex. type MessageSend struct { - Content string `json:"content,omitempty"` - Embed *MessageEmbed `json:"embed,omitempty"` - Tts bool `json:"tts"` - Files []*File `json:"-"` + Content string `json:"content,omitempty"` + Embed *MessageEmbed `json:"embed,omitempty"` + TTS bool `json:"tts"` + Files []*File `json:"-"` + AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"` // TODO: Remove this when compatibility is not required. File *File `json:"-"` @@ -141,8 +142,9 @@ type MessageSend struct { // MessageEdit is used to chain parameters via ChannelMessageEditComplex, which // is also where you should get the instance from. type MessageEdit struct { - Content *string `json:"content,omitempty"` - Embed *MessageEmbed `json:"embed,omitempty"` + Content *string `json:"content,omitempty"` + Embed *MessageEmbed `json:"embed,omitempty"` + AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"` ID string Channel string @@ -171,6 +173,42 @@ func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit { return m } +// AllowedMentionType describes the types of mentions used +// in the MessageAllowedMentions type. +type AllowedMentionType string + +// The types of mentions used in MessageAllowedMentions. +const ( + AllowedMentionTypeRoles AllowedMentionType = "roles" + AllowedMentionTypeUsers AllowedMentionType = "users" + AllowedMentionTypeEveryone AllowedMentionType = "everyone" +) + +// MessageAllowedMentions allows the user to specify which mentions +// Discord is allowed to parse in this message. This is useful when +// sending user input as a message, as it prevents unwanted mentions. +// If this type is used, all mentions must be explicitly whitelisted, +// either by putting an AllowedMentionType in the Parse slice +// (allowing all mentions of that type) or, in the case of roles and +// users, explicitly allowing those mentions on an ID-by-ID basis. +// For more information on this functionality, see: +// https://discordapp.com/developers/docs/resources/channel#allowed-mentions-object-allowed-mentions-reference +type MessageAllowedMentions struct { + // The mention types that are allowed to be parsed in this message. + // Please note that this is purposely **not** marked as omitempty, + // so if a zero-value MessageAllowedMentions object is provided no + // mentions will be allowed. + Parse []AllowedMentionType `json:"parse"` + + // A list of role IDs to allow. This cannot be used when specifying + // AllowedMentionTypeRoles in the Parse slice. + Roles []string `json:"roles,omitempty"` + + // A list of user IDs to allow. This cannot be used when specifying + // AllowedMentionTypeUsers in the Parse slice. + Users []string `json:"users,omitempty"` +} + // A MessageAttachment stores data for message attachments. type MessageAttachment struct { ID string `json:"id"` diff --git a/vendor/github.com/matterbridge/discordgo/restapi.go b/vendor/github.com/matterbridge/discordgo/restapi.go index b5fa0fa4..b2bbed31 100644 --- a/vendor/github.com/matterbridge/discordgo/restapi.go +++ b/vendor/github.com/matterbridge/discordgo/restapi.go @@ -38,7 +38,7 @@ var ( ErrPruneDaysBounds = errors.New("the number of days should be more than or equal to 1") ErrGuildNoIcon = errors.New("guild does not have an icon set") ErrGuildNoSplash = errors.New("guild does not have a splash set") - ErrUnauthorized = errors.New("HTTP request was unauthorized. This could be because the provided token was not a bot token. Please add \"Bot \" to the start of your token. https://discordapp.com/developers/docs/reference#authentication-example-bot-token-authorization-header") + ErrUnauthorized = errors.New("HTTP request was unauthorized. This could be because the provided token was not a bot token. Please add \"Bot \" to the start of your token. https://discord.com/developers/docs/reference#authentication-example-bot-token-authorization-header") ) // Request is the same as RequestWithBucketID but the bucket id is the same as the urlStr @@ -506,7 +506,7 @@ func (s *Session) UserChannelPermissions(userID, channelID string) (apermissions } // Calculates the permissions for a member. -// https://support.discordapp.com/hc/en-us/articles/206141927-How-is-the-permission-hierarchy-structured- +// https://support.discord.com/hc/en-us/articles/206141927-How-is-the-permission-hierarchy-structured- func memberPermissions(guild *Guild, channel *Channel, member *Member) (apermissions int) { userID := member.User.ID @@ -583,14 +583,6 @@ func memberPermissions(guild *Guild, channel *Channel, member *Member) (apermiss // Guild returns a Guild structure of a specific Guild. // guildID : The ID of a Guild func (s *Session) Guild(guildID string) (st *Guild, err error) { - if s.StateEnabled { - // Attempt to grab the guild from State first. - st, err = s.State.Guild(guildID) - if err == nil && !st.Unavailable { - return - } - } - body, err := s.RequestWithBucketID("GET", EndpointGuild(guildID), nil, EndpointGuild(guildID)) if err != nil { return @@ -931,6 +923,8 @@ type GuildChannelCreateData struct { Topic string `json:"topic,omitempty"` Bitrate int `json:"bitrate,omitempty"` UserLimit int `json:"user_limit,omitempty"` + RateLimitPerUser int `json:"rate_limit_per_user,omitempty"` + Position int `json:"position,omitempty"` PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"` ParentID string `json:"parent_id,omitempty"` NSFW bool `json:"nsfw,omitempty"` @@ -1593,7 +1587,7 @@ func (s *Session) ChannelMessageSendComplex(channelID string, data *MessageSend) func (s *Session) ChannelMessageSendTTS(channelID string, content string) (*Message, error) { return s.ChannelMessageSendComplex(channelID, &MessageSend{ Content: content, - Tts: true, + TTS: true, }) } @@ -2191,7 +2185,9 @@ func (s *Session) MessageReactionsRemoveAll(channelID, messageID string) error { // messageID : The message ID. // emojiID : Either the unicode emoji for the reaction, or a guild emoji identifier. // limit : max number of users to return (max 100) -func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit int) (st []*User, err error) { +// beforeID : If provided all reactions returned will be before given ID. +// afterID : If provided all reactions returned will be after given ID. +func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit int, beforeID, afterID string) (st []*User, err error) { // emoji such as #⃣ need to have # escaped emojiID = strings.Replace(emojiID, "#", "%23", -1) uri := EndpointMessageReactions(channelID, messageID, emojiID) @@ -2202,6 +2198,13 @@ func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit i v.Set("limit", strconv.Itoa(limit)) } + if afterID != "" { + v.Set("after", afterID) + } + if beforeID != "" { + v.Set("before", beforeID) + } + if len(v) > 0 { uri += "?" + v.Encode() } diff --git a/vendor/github.com/matterbridge/discordgo/state.go b/vendor/github.com/matterbridge/discordgo/state.go index 7babc115..80bd8dfa 100644 --- a/vendor/github.com/matterbridge/discordgo/state.go +++ b/vendor/github.com/matterbridge/discordgo/state.go @@ -848,6 +848,12 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) { err = s.MemberAdd(t.Members[i]) } } + + if s.TrackPresences { + for _, p := range t.Presences { + err = s.PresenceAdd(t.GuildID, p) + } + } case *GuildRoleCreate: if s.TrackRoles { err = s.RoleAdd(t.GuildID, t.Role) @@ -893,6 +899,13 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) { } case *MessageDelete: if s.MaxMessageCount != 0 { + var old *Message + old, err = s.Message(t.ChannelID, t.ID) + if err == nil { + oldCopy := *old + t.BeforeDelete = &oldCopy + } + err = s.MessageRemove(t.Message) } case *MessageDeleteBulk: diff --git a/vendor/github.com/matterbridge/discordgo/structs.go b/vendor/github.com/matterbridge/discordgo/structs.go index b19d3a67..620489cc 100644 --- a/vendor/github.com/matterbridge/discordgo/structs.go +++ b/vendor/github.com/matterbridge/discordgo/structs.go @@ -29,8 +29,10 @@ type Session struct { // General configurable settings. // Authentication token for this session + // TODO: Remove Below, Deprecated, Use Identify struct Token string - MFA bool + + MFA bool // Debug for printing JSON request/responses Debug bool // Deprecated, will be removed. @@ -39,6 +41,11 @@ type Session struct { // Should the session reconnect the websocket on errors. ShouldReconnectOnError bool + // Identify is sent during initial handshake with the discord gateway. + // https://discord.com/developers/docs/topics/gateway#identify + Identify Identify + + // TODO: Remove Below, Deprecated, Use Identify struct // Should the session request compressed websocket data. Compress bool @@ -587,12 +594,13 @@ type VoiceState struct { // A Presence stores the online, offline, or idle and game status of Guild members. type Presence struct { - User *User `json:"user"` - Status Status `json:"status"` - Game *Game `json:"game"` - Nick string `json:"nick"` - Roles []string `json:"roles"` - Since *int `json:"since"` + User *User `json:"user"` + Status Status `json:"status"` + Game *Game `json:"game"` + Activities []*Game `json:"activities"` + Nick string `json:"nick"` + Roles []string `json:"roles"` + Since *int `json:"since"` } // GameType is the type of "game" (see GameType* consts) in the Game struct @@ -604,6 +612,7 @@ const ( GameTypeStreaming GameTypeListening GameTypeWatching + GameTypeCustom ) // A Game struct holds the name of the "playing .." game for a user @@ -687,7 +696,7 @@ type Settings struct { RenderEmbeds bool `json:"render_embeds"` InlineEmbedMedia bool `json:"inline_embed_media"` InlineAttachmentMedia bool `json:"inline_attachment_media"` - EnableTtsCommand bool `json:"enable_tts_command"` + EnableTTSCommand bool `json:"enable_tts_command"` MessageDisplayCompact bool `json:"message_display_compact"` ShowCurrentGame bool `json:"show_current_game"` ConvertEmoticons bool `json:"convert_emoticons"` @@ -909,8 +918,63 @@ type GatewayBotResponse struct { Shards int `json:"shards"` } +// GatewayStatusUpdate is sent by the client to indicate a presence or status update +// https://discord.com/developers/docs/topics/gateway#update-status-gateway-status-update-structure +type GatewayStatusUpdate struct { + Since int `json:"since"` + Game Activity `json:"game"` + Status string `json:"status"` + AFK bool `json:"afk"` +} + +// Activity defines the Activity sent with GatewayStatusUpdate +// https://discord.com/developers/docs/topics/gateway#activity-object +type Activity struct { + Name string + Type ActivityType + URL string +} + +// ActivityType is the type of Activity (see ActivityType* consts) in the Activity struct +// https://discord.com/developers/docs/topics/gateway#activity-object-activity-types +type ActivityType int + +// Valid ActivityType values +// https://discord.com/developers/docs/topics/gateway#activity-object-activity-types +const ( + ActivityTypeGame GameType = iota + ActivityTypeStreaming + ActivityTypeListening + // ActivityTypeWatching // not valid in this use case? + ActivityTypeCustom = 4 +) + +// Identify is sent during initial handshake with the discord gateway. +// https://discord.com/developers/docs/topics/gateway#identify +type Identify struct { + Token string `json:"token"` + Properties IdentifyProperties `json:"properties"` + Compress bool `json:"compress"` + LargeThreshold int `json:"large_threshold"` + Shard *[2]int `json:"shard,omitempty"` + Presence GatewayStatusUpdate `json:"presence,omitempty"` + GuildSubscriptions bool `json:"guild_subscriptions"` + Intents *Intent `json:"intents,omitempty"` +} + +// IdentifyProperties contains the "properties" portion of an Identify packet +// https://discord.com/developers/docs/topics/gateway#identify-identify-connection-properties +type IdentifyProperties struct { + OS string `json:"$os"` + Browser string `json:"$browser"` + Device string `json:"$device"` + Referer string `json:"$referer"` + ReferringDomain string `json:"$referring_domain"` +} + // Constants for the different bit offsets of text channel permissions const ( + // Deprecated: PermissionReadMessages has been replaced with PermissionViewChannel for text and voice channels PermissionReadMessages = 1 << (iota + 10) PermissionSendMessages PermissionSendTTSMessages @@ -952,8 +1016,9 @@ const ( PermissionManageServer PermissionAddReactions PermissionViewAuditLogs + PermissionViewChannel = 1 << (iota + 2) - PermissionAllText = PermissionReadMessages | + PermissionAllText = PermissionViewChannel | PermissionSendMessages | PermissionSendTTSMessages | PermissionManageMessages | @@ -961,7 +1026,8 @@ const ( PermissionAttachFiles | PermissionReadMessageHistory | PermissionMentionEveryone - PermissionAllVoice = PermissionVoiceConnect | + PermissionAllVoice = PermissionViewChannel | + PermissionVoiceConnect | PermissionVoiceSpeak | PermissionVoiceMuteMembers | PermissionVoiceDeafenMembers | @@ -1037,3 +1103,49 @@ const ( ErrCodeReactionBlocked = 90001 ) + +// Intent is the type of a Gateway Intent +// https://discord.com/developers/docs/topics/gateway#gateway-intents +type Intent int + +// Constants for the different bit offsets of intents +const ( + IntentsGuilds Intent = 1 << iota + IntentsGuildMembers + IntentsGuildBans + IntentsGuildEmojis + IntentsGuildIntegrations + IntentsGuildWebhooks + IntentsGuildInvites + IntentsGuildVoiceStates + IntentsGuildPresences + IntentsGuildMessages + IntentsGuildMessageReactions + IntentsGuildMessageTyping + IntentsDirectMessages + IntentsDirectMessageReactions + IntentsDirectMessageTyping + + IntentsAllWithoutPrivileged = IntentsGuilds | + IntentsGuildBans | + IntentsGuildEmojis | + IntentsGuildIntegrations | + IntentsGuildWebhooks | + IntentsGuildInvites | + IntentsGuildVoiceStates | + IntentsGuildMessages | + IntentsGuildMessageReactions | + IntentsGuildMessageTyping | + IntentsDirectMessages | + IntentsDirectMessageReactions | + IntentsDirectMessageTyping + IntentsAll = IntentsAllWithoutPrivileged | + IntentsGuildMembers | + IntentsGuildPresences + IntentsNone Intent = 0 +) + +// MakeIntent helps convert a gateway intent value for use in the Identify structure. +func MakeIntent(intents Intent) *Intent { + return &intents +} diff --git a/vendor/github.com/matterbridge/discordgo/util.go b/vendor/github.com/matterbridge/discordgo/util.go index 02443ca1..8a2b2e01 100644 --- a/vendor/github.com/matterbridge/discordgo/util.go +++ b/vendor/github.com/matterbridge/discordgo/util.go @@ -12,6 +12,6 @@ func SnowflakeTimestamp(ID string) (t time.Time, err error) { return } timestamp := (i >> 22) + 1420070400000 - t = time.Unix(timestamp/1000, 0) + t = time.Unix(0, timestamp*1000000) return } diff --git a/vendor/github.com/matterbridge/discordgo/voice.go b/vendor/github.com/matterbridge/discordgo/voice.go index 51ac16c8..586b783f 100644 --- a/vendor/github.com/matterbridge/discordgo/voice.go +++ b/vendor/github.com/matterbridge/discordgo/voice.go @@ -346,6 +346,25 @@ func (v *VoiceConnection) wsListen(wsConn *websocket.Conn, close <-chan struct{} for { _, message, err := v.wsConn.ReadMessage() if err != nil { + // 4014 indicates a manual disconnection by someone in the guild; + // we shouldn't reconnect. + if websocket.IsCloseError(err, 4014) { + v.log(LogInformational, "received 4014 manual disconnection") + + // Abandon the voice WS connection + v.Lock() + v.wsConn = nil + v.Unlock() + + v.session.Lock() + delete(v.session.VoiceConnections, v.GuildID) + v.session.Unlock() + + v.Close() + + return + } + // Detect if we have been closed manually. If a Close() has already // happened, the websocket we are listening on will be different to the // current session. diff --git a/vendor/github.com/matterbridge/discordgo/wsapi.go b/vendor/github.com/matterbridge/discordgo/wsapi.go index eccbb9f4..1cf1598e 100644 --- a/vendor/github.com/matterbridge/discordgo/wsapi.go +++ b/vendor/github.com/matterbridge/discordgo/wsapi.go @@ -18,7 +18,6 @@ import ( "fmt" "io" "net/http" - "runtime" "sync/atomic" "time" @@ -47,7 +46,7 @@ type resumePacket struct { } // Open creates a websocket connection to Discord. -// See: https://discordapp.com/developers/docs/topics/gateway#connecting +// See: https://discord.com/developers/docs/topics/gateway#connecting func (s *Session) Open() error { s.log(LogInformational, "called") @@ -80,7 +79,7 @@ func (s *Session) Open() error { header.Add("accept-encoding", "zlib") s.wsConn, _, err = websocket.DefaultDialer.Dial(s.gateway, header) if err != nil { - s.log(LogWarning, "error connecting to gateway %s, %s", s.gateway, err) + s.log(LogError, "error connecting to gateway %s, %s", s.gateway, err) s.gateway = "" // clear cached gateway s.wsConn = nil // Just to be safe. return err @@ -399,9 +398,10 @@ func (s *Session) UpdateStatusComplex(usd UpdateStatusData) (err error) { } type requestGuildMembersData struct { - GuildID string `json:"guild_id"` - Query string `json:"query"` - Limit int `json:"limit"` + GuildIDs []string `json:"guild_id"` + Query string `json:"query"` + Limit int `json:"limit"` + Presences bool `json:"presences"` } type requestGuildMembersOp struct { @@ -411,10 +411,39 @@ type requestGuildMembersOp struct { // RequestGuildMembers requests guild members from the gateway // The gateway responds with GuildMembersChunk events -// guildID : The ID of the guild to request members of -// query : String that username starts with, leave empty to return all members -// limit : Max number of items to return, or 0 to request all members matched -func (s *Session) RequestGuildMembers(guildID, query string, limit int) (err error) { +// guildID : Single Guild ID to request members of +// query : String that username starts with, leave empty to return all members +// limit : Max number of items to return, or 0 to request all members matched +// presences : Whether to request presences of guild members +func (s *Session) RequestGuildMembers(guildID string, query string, limit int, presences bool) (err error) { + data := requestGuildMembersData{ + GuildIDs: []string{guildID}, + Query: query, + Limit: limit, + Presences: presences, + } + err = s.requestGuildMembers(data) + return +} + +// RequestGuildMembersBatch requests guild members from the gateway +// The gateway responds with GuildMembersChunk events +// guildID : Slice of guild IDs to request members of +// query : String that username starts with, leave empty to return all members +// limit : Max number of items to return, or 0 to request all members matched +// presences : Whether to request presences of guild members +func (s *Session) RequestGuildMembersBatch(guildIDs []string, query string, limit int, presences bool) (err error) { + data := requestGuildMembersData{ + GuildIDs: guildIDs, + Query: query, + Limit: limit, + Presences: presences, + } + err = s.requestGuildMembers(data) + return +} + +func (s *Session) requestGuildMembers(data requestGuildMembersData) (err error) { s.log(LogInformational, "called") s.RLock() @@ -423,12 +452,6 @@ func (s *Session) RequestGuildMembers(guildID, query string, limit int) (err err return ErrWSNotFound } - data := requestGuildMembersData{ - GuildID: guildID, - Query: query, - Limit: limit, - } - s.wsMutex.Lock() err = s.wsConn.WriteJSON(requestGuildMembersOp{8, data}) s.wsMutex.Unlock() @@ -498,7 +521,7 @@ func (s *Session) onEvent(messageType int, message []byte) (*Event, error) { // Must immediately disconnect from gateway and reconnect to new gateway. if e.Operation == 7 { s.log(LogInformational, "Closing and reconnecting in response to Op7") - s.Close() + s.CloseWithCode(websocket.CloseServiceRestart) s.reconnect() return e, nil } @@ -722,55 +745,42 @@ func (s *Session) onVoiceServerUpdate(st *VoiceServerUpdate) { } } -type identifyProperties struct { - OS string `json:"$os"` - Browser string `json:"$browser"` - Device string `json:"$device"` - Referer string `json:"$referer"` - ReferringDomain string `json:"$referring_domain"` -} - -type identifyData struct { - Token string `json:"token"` - Properties identifyProperties `json:"properties"` - LargeThreshold int `json:"large_threshold"` - Compress bool `json:"compress"` - Shard *[2]int `json:"shard,omitempty"` -} - type identifyOp struct { - Op int `json:"op"` - Data identifyData `json:"d"` + Op int `json:"op"` + Data Identify `json:"d"` } // identify sends the identify packet to the gateway func (s *Session) identify() error { + s.log(LogDebug, "called") - properties := identifyProperties{runtime.GOOS, - "Discordgo v" + VERSION, - "", - "", - "", + // TODO: This is a temporary block of code to help + // maintain backwards compatability + if s.Compress == false { + s.Identify.Compress = false } - data := identifyData{s.Token, - properties, - 250, - s.Compress, - nil, + // TODO: This is a temporary block of code to help + // maintain backwards compatability + if s.Token != "" && s.Identify.Token == "" { + s.Identify.Token = s.Token } + // TODO: Below block should be refactored so ShardID and ShardCount + // can be deprecated and their usage moved to the Session.Identify + // struct if s.ShardCount > 1 { if s.ShardID >= s.ShardCount { return ErrWSShardBounds } - data.Shard = &[2]int{s.ShardID, s.ShardCount} + s.Identify.Shard = &[2]int{s.ShardID, s.ShardCount} } - op := identifyOp{2, data} - + // Send Identify packet to Discord + op := identifyOp{2, s.Identify} + s.log(LogDebug, "Identify Packet: \n%#v", op) s.wsMutex.Lock() err := s.wsConn.WriteJSON(op) s.wsMutex.Unlock() @@ -834,8 +844,15 @@ func (s *Session) reconnect() { } // Close closes a websocket and stops all listening/heartbeat goroutines. +// TODO: Add support for Voice WS/UDP +func (s *Session) Close() error { + return s.CloseWithCode(websocket.CloseNormalClosure) +} + +// CloseWithCode closes a websocket using the provided closeCode and stops all +// listening/heartbeat goroutines. // TODO: Add support for Voice WS/UDP connections -func (s *Session) Close() (err error) { +func (s *Session) CloseWithCode(closeCode int) (err error) { s.log(LogInformational, "called") s.Lock() @@ -857,7 +874,7 @@ func (s *Session) Close() (err error) { // To cleanly close a connection, a client should send a close // frame and wait for the server to close the connection. s.wsMutex.Lock() - err := s.wsConn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) + err := s.wsConn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, "")) s.wsMutex.Unlock() if err != nil { s.log(LogInformational, "error closing websocket, %s", err) diff --git a/vendor/github.com/slack-go/slack/.travis.yml b/vendor/github.com/slack-go/slack/.travis.yml index 6a968232..f2019d72 100644 --- a/vendor/github.com/slack-go/slack/.travis.yml +++ b/vendor/github.com/slack-go/slack/.travis.yml @@ -32,6 +32,8 @@ matrix: script: go test -v -mod=vendor ./... - go: "1.13.x" script: go test -v -mod=vendor ./... + - go: "1.14.x" + script: go test -v -mod=vendor ./... - go: "tip" script: go test -v -mod=vendor ./... diff --git a/vendor/github.com/slack-go/slack/block.go b/vendor/github.com/slack-go/slack/block.go index dbc34496..4b4b1559 100644 --- a/vendor/github.com/slack-go/slack/block.go +++ b/vendor/github.com/slack-go/slack/block.go @@ -32,23 +32,26 @@ type Blocks struct { // BlockAction is the action callback sent when a block is interacted with type BlockAction struct { - ActionID string `json:"action_id"` - BlockID string `json:"block_id"` - Type actionType `json:"type"` - Text TextBlockObject `json:"text"` - Value string `json:"value"` - ActionTs string `json:"action_ts"` - SelectedOption OptionBlockObject `json:"selected_option"` - SelectedOptions []OptionBlockObject `json:"selected_options"` - SelectedUser string `json:"selected_user"` - SelectedChannel string `json:"selected_channel"` - SelectedConversation string `json:"selected_conversation"` - SelectedDate string `json:"selected_date"` - InitialOption OptionBlockObject `json:"initial_option"` - InitialUser string `json:"initial_user"` - InitialChannel string `json:"initial_channel"` - InitialConversation string `json:"initial_conversation"` - InitialDate string `json:"initial_date"` + ActionID string `json:"action_id"` + BlockID string `json:"block_id"` + Type actionType `json:"type"` + Text TextBlockObject `json:"text"` + Value string `json:"value"` + ActionTs string `json:"action_ts"` + SelectedOption OptionBlockObject `json:"selected_option"` + SelectedOptions []OptionBlockObject `json:"selected_options"` + SelectedUser string `json:"selected_user"` + SelectedUsers []string `json:"selected_users"` + SelectedChannel string `json:"selected_channel"` + SelectedChannels []string `json:"selected_channels"` + SelectedConversation string `json:"selected_conversation"` + SelectedConversations []string `json:"selected_conversations"` + SelectedDate string `json:"selected_date"` + InitialOption OptionBlockObject `json:"initial_option"` + InitialUser string `json:"initial_user"` + InitialChannel string `json:"initial_channel"` + InitialConversation string `json:"initial_conversation"` + InitialDate string `json:"initial_date"` } // actionType returns the type of the action diff --git a/vendor/github.com/slack-go/slack/block_conv.go b/vendor/github.com/slack-go/slack/block_conv.go index 00d59c3b..3fda5431 100644 --- a/vendor/github.com/slack-go/slack/block_conv.go +++ b/vendor/github.com/slack-go/slack/block_conv.go @@ -2,6 +2,7 @@ package slack import ( "encoding/json" + "fmt" "github.com/pkg/errors" ) @@ -172,10 +173,12 @@ func (b *BlockElements) UnmarshalJSON(data []byte) error { blockElement = &DatePickerBlockElement{} case "plain_text_input": blockElement = &PlainTextInputBlockElement{} + case "checkboxes": + blockElement = &CheckboxGroupsBlockElement{} case "static_select", "external_select", "users_select", "conversations_select", "channels_select": blockElement = &SelectBlockElement{} default: - return errors.New("unsupported block element type") + return fmt.Errorf("unsupported block element type %v", blockElementType) } err = json.Unmarshal(r, blockElement) @@ -275,6 +278,12 @@ func (a *Accessory) UnmarshalJSON(data []byte) error { return err } a.MultiSelectElement = element.(*MultiSelectBlockElement) + case "checkboxes": + element, err := unmarshalBlockElement(r, &CheckboxGroupsBlockElement{}) + if err != nil { + return err + } + a.CheckboxGroupsBlockElement = element.(*CheckboxGroupsBlockElement) default: element, err := unmarshalBlockElement(r, &UnknownBlockElement{}) if err != nil { @@ -313,6 +322,9 @@ func toBlockElement(element *Accessory) BlockElement { if element.RadioButtonsElement != nil { return element.RadioButtonsElement } + if element.CheckboxGroupsBlockElement != nil { + return element.CheckboxGroupsBlockElement + } if element.SelectElement != nil { return element.SelectElement } diff --git a/vendor/github.com/slack-go/slack/block_element.go b/vendor/github.com/slack-go/slack/block_element.go index 50971bfa..bca4e314 100644 --- a/vendor/github.com/slack-go/slack/block_element.go +++ b/vendor/github.com/slack-go/slack/block_element.go @@ -40,15 +40,16 @@ type MixedElement interface { } type Accessory struct { - ImageElement *ImageBlockElement - ButtonElement *ButtonBlockElement - OverflowElement *OverflowBlockElement - DatePickerElement *DatePickerBlockElement - PlainTextInputElement *PlainTextInputBlockElement - RadioButtonsElement *RadioButtonsBlockElement - SelectElement *SelectBlockElement - MultiSelectElement *MultiSelectBlockElement - UnknownElement *UnknownBlockElement + ImageElement *ImageBlockElement + ButtonElement *ButtonBlockElement + OverflowElement *OverflowBlockElement + DatePickerElement *DatePickerBlockElement + PlainTextInputElement *PlainTextInputBlockElement + RadioButtonsElement *RadioButtonsBlockElement + SelectElement *SelectBlockElement + MultiSelectElement *MultiSelectBlockElement + CheckboxGroupsBlockElement *CheckboxGroupsBlockElement + UnknownElement *UnknownBlockElement } // NewAccessory returns a new Accessory for a given block element @@ -70,6 +71,8 @@ func NewAccessory(element BlockElement) *Accessory { return &Accessory{SelectElement: element.(*SelectBlockElement)} case *MultiSelectBlockElement: return &Accessory{MultiSelectElement: element.(*MultiSelectBlockElement)} + case *CheckboxGroupsBlockElement: + return &Accessory{CheckboxGroupsBlockElement: element.(*CheckboxGroupsBlockElement)} default: return &Accessory{UnknownElement: element.(*UnknownBlockElement)} } @@ -152,9 +155,10 @@ func (s ButtonBlockElement) ElementType() MessageElementType { return s.Type } -// add styling to button object -func (s *ButtonBlockElement) WithStyle(style Style) { +// WithStyling adds styling to the button object and returns the modified ButtonBlockElement +func (s *ButtonBlockElement) WithStyle(style Style) *ButtonBlockElement { s.Style = style + return s } // NewButtonBlockElement returns an instance of a new button element to be used within a block @@ -186,17 +190,19 @@ type OptionGroupsResponse struct { // // More Information: https://api.slack.com/reference/messaging/block-elements#select type SelectBlockElement struct { - Type string `json:"type,omitempty"` - Placeholder *TextBlockObject `json:"placeholder,omitempty"` - ActionID string `json:"action_id,omitempty"` - Options []*OptionBlockObject `json:"options,omitempty"` - OptionGroups []*OptionGroupBlockObject `json:"option_groups,omitempty"` - InitialOption *OptionBlockObject `json:"initial_option,omitempty"` - InitialUser string `json:"initial_user,omitempty"` - InitialConversation string `json:"initial_conversation,omitempty"` - InitialChannel string `json:"initial_channel,omitempty"` - MinQueryLength *int `json:"min_query_length,omitempty"` - Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` + Type string `json:"type,omitempty"` + Placeholder *TextBlockObject `json:"placeholder,omitempty"` + ActionID string `json:"action_id,omitempty"` + Options []*OptionBlockObject `json:"options,omitempty"` + OptionGroups []*OptionGroupBlockObject `json:"option_groups,omitempty"` + InitialOption *OptionBlockObject `json:"initial_option,omitempty"` + InitialUser string `json:"initial_user,omitempty"` + InitialConversation string `json:"initial_conversation,omitempty"` + InitialChannel string `json:"initial_channel,omitempty"` + DefaultToCurrentConversation bool `json:"default_to_current_conversation,omitempty"` + ResponseURLEnabled bool `json:"response_url_enabled,omitempty"` + MinQueryLength *int `json:"min_query_length,omitempty"` + Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` } // ElementType returns the type of the Element @@ -315,7 +321,7 @@ func NewOverflowBlockElement(actionID string, options ...*OptionBlockObject) *Ov // More Information: https://api.slack.com/reference/messaging/block-elements#datepicker type DatePickerBlockElement struct { Type MessageElementType `json:"type"` - ActionID string `json:"action_id"` + ActionID string `json:"action_id,omitempty"` Placeholder *TextBlockObject `json:"placeholder,omitempty"` InitialDate string `json:"initial_date,omitempty"` Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` @@ -341,7 +347,7 @@ func NewDatePickerBlockElement(actionID string) *DatePickerBlockElement { // More Information: https://api.slack.com/reference/block-kit/block-elements#input type PlainTextInputBlockElement struct { Type MessageElementType `json:"type"` - ActionID string `json:"action_id"` + ActionID string `json:"action_id,omitempty"` Placeholder *TextBlockObject `json:"placeholder,omitempty"` InitialValue string `json:"initial_value,omitempty"` Multiline bool `json:"multiline,omitempty"` @@ -370,7 +376,7 @@ func NewPlainTextInputBlockElement(placeholder *TextBlockObject, actionID string // More Information: https://api.slack.com/reference/block-kit/block-elements#checkboxes type CheckboxGroupsBlockElement struct { Type MessageElementType `json:"type"` - ActionID string `json:"action_id"` + ActionID string `json:"action_id,omitempty"` Options []*OptionBlockObject `json:"options"` InitialOptions []*OptionBlockObject `json:"initial_options,omitempty"` Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` @@ -381,7 +387,7 @@ func (c CheckboxGroupsBlockElement) ElementType() MessageElementType { return c.Type } -// NewRadioButtonsBlockElement returns an instance of a radio block element +// NewCheckboxGroupsBlockElement returns an instance of a radio block element func NewCheckboxGroupsBlockElement(actionID string, options ...*OptionBlockObject) *CheckboxGroupsBlockElement { return &CheckboxGroupsBlockElement{ Type: METCheckboxGroups, @@ -396,7 +402,7 @@ func NewCheckboxGroupsBlockElement(actionID string, options ...*OptionBlockObjec // More Information: https://api.slack.com/reference/block-kit/block-elements#radio type RadioButtonsBlockElement struct { Type MessageElementType `json:"type"` - ActionID string `json:"action_id"` + ActionID string `json:"action_id,omitempty"` Options []*OptionBlockObject `json:"options"` InitialOption *OptionBlockObject `json:"initial_option,omitempty"` Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` diff --git a/vendor/github.com/slack-go/slack/block_image.go b/vendor/github.com/slack-go/slack/block_image.go index 6de3f63a..90cbd14e 100644 --- a/vendor/github.com/slack-go/slack/block_image.go +++ b/vendor/github.com/slack-go/slack/block_image.go @@ -8,7 +8,7 @@ type ImageBlock struct { ImageURL string `json:"image_url"` AltText string `json:"alt_text"` BlockID string `json:"block_id,omitempty"` - Title *TextBlockObject `json:"title"` + Title *TextBlockObject `json:"title,omitempty"` } // BlockType returns the type of the block diff --git a/vendor/github.com/slack-go/slack/block_object.go b/vendor/github.com/slack-go/slack/block_object.go index cf3536d0..b6f1da4a 100644 --- a/vendor/github.com/slack-go/slack/block_object.go +++ b/vendor/github.com/slack-go/slack/block_object.go @@ -163,6 +163,7 @@ type ConfirmationBlockObject struct { Text *TextBlockObject `json:"text"` Confirm *TextBlockObject `json:"confirm"` Deny *TextBlockObject `json:"deny"` + Style Style `json:"style,omitempty"` } // validateType enforces block objects for element and block parameters @@ -170,6 +171,11 @@ func (s ConfirmationBlockObject) validateType() MessageObjectType { return motConfirmation } +// add styling to confirmation object +func (s *ConfirmationBlockObject) WithStyle(style Style) { + s.Style = style +} + // NewConfirmationBlockObject returns an instance of a new Confirmation Block Object func NewConfirmationBlockObject(title, text, confirm, deny *TextBlockObject) *ConfirmationBlockObject { return &ConfirmationBlockObject{ diff --git a/vendor/github.com/slack-go/slack/chat.go b/vendor/github.com/slack-go/slack/chat.go index c5b524c1..a9f51e1f 100644 --- a/vendor/github.com/slack-go/slack/chat.go +++ b/vendor/github.com/slack-go/slack/chat.go @@ -1,8 +1,10 @@ package slack import ( + "bytes" "context" "encoding/json" + "io/ioutil" "net/http" "net/url" "strconv" @@ -206,6 +208,15 @@ func (api *Client) SendMessageContext(ctx context.Context, channelID string, opt return "", "", "", err } + if api.Debug() { + reqBody, err := ioutil.ReadAll(req.Body) + if err != nil { + return "", "", "", err + } + req.Body = ioutil.NopCloser(bytes.NewBuffer(reqBody)) + api.Debugf("Sending request: %s", string(reqBody)) + } + if err = doPost(ctx, api.httpclient, req, parser(&response), api); err != nil { return "", "", "", err } diff --git a/vendor/github.com/slack-go/slack/go.mod b/vendor/github.com/slack-go/slack/go.mod index 2107e612..32fc4b93 100644 --- a/vendor/github.com/slack-go/slack/go.mod +++ b/vendor/github.com/slack-go/slack/go.mod @@ -1,9 +1,11 @@ module github.com/slack-go/slack require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-test/deep v1.0.4 - github.com/gorilla/websocket v1.2.0 + github.com/gorilla/websocket v1.4.2 github.com/pkg/errors v0.8.0 + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 ) diff --git a/vendor/github.com/slack-go/slack/go.sum b/vendor/github.com/slack-go/slack/go.sum index 7a0ae46e..a66560ac 100644 --- a/vendor/github.com/slack-go/slack/go.sum +++ b/vendor/github.com/slack-go/slack/go.sum @@ -4,6 +4,8 @@ github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/vendor/github.com/slack-go/slack/interactions.go b/vendor/github.com/slack-go/slack/interactions.go index ec662ee3..c7f59217 100644 --- a/vendor/github.com/slack-go/slack/interactions.go +++ b/vendor/github.com/slack-go/slack/interactions.go @@ -59,8 +59,13 @@ type InteractionCallback struct { } type Container struct { - Type string `json:"type"` - ViewID string `json:"view_id"` + Type string `json:"type"` + ViewID string `json:"view_id"` + MessageTs string `json:"message_ts"` + AttachmentID json.Number `json:"attachment_id"` + ChannelID string `json:"channel_id"` + IsEphemeral bool `json:"is_ephemeral"` + IsAppUnfurl bool `json:"is_app_unfurl"` } // ActionCallback is a convenience struct defined to allow dynamic unmarshalling of @@ -135,7 +140,7 @@ func (a *ActionCallbacks) UnmarshalJSON(data []byte) error { } a.BlockActions = append(a.BlockActions, action.(*BlockAction)) - return nil + continue } action, err := unmarshalAction(r, &AttachmentAction{}) diff --git a/vendor/github.com/slack-go/slack/oauth.go b/vendor/github.com/slack-go/slack/oauth.go index 43139768..4dc23b11 100644 --- a/vendor/github.com/slack-go/slack/oauth.go +++ b/vendor/github.com/slack-go/slack/oauth.go @@ -78,10 +78,26 @@ func GetOAuthTokenContext(ctx context.Context, client httpClient, clientID, clie return response.AccessToken, response.Scope, nil } +// GetBotOAuthToken retrieves top-level and bot AccessToken - https://api.slack.com/legacy/oauth#bot_user_access_tokens +func GetBotOAuthToken(client httpClient, clientID, clientSecret, code, redirectURI string) (accessToken string, scope string, bot OAuthResponseBot, err error) { + return GetBotOAuthTokenContext(context.Background(), client, clientID, clientSecret, code, redirectURI) +} + +// GetBotOAuthTokenContext retrieves top-level and bot AccessToken with a custom context +func GetBotOAuthTokenContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string) (accessToken string, scope string, bot OAuthResponseBot, err error) { + response, err := GetOAuthResponseContext(ctx, client, clientID, clientSecret, code, redirectURI) + if err != nil { + return "", "", OAuthResponseBot{}, err + } + return response.AccessToken, response.Scope, response.Bot, nil +} + +// GetOAuthResponse retrieves OAuth response func GetOAuthResponse(client httpClient, clientID, clientSecret, code, redirectURI string) (resp *OAuthResponse, err error) { return GetOAuthResponseContext(context.Background(), client, clientID, clientSecret, code, redirectURI) } +// GetOAuthResponseContext retrieves OAuth response with custom context func GetOAuthResponseContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string) (resp *OAuthResponse, err error) { values := url.Values{ "client_id": {clientID}, diff --git a/vendor/github.com/slack-go/slack/webhooks.go b/vendor/github.com/slack-go/slack/webhooks.go index 1016cb4f..39fff441 100644 --- a/vendor/github.com/slack-go/slack/webhooks.go +++ b/vendor/github.com/slack-go/slack/webhooks.go @@ -14,6 +14,7 @@ type WebhookMessage struct { Text string `json:"text,omitempty"` Attachments []Attachment `json:"attachments,omitempty"` Parse string `json:"parse,omitempty"` + Blocks *Blocks `json:"blocks,omitempty"` } func PostWebhook(url string, msg *WebhookMessage) error { diff --git a/vendor/github.com/yaegashi/msgraph.go/msauth/README.md b/vendor/github.com/yaegashi/msgraph.go/msauth/README.md index 43aead20..50c314f1 100644 --- a/vendor/github.com/yaegashi/msgraph.go/msauth/README.md +++ b/vendor/github.com/yaegashi/msgraph.go/msauth/README.md @@ -58,6 +58,32 @@ var scopes = []string{msauth.DefaultMSGraphScope} ... ``` +### Resource owner password credentials grant + +- [OAuth 2.0 resource owner passowrd credentials grant flow] + +```go +const ( + tenantID = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" + clientID = "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY" + clientSecret = "ZZZZZZZZZZZZZZZZZZZZZZZZ" + username = "user.name@your-domain.com" + password = "secure-password" +) + +var scopes = []string{msauth.DefaultMSGraphScope} + + ctx := context.Background() + m := msauth.NewManager() + ts, err := m.ResourceOwnerPasswordGrant(ctx, tenantID, clientID, clientSecret, username, password, scopes) + if err != nil { + log.Fatal(err) + } + + httpClient := oauth2.NewClient(ctx, ts) + ... +``` + ### Authorization code grant - [OAuth 2.0 authorization code grant flow] @@ -67,4 +93,5 @@ var scopes = []string{msauth.DefaultMSGraphScope} [v2.0 endpoint]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-overview [OAuth 2.0 device authorization grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code [OAuth 2.0 client credentials grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow -[OAuth 2.0 authorization code grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
\ No newline at end of file +[OAuth 2.0 authorization code grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow +[OAuth 2.0 resource owner passowrd credentials grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc diff --git a/vendor/github.com/yaegashi/msgraph.go/msauth/device_authorization_grant.go b/vendor/github.com/yaegashi/msgraph.go/msauth/device_authorization_grant.go index 4baafd8d..9ff23b3c 100644 --- a/vendor/github.com/yaegashi/msgraph.go/msauth/device_authorization_grant.go +++ b/vendor/github.com/yaegashi/msgraph.go/msauth/device_authorization_grant.go @@ -39,9 +39,10 @@ func (m *Manager) DeviceAuthorizationGrant(ctx context.Context, tenantID, client Endpoint: endpoint, Scopes: scopes, } - if t, ok := m.TokenCache[generateKey(tenantID, clientID)]; ok { + if t, ok := m.GetToken(CacheKey(tenantID, clientID)); ok { tt, err := config.TokenSource(ctx, t).Token() if err == nil { + m.PutToken(CacheKey(tenantID, clientID), tt) return config.TokenSource(ctx, tt), nil } if _, ok := err.(*oauth2.RetrieveError); !ok { @@ -85,7 +86,7 @@ func (m *Manager) DeviceAuthorizationGrant(ctx context.Context, tenantID, client time.Sleep(time.Second * time.Duration(interval)) token, err := m.requestToken(ctx, tenantID, clientID, values) if err == nil { - m.Cache(tenantID, clientID, token) + m.PutToken(CacheKey(tenantID, clientID), token) return config.TokenSource(ctx, token), nil } tokenError, ok := err.(*TokenError) diff --git a/vendor/github.com/yaegashi/msgraph.go/msauth/msauth.go b/vendor/github.com/yaegashi/msgraph.go/msauth/msauth.go index c2a86985..014f2522 100644 --- a/vendor/github.com/yaegashi/msgraph.go/msauth/msauth.go +++ b/vendor/github.com/yaegashi/msgraph.go/msauth/msauth.go @@ -36,10 +36,6 @@ func (t *TokenError) Error() string { return fmt.Sprintf("%s: %s", t.ErrorObject, t.ErrorDescription) } -func generateKey(tenantID, clientID string) string { - return fmt.Sprintf("%s:%s", tenantID, clientID) -} - func deviceCodeURL(tenantID string) string { return fmt.Sprintf(endpointURLFormat, tenantID, "devicecode") } @@ -65,6 +61,7 @@ func (e *tokenJSON) expiry() (t time.Time) { // Manager is oauth2 token cache manager type Manager struct { mu sync.Mutex + Dirty bool TokenCache map[string]*oauth2.Token } @@ -87,27 +84,64 @@ func (m *Manager) SaveBytes() ([]byte, error) { return json.Marshal(m.TokenCache) } -// LoadFile loads token cache from file +// LoadFile loads token cache from file with dirty state control func (m *Manager) LoadFile(path string) error { - b, err := ioutil.ReadFile(path) + m.mu.Lock() + defer m.mu.Unlock() + b, err := ReadLocation(path) + if err != nil { + return err + } + err = json.Unmarshal(b, &m.TokenCache) if err != nil { return err } - return m.LoadBytes(b) + m.Dirty = false + return nil } -// SaveFile saves token cache to file +// SaveFile saves token cache to file with dirty state control func (m *Manager) SaveFile(path string) error { - b, err := m.SaveBytes() + m.mu.Lock() + defer m.mu.Unlock() + if !m.Dirty { + return nil + } + b, err := json.Marshal(m.TokenCache) + if err != nil { + return err + } + err = WriteLocation(path, b, 0644) if err != nil { return err } - return ioutil.WriteFile(path, b, 0644) + m.Dirty = false + return nil +} + +// CacheKey generates a token cache key from tenantID/clientID +func CacheKey(tenantID, clientID string) string { + return fmt.Sprintf("%s:%s", tenantID, clientID) +} + +// GetToken gets a token from token cache +func (m *Manager) GetToken(cacheKey string) (*oauth2.Token, bool) { + m.mu.Lock() + defer m.mu.Unlock() + token, ok := m.TokenCache[cacheKey] + return token, ok } -// Cache stores a token into token cache -func (m *Manager) Cache(tenantID, clientID string, token *oauth2.Token) { - m.TokenCache[generateKey(tenantID, clientID)] = token +// PutToken puts a token into token cache +func (m *Manager) PutToken(cacheKey string, token *oauth2.Token) { + m.mu.Lock() + defer m.mu.Unlock() + oldToken, ok := m.TokenCache[cacheKey] + if ok && *oldToken == *token { + return + } + m.TokenCache[cacheKey] = token + m.Dirty = true } // requestToken requests a token from the token endpoint diff --git a/vendor/github.com/yaegashi/msgraph.go/msauth/resource_owner_password_grant.go b/vendor/github.com/yaegashi/msgraph.go/msauth/resource_owner_password_grant.go new file mode 100644 index 00000000..cf127607 --- /dev/null +++ b/vendor/github.com/yaegashi/msgraph.go/msauth/resource_owner_password_grant.go @@ -0,0 +1,26 @@ +package msauth + +import ( + "context" + + "golang.org/x/oauth2" + "golang.org/x/oauth2/microsoft" +) + +// ResourceOwnerPasswordGrant preforms OAuth 2.0 client resource owner password grant and returns a token. +func (m *Manager) ResourceOwnerPasswordGrant(ctx context.Context, tenantID, clientID, clientSecret, username, password string, scopes []string) (oauth2.TokenSource, error) { + endpoint := microsoft.AzureADEndpoint(tenantID) + endpoint.AuthStyle = oauth2.AuthStyleInParams + config := &oauth2.Config{ + ClientID: clientID, + ClientSecret: clientSecret, + Endpoint: endpoint, + Scopes: scopes, + } + t, err := config.PasswordCredentialsToken(ctx, username, password) + if err != nil { + return nil, err + } + ts := config.TokenSource(ctx, t) + return ts, nil +} diff --git a/vendor/github.com/yaegashi/msgraph.go/msauth/storage.go b/vendor/github.com/yaegashi/msgraph.go/msauth/storage.go new file mode 100644 index 00000000..7d8db8ae --- /dev/null +++ b/vendor/github.com/yaegashi/msgraph.go/msauth/storage.go @@ -0,0 +1,70 @@ +package msauth + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "strings" +) + +// ReadLocation reads data from file with path or URL +func ReadLocation(loc string) ([]byte, error) { + u, err := url.Parse(loc) + if err != nil { + return nil, err + } + switch u.Scheme { + case "", "file": + return ioutil.ReadFile(u.Path) + case "http", "https": + res, err := http.Get(loc) + if err != nil { + return nil, err + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s", res.Status) + } + b, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + return b, nil + } + return nil, fmt.Errorf("Unsupported location to load: %s", loc) +} + +// WriteLocation writes data to file with path or URL +func WriteLocation(loc string, b []byte, m os.FileMode) error { + u, err := url.Parse(loc) + if err != nil { + return err + } + switch u.Scheme { + case "", "file": + return ioutil.WriteFile(u.Path, b, m) + case "http", "https": + if strings.HasSuffix(u.Host, ".blob.core.windows.net") { + // Azure Blob Storage URL with SAS assumed here + cli := &http.Client{} + req, err := http.NewRequest(http.MethodPut, loc, bytes.NewBuffer(b)) + if err != nil { + return err + } + req.Header.Set("x-ms-blob-type", "BlockBlob") + res, err := cli.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + if res.StatusCode != http.StatusCreated { + return fmt.Errorf("%s", res.Status) + } + return nil + } + } + return fmt.Errorf("Unsupported location to save: %s", loc) +} |