Update dependencies and fix whatsmeow API changes (#1887)

* Update dependencies

* Fix whatsmau API changes
This commit is contained in:
Wim 2022-09-05 21:00:54 +02:00 committed by GitHub
parent 7abf1a5884
commit fda05f2262
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 2008 additions and 1703 deletions

View File

@ -1,3 +1,4 @@
//go:build whatsappmulti
// +build whatsappmulti // +build whatsappmulti
package bwhatsapp package bwhatsapp
@ -77,7 +78,7 @@ func (b *Bwhatsapp) getSenderNotify(senderJid types.JID) string {
func (b *Bwhatsapp) GetProfilePicThumb(jid string) (*types.ProfilePictureInfo, error) { func (b *Bwhatsapp) GetProfilePicThumb(jid string) (*types.ProfilePictureInfo, error) {
pjid, _ := types.ParseJID(jid) pjid, _ := types.ParseJID(jid)
info, err := b.wc.GetProfilePictureInfo(pjid, true) info, err := b.wc.GetProfilePictureInfo(pjid, true, "")
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get avatar: %v", err) return nil, fmt.Errorf("failed to get avatar: %v", err)
} }

View File

@ -1,3 +1,4 @@
//go:build whatsappmulti
// +build whatsappmulti // +build whatsappmulti
package bwhatsapp package bwhatsapp
@ -234,7 +235,7 @@ func (b *Bwhatsapp) PostDocumentMessage(msg config.Message, filetype string) (st
b.Log.Debugf("=> Sending %#v", msg) b.Log.Debugf("=> Sending %#v", msg)
ID := whatsmeow.GenerateMessageID() ID := whatsmeow.GenerateMessageID()
_, err = b.wc.SendMessage(groupJID, ID, &message) _, err = b.wc.SendMessage(context.TODO(), groupJID, ID, &message)
return ID, err return ID, err
} }
@ -268,7 +269,7 @@ func (b *Bwhatsapp) PostImageMessage(msg config.Message, filetype string) (strin
b.Log.Debugf("=> Sending %#v", msg) b.Log.Debugf("=> Sending %#v", msg)
ID := whatsmeow.GenerateMessageID() ID := whatsmeow.GenerateMessageID()
_, err = b.wc.SendMessage(groupJID, ID, &message) _, err = b.wc.SendMessage(context.TODO(), groupJID, ID, &message)
return ID, err return ID, err
} }
@ -327,7 +328,7 @@ func (b *Bwhatsapp) Send(msg config.Message) (string, error) {
message.Conversation = &text message.Conversation = &text
ID := whatsmeow.GenerateMessageID() ID := whatsmeow.GenerateMessageID()
_, err := b.wc.SendMessage(groupJID, ID, &message) _, err := b.wc.SendMessage(context.TODO(), groupJID, ID, &message)
return ID, err return ID, err
} }

16
go.mod
View File

@ -7,12 +7,12 @@ require (
github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560 github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560
github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c
github.com/SevereCloud/vksdk/v2 v2.15.0 github.com/SevereCloud/vksdk/v2 v2.15.0
github.com/bwmarrin/discordgo v0.25.0 github.com/bwmarrin/discordgo v0.26.1
github.com/d5/tengo/v2 v2.12.1 github.com/d5/tengo/v2 v2.12.2
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/fsnotify/fsnotify v1.5.4 github.com/fsnotify/fsnotify v1.5.4
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
github.com/gomarkdown/markdown v0.0.0-20220731190611-dcdaee8e7a53 github.com/gomarkdown/markdown v0.0.0-20220830015526-01a3c37d6f50
github.com/google/gops v0.3.25 github.com/google/gops v0.3.25
github.com/gorilla/schema v1.2.0 github.com/gorilla/schema v1.2.0
github.com/gorilla/websocket v1.5.0 github.com/gorilla/websocket v1.5.0
@ -21,8 +21,8 @@ require (
github.com/jpillora/backoff v1.0.0 github.com/jpillora/backoff v1.0.0
github.com/keybase/go-keybase-chat-bot v0.0.0-20220322223021-75d497527469 github.com/keybase/go-keybase-chat-bot v0.0.0-20220322223021-75d497527469
github.com/kyokomi/emoji/v2 v2.2.10 github.com/kyokomi/emoji/v2 v2.2.10
github.com/labstack/echo/v4 v4.8.0 github.com/labstack/echo/v4 v4.9.0
github.com/lrstanley/girc v0.0.0-20220812131643-56459d73b75a github.com/lrstanley/girc v0.0.0-20220821023908-8e7df6d970f8
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696 github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696
github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be
github.com/matterbridge/gomatrix v0.0.0-20220411225302-271e5088ea27 github.com/matterbridge/gomatrix v0.0.0-20220411225302-271e5088ea27
@ -47,9 +47,9 @@ require (
github.com/writeas/go-strip-markdown v2.0.1+incompatible github.com/writeas/go-strip-markdown v2.0.1+incompatible
github.com/yaegashi/msgraph.go v0.1.4 github.com/yaegashi/msgraph.go v0.1.4
github.com/zfjagann/golang-ring v0.0.0-20220330170733-19bcea1b6289 github.com/zfjagann/golang-ring v0.0.0-20220330170733-19bcea1b6289
go.mau.fi/whatsmeow v0.0.0-20220804175245-31c5af44cb82 go.mau.fi/whatsmeow v0.0.0-20220811191500-f650c10b0068
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 golang.org/x/image v0.0.0-20220902085622-e7cb96979f69
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7 golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
golang.org/x/text v0.3.7 golang.org/x/text v0.3.7
gomod.garykim.dev/nc-talk v0.3.0 gomod.garykim.dev/nc-talk v0.3.0
google.golang.org/protobuf v1.28.1 google.golang.org/protobuf v1.28.1

32
go.sum
View File

@ -285,8 +285,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bwmarrin/discordgo v0.25.0 h1:NXhdfHRNxtwso6FPdzW2i3uBvvU7UIQTghmV2T4nqAs= github.com/bwmarrin/discordgo v0.26.1 h1:AIrM+g3cl+iYBr4yBxCBp9tD9jR3K7upEjl0d89FRkE=
github.com/bwmarrin/discordgo v0.25.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/bwmarrin/discordgo v0.26.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -445,8 +445,8 @@ github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1S
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
github.com/d5/tengo/v2 v2.12.1 h1:0dhup9b1wlEKe4bVyidZ+A5wccRFzYGG+ixTZkhS0mM= github.com/d5/tengo/v2 v2.12.2 h1:79yyTgfWCABEJeuMuWy8R4xBnXA4Yp9i3EB0PCfoxLQ=
github.com/d5/tengo/v2 v2.12.1/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8= github.com/d5/tengo/v2 v2.12.2/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8=
github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA= github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -703,8 +703,8 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomarkdown/markdown v0.0.0-20220731190611-dcdaee8e7a53 h1:JguE3sS3yLzLiCTCnsmzVFuTvTMDJALbzCgurwY5G/0= github.com/gomarkdown/markdown v0.0.0-20220830015526-01a3c37d6f50 h1:tSuUky4sFWjiIIEOefDDBjx5BUIT3kZwcXHM2CNDdTk=
github.com/gomarkdown/markdown v0.0.0-20220731190611-dcdaee8e7a53/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/gomarkdown/markdown v0.0.0-20220830015526-01a3c37d6f50/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -1033,8 +1033,8 @@ github.com/kyokomi/emoji/v2 v2.2.10 h1:1z5eMVcxFifsmEoNpdeq4UahbcicgQ4FEHuzrCVwm
github.com/kyokomi/emoji/v2 v2.2.10/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE= github.com/kyokomi/emoji/v2 v2.2.10/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
github.com/labstack/echo/v4 v4.8.0 h1:wdc6yKVaHxkNOEdz4cRZs1pQkwSXPiRjq69yWP4QQS8= github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY=
github.com/labstack/echo/v4 v4.8.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
@ -1052,8 +1052,8 @@ github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lrstanley/girc v0.0.0-20220812131643-56459d73b75a h1:Ts1KhJMUe+9F0B1QyEKN8F8I748xdRXCbSeF8RAyYI4= github.com/lrstanley/girc v0.0.0-20220821023908-8e7df6d970f8 h1:OeTVm9ph5q9eq9E+HDkUbiJtVvu+kNOhuLe5Qs83sEs=
github.com/lrstanley/girc v0.0.0-20220812131643-56459d73b75a/go.mod h1:lgrnhcF8bg/Bd5HA5DOb4Z+uGqUqGnp4skr+J2GwVgI= github.com/lrstanley/girc v0.0.0-20220821023908-8e7df6d970f8/go.mod h1:lgrnhcF8bg/Bd5HA5DOb4Z+uGqUqGnp4skr+J2GwVgI=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@ -1725,8 +1725,8 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.mau.fi/libsignal v0.0.0-20220628090436-4d18b66b087e h1:ByHDg+D+dMIGuBA2n+1xOUf4xr3FJFYg8yxl06s1YBE= go.mau.fi/libsignal v0.0.0-20220628090436-4d18b66b087e h1:ByHDg+D+dMIGuBA2n+1xOUf4xr3FJFYg8yxl06s1YBE=
go.mau.fi/libsignal v0.0.0-20220628090436-4d18b66b087e/go.mod h1:RCdzkTWSJv0AKGqurzPXJsEGIVMuQps3E/h7CMUPous= go.mau.fi/libsignal v0.0.0-20220628090436-4d18b66b087e/go.mod h1:RCdzkTWSJv0AKGqurzPXJsEGIVMuQps3E/h7CMUPous=
go.mau.fi/whatsmeow v0.0.0-20220804175245-31c5af44cb82 h1:puhLha4NZeIXdwujCBduTR5MxG4+R/Q0vrCx8bYhZn8= go.mau.fi/whatsmeow v0.0.0-20220811191500-f650c10b0068 h1:DgSTWZ1LHSBxJFa3dvTvtMJGzqfYjinUFGLR3DujEts=
go.mau.fi/whatsmeow v0.0.0-20220804175245-31c5af44cb82/go.mod h1:hsjqq2xLuoFew8vbsDCJcGf5EbXCRcR/yoQ+87w6m3k= go.mau.fi/whatsmeow v0.0.0-20220811191500-f650c10b0068/go.mod h1:hsjqq2xLuoFew8vbsDCJcGf5EbXCRcR/yoQ+87w6m3k=
go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8= go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
@ -1839,8 +1839,8 @@ golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20220321031419-a8550c1d254a/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20220321031419-a8550c1d254a/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU= golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -1972,8 +1972,8 @@ golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7 h1:dtndE8FcEta75/4kHF3AbpuWzV6f1LjnLrM4pe2SZrw= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8=
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

87
vendor/github.com/bwmarrin/discordgo/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,87 @@
# Getting started
To start off you can check out existing Pull Requests and Issues to get a gasp of what problems were currently solving and what features you can implement.
## Issues
Our issues are mostly used for bugs, however we welcome refactoring and conceptual issues.
Any other conversation would belong and would be moved into “Discussions”.
## Discussions
We use discussions for ideas, polls, announcements and help questions.
Dont hesitate to ask, we always would try to help.
## Pull Requests
If you want to help us by improving existing or adding new features, you create whats called a Pull Request (aka PR). It allows us to review your code, suggest changes and merge it.
Here are some tips on how to make a good first PR:
- When creating a PR, please consider a distinctive name and description for it, so the maintainers can understand what your PR changes / adds / removes.
- Its always a good idea to link documentation when implementing a new feature / endpoint
- If youre resolving an issue, dont forget to [link it](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) in the description.
- Enable the checkbox to allow maintainers to edit your PR and make commits in the PR branch when necessary.
- We may ask for changes, usually through suggestions or pull request comments. You can apply suggestions right in the UI. Any other change needs to be done manually.
- Dont forget to mark PR comments resolved when youre done applying the changes.
- Be patient and dont close and reopen your PR when no one responds, sometimes it might be held for a while. There might be a lot of reasons: release preparation, the feature is not significant, maintainers are busy, etc.
When your changes are still incomplete (i.e. in Work In Progress state), you can still create a PR, but consider making it a draft.
To make a draft PR, you can change the type of PR by clicking to a triangle next to the “Create Pull Request” button.
Once youre done, you can mark it as “Ready for review”, and well get right on it.
# Code style
To standardize and make things less messy we have a certain code style, that is persistent throughout the codebase.
## Naming
### REST methods
When naming a REST method, while it might seem counterintuitive, we specify the entity before the action verb (for GET endpoints we dont specify one however). Heres an example:
> Endpoint name: Get Channel Message
>
> Method name: `ChannelMessage`
> Endpoint name: Edit Channel Message
>
> Method name: `ChannelMessageEdit`
### Parameter structures
When making a complex REST endpoint, sometimes you might need to implement a `Param` structure. This structure contains parameters for certain endpoint/set of endpoints.
- If an endpoint/set of endpoints have mostly same parameters, its a good idea to use a single `Param` structure for them. Heres an example:
> Endpoint: `GuildMemberEdit`
>
> `Param` structure: `GuildMemberParams`
- If an endpoint/set of endpoints have differentiating parameters, `Param` structure can be named after the endpoints verb. Heres an example:
> Endpoint: `ChannelMessageSendComplex`
>
> `Param` structure: `MessageSend`
> Endpoint: `ChannelMessageEditComplex`
>
> `Param` structure: `MessageEdit`
### Events
When naming an event, we follow gateways internal naming (which often matches with the official event name in the docs). Heres an example:
> Event name: Interaction Create (`INTERACTION_CREATE`)
>
> Structure name: `InteractionCreate`
## Returns
In our REST functions we usually favor named returns instead of regular anonymous returns. This helps readability.
Additionally we try to avoid naked return statements for functions with a long body. Since its easier to loose track of the return result.

View File

@ -1,6 +1,6 @@
# DiscordGo # DiscordGo
[![Go Reference](https://pkg.go.dev/badge/github.com/bwmarrin/discordgo.svg)](https://pkg.go.dev/github.com/bwmarrin/discordgo) [![Go Report Card](https://goreportcard.com/badge/github.com/bwmarrin/discordgo)](https://goreportcard.com/report/github.com/bwmarrin/discordgo) [![Build Status](https://travis-ci.com/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.com/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/golang) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discord.com/invite/discord-api) [![Go Reference](https://pkg.go.dev/badge/github.com/bwmarrin/discordgo.svg)](https://pkg.go.dev/github.com/bwmarrin/discordgo) [![Go Report Card](https://goreportcard.com/badge/github.com/bwmarrin/discordgo)](https://goreportcard.com/report/github.com/bwmarrin/discordgo) [![CI](https://github.com/bwmarrin/discordgo/actions/workflows/ci.yml/badge.svg)](https://github.com/bwmarrin/discordgo/actions/workflows/ci.yml) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/golang) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discord.com/invite/discord-api)
<img align="right" alt="DiscordGo logo" src="docs/img/discordgo.svg" width="400"> <img align="right" alt="DiscordGo logo" src="docs/img/discordgo.svg" width="400">
@ -61,11 +61,9 @@ See Documentation and Examples below for more detailed information.
Because of that there may be major changes to library in the future. Because of that there may be major changes to library in the future.
The DiscordGo code is fairly well documented at this point and is currently The DiscordGo code is fairly well documented at this point and is currently
the only documentation available. Both GoDoc and GoWalker (below) present the only documentation available. Go reference (below) presents that information in a nice format.
that information in a nice format.
- [![Go Reference](https://pkg.go.dev/badge/github.com/bwmarrin/discordgo.svg)](https://pkg.go.dev/github.com/bwmarrin/discordgo) - [![Go Reference](https://pkg.go.dev/badge/github.com/bwmarrin/discordgo.svg)](https://pkg.go.dev/github.com/bwmarrin/discordgo)
- [![Go Walker](https://gowalker.org/api/v1/badge)](https://gowalker.org/github.com/bwmarrin/discordgo)
- Hand crafted documentation coming eventually. - Hand crafted documentation coming eventually.

View File

@ -17,10 +17,12 @@ import (
"net/http" "net/http"
"runtime" "runtime"
"time" "time"
"github.com/gorilla/websocket"
) )
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/) // VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
const VERSION = "0.25.0" const VERSION = "0.26.1"
// New creates a new Discord session with provided token. // New creates a new Discord session with provided token.
// If the token is for a bot, it must be prefixed with "Bot " // If the token is for a bot, it must be prefixed with "Bot "
@ -41,12 +43,13 @@ func New(token string) (s *Session, err error) {
ShardCount: 1, ShardCount: 1,
MaxRestRetries: 3, MaxRestRetries: 3,
Client: &http.Client{Timeout: (20 * time.Second)}, Client: &http.Client{Timeout: (20 * time.Second)},
Dialer: websocket.DefaultDialer,
UserAgent: "DiscordBot (https://github.com/bwmarrin/discordgo, v" + VERSION + ")", UserAgent: "DiscordBot (https://github.com/bwmarrin/discordgo, v" + VERSION + ")",
sequence: new(int64), sequence: new(int64),
LastHeartbeatAck: time.Now().UTC(), LastHeartbeatAck: time.Now().UTC(),
} }
// Initilize the Identify Package with defaults // Initialize the Identify Package with defaults
// These can be modified prior to calling Open() // These can be modified prior to calling Open()
s.Identify.Compress = true s.Identify.Compress = true
s.Identify.LargeThreshold = 250 s.Identify.LargeThreshold = 250

View File

@ -46,8 +46,6 @@ var (
EndpointVoice = EndpointAPI + "/voice/" EndpointVoice = EndpointAPI + "/voice/"
EndpointVoiceRegions = EndpointVoice + "regions" EndpointVoiceRegions = EndpointVoice + "regions"
// TODO: EndpointUserGuildMember
EndpointUser = func(uID string) string { return EndpointUsers + uID } EndpointUser = func(uID string) string { return EndpointUsers + uID }
EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" } EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" } EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" }
@ -64,10 +62,14 @@ var (
EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" } EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID } EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
EndpointUserGuildMember = func(uID, gID string) string { return EndpointUserGuild(uID, gID) + "/member" }
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" } EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" } EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
EndpointGuild = func(gID string) string { return EndpointGuilds + gID } EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
EndpointGuildAutoModeration = func(gID string) string { return EndpointGuild(gID) + "/auto-moderation" }
EndpointGuildAutoModerationRules = func(gID string) string { return EndpointGuildAutoModeration(gID) + "/rules" }
EndpointGuildAutoModerationRule = func(gID, rID string) string { return EndpointGuildAutoModerationRules(gID) + "/" + rID }
EndpointGuildThreads = func(gID string) string { return EndpointGuild(gID) + "/threads" } EndpointGuildThreads = func(gID string) string { return EndpointGuild(gID) + "/threads" }
EndpointGuildActiveThreads = func(gID string) string { return EndpointGuildThreads(gID) + "/active" } EndpointGuildActiveThreads = func(gID string) string { return EndpointGuildThreads(gID) + "/active" }
EndpointGuildPreview = func(gID string) string { return EndpointGuilds + gID + "/preview" } EndpointGuildPreview = func(gID string) string { return EndpointGuilds + gID + "/preview" }

View File

@ -7,69 +7,168 @@ package discordgo
// Event type values are used to match the events returned by Discord. // Event type values are used to match the events returned by Discord.
// EventTypes surrounded by __ are synthetic and are internal to DiscordGo. // EventTypes surrounded by __ are synthetic and are internal to DiscordGo.
const ( const (
channelCreateEventType = "CHANNEL_CREATE" applicationCommandPermissionsUpdateEventType = "APPLICATION_COMMAND_PERMISSIONS_UPDATE"
channelDeleteEventType = "CHANNEL_DELETE" autoModerationActionExecutionEventType = "AUTO_MODERATION_ACTION_EXECUTION"
channelPinsUpdateEventType = "CHANNEL_PINS_UPDATE" autoModerationRuleCreateEventType = "AUTO_MODERATION_RULE_CREATE"
channelUpdateEventType = "CHANNEL_UPDATE" autoModerationRuleDeleteEventType = "AUTO_MODERATION_RULE_DELETE"
connectEventType = "__CONNECT__" autoModerationRuleUpdateEventType = "AUTO_MODERATION_RULE_UPDATE"
disconnectEventType = "__DISCONNECT__" channelCreateEventType = "CHANNEL_CREATE"
eventEventType = "__EVENT__" channelDeleteEventType = "CHANNEL_DELETE"
guildBanAddEventType = "GUILD_BAN_ADD" channelPinsUpdateEventType = "CHANNEL_PINS_UPDATE"
guildBanRemoveEventType = "GUILD_BAN_REMOVE" channelUpdateEventType = "CHANNEL_UPDATE"
guildCreateEventType = "GUILD_CREATE" connectEventType = "__CONNECT__"
guildDeleteEventType = "GUILD_DELETE" disconnectEventType = "__DISCONNECT__"
guildEmojisUpdateEventType = "GUILD_EMOJIS_UPDATE" eventEventType = "__EVENT__"
guildIntegrationsUpdateEventType = "GUILD_INTEGRATIONS_UPDATE" guildBanAddEventType = "GUILD_BAN_ADD"
guildMemberAddEventType = "GUILD_MEMBER_ADD" guildBanRemoveEventType = "GUILD_BAN_REMOVE"
guildMemberRemoveEventType = "GUILD_MEMBER_REMOVE" guildCreateEventType = "GUILD_CREATE"
guildMemberUpdateEventType = "GUILD_MEMBER_UPDATE" guildDeleteEventType = "GUILD_DELETE"
guildMembersChunkEventType = "GUILD_MEMBERS_CHUNK" guildEmojisUpdateEventType = "GUILD_EMOJIS_UPDATE"
guildRoleCreateEventType = "GUILD_ROLE_CREATE" guildIntegrationsUpdateEventType = "GUILD_INTEGRATIONS_UPDATE"
guildRoleDeleteEventType = "GUILD_ROLE_DELETE" guildMemberAddEventType = "GUILD_MEMBER_ADD"
guildRoleUpdateEventType = "GUILD_ROLE_UPDATE" guildMemberRemoveEventType = "GUILD_MEMBER_REMOVE"
guildStageInstanceCreateEventType = "STAGE_INSTANCE_CREATE" guildMemberUpdateEventType = "GUILD_MEMBER_UPDATE"
guildStageInstanceUpdateEventType = "STAGE_INSTANCE_UPDATE" guildMembersChunkEventType = "GUILD_MEMBERS_CHUNK"
guildStageInstanceDeleteEventType = "STAGE_INSTANCE_DELETE" guildRoleCreateEventType = "GUILD_ROLE_CREATE"
guildScheduledEventCreateEventType = "GUILD_SCHEDULED_EVENT_CREATE" guildRoleDeleteEventType = "GUILD_ROLE_DELETE"
guildScheduledEventDeleteEventType = "GUILD_SCHEDULED_EVENT_DELETE" guildRoleUpdateEventType = "GUILD_ROLE_UPDATE"
guildScheduledEventUpdateEventType = "GUILD_SCHEDULED_EVENT_UPDATE" guildScheduledEventCreateEventType = "GUILD_SCHEDULED_EVENT_CREATE"
guildScheduledEventUserAddEventType = "GUILD_SCHEDULED_EVENT_USER_ADD" guildScheduledEventDeleteEventType = "GUILD_SCHEDULED_EVENT_DELETE"
guildScheduledEventUserRemoveEventType = "GUILD_SCHEDULED_EVENT_USER_REMOVE" guildScheduledEventUpdateEventType = "GUILD_SCHEDULED_EVENT_UPDATE"
guildUpdateEventType = "GUILD_UPDATE" guildScheduledEventUserAddEventType = "GUILD_SCHEDULED_EVENT_USER_ADD"
interactionCreateEventType = "INTERACTION_CREATE" guildScheduledEventUserRemoveEventType = "GUILD_SCHEDULED_EVENT_USER_REMOVE"
inviteCreateEventType = "INVITE_CREATE" guildUpdateEventType = "GUILD_UPDATE"
inviteDeleteEventType = "INVITE_DELETE" interactionCreateEventType = "INTERACTION_CREATE"
messageAckEventType = "MESSAGE_ACK" inviteCreateEventType = "INVITE_CREATE"
messageCreateEventType = "MESSAGE_CREATE" inviteDeleteEventType = "INVITE_DELETE"
messageDeleteEventType = "MESSAGE_DELETE" messageCreateEventType = "MESSAGE_CREATE"
messageDeleteBulkEventType = "MESSAGE_DELETE_BULK" messageDeleteEventType = "MESSAGE_DELETE"
messageReactionAddEventType = "MESSAGE_REACTION_ADD" messageDeleteBulkEventType = "MESSAGE_DELETE_BULK"
messageReactionRemoveEventType = "MESSAGE_REACTION_REMOVE" messageReactionAddEventType = "MESSAGE_REACTION_ADD"
messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL" messageReactionRemoveEventType = "MESSAGE_REACTION_REMOVE"
messageUpdateEventType = "MESSAGE_UPDATE" messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL"
presenceUpdateEventType = "PRESENCE_UPDATE" messageUpdateEventType = "MESSAGE_UPDATE"
presencesReplaceEventType = "PRESENCES_REPLACE" presenceUpdateEventType = "PRESENCE_UPDATE"
rateLimitEventType = "__RATE_LIMIT__" presencesReplaceEventType = "PRESENCES_REPLACE"
readyEventType = "READY" rateLimitEventType = "__RATE_LIMIT__"
relationshipAddEventType = "RELATIONSHIP_ADD" readyEventType = "READY"
relationshipRemoveEventType = "RELATIONSHIP_REMOVE" resumedEventType = "RESUMED"
resumedEventType = "RESUMED" stageInstanceEventCreateEventType = "STAGE_INSTANCE_EVENT_CREATE"
threadCreateEventType = "THREAD_CREATE" stageInstanceEventDeleteEventType = "STAGE_INSTANCE_EVENT_DELETE"
threadDeleteEventType = "THREAD_DELETE" stageInstanceEventUpdateEventType = "STAGE_INSTANCE_EVENT_UPDATE"
threadListSyncEventType = "THREAD_LIST_SYNC" threadCreateEventType = "THREAD_CREATE"
threadMemberUpdateEventType = "THREAD_MEMBER_UPDATE" threadDeleteEventType = "THREAD_DELETE"
threadMembersUpdateEventType = "THREAD_MEMBERS_UPDATE" threadListSyncEventType = "THREAD_LIST_SYNC"
threadUpdateEventType = "THREAD_UPDATE" threadMemberUpdateEventType = "THREAD_MEMBER_UPDATE"
typingStartEventType = "TYPING_START" threadMembersUpdateEventType = "THREAD_MEMBERS_UPDATE"
userGuildSettingsUpdateEventType = "USER_GUILD_SETTINGS_UPDATE" threadUpdateEventType = "THREAD_UPDATE"
userNoteUpdateEventType = "USER_NOTE_UPDATE" typingStartEventType = "TYPING_START"
userSettingsUpdateEventType = "USER_SETTINGS_UPDATE" userUpdateEventType = "USER_UPDATE"
userUpdateEventType = "USER_UPDATE" voiceServerUpdateEventType = "VOICE_SERVER_UPDATE"
voiceServerUpdateEventType = "VOICE_SERVER_UPDATE" voiceStateUpdateEventType = "VOICE_STATE_UPDATE"
voiceStateUpdateEventType = "VOICE_STATE_UPDATE" webhooksUpdateEventType = "WEBHOOKS_UPDATE"
webhooksUpdateEventType = "WEBHOOKS_UPDATE"
) )
// applicationCommandPermissionsUpdateEventHandler is an event handler for ApplicationCommandPermissionsUpdate events.
type applicationCommandPermissionsUpdateEventHandler func(*Session, *ApplicationCommandPermissionsUpdate)
// Type returns the event type for ApplicationCommandPermissionsUpdate events.
func (eh applicationCommandPermissionsUpdateEventHandler) Type() string {
return applicationCommandPermissionsUpdateEventType
}
// New returns a new instance of ApplicationCommandPermissionsUpdate.
func (eh applicationCommandPermissionsUpdateEventHandler) New() interface{} {
return &ApplicationCommandPermissionsUpdate{}
}
// Handle is the handler for ApplicationCommandPermissionsUpdate events.
func (eh applicationCommandPermissionsUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*ApplicationCommandPermissionsUpdate); ok {
eh(s, t)
}
}
// autoModerationActionExecutionEventHandler is an event handler for AutoModerationActionExecution events.
type autoModerationActionExecutionEventHandler func(*Session, *AutoModerationActionExecution)
// Type returns the event type for AutoModerationActionExecution events.
func (eh autoModerationActionExecutionEventHandler) Type() string {
return autoModerationActionExecutionEventType
}
// New returns a new instance of AutoModerationActionExecution.
func (eh autoModerationActionExecutionEventHandler) New() interface{} {
return &AutoModerationActionExecution{}
}
// Handle is the handler for AutoModerationActionExecution events.
func (eh autoModerationActionExecutionEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*AutoModerationActionExecution); ok {
eh(s, t)
}
}
// autoModerationRuleCreateEventHandler is an event handler for AutoModerationRuleCreate events.
type autoModerationRuleCreateEventHandler func(*Session, *AutoModerationRuleCreate)
// Type returns the event type for AutoModerationRuleCreate events.
func (eh autoModerationRuleCreateEventHandler) Type() string {
return autoModerationRuleCreateEventType
}
// New returns a new instance of AutoModerationRuleCreate.
func (eh autoModerationRuleCreateEventHandler) New() interface{} {
return &AutoModerationRuleCreate{}
}
// Handle is the handler for AutoModerationRuleCreate events.
func (eh autoModerationRuleCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*AutoModerationRuleCreate); ok {
eh(s, t)
}
}
// autoModerationRuleDeleteEventHandler is an event handler for AutoModerationRuleDelete events.
type autoModerationRuleDeleteEventHandler func(*Session, *AutoModerationRuleDelete)
// Type returns the event type for AutoModerationRuleDelete events.
func (eh autoModerationRuleDeleteEventHandler) Type() string {
return autoModerationRuleDeleteEventType
}
// New returns a new instance of AutoModerationRuleDelete.
func (eh autoModerationRuleDeleteEventHandler) New() interface{} {
return &AutoModerationRuleDelete{}
}
// Handle is the handler for AutoModerationRuleDelete events.
func (eh autoModerationRuleDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*AutoModerationRuleDelete); ok {
eh(s, t)
}
}
// autoModerationRuleUpdateEventHandler is an event handler for AutoModerationRuleUpdate events.
type autoModerationRuleUpdateEventHandler func(*Session, *AutoModerationRuleUpdate)
// Type returns the event type for AutoModerationRuleUpdate events.
func (eh autoModerationRuleUpdateEventHandler) Type() string {
return autoModerationRuleUpdateEventType
}
// New returns a new instance of AutoModerationRuleUpdate.
func (eh autoModerationRuleUpdateEventHandler) New() interface{} {
return &AutoModerationRuleUpdate{}
}
// Handle is the handler for AutoModerationRuleUpdate events.
func (eh autoModerationRuleUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*AutoModerationRuleUpdate); ok {
eh(s, t)
}
}
// channelCreateEventHandler is an event handler for ChannelCreate events. // channelCreateEventHandler is an event handler for ChannelCreate events.
type channelCreateEventHandler func(*Session, *ChannelCreate) type channelCreateEventHandler func(*Session, *ChannelCreate)
@ -455,66 +554,6 @@ func (eh guildRoleUpdateEventHandler) Handle(s *Session, i interface{}) {
} }
} }
// guildStageInstanceEventCreateHandler is an event handler for StageInstanceEventCreate events.
type guildStageInstanceEventCreateHandler func(*Session, *StageInstanceEventCreate)
// Type returns the event type for StageInstanceEventCreate events.
func (eh guildStageInstanceEventCreateHandler) Type() string {
return guildStageInstanceCreateEventType
}
// New returns a new instance of StageInstanceEventCreate.
func (eh guildStageInstanceEventCreateHandler) New() interface{} {
return &StageInstanceEventCreate{}
}
// Handle is the handler for StageInstanceEventCreate events.
func (eh guildStageInstanceEventCreateHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*StageInstanceEventCreate); ok {
eh(s, t)
}
}
// guildStageInstanceEventUpdateHandler is an event handler for StageInstanceEventUpdate events.
type guildStageInstanceEventUpdateHandler func(*Session, *StageInstanceEventUpdate)
// Type returns the event type for StageInstanceEventUpdate events.
func (eh guildStageInstanceEventUpdateHandler) Type() string {
return guildStageInstanceCreateEventType
}
// New returns a new instance of StageInstanceEventUpdate.
func (eh guildStageInstanceEventUpdateHandler) New() interface{} {
return &StageInstanceEventUpdate{}
}
// Handle is the handler for StageInstanceEventUpdate events.
func (eh guildStageInstanceEventUpdateHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*StageInstanceEventUpdate); ok {
eh(s, t)
}
}
// guildStageInstanceEventDeleteHandler is an event handler for StageInstanceEventDelete events.
type guildStageInstanceEventDeleteHandler func(*Session, *StageInstanceEventDelete)
// Type returns the event type for StageInstanceEventDelete events.
func (eh guildStageInstanceEventDeleteHandler) Type() string {
return guildStageInstanceCreateEventType
}
// New returns a new instance of StageInstanceEventDelete.
func (eh guildStageInstanceEventDeleteHandler) New() interface{} {
return &StageInstanceEventDelete{}
}
// Handle is the handler for StageInstanceEventDelete events.
func (eh guildStageInstanceEventDeleteHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*StageInstanceEventDelete); ok {
eh(s, t)
}
}
// guildScheduledEventCreateEventHandler is an event handler for GuildScheduledEventCreate events. // guildScheduledEventCreateEventHandler is an event handler for GuildScheduledEventCreate events.
type guildScheduledEventCreateEventHandler func(*Session, *GuildScheduledEventCreate) type guildScheduledEventCreateEventHandler func(*Session, *GuildScheduledEventCreate)
@ -695,26 +734,6 @@ func (eh inviteDeleteEventHandler) Handle(s *Session, i interface{}) {
} }
} }
// messageAckEventHandler is an event handler for MessageAck events.
type messageAckEventHandler func(*Session, *MessageAck)
// Type returns the event type for MessageAck events.
func (eh messageAckEventHandler) Type() string {
return messageAckEventType
}
// New returns a new instance of MessageAck.
func (eh messageAckEventHandler) New() interface{} {
return &MessageAck{}
}
// Handle is the handler for MessageAck events.
func (eh messageAckEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*MessageAck); ok {
eh(s, t)
}
}
// messageCreateEventHandler is an event handler for MessageCreate events. // messageCreateEventHandler is an event handler for MessageCreate events.
type messageCreateEventHandler func(*Session, *MessageCreate) type messageCreateEventHandler func(*Session, *MessageCreate)
@ -930,46 +949,6 @@ func (eh readyEventHandler) Handle(s *Session, i interface{}) {
} }
} }
// relationshipAddEventHandler is an event handler for RelationshipAdd events.
type relationshipAddEventHandler func(*Session, *RelationshipAdd)
// Type returns the event type for RelationshipAdd events.
func (eh relationshipAddEventHandler) Type() string {
return relationshipAddEventType
}
// New returns a new instance of RelationshipAdd.
func (eh relationshipAddEventHandler) New() interface{} {
return &RelationshipAdd{}
}
// Handle is the handler for RelationshipAdd events.
func (eh relationshipAddEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*RelationshipAdd); ok {
eh(s, t)
}
}
// relationshipRemoveEventHandler is an event handler for RelationshipRemove events.
type relationshipRemoveEventHandler func(*Session, *RelationshipRemove)
// Type returns the event type for RelationshipRemove events.
func (eh relationshipRemoveEventHandler) Type() string {
return relationshipRemoveEventType
}
// New returns a new instance of RelationshipRemove.
func (eh relationshipRemoveEventHandler) New() interface{} {
return &RelationshipRemove{}
}
// Handle is the handler for RelationshipRemove events.
func (eh relationshipRemoveEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*RelationshipRemove); ok {
eh(s, t)
}
}
// resumedEventHandler is an event handler for Resumed events. // resumedEventHandler is an event handler for Resumed events.
type resumedEventHandler func(*Session, *Resumed) type resumedEventHandler func(*Session, *Resumed)
@ -990,6 +969,66 @@ func (eh resumedEventHandler) Handle(s *Session, i interface{}) {
} }
} }
// stageInstanceEventCreateEventHandler is an event handler for StageInstanceEventCreate events.
type stageInstanceEventCreateEventHandler func(*Session, *StageInstanceEventCreate)
// Type returns the event type for StageInstanceEventCreate events.
func (eh stageInstanceEventCreateEventHandler) Type() string {
return stageInstanceEventCreateEventType
}
// New returns a new instance of StageInstanceEventCreate.
func (eh stageInstanceEventCreateEventHandler) New() interface{} {
return &StageInstanceEventCreate{}
}
// Handle is the handler for StageInstanceEventCreate events.
func (eh stageInstanceEventCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*StageInstanceEventCreate); ok {
eh(s, t)
}
}
// stageInstanceEventDeleteEventHandler is an event handler for StageInstanceEventDelete events.
type stageInstanceEventDeleteEventHandler func(*Session, *StageInstanceEventDelete)
// Type returns the event type for StageInstanceEventDelete events.
func (eh stageInstanceEventDeleteEventHandler) Type() string {
return stageInstanceEventDeleteEventType
}
// New returns a new instance of StageInstanceEventDelete.
func (eh stageInstanceEventDeleteEventHandler) New() interface{} {
return &StageInstanceEventDelete{}
}
// Handle is the handler for StageInstanceEventDelete events.
func (eh stageInstanceEventDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*StageInstanceEventDelete); ok {
eh(s, t)
}
}
// stageInstanceEventUpdateEventHandler is an event handler for StageInstanceEventUpdate events.
type stageInstanceEventUpdateEventHandler func(*Session, *StageInstanceEventUpdate)
// Type returns the event type for StageInstanceEventUpdate events.
func (eh stageInstanceEventUpdateEventHandler) Type() string {
return stageInstanceEventUpdateEventType
}
// New returns a new instance of StageInstanceEventUpdate.
func (eh stageInstanceEventUpdateEventHandler) New() interface{} {
return &StageInstanceEventUpdate{}
}
// Handle is the handler for StageInstanceEventUpdate events.
func (eh stageInstanceEventUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*StageInstanceEventUpdate); ok {
eh(s, t)
}
}
// threadCreateEventHandler is an event handler for ThreadCreate events. // threadCreateEventHandler is an event handler for ThreadCreate events.
type threadCreateEventHandler func(*Session, *ThreadCreate) type threadCreateEventHandler func(*Session, *ThreadCreate)
@ -1130,66 +1169,6 @@ func (eh typingStartEventHandler) Handle(s *Session, i interface{}) {
} }
} }
// userGuildSettingsUpdateEventHandler is an event handler for UserGuildSettingsUpdate events.
type userGuildSettingsUpdateEventHandler func(*Session, *UserGuildSettingsUpdate)
// Type returns the event type for UserGuildSettingsUpdate events.
func (eh userGuildSettingsUpdateEventHandler) Type() string {
return userGuildSettingsUpdateEventType
}
// New returns a new instance of UserGuildSettingsUpdate.
func (eh userGuildSettingsUpdateEventHandler) New() interface{} {
return &UserGuildSettingsUpdate{}
}
// Handle is the handler for UserGuildSettingsUpdate events.
func (eh userGuildSettingsUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*UserGuildSettingsUpdate); ok {
eh(s, t)
}
}
// userNoteUpdateEventHandler is an event handler for UserNoteUpdate events.
type userNoteUpdateEventHandler func(*Session, *UserNoteUpdate)
// Type returns the event type for UserNoteUpdate events.
func (eh userNoteUpdateEventHandler) Type() string {
return userNoteUpdateEventType
}
// New returns a new instance of UserNoteUpdate.
func (eh userNoteUpdateEventHandler) New() interface{} {
return &UserNoteUpdate{}
}
// Handle is the handler for UserNoteUpdate events.
func (eh userNoteUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*UserNoteUpdate); ok {
eh(s, t)
}
}
// userSettingsUpdateEventHandler is an event handler for UserSettingsUpdate events.
type userSettingsUpdateEventHandler func(*Session, *UserSettingsUpdate)
// Type returns the event type for UserSettingsUpdate events.
func (eh userSettingsUpdateEventHandler) Type() string {
return userSettingsUpdateEventType
}
// New returns a new instance of UserSettingsUpdate.
func (eh userSettingsUpdateEventHandler) New() interface{} {
return &UserSettingsUpdate{}
}
// Handle is the handler for UserSettingsUpdate events.
func (eh userSettingsUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*UserSettingsUpdate); ok {
eh(s, t)
}
}
// userUpdateEventHandler is an event handler for UserUpdate events. // userUpdateEventHandler is an event handler for UserUpdate events.
type userUpdateEventHandler func(*Session, *UserUpdate) type userUpdateEventHandler func(*Session, *UserUpdate)
@ -1274,6 +1253,16 @@ func handlerForInterface(handler interface{}) EventHandler {
switch v := handler.(type) { switch v := handler.(type) {
case func(*Session, interface{}): case func(*Session, interface{}):
return interfaceEventHandler(v) return interfaceEventHandler(v)
case func(*Session, *ApplicationCommandPermissionsUpdate):
return applicationCommandPermissionsUpdateEventHandler(v)
case func(*Session, *AutoModerationActionExecution):
return autoModerationActionExecutionEventHandler(v)
case func(*Session, *AutoModerationRuleCreate):
return autoModerationRuleCreateEventHandler(v)
case func(*Session, *AutoModerationRuleDelete):
return autoModerationRuleDeleteEventHandler(v)
case func(*Session, *AutoModerationRuleUpdate):
return autoModerationRuleUpdateEventHandler(v)
case func(*Session, *ChannelCreate): case func(*Session, *ChannelCreate):
return channelCreateEventHandler(v) return channelCreateEventHandler(v)
case func(*Session, *ChannelDelete): case func(*Session, *ChannelDelete):
@ -1332,8 +1321,6 @@ func handlerForInterface(handler interface{}) EventHandler {
return inviteCreateEventHandler(v) return inviteCreateEventHandler(v)
case func(*Session, *InviteDelete): case func(*Session, *InviteDelete):
return inviteDeleteEventHandler(v) return inviteDeleteEventHandler(v)
case func(*Session, *MessageAck):
return messageAckEventHandler(v)
case func(*Session, *MessageCreate): case func(*Session, *MessageCreate):
return messageCreateEventHandler(v) return messageCreateEventHandler(v)
case func(*Session, *MessageDelete): case func(*Session, *MessageDelete):
@ -1356,12 +1343,14 @@ func handlerForInterface(handler interface{}) EventHandler {
return rateLimitEventHandler(v) return rateLimitEventHandler(v)
case func(*Session, *Ready): case func(*Session, *Ready):
return readyEventHandler(v) return readyEventHandler(v)
case func(*Session, *RelationshipAdd):
return relationshipAddEventHandler(v)
case func(*Session, *RelationshipRemove):
return relationshipRemoveEventHandler(v)
case func(*Session, *Resumed): case func(*Session, *Resumed):
return resumedEventHandler(v) return resumedEventHandler(v)
case func(*Session, *StageInstanceEventCreate):
return stageInstanceEventCreateEventHandler(v)
case func(*Session, *StageInstanceEventDelete):
return stageInstanceEventDeleteEventHandler(v)
case func(*Session, *StageInstanceEventUpdate):
return stageInstanceEventUpdateEventHandler(v)
case func(*Session, *ThreadCreate): case func(*Session, *ThreadCreate):
return threadCreateEventHandler(v) return threadCreateEventHandler(v)
case func(*Session, *ThreadDelete): case func(*Session, *ThreadDelete):
@ -1376,12 +1365,6 @@ func handlerForInterface(handler interface{}) EventHandler {
return threadUpdateEventHandler(v) return threadUpdateEventHandler(v)
case func(*Session, *TypingStart): case func(*Session, *TypingStart):
return typingStartEventHandler(v) return typingStartEventHandler(v)
case func(*Session, *UserGuildSettingsUpdate):
return userGuildSettingsUpdateEventHandler(v)
case func(*Session, *UserNoteUpdate):
return userNoteUpdateEventHandler(v)
case func(*Session, *UserSettingsUpdate):
return userSettingsUpdateEventHandler(v)
case func(*Session, *UserUpdate): case func(*Session, *UserUpdate):
return userUpdateEventHandler(v) return userUpdateEventHandler(v)
case func(*Session, *VoiceServerUpdate): case func(*Session, *VoiceServerUpdate):
@ -1396,6 +1379,11 @@ func handlerForInterface(handler interface{}) EventHandler {
} }
func init() { func init() {
registerInterfaceProvider(applicationCommandPermissionsUpdateEventHandler(nil))
registerInterfaceProvider(autoModerationActionExecutionEventHandler(nil))
registerInterfaceProvider(autoModerationRuleCreateEventHandler(nil))
registerInterfaceProvider(autoModerationRuleDeleteEventHandler(nil))
registerInterfaceProvider(autoModerationRuleUpdateEventHandler(nil))
registerInterfaceProvider(channelCreateEventHandler(nil)) registerInterfaceProvider(channelCreateEventHandler(nil))
registerInterfaceProvider(channelDeleteEventHandler(nil)) registerInterfaceProvider(channelDeleteEventHandler(nil))
registerInterfaceProvider(channelPinsUpdateEventHandler(nil)) registerInterfaceProvider(channelPinsUpdateEventHandler(nil))
@ -1422,7 +1410,6 @@ func init() {
registerInterfaceProvider(interactionCreateEventHandler(nil)) registerInterfaceProvider(interactionCreateEventHandler(nil))
registerInterfaceProvider(inviteCreateEventHandler(nil)) registerInterfaceProvider(inviteCreateEventHandler(nil))
registerInterfaceProvider(inviteDeleteEventHandler(nil)) registerInterfaceProvider(inviteDeleteEventHandler(nil))
registerInterfaceProvider(messageAckEventHandler(nil))
registerInterfaceProvider(messageCreateEventHandler(nil)) registerInterfaceProvider(messageCreateEventHandler(nil))
registerInterfaceProvider(messageDeleteEventHandler(nil)) registerInterfaceProvider(messageDeleteEventHandler(nil))
registerInterfaceProvider(messageDeleteBulkEventHandler(nil)) registerInterfaceProvider(messageDeleteBulkEventHandler(nil))
@ -1433,9 +1420,10 @@ func init() {
registerInterfaceProvider(presenceUpdateEventHandler(nil)) registerInterfaceProvider(presenceUpdateEventHandler(nil))
registerInterfaceProvider(presencesReplaceEventHandler(nil)) registerInterfaceProvider(presencesReplaceEventHandler(nil))
registerInterfaceProvider(readyEventHandler(nil)) registerInterfaceProvider(readyEventHandler(nil))
registerInterfaceProvider(relationshipAddEventHandler(nil))
registerInterfaceProvider(relationshipRemoveEventHandler(nil))
registerInterfaceProvider(resumedEventHandler(nil)) registerInterfaceProvider(resumedEventHandler(nil))
registerInterfaceProvider(stageInstanceEventCreateEventHandler(nil))
registerInterfaceProvider(stageInstanceEventDeleteEventHandler(nil))
registerInterfaceProvider(stageInstanceEventUpdateEventHandler(nil))
registerInterfaceProvider(threadCreateEventHandler(nil)) registerInterfaceProvider(threadCreateEventHandler(nil))
registerInterfaceProvider(threadDeleteEventHandler(nil)) registerInterfaceProvider(threadDeleteEventHandler(nil))
registerInterfaceProvider(threadListSyncEventHandler(nil)) registerInterfaceProvider(threadListSyncEventHandler(nil))
@ -1443,9 +1431,6 @@ func init() {
registerInterfaceProvider(threadMembersUpdateEventHandler(nil)) registerInterfaceProvider(threadMembersUpdateEventHandler(nil))
registerInterfaceProvider(threadUpdateEventHandler(nil)) registerInterfaceProvider(threadUpdateEventHandler(nil))
registerInterfaceProvider(typingStartEventHandler(nil)) registerInterfaceProvider(typingStartEventHandler(nil))
registerInterfaceProvider(userGuildSettingsUpdateEventHandler(nil))
registerInterfaceProvider(userNoteUpdateEventHandler(nil))
registerInterfaceProvider(userSettingsUpdateEventHandler(nil))
registerInterfaceProvider(userUpdateEventHandler(nil)) registerInterfaceProvider(userUpdateEventHandler(nil))
registerInterfaceProvider(voiceServerUpdateEventHandler(nil)) registerInterfaceProvider(voiceServerUpdateEventHandler(nil))
registerInterfaceProvider(voiceStateUpdateEventHandler(nil)) registerInterfaceProvider(voiceStateUpdateEventHandler(nil))

View File

@ -36,19 +36,13 @@ type Event struct {
// A Ready stores all data for the websocket READY event. // A Ready stores all data for the websocket READY event.
type Ready struct { type Ready struct {
Version int `json:"v"` Version int `json:"v"`
SessionID string `json:"session_id"` SessionID string `json:"session_id"`
User *User `json:"user"` User *User `json:"user"`
ReadState []*ReadState `json:"read_state"` Guilds []*Guild `json:"guilds"`
PrivateChannels []*Channel `json:"private_channels"` PrivateChannels []*Channel `json:"private_channels"`
Guilds []*Guild `json:"guilds"`
// Undocumented fields // TODO: Application and Shard
Settings *Settings `json:"user_settings"`
UserGuildSettings []*UserGuildSettings `json:"user_guild_settings"`
Relationships []*Relationship `json:"relationships"`
Presences []*Presence `json:"presences"`
Notes map[string]string `json:"notes"`
} }
// ChannelCreate is the data for a ChannelCreate event. // ChannelCreate is the data for a ChannelCreate event.
@ -245,12 +239,6 @@ type GuildScheduledEventUserRemove struct {
GuildID string `json:"guild_id"` GuildID string `json:"guild_id"`
} }
// MessageAck is the data for a MessageAck event.
type MessageAck struct {
MessageID string `json:"message_id"`
ChannelID string `json:"channel_id"`
}
// MessageCreate is the data for a MessageCreate event. // MessageCreate is the data for a MessageCreate event.
type MessageCreate struct { type MessageCreate struct {
*Message *Message
@ -314,16 +302,6 @@ type Resumed struct {
Trace []string `json:"_trace"` Trace []string `json:"_trace"`
} }
// RelationshipAdd is the data for a RelationshipAdd event.
type RelationshipAdd struct {
*Relationship
}
// RelationshipRemove is the data for a RelationshipRemove event.
type RelationshipRemove struct {
*Relationship
}
// TypingStart is the data for a TypingStart event. // TypingStart is the data for a TypingStart event.
type TypingStart struct { type TypingStart struct {
UserID string `json:"user_id"` UserID string `json:"user_id"`
@ -337,20 +315,6 @@ type UserUpdate struct {
*User *User
} }
// UserSettingsUpdate is the data for a UserSettingsUpdate event.
type UserSettingsUpdate map[string]interface{}
// UserGuildSettingsUpdate is the data for a UserGuildSettingsUpdate event.
type UserGuildSettingsUpdate struct {
*UserGuildSettings
}
// UserNoteUpdate is the data for a UserNoteUpdate event.
type UserNoteUpdate struct {
ID string `json:"id"`
Note string `json:"note"`
}
// VoiceServerUpdate is the data for a VoiceServerUpdate event. // VoiceServerUpdate is the data for a VoiceServerUpdate event.
type VoiceServerUpdate struct { type VoiceServerUpdate struct {
Token string `json:"token"` Token string `json:"token"`
@ -401,3 +365,38 @@ type InviteDelete struct {
GuildID string `json:"guild_id"` GuildID string `json:"guild_id"`
Code string `json:"code"` Code string `json:"code"`
} }
// ApplicationCommandPermissionsUpdate is the data for an ApplicationCommandPermissionsUpdate event
type ApplicationCommandPermissionsUpdate struct {
*GuildApplicationCommandPermissions
}
// AutoModerationRuleCreate is the data for an AutoModerationRuleCreate event.
type AutoModerationRuleCreate struct {
*AutoModerationRule
}
// AutoModerationRuleUpdate is the data for an AutoModerationRuleUpdate event.
type AutoModerationRuleUpdate struct {
*AutoModerationRule
}
// AutoModerationRuleDelete is the data for an AutoModerationRuleDelete event.
type AutoModerationRuleDelete struct {
*AutoModerationRule
}
// AutoModerationActionExecution is the data for an AutoModerationActionExecution event.
type AutoModerationActionExecution struct {
GuildID string `json:"guild_id"`
Action AutoModerationAction `json:"action"`
RuleID string `json:"rule_id"`
RuleTriggerType AutoModerationRuleTriggerType `json:"rule_trigger_type"`
UserID string `json:"user_id"`
ChannelID string `json:"channel_id"`
MessageID string `json:"message_id"`
AlertSystemMessageID string `json:"alert_system_message_id"`
Content string `json:"content"`
MatchedKeyword string `json:"matched_keyword"`
MatchedContent string `json:"matched_content"`
}

View File

@ -9,6 +9,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strconv"
"time" "time"
) )
@ -32,11 +33,15 @@ const (
type ApplicationCommand struct { type ApplicationCommand struct {
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
ApplicationID string `json:"application_id,omitempty"` ApplicationID string `json:"application_id,omitempty"`
GuildID string `json:"guild_id,omitempty"`
Version string `json:"version,omitempty"` Version string `json:"version,omitempty"`
Type ApplicationCommandType `json:"type,omitempty"` Type ApplicationCommandType `json:"type,omitempty"`
Name string `json:"name"` Name string `json:"name"`
NameLocalizations *map[Locale]string `json:"name_localizations,omitempty"` NameLocalizations *map[Locale]string `json:"name_localizations,omitempty"`
DefaultPermission *bool `json:"default_permission,omitempty"` // NOTE: DefaultPermission will be soon deprecated. Use DefaultMemberPermissions and DMPermission instead.
DefaultPermission *bool `json:"default_permission,omitempty"`
DefaultMemberPermissions *int64 `json:"default_member_permissions,string,omitempty"`
DMPermission *bool `json:"dm_permission,omitempty"`
// NOTE: Chat commands only. Otherwise it mustn't be set. // NOTE: Chat commands only. Otherwise it mustn't be set.
@ -113,6 +118,10 @@ type ApplicationCommandOption struct {
MinValue *float64 `json:"min_value,omitempty"` MinValue *float64 `json:"min_value,omitempty"`
// Maximum value of number/integer option. // Maximum value of number/integer option.
MaxValue float64 `json:"max_value,omitempty"` MaxValue float64 `json:"max_value,omitempty"`
// Minimum length of string option.
MinLength *int `json:"min_length,omitempty"`
// Maximum length of string option.
MaxLength int `json:"max_length,omitempty"`
} }
// ApplicationCommandOptionChoice represents a slash command option choice. // ApplicationCommandOptionChoice represents a slash command option choice.
@ -129,6 +138,18 @@ type ApplicationCommandPermissions struct {
Permission bool `json:"permission"` Permission bool `json:"permission"`
} }
// GuildAllChannelsID is a helper function which returns guild_id-1.
// It is used in ApplicationCommandPermissions to target all the channels within a guild.
func GuildAllChannelsID(guild string) (id string, err error) {
var v uint64
v, err = strconv.ParseUint(guild, 10, 64)
if err != nil {
return
}
return strconv.FormatUint(v-1, 10), nil
}
// ApplicationCommandPermissionsList represents a list of ApplicationCommandPermissions, needed for serializing to JSON. // ApplicationCommandPermissionsList represents a list of ApplicationCommandPermissions, needed for serializing to JSON.
type ApplicationCommandPermissionsList struct { type ApplicationCommandPermissionsList struct {
Permissions []*ApplicationCommandPermissions `json:"permissions"` Permissions []*ApplicationCommandPermissions `json:"permissions"`
@ -147,8 +168,9 @@ type ApplicationCommandPermissionType uint8
// Application command permission types. // Application command permission types.
const ( const (
ApplicationCommandPermissionTypeRole ApplicationCommandPermissionType = 1 ApplicationCommandPermissionTypeRole ApplicationCommandPermissionType = 1
ApplicationCommandPermissionTypeUser ApplicationCommandPermissionType = 2 ApplicationCommandPermissionTypeUser ApplicationCommandPermissionType = 2
ApplicationCommandPermissionTypeChannel ApplicationCommandPermissionType = 3
) )
// InteractionType indicates the type of an interaction event. // InteractionType indicates the type of an interaction event.
@ -190,6 +212,9 @@ type Interaction struct {
// NOTE: this field is only filled when a button click triggered the interaction. Otherwise it will be nil. // NOTE: this field is only filled when a button click triggered the interaction. Otherwise it will be nil.
Message *Message `json:"message"` Message *Message `json:"message"`
// Bitwise set of permissions the app or bot has within the channel the interaction was sent from
AppPermissions int64 `json:"app_permissions,string"`
// The member who invoked this interaction. // The member who invoked this interaction.
// NOTE: this field is only filled when the slash command was invoked in a guild; // NOTE: this field is only filled when the slash command was invoked in a guild;
// if it was invoked in a DM, the `User` field will be filled instead. // if it was invoked in a DM, the `User` field will be filled instead.
@ -517,9 +542,11 @@ type InteractionResponseData struct {
Components []MessageComponent `json:"components"` Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds"` Embeds []*MessageEmbed `json:"embeds"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"` AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
Flags uint64 `json:"flags,omitempty"`
Files []*File `json:"-"` Files []*File `json:"-"`
// NOTE: only MessageFlagsSuppressEmbeds and MessageFlagsEphemeral can be set.
Flags MessageFlags `json:"flags,omitempty"`
// NOTE: autocomplete interaction only. // NOTE: autocomplete interaction only.
Choices []*ApplicationCommandOptionChoice `json:"choices,omitempty"` Choices []*ApplicationCommandOptionChoice `json:"choices,omitempty"`

View File

@ -90,7 +90,7 @@ func (v *VoiceConnection) log(msgL int, format string, a ...interface{}) {
msglog(msgL, 2, format, a...) msglog(msgL, 2, format, a...)
} }
// printJSON is a helper function to display JSON data in a easy to read format. // printJSON is a helper function to display JSON data in an easy to read format.
/* NOT USED ATM /* NOT USED ATM
func printJSON(body []byte) { func printJSON(body []byte) {
var prettyJSON bytes.Buffer var prettyJSON bytes.Buffer

View File

@ -321,6 +321,9 @@ type MessageAllowedMentions struct {
// A list of user IDs to allow. This cannot be used when specifying // A list of user IDs to allow. This cannot be used when specifying
// AllowedMentionTypeUsers in the Parse slice. // AllowedMentionTypeUsers in the Parse slice.
Users []string `json:"users,omitempty"` Users []string `json:"users,omitempty"`
// For replies, whether to mention the author of the message being replied to
RepliedUser bool `json:"replied_user"`
} }
// A MessageAttachment stores data for message attachments. // A MessageAttachment stores data for message attachments.
@ -454,7 +457,7 @@ type MessageApplication struct {
// MessageReference contains reference data sent with crossposted messages // MessageReference contains reference data sent with crossposted messages
type MessageReference struct { type MessageReference struct {
MessageID string `json:"message_id"` MessageID string `json:"message_id"`
ChannelID string `json:"channel_id"` ChannelID string `json:"channel_id,omitempty"`
GuildID string `json:"guild_id,omitempty"` GuildID string `json:"guild_id,omitempty"`
} }

View File

@ -334,6 +334,18 @@ func (s *Session) UserChannelCreate(recipientID string) (st *Channel, err error)
return return
} }
// UserGuildMember returns a guild member object for the current user in the given Guild.
// guildID : ID of the guild
func (s *Session) UserGuildMember(guildID string) (st *Member, err error) {
body, err := s.RequestWithBucketID("GET", EndpointUserGuildMember("@me", guildID), nil, EndpointUserGuildMember("@me", guildID))
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// UserGuilds returns an array of UserGuild structures for all guilds. // UserGuilds returns an array of UserGuild structures for all guilds.
// limit : The number guilds that can be returned. (max 100) // limit : The number guilds that can be returned. (max 100)
// beforeID : If provided all guilds returned will be before given ID. // beforeID : If provided all guilds returned will be before given ID.
@ -541,7 +553,7 @@ func (s *Session) GuildCreate(name string) (st *Guild, err error) {
// GuildEdit edits a new Guild // GuildEdit edits a new Guild
// guildID : The ID of a Guild // guildID : The ID of a Guild
// g : A GuildParams struct with the values Name, Region and VerificationLevel defined. // g : A GuildParams struct with the values Name, Region and VerificationLevel defined.
func (s *Session) GuildEdit(guildID string, g GuildParams) (st *Guild, err error) { func (s *Session) GuildEdit(guildID string, g *GuildParams) (st *Guild, err error) {
// Bounds checking for VerificationLevel, interval: [0, 4] // Bounds checking for VerificationLevel, interval: [0, 4]
if g.VerificationLevel != nil { if g.VerificationLevel != nil {
@ -760,22 +772,10 @@ func (s *Session) GuildMember(guildID, userID string) (st *Member, err error) {
} }
// GuildMemberAdd force joins a user to the guild. // GuildMemberAdd force joins a user to the guild.
// accessToken : Valid access_token for the user.
// guildID : The ID of a Guild. // guildID : The ID of a Guild.
// userID : The ID of a User. // userID : The ID of a User.
// nick : Value to set users nickname to // data : Parameters of the user to add.
// roles : A list of role ID's to set on the member. func (s *Session) GuildMemberAdd(guildID, userID string, data *GuildMemberAddParams) (err error) {
// mute : If the user is muted.
// deaf : If the user is deafened.
func (s *Session) GuildMemberAdd(accessToken, guildID, userID, nick string, roles []string, mute, deaf bool) (err error) {
data := struct {
AccessToken string `json:"access_token"`
Nick string `json:"nick,omitempty"`
Roles []string `json:"roles,omitempty"`
Mute bool `json:"mute,omitempty"`
Deaf bool `json:"deaf,omitempty"`
}{accessToken, nick, roles, mute, deaf}
_, err = s.RequestWithBucketID("PUT", EndpointGuildMember(guildID, userID), data, EndpointGuildMember(guildID, "")) _, err = s.RequestWithBucketID("PUT", EndpointGuildMember(guildID, userID), data, EndpointGuildMember(guildID, ""))
if err != nil { if err != nil {
@ -808,25 +808,11 @@ func (s *Session) GuildMemberDeleteWithReason(guildID, userID, reason string) (e
return return
} }
// GuildMemberEdit edits the roles of a member. // GuildMemberEdit edits and returns updated member.
// guildID : The ID of a Guild. // guildID : The ID of a Guild.
// userID : The ID of a User. // userID : The ID of a User.
// roles : A list of role ID's to set on the member. // data : Updated GuildMember data.
func (s *Session) GuildMemberEdit(guildID, userID string, roles []string) (err error) { func (s *Session) GuildMemberEdit(guildID, userID string, data *GuildMemberParams) (st *Member, err error) {
data := struct {
Roles []string `json:"roles"`
}{roles}
_, err = s.RequestWithBucketID("PATCH", EndpointGuildMember(guildID, userID), data, EndpointGuildMember(guildID, ""))
return
}
// GuildMemberEditComplex edits the nickname and roles of a member.
// guildID : The ID of a Guild.
// userID : The ID of a User.
// data : A GuildMemberEditData struct with the new nickname and roles
func (s *Session) GuildMemberEditComplex(guildID, userID string, data GuildMemberParams) (st *Member, err error) {
var body []byte var body []byte
body, err = s.RequestWithBucketID("PATCH", EndpointGuildMember(guildID, userID), data, EndpointGuildMember(guildID, "")) body, err = s.RequestWithBucketID("PATCH", EndpointGuildMember(guildID, userID), data, EndpointGuildMember(guildID, ""))
if err != nil { if err != nil {
@ -837,6 +823,15 @@ func (s *Session) GuildMemberEditComplex(guildID, userID string, data GuildMembe
return return
} }
// GuildMemberEditComplex edits the nickname and roles of a member.
// NOTE: deprecated, use GuildMemberEdit instead.
// guildID : The ID of a Guild.
// userID : The ID of a User.
// data : A GuildMemberEditData struct with the new nickname and roles
func (s *Session) GuildMemberEditComplex(guildID, userID string, data *GuildMemberParams) (st *Member, err error) {
return s.GuildMemberEdit(guildID, userID, data)
}
// GuildMemberMove moves a guild member from one voice channel to another/none // GuildMemberMove moves a guild member from one voice channel to another/none
// guildID : The ID of a Guild. // guildID : The ID of a Guild.
// userID : The ID of a User. // userID : The ID of a User.
@ -1031,11 +1026,11 @@ func (s *Session) GuildRoles(guildID string) (st []*Role, err error) {
return // TODO return pointer return // TODO return pointer
} }
// GuildRoleCreate returns a new Guild Role. // GuildRoleCreate creates a new Guild Role and returns it.
// guildID: The ID of a Guild. // guildID : The ID of a Guild.
func (s *Session) GuildRoleCreate(guildID string) (st *Role, err error) { // data : New Role parameters.
func (s *Session) GuildRoleCreate(guildID string, data *RoleParams) (st *Role, err error) {
body, err := s.RequestWithBucketID("POST", EndpointGuildRoles(guildID), nil, EndpointGuildRoles(guildID)) body, err := s.RequestWithBucketID("POST", EndpointGuildRoles(guildID), data, EndpointGuildRoles(guildID))
if err != nil { if err != nil {
return return
} }
@ -1045,30 +1040,17 @@ func (s *Session) GuildRoleCreate(guildID string) (st *Role, err error) {
return return
} }
// GuildRoleEdit updates an existing Guild Role with new values // GuildRoleEdit updates an existing Guild Role and returns updated Role data.
// guildID : The ID of a Guild. // guildID : The ID of a Guild.
// roleID : The ID of a Role. // roleID : The ID of a Role.
// name : The name of the Role. // data : Updated Role data.
// color : The color of the role (decimal, not hex). func (s *Session) GuildRoleEdit(guildID, roleID string, data *RoleParams) (st *Role, err error) {
// hoist : Whether to display the role's users separately.
// perm : The permissions for the role.
// mention : Whether this role is mentionable
func (s *Session) GuildRoleEdit(guildID, roleID, name string, color int, hoist bool, perm int64, mention bool) (st *Role, err error) {
// Prevent sending a color int that is too big. // Prevent sending a color int that is too big.
if color > 0xFFFFFF { if data.Color != nil && *data.Color > 0xFFFFFF {
err = fmt.Errorf("color value cannot be larger than 0xFFFFFF") return nil, fmt.Errorf("color value cannot be larger than 0xFFFFFF")
return nil, err
} }
data := struct {
Name string `json:"name"` // The role's name (overwrites existing)
Color int `json:"color"` // The color the role should have (as a decimal, not hex)
Hoist bool `json:"hoist"` // Whether to display the role's users separately
Permissions int64 `json:"permissions,string"` // The overall permissions number of the role (overwrites existing)
Mentionable bool `json:"mentionable"` // Whether this role is mentionable
}{name, color, hoist, perm, mention}
body, err := s.RequestWithBucketID("PATCH", EndpointGuildRole(guildID, roleID), data, EndpointGuildRole(guildID, "")) body, err := s.RequestWithBucketID("PATCH", EndpointGuildRole(guildID, roleID), data, EndpointGuildRole(guildID, ""))
if err != nil { if err != nil {
return return
@ -1286,12 +1268,10 @@ func (s *Session) GuildEmbed(guildID string) (st *GuildEmbed, err error) {
return return
} }
// GuildEmbedEdit returns the embed for a Guild. // GuildEmbedEdit edits the embed of a Guild.
// guildID : The ID of a Guild. // guildID : The ID of a Guild.
func (s *Session) GuildEmbedEdit(guildID string, enabled bool, channelID string) (err error) { // data : New GuildEmbed data.
func (s *Session) GuildEmbedEdit(guildID string, data *GuildEmbed) (err error) {
data := GuildEmbed{enabled, channelID}
_, err = s.RequestWithBucketID("PATCH", EndpointGuildEmbed(guildID), data, EndpointGuildEmbed(guildID)) _, err = s.RequestWithBucketID("PATCH", EndpointGuildEmbed(guildID), data, EndpointGuildEmbed(guildID))
return return
} }
@ -1359,19 +1339,10 @@ func (s *Session) GuildEmoji(guildID, emojiID string) (emoji *Emoji, err error)
return return
} }
// GuildEmojiCreate creates a new emoji // GuildEmojiCreate creates a new Emoji.
// guildID : The ID of a Guild. // guildID : The ID of a Guild.
// name : The Name of the Emoji. // data : New Emoji data.
// image : The base64 encoded emoji image, has to be smaller than 256KB. func (s *Session) GuildEmojiCreate(guildID string, data *EmojiParams) (emoji *Emoji, err error) {
// roles : The roles for which this emoji will be whitelisted, can be nil.
func (s *Session) GuildEmojiCreate(guildID, name, image string, roles []string) (emoji *Emoji, err error) {
data := struct {
Name string `json:"name"`
Image string `json:"image"`
Roles []string `json:"roles,omitempty"`
}{name, image, roles}
body, err := s.RequestWithBucketID("POST", EndpointGuildEmojis(guildID), data, EndpointGuildEmojis(guildID)) body, err := s.RequestWithBucketID("POST", EndpointGuildEmojis(guildID), data, EndpointGuildEmojis(guildID))
if err != nil { if err != nil {
return return
@ -1381,18 +1352,11 @@ func (s *Session) GuildEmojiCreate(guildID, name, image string, roles []string)
return return
} }
// GuildEmojiEdit modifies an emoji // GuildEmojiEdit modifies and returns updated Emoji.
// guildID : The ID of a Guild. // guildID : The ID of a Guild.
// emojiID : The ID of an Emoji. // emojiID : The ID of an Emoji.
// name : The Name of the Emoji. // data : Updated Emoji data.
// roles : The roles for which this emoji will be whitelisted, if nil or empty the roles will be reset. func (s *Session) GuildEmojiEdit(guildID, emojiID string, data *EmojiParams) (emoji *Emoji, err error) {
func (s *Session) GuildEmojiEdit(guildID, emojiID, name string, roles []string) (emoji *Emoji, err error) {
data := struct {
Name string `json:"name"`
Roles []string `json:"roles"`
}{name, roles}
body, err := s.RequestWithBucketID("PATCH", EndpointGuildEmoji(guildID, emojiID), data, EndpointGuildEmojis(guildID)) body, err := s.RequestWithBucketID("PATCH", EndpointGuildEmoji(guildID, emojiID), data, EndpointGuildEmojis(guildID))
if err != nil { if err != nil {
return return
@ -1458,16 +1422,9 @@ func (s *Session) GuildTemplates(guildID string) (st []*GuildTemplate, err error
} }
// GuildTemplateCreate creates a template for the guild // GuildTemplateCreate creates a template for the guild
// guildID: The ID of the guild // guildID : The ID of the guild
// name: The name of the template (1-100 characters) // data : Template metadata
// description: The description for the template (0-120 characters) func (s *Session) GuildTemplateCreate(guildID string, data *GuildTemplateParams) (st *GuildTemplate) {
func (s *Session) GuildTemplateCreate(guildID, name, description string) (st *GuildTemplate) {
data := struct {
Name string `json:"name"`
Description string `json:"description"`
}{name, description}
body, err := s.RequestWithBucketID("POST", EndpointGuildTemplates(guildID), data, EndpointGuildTemplates(guildID)) body, err := s.RequestWithBucketID("POST", EndpointGuildTemplates(guildID), data, EndpointGuildTemplates(guildID))
if err != nil { if err != nil {
return return
@ -1487,16 +1444,10 @@ func (s *Session) GuildTemplateSync(guildID, templateCode string) (err error) {
} }
// GuildTemplateEdit modifies the template's metadata // GuildTemplateEdit modifies the template's metadata
// guildID: The ID of the guild // guildID : The ID of the guild
// templateCode: The code of the template // templateCode : The code of the template
// name: The name of the template (1-100 characters) // data : New template metadata
// description: The description for the template (0-120 characters) func (s *Session) GuildTemplateEdit(guildID, templateCode string, data *GuildTemplateParams) (st *GuildTemplate, err error) {
func (s *Session) GuildTemplateEdit(guildID, templateCode, name, description string) (st *GuildTemplate, err error) {
data := struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
}{name, description}
body, err := s.RequestWithBucketID("PATCH", EndpointGuildTemplateSync(guildID, templateCode), data, EndpointGuildTemplateSync(guildID, "")) body, err := s.RequestWithBucketID("PATCH", EndpointGuildTemplateSync(guildID, templateCode), data, EndpointGuildTemplateSync(guildID, ""))
if err != nil { if err != nil {
@ -1532,19 +1483,10 @@ func (s *Session) Channel(channelID string) (st *Channel, err error) {
return return
} }
// ChannelEdit edits the given channel // ChannelEdit edits the given channel and returns the updated Channel data.
// channelID : The ID of a Channel // channelID : The ID of a Channel.
// name : The new name to assign the channel. // data : New Channel data.
func (s *Session) ChannelEdit(channelID, name string) (*Channel, error) { func (s *Session) ChannelEdit(channelID string, data *ChannelEdit) (st *Channel, err error) {
return s.ChannelEditComplex(channelID, &ChannelEdit{
Name: name,
})
}
// ChannelEditComplex edits an existing channel, replacing the parameters entirely with ChannelEdit struct
// channelID : The ID of a Channel
// data : The channel struct to send
func (s *Session) ChannelEditComplex(channelID string, data *ChannelEdit) (st *Channel, err error) {
body, err := s.RequestWithBucketID("PATCH", EndpointChannel(channelID), data, EndpointChannel(channelID)) body, err := s.RequestWithBucketID("PATCH", EndpointChannel(channelID), data, EndpointChannel(channelID))
if err != nil { if err != nil {
return return
@ -1552,6 +1494,15 @@ func (s *Session) ChannelEditComplex(channelID string, data *ChannelEdit) (st *C
err = unmarshal(body, &st) err = unmarshal(body, &st)
return return
}
// ChannelEditComplex edits an existing channel, replacing the parameters entirely with ChannelEdit struct
// NOTE: deprecated, use ChannelEdit instead
// channelID : The ID of a Channel
// data : The channel struct to send
func (s *Session) ChannelEditComplex(channelID string, data *ChannelEdit) (st *Channel, err error) {
return s.ChannelEdit(channelID, data)
} }
// ChannelDelete deletes the given channel // ChannelDelete deletes the given channel
@ -1729,6 +1680,28 @@ func (s *Session) ChannelMessageSendReply(channelID string, content string, refe
}) })
} }
// ChannelMessageSendEmbedReply sends a message to the given channel with reference data and embedded data.
// channelID : The ID of a Channel.
// embed : The embed data to send.
// reference : The message reference to send.
func (s *Session) ChannelMessageSendEmbedReply(channelID string, embed *MessageEmbed, reference *MessageReference) (*Message, error) {
return s.ChannelMessageSendEmbedsReply(channelID, []*MessageEmbed{embed}, reference)
}
// ChannelMessageSendEmbedsReply sends a message to the given channel with reference data and multiple embedded data.
// channelID : The ID of a Channel.
// embeds : The embeds data to send.
// reference : The message reference to send.
func (s *Session) ChannelMessageSendEmbedsReply(channelID string, embeds []*MessageEmbed, reference *MessageReference) (*Message, error) {
if reference == nil {
return nil, fmt.Errorf("reply attempted with nil message reference")
}
return s.ChannelMessageSendComplex(channelID, &MessageSend{
Embeds: embeds,
Reference: reference,
})
}
// ChannelMessageEdit edits an existing message, replacing it entirely with // ChannelMessageEdit edits an existing message, replacing it entirely with
// the given content. // the given content.
// channelID : The ID of a Channel // channelID : The ID of a Channel
@ -2792,7 +2765,7 @@ func (s *Session) ApplicationCommands(appID, guildID string) (cmd []*Application
endpoint = EndpointApplicationGuildCommands(appID, guildID) endpoint = EndpointApplicationGuildCommands(appID, guildID)
} }
body, err := s.RequestWithBucketID("GET", endpoint, nil, endpoint) body, err := s.RequestWithBucketID("GET", endpoint+"?with_localizations=true", nil, "GET "+endpoint)
if err != nil { if err != nil {
return return
} }
@ -2840,6 +2813,8 @@ func (s *Session) ApplicationCommandPermissions(appID, guildID, cmdID string) (p
// guildID : The guild ID containing the application command // guildID : The guild ID containing the application command
// cmdID : The command ID to edit the permissions of // cmdID : The command ID to edit the permissions of
// permissions : An object containing a list of permissions for the application command // permissions : An object containing a list of permissions for the application command
//
// NOTE: Requires OAuth2 token with applications.commands.permissions.update scope
func (s *Session) ApplicationCommandPermissionsEdit(appID, guildID, cmdID string, permissions *ApplicationCommandPermissionsList) (err error) { func (s *Session) ApplicationCommandPermissionsEdit(appID, guildID, cmdID string, permissions *ApplicationCommandPermissionsList) (err error) {
endpoint := EndpointApplicationCommandPermissions(appID, guildID, cmdID) endpoint := EndpointApplicationCommandPermissions(appID, guildID, cmdID)
@ -2851,6 +2826,8 @@ func (s *Session) ApplicationCommandPermissionsEdit(appID, guildID, cmdID string
// appID : The Application ID // appID : The Application ID
// guildID : The guild ID to batch edit commands of // guildID : The guild ID to batch edit commands of
// permissions : A list of permissions paired with a command ID, guild ID, and application ID per application command // permissions : A list of permissions paired with a command ID, guild ID, and application ID per application command
//
// NOTE: This endpoint has been disabled with updates to command permissions (Permissions v2). Please use ApplicationCommandPermissionsEdit instead.
func (s *Session) ApplicationCommandPermissionsBatchEdit(appID, guildID string, permissions []*GuildApplicationCommandPermissions) (err error) { func (s *Session) ApplicationCommandPermissionsBatchEdit(appID, guildID string, permissions []*GuildApplicationCommandPermissions) (err error) {
endpoint := EndpointApplicationCommandsGuildPermissions(appID, guildID) endpoint := EndpointApplicationCommandsGuildPermissions(appID, guildID)
@ -3085,3 +3062,80 @@ func (s *Session) GuildScheduledEventUsers(guildID, eventID string, limit int, w
err = unmarshal(body, &st) err = unmarshal(body, &st)
return return
} }
// ----------------------------------------------------------------------
// Functions specific to auto moderation
// ----------------------------------------------------------------------
// AutoModerationRules returns a list of auto moderation rules.
// guildID : ID of the guild
func (s *Session) AutoModerationRules(guildID string) (st []*AutoModerationRule, err error) {
endpoint := EndpointGuildAutoModerationRules(guildID)
var body []byte
body, err = s.RequestWithBucketID("GET", endpoint, nil, endpoint)
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// AutoModerationRule returns an auto moderation rule.
// guildID : ID of the guild
// ruleID : ID of the auto moderation rule
func (s *Session) AutoModerationRule(guildID, ruleID string) (st *AutoModerationRule, err error) {
endpoint := EndpointGuildAutoModerationRule(guildID, ruleID)
var body []byte
body, err = s.RequestWithBucketID("GET", endpoint, nil, endpoint)
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// AutoModerationRuleCreate creates an auto moderation rule with the given data and returns it.
// guildID : ID of the guild
// rule : Rule data
func (s *Session) AutoModerationRuleCreate(guildID string, rule *AutoModerationRule) (st *AutoModerationRule, err error) {
endpoint := EndpointGuildAutoModerationRules(guildID)
var body []byte
body, err = s.RequestWithBucketID("POST", endpoint, rule, endpoint)
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// AutoModerationRuleEdit edits and returns the updated auto moderation rule.
// guildID : ID of the guild
// ruleID : ID of the auto moderation rule
// rule : New rule data
func (s *Session) AutoModerationRuleEdit(guildID, ruleID string, rule *AutoModerationRule) (st *AutoModerationRule, err error) {
endpoint := EndpointGuildAutoModerationRule(guildID, ruleID)
var body []byte
body, err = s.RequestWithBucketID("PATCH", endpoint, rule, endpoint)
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// AutoModerationRuleDelete deletes an auto moderation rule.
// guildID : ID of the guild
// ruleID : ID of the auto moderation rule
func (s *Session) AutoModerationRuleDelete(guildID, ruleID string) (err error) {
endpoint := EndpointGuildAutoModerationRule(guildID, ruleID)
_, err = s.RequestWithBucketID("DELETE", endpoint, nil, endpoint)
return
}

View File

@ -7,7 +7,7 @@
// This file contains code related to state tracking. If enabled, state // This file contains code related to state tracking. If enabled, state
// tracking will capture the initial READY packet and many other websocket // tracking will capture the initial READY packet and many other websocket
// events and maintain an in-memory state of of guilds, channels, users, and // events and maintain an in-memory state of guilds, channels, users, and
// so forth. This information can be accessed through the Session.State struct. // so forth. This information can be accessed through the Session.State struct.
package discordgo package discordgo
@ -661,18 +661,6 @@ func (s *State) ThreadMemberUpdate(mu *ThreadMemberUpdate) error {
return nil return nil
} }
// GuildChannel gets a channel by ID from a guild.
// This method is Deprecated, use Channel(channelID)
func (s *State) GuildChannel(guildID, channelID string) (*Channel, error) {
return s.Channel(channelID)
}
// PrivateChannel gets a private channel by ID.
// This method is Deprecated, use Channel(channelID)
func (s *State) PrivateChannel(channelID string) (*Channel, error) {
return s.Channel(channelID)
}
// Channel gets a channel by ID, it will look in all guilds and private channels. // Channel gets a channel by ID, it will look in all guilds and private channels.
func (s *State) Channel(channelID string) (*Channel, error) { func (s *State) Channel(channelID string) (*Channel, error) {
if s == nil { if s == nil {

View File

@ -59,12 +59,12 @@ type Session struct {
ShardCount int ShardCount int
// Should state tracking be enabled. // Should state tracking be enabled.
// State tracking is the best way for getting the the users // State tracking is the best way for getting the users
// active guilds and the members of the guilds. // active guilds and the members of the guilds.
StateEnabled bool StateEnabled bool
// Whether or not to call event handlers synchronously. // Whether or not to call event handlers synchronously.
// e.g false = launch event handlers in their own goroutines. // e.g. false = launch event handlers in their own goroutines.
SyncEvents bool SyncEvents bool
// Exposed but should not be modified by User. // Exposed but should not be modified by User.
@ -75,7 +75,7 @@ type Session struct {
// Max number of REST API retries // Max number of REST API retries
MaxRestRetries int MaxRestRetries int
// Status stores the currect status of the websocket connection // Status stores the current status of the websocket connection
// this is being tested, may stay, may go away. // this is being tested, may stay, may go away.
status int32 status int32
@ -95,6 +95,9 @@ type Session struct {
// The http client used for REST requests // The http client used for REST requests
Client *http.Client Client *http.Client
// The dialer used for WebSocket connection
Dialer *websocket.Dialer
// The user agent used for REST APIs // The user agent used for REST APIs
UserAgent string UserAgent string
@ -197,23 +200,8 @@ type IntegrationAccount struct {
// A VoiceRegion stores data for a specific voice region server. // A VoiceRegion stores data for a specific voice region server.
type VoiceRegion struct { type VoiceRegion struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Hostname string `json:"sample_hostname"`
Port int `json:"sample_port"`
}
// A VoiceICE stores data for voice ICE servers.
type VoiceICE struct {
TTL string `json:"ttl"`
Servers []*ICEServer `json:"servers"`
}
// A ICEServer stores data for a specific voice ICE server.
type ICEServer struct {
URL string `json:"url"`
Username string `json:"username"`
Credential string `json:"credential"`
} }
// InviteTargetType indicates the type of target of an invite // InviteTargetType indicates the type of target of an invite
@ -222,8 +210,8 @@ type InviteTargetType uint8
// Invite target types // Invite target types
const ( const (
InviteTargetStream InviteTargetType = 1 InviteTargetStream InviteTargetType = 1
InviteTargetEmbeddedAppliction InviteTargetType = 2 InviteTargetEmbeddedApplication InviteTargetType = 2
) )
// A Invite stores all data related to a specific Discord Guild or Channel invite. // A Invite stores all data related to a specific Discord Guild or Channel invite.
@ -246,6 +234,8 @@ type Invite struct {
// will only be filled when using InviteWithCounts // will only be filled when using InviteWithCounts
ApproximatePresenceCount int `json:"approximate_presence_count"` ApproximatePresenceCount int `json:"approximate_presence_count"`
ApproximateMemberCount int `json:"approximate_member_count"` ApproximateMemberCount int `json:"approximate_member_count"`
ExpiresAt *time.Time `json:"expires_at"`
} }
// ChannelType is the type of a Channel // ChannelType is the type of a Channel
@ -358,7 +348,7 @@ func (c *Channel) IsThread() bool {
type ChannelEdit struct { type ChannelEdit struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Topic string `json:"topic,omitempty"` Topic string `json:"topic,omitempty"`
NSFW bool `json:"nsfw,omitempty"` NSFW *bool `json:"nsfw,omitempty"`
Position int `json:"position"` Position int `json:"position"`
Bitrate int `json:"bitrate,omitempty"` Bitrate int `json:"bitrate,omitempty"`
UserLimit int `json:"user_limit,omitempty"` UserLimit int `json:"user_limit,omitempty"`
@ -368,10 +358,10 @@ type ChannelEdit struct {
// NOTE: threads only // NOTE: threads only
Archived bool `json:"archived,omitempty"` Archived *bool `json:"archived,omitempty"`
AutoArchiveDuration int `json:"auto_archive_duration,omitempty"` AutoArchiveDuration int `json:"auto_archive_duration,omitempty"`
Locked bool `json:"locked,bool"` Locked *bool `json:"locked,omitempty"`
Invitable bool `json:"invitable,omitempty"` Invitable *bool `json:"invitable,omitempty"`
} }
// A ChannelFollow holds data returned after following a news channel // A ChannelFollow holds data returned after following a news channel
@ -489,6 +479,17 @@ func (e *Emoji) APIName() string {
return e.ID return e.ID
} }
// EmojiParams represents parameters needed to create or update an Emoji.
type EmojiParams struct {
// Name of the emoji
Name string `json:"name,omitempty"`
// A base64 encoded emoji image, has to be smaller than 256KB.
// NOTE: can be only set on creation.
Image string `json:"image,omitempty"`
// Roles for which this emoji will be available.
Roles []string `json:"roles,omitempty"`
}
// StickerFormat is the file format of the Sticker. // StickerFormat is the file format of the Sticker.
type StickerFormat int type StickerFormat int
@ -694,7 +695,7 @@ type Guild struct {
NSFWLevel GuildNSFWLevel `json:"nsfw_level"` NSFWLevel GuildNSFWLevel `json:"nsfw_level"`
// The list of enabled guild features // The list of enabled guild features
Features []string `json:"features"` Features []GuildFeature `json:"features"`
// Required MFA level for the guild // Required MFA level for the guild
MfaLevel MfaLevel `json:"mfa_level"` MfaLevel MfaLevel `json:"mfa_level"`
@ -946,19 +947,19 @@ type GuildScheduledEventUser struct {
Member *Member `json:"member"` Member *Member `json:"member"`
} }
// A GuildTemplate represents // A GuildTemplate represents a replicable template for guild creation
type GuildTemplate struct { type GuildTemplate struct {
// The unique code for the guild template // The unique code for the guild template
Code string `json:"code"` Code string `json:"code"`
// The name of the template // The name of the template
Name string `json:"name"` Name string `json:"name,omitempty"`
// The description for the template // The description for the template
Description string `json:"description"` Description *string `json:"description,omitempty"`
// The number of times this template has been used // The number of times this template has been used
UsageCount string `json:"usage_count"` UsageCount int `json:"usage_count"`
// The ID of the user who created the template // The ID of the user who created the template
CreatorID string `json:"creator_id"` CreatorID string `json:"creator_id"`
@ -982,6 +983,14 @@ type GuildTemplate struct {
IsDirty bool `json:"is_dirty"` IsDirty bool `json:"is_dirty"`
} }
// GuildTemplateParams stores the data needed to create or update a GuildTemplate.
type GuildTemplateParams struct {
// The name of the template (1-100 characters)
Name string `json:"name,omitempty"`
// The description of the template (0-120 characters)
Description string `json:"description,omitempty"`
}
// MessageNotifications is the notification level for a guild // MessageNotifications is the notification level for a guild
// https://discord.com/developers/docs/resources/guild#guild-object-default-message-notification-level // https://discord.com/developers/docs/resources/guild#guild-object-default-message-notification-level
type MessageNotifications int type MessageNotifications int
@ -1025,13 +1034,42 @@ func (g *Guild) BannerURL() string {
// A UserGuild holds a brief version of a Guild // A UserGuild holds a brief version of a Guild
type UserGuild struct { type UserGuild struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Icon string `json:"icon"` Icon string `json:"icon"`
Owner bool `json:"owner"` Owner bool `json:"owner"`
Permissions int64 `json:"permissions,string"` Permissions int64 `json:"permissions,string"`
Features []GuildFeature `json:"features"`
} }
// GuildFeature indicates the presence of a feature in a guild
type GuildFeature string
// Constants for GuildFeature
const (
GuildFeatureAnimatedBanner GuildFeature = "ANIMATED_BANNER"
GuildFeatureAnimatedIcon GuildFeature = "ANIMATED_ICON"
GuildFeatureAutoModeration GuildFeature = "AUTO_MODERATION"
GuildFeatureBanner GuildFeature = "BANNER"
GuildFeatureCommunity GuildFeature = "COMMUNITY"
GuildFeatureDiscoverable GuildFeature = "DISCOVERABLE"
GuildFeatureFeaturable GuildFeature = "FEATURABLE"
GuildFeatureInviteSplash GuildFeature = "INVITE_SPLASH"
GuildFeatureMemberVerificationGateEnabled GuildFeature = "MEMBER_VERIFICATION_GATE_ENABLED"
GuildFeatureMonetizationEnabled GuildFeature = "MONETIZATION_ENABLED"
GuildFeatureMoreStickers GuildFeature = "MORE_STICKERS"
GuildFeatureNews GuildFeature = "NEWS"
GuildFeaturePartnered GuildFeature = "PARTNERED"
GuildFeaturePreviewEnabled GuildFeature = "PREVIEW_ENABLED"
GuildFeaturePrivateThreads GuildFeature = "PRIVATE_THREADS"
GuildFeatureRoleIcons GuildFeature = "ROLE_ICONS"
GuildFeatureTicketedEventsEnabled GuildFeature = "TICKETED_EVENTS_ENABLED"
GuildFeatureVanityURL GuildFeature = "VANITY_URL"
GuildFeatureVerified GuildFeature = "VERIFIED"
GuildFeatureVipRegions GuildFeature = "VIP_REGIONS"
GuildFeatureWelcomeScreenEnabled GuildFeature = "WELCOME_SCREEN_ENABLED"
)
// A GuildParams stores all the data needed to update discord guild settings // A GuildParams stores all the data needed to update discord guild settings
type GuildParams struct { type GuildParams struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
@ -1081,6 +1119,20 @@ func (r *Role) Mention() string {
return fmt.Sprintf("<@&%s>", r.ID) return fmt.Sprintf("<@&%s>", r.ID)
} }
// RoleParams represents the parameters needed to create or update a Role
type RoleParams struct {
// The role's name
Name string `json:"name,omitempty"`
// The color the role should have (as a decimal, not hex)
Color *int `json:"color,omitempty"`
// Whether to display the role's users separately
Hoist *bool `json:"hoist,omitempty"`
// The overall permissions number of the role
Permissions *int64 `json:"permissions,omitempty,string"`
// Whether this role is mentionable
Mentionable *bool `json:"mentionable,omitempty"`
}
// Roles are a collection of Role // Roles are a collection of Role
type Roles []*Role type Roles []*Role
@ -1098,15 +1150,19 @@ func (r Roles) Swap(i, j int) {
// A VoiceState stores the voice states of Guilds // A VoiceState stores the voice states of Guilds
type VoiceState struct { type VoiceState struct {
UserID string `json:"user_id"` GuildID string `json:"guild_id"`
SessionID string `json:"session_id"` ChannelID string `json:"channel_id"`
ChannelID string `json:"channel_id"` UserID string `json:"user_id"`
GuildID string `json:"guild_id"` Member *Member `json:"member"`
Suppress bool `json:"suppress"` SessionID string `json:"session_id"`
SelfMute bool `json:"self_mute"` Deaf bool `json:"deaf"`
SelfDeaf bool `json:"self_deaf"` Mute bool `json:"mute"`
Mute bool `json:"mute"` SelfDeaf bool `json:"self_deaf"`
Deaf bool `json:"deaf"` SelfMute bool `json:"self_mute"`
SelfStream bool `json:"self_stream"`
SelfVideo bool `json:"self_video"`
Suppress bool `json:"suppress"`
RequestToSpeakTimestamp *time.Time `json:"request_to_speak_timestamp"`
} }
// A Presence stores the online, offline, or idle and game status of Guild members. // A Presence stores the online, offline, or idle and game status of Guild members.
@ -1206,25 +1262,6 @@ func (m *Member) AvatarURL(size string) string {
} }
// A Settings stores data for a specific users Discord client settings.
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"`
MessageDisplayCompact bool `json:"message_display_compact"`
ShowCurrentGame bool `json:"show_current_game"`
ConvertEmoticons bool `json:"convert_emoticons"`
Locale string `json:"locale"`
Theme string `json:"theme"`
GuildPositions []string `json:"guild_positions"`
RestrictedGuilds []string `json:"restricted_guilds"`
FriendSourceFlags *FriendSourceFlags `json:"friend_source_flags"`
Status Status `json:"status"`
DetectPlatformAccounts bool `json:"detect_platform_accounts"`
DeveloperMode bool `json:"developer_mode"`
}
// Status type definition // Status type definition
type Status string type Status string
@ -1237,20 +1274,6 @@ const (
StatusOffline Status = "offline" StatusOffline Status = "offline"
) )
// FriendSourceFlags stores ... TODO :)
type FriendSourceFlags struct {
All bool `json:"all"`
MutualGuilds bool `json:"mutual_guilds"`
MutualFriends bool `json:"mutual_friends"`
}
// A Relationship between the logged in user and Relationship.User
type Relationship struct {
User *User `json:"user"`
Type int `json:"type"` // 1 = friend, 2 = blocked, 3 = incoming friend req, 4 = sent friend req
ID string `json:"id"`
}
// A TooManyRequests struct holds information received from Discord // A TooManyRequests struct holds information received from Discord
// when receiving a HTTP 429 response. // when receiving a HTTP 429 response.
type TooManyRequests struct { type TooManyRequests struct {
@ -1286,11 +1309,6 @@ type ReadState struct {
ID string `json:"id"` ID string `json:"id"`
} }
// An Ack is used to ack messages
type Ack struct {
Token string `json:"token"`
}
// A GuildRole stores data for guild roles. // A GuildRole stores data for guild roles.
type GuildRole struct { type GuildRole struct {
Role *Role `json:"role"` Role *Role `json:"role"`
@ -1303,10 +1321,92 @@ type GuildBan struct {
User *User `json:"user"` User *User `json:"user"`
} }
// AutoModerationRule stores data for an auto moderation rule.
type AutoModerationRule struct {
ID string `json:"id,omitempty"`
GuildID string `json:"guild_id,omitempty"`
Name string `json:"name,omitempty"`
CreatorID string `json:"creator_id,omitempty"`
EventType AutoModerationRuleEventType `json:"event_type,omitempty"`
TriggerType AutoModerationRuleTriggerType `json:"trigger_type,omitempty"`
TriggerMetadata *AutoModerationTriggerMetadata `json:"trigger_metadata,omitempty"`
Actions []AutoModerationAction `json:"actions,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
ExemptRoles *[]string `json:"exempt_roles,omitempty"`
ExemptChannels *[]string `json:"exempt_channels,omitempty"`
}
// AutoModerationRuleEventType indicates in what event context a rule should be checked.
type AutoModerationRuleEventType int
// Auto moderation rule event types.
const (
// AutoModerationEventMessageSend is checked when a member sends or edits a message in the guild
AutoModerationEventMessageSend AutoModerationRuleEventType = 1
)
// AutoModerationRuleTriggerType represents the type of content which can trigger the rule.
type AutoModerationRuleTriggerType int
// Auto moderation rule trigger types.
const (
AutoModerationEventTriggerKeyword AutoModerationRuleTriggerType = 1
AutoModerationEventTriggerHarmfulLink AutoModerationRuleTriggerType = 2
AutoModerationEventTriggerSpam AutoModerationRuleTriggerType = 3
AutoModerationEventTriggerKeywordPreset AutoModerationRuleTriggerType = 4
)
// AutoModerationKeywordPreset represents an internally pre-defined wordset.
type AutoModerationKeywordPreset uint
// Auto moderation keyword presets.
const (
AutoModerationKeywordPresetProfanity AutoModerationKeywordPreset = 1
AutoModerationKeywordPresetSexualContent AutoModerationKeywordPreset = 2
AutoModerationKeywordPresetSlurs AutoModerationKeywordPreset = 3
)
// AutoModerationTriggerMetadata represents additional metadata used to determine whether rule should be triggered.
type AutoModerationTriggerMetadata struct {
// Substrings which will be searched for in content.
// NOTE: should be only used with keyword trigger type.
KeywordFilter []string `json:"keyword_filter,omitempty"`
// Internally pre-defined wordsets which will be searched for in content.
// NOTE: should be only used with keyword preset trigger type.
Presets []AutoModerationKeywordPreset `json:"presets,omitempty"`
}
// AutoModerationActionType represents an action which will execute whenever a rule is triggered.
type AutoModerationActionType int
// Auto moderation actions types.
const (
AutoModerationRuleActionBlockMessage AutoModerationActionType = 1
AutoModerationRuleActionSendAlertMessage AutoModerationActionType = 2
AutoModerationRuleActionTimeout AutoModerationActionType = 3
)
// AutoModerationActionMetadata represents additional metadata needed during execution for a specific action type.
type AutoModerationActionMetadata struct {
// Channel to which user content should be logged.
// NOTE: should be only used with send alert message action type.
ChannelID string `json:"channel_id,omitempty"`
// Timeout duration in seconds (maximum of 2419200 - 4 weeks).
// NOTE: should be only used with timeout action type.
Duration int `json:"duration_seconds,omitempty"`
}
// AutoModerationAction stores data for an auto moderation action.
type AutoModerationAction struct {
Type AutoModerationActionType `json:"type"`
Metadata *AutoModerationActionMetadata `json:"metadata,omitempty"`
}
// A GuildEmbed stores data for a guild embed. // A GuildEmbed stores data for a guild embed.
type GuildEmbed struct { type GuildEmbed struct {
Enabled bool `json:"enabled"` Enabled *bool `json:"enabled,omitempty"`
ChannelID string `json:"channel_id"` ChannelID string `json:"channel_id,omitempty"`
} }
// A GuildAuditLog stores data for a guild audit log. // A GuildAuditLog stores data for a guild audit log.
@ -1574,41 +1674,79 @@ const (
AuditLogActionThreadCreate AuditLogAction = 110 AuditLogActionThreadCreate AuditLogAction = 110
AuditLogActionThreadUpdate AuditLogAction = 111 AuditLogActionThreadUpdate AuditLogAction = 111
AuditLogActionThreadDelete AuditLogAction = 112 AuditLogActionThreadDelete AuditLogAction = 112
AuditLogActionApplicationCommandPermissionUpdate AuditLogAction = 121
) )
// A UserGuildSettingsChannelOverride stores data for a channel override for a users guild settings.
type UserGuildSettingsChannelOverride struct {
Muted bool `json:"muted"`
MessageNotifications int `json:"message_notifications"`
ChannelID string `json:"channel_id"`
}
// A UserGuildSettings stores data for a users guild settings.
type UserGuildSettings struct {
SupressEveryone bool `json:"suppress_everyone"`
Muted bool `json:"muted"`
MobilePush bool `json:"mobile_push"`
MessageNotifications int `json:"message_notifications"`
GuildID string `json:"guild_id"`
ChannelOverrides []*UserGuildSettingsChannelOverride `json:"channel_overrides"`
}
// A UserGuildSettingsEdit stores data for editing UserGuildSettings
type UserGuildSettingsEdit struct {
SupressEveryone bool `json:"suppress_everyone"`
Muted bool `json:"muted"`
MobilePush bool `json:"mobile_push"`
MessageNotifications int `json:"message_notifications"`
ChannelOverrides map[string]*UserGuildSettingsChannelOverride `json:"channel_overrides"`
}
// GuildMemberParams stores data needed to update a member // GuildMemberParams stores data needed to update a member
// https://discord.com/developers/docs/resources/guild#modify-guild-member // https://discord.com/developers/docs/resources/guild#modify-guild-member
type GuildMemberParams struct { type GuildMemberParams struct {
// Value to set user's nickname to // Value to set user's nickname to.
Nick string `json:"nick,omitempty"` Nick string `json:"nick,omitempty"`
// Array of role ids the member is assigned // Array of role ids the member is assigned.
Roles *[]string `json:"roles,omitempty"` Roles *[]string `json:"roles,omitempty"`
// ID of channel to move user to (if they are connected to voice).
// Set to "" to remove user from a voice channel.
ChannelID *string `json:"channel_id,omitempty"`
// Whether the user is muted in voice channels.
Mute *bool `json:"mute,omitempty"`
// Whether the user is deafened in voice channels.
Deaf *bool `json:"deaf,omitempty"`
// When the user's timeout will expire and the user will be able
// to communicate in the guild again (up to 28 days in the future).
// Set to time.Time{} to remove timeout.
CommunicationDisabledUntil *time.Time `json:"communication_disabled_until,omitempty"`
}
// MarshalJSON is a helper function to marshal GuildMemberParams.
func (p GuildMemberParams) MarshalJSON() (res []byte, err error) {
type guildMemberParams GuildMemberParams
v := struct {
guildMemberParams
ChannelID json.RawMessage `json:"channel_id,omitempty"`
CommunicationDisabledUntil json.RawMessage `json:"communication_disabled_until,omitempty"`
}{guildMemberParams: guildMemberParams(p)}
if p.ChannelID != nil {
if *p.ChannelID == "" {
v.ChannelID = json.RawMessage(`null`)
} else {
res, err = json.Marshal(p.ChannelID)
if err != nil {
return
}
v.ChannelID = res
}
}
if p.CommunicationDisabledUntil != nil {
if p.CommunicationDisabledUntil.IsZero() {
v.CommunicationDisabledUntil = json.RawMessage(`null`)
} else {
res, err = json.Marshal(p.CommunicationDisabledUntil)
if err != nil {
return
}
v.CommunicationDisabledUntil = res
}
}
return json.Marshal(v)
}
// GuildMemberAddParams stores data needed to add a user to a guild.
// NOTE: All fields are optional, except AccessToken.
type GuildMemberAddParams struct {
// Valid access_token for the user.
AccessToken string `json:"access_token"`
// Value to set users nickname to.
Nick string `json:"nick,omitempty"`
// A list of role ID's to set on the member.
Roles []string `json:"roles,omitempty"`
// Whether the user is muted.
Mute bool `json:"mute,omitempty"`
// Whether the user is deafened.
Deaf bool `json:"deaf,omitempty"`
} }
// An APIErrorMessage is an api error message returned from discord // An APIErrorMessage is an api error message returned from discord
@ -2059,23 +2197,25 @@ type Intent int
// Constants for the different bit offsets of intents // Constants for the different bit offsets of intents
const ( const (
IntentGuilds Intent = 1 << 0 IntentGuilds Intent = 1 << 0
IntentGuildMembers Intent = 1 << 1 IntentGuildMembers Intent = 1 << 1
IntentGuildBans Intent = 1 << 2 IntentGuildBans Intent = 1 << 2
IntentGuildEmojis Intent = 1 << 3 IntentGuildEmojis Intent = 1 << 3
IntentGuildIntegrations Intent = 1 << 4 IntentGuildIntegrations Intent = 1 << 4
IntentGuildWebhooks Intent = 1 << 5 IntentGuildWebhooks Intent = 1 << 5
IntentGuildInvites Intent = 1 << 6 IntentGuildInvites Intent = 1 << 6
IntentGuildVoiceStates Intent = 1 << 7 IntentGuildVoiceStates Intent = 1 << 7
IntentGuildPresences Intent = 1 << 8 IntentGuildPresences Intent = 1 << 8
IntentGuildMessages Intent = 1 << 9 IntentGuildMessages Intent = 1 << 9
IntentGuildMessageReactions Intent = 1 << 10 IntentGuildMessageReactions Intent = 1 << 10
IntentGuildMessageTyping Intent = 1 << 11 IntentGuildMessageTyping Intent = 1 << 11
IntentDirectMessages Intent = 1 << 12 IntentDirectMessages Intent = 1 << 12
IntentDirectMessageReactions Intent = 1 << 13 IntentDirectMessageReactions Intent = 1 << 13
IntentDirectMessageTyping Intent = 1 << 14 IntentDirectMessageTyping Intent = 1 << 14
IntentMessageContent Intent = 1 << 15 IntentMessageContent Intent = 1 << 15
IntentGuildScheduledEvents Intent = 1 << 16 IntentGuildScheduledEvents Intent = 1 << 16
IntentAutoModerationConfiguration Intent = 1 << 20
IntentAutoModerationExecution Intent = 1 << 21
// TODO: remove when compatibility is not needed // TODO: remove when compatibility is not needed
@ -2110,7 +2250,9 @@ const (
IntentDirectMessages | IntentDirectMessages |
IntentDirectMessageReactions | IntentDirectMessageReactions |
IntentDirectMessageTyping | IntentDirectMessageTyping |
IntentGuildScheduledEvents IntentGuildScheduledEvents |
IntentAutoModerationConfiguration |
IntentAutoModerationExecution
IntentsAll = IntentsAllWithoutPrivileged | IntentsAll = IntentsAllWithoutPrivileged |
IntentGuildMembers | IntentGuildMembers |

View File

@ -120,9 +120,9 @@ func (v *VoiceConnection) ChangeChannel(channelID string, mute, deaf bool) (err
v.log(LogInformational, "called") v.log(LogInformational, "called")
data := voiceChannelJoinOp{4, voiceChannelJoinData{&v.GuildID, &channelID, mute, deaf}} data := voiceChannelJoinOp{4, voiceChannelJoinData{&v.GuildID, &channelID, mute, deaf}}
v.wsMutex.Lock() v.session.wsMutex.Lock()
err = v.session.wsConn.WriteJSON(data) err = v.session.wsConn.WriteJSON(data)
v.wsMutex.Unlock() v.session.wsMutex.Unlock()
if err != nil { if err != nil {
return return
} }
@ -304,7 +304,7 @@ func (v *VoiceConnection) open() (err error) {
// Connect to VoiceConnection Websocket // Connect to VoiceConnection Websocket
vg := "wss://" + strings.TrimSuffix(v.endpoint, ":80") vg := "wss://" + strings.TrimSuffix(v.endpoint, ":80")
v.log(LogInformational, "connecting to voice endpoint %s", vg) v.log(LogInformational, "connecting to voice endpoint %s", vg)
v.wsConn, _, err = websocket.DefaultDialer.Dial(vg, nil) v.wsConn, _, err = v.session.Dialer.Dial(vg, nil)
if err != nil { if err != nil {
v.log(LogWarning, "error connecting to voice endpoint %s, %s", vg, err) v.log(LogWarning, "error connecting to voice endpoint %s, %s", vg, err)
v.log(LogDebug, "voice struct: %#v\n", v) v.log(LogDebug, "voice struct: %#v\n", v)
@ -323,7 +323,9 @@ func (v *VoiceConnection) open() (err error) {
} }
data := voiceHandshakeOp{0, voiceHandshakeData{v.GuildID, v.UserID, v.sessionID, v.token}} data := voiceHandshakeOp{0, voiceHandshakeData{v.GuildID, v.UserID, v.sessionID, v.token}}
v.wsMutex.Lock()
err = v.wsConn.WriteJSON(data) err = v.wsConn.WriteJSON(data)
v.wsMutex.Unlock()
if err != nil { if err != nil {
v.log(LogWarning, "error sending init packet, %s", err) v.log(LogWarning, "error sending init packet, %s", err)
return return
@ -829,7 +831,12 @@ func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct
p.SSRC = binary.BigEndian.Uint32(recvbuf[8:12]) p.SSRC = binary.BigEndian.Uint32(recvbuf[8:12])
// decrypt opus data // decrypt opus data
copy(nonce[:], recvbuf[0:12]) copy(nonce[:], recvbuf[0:12])
p.Opus, _ = secretbox.Open(nil, recvbuf[12:rlen], &nonce, &v.op4.SecretKey)
if opus, ok := secretbox.Open(nil, recvbuf[12:rlen], &nonce, &v.op4.SecretKey); ok {
p.Opus = opus
} else {
return
}
// extension bit set, and not a RTCP packet // extension bit set, and not a RTCP packet
if ((recvbuf[0] & 0x10) == 0x10) && ((recvbuf[1] & 0x80) == 0) { if ((recvbuf[0] & 0x10) == 0x10) && ((recvbuf[1] & 0x80) == 0) {
@ -870,7 +877,11 @@ func (v *VoiceConnection) reconnect() {
v.reconnecting = true v.reconnecting = true
v.Unlock() v.Unlock()
defer func() { v.reconnecting = false }() defer func() {
v.Lock()
v.reconnecting = false
v.Unlock()
}()
// Close any currently open connections // Close any currently open connections
v.Close() v.Close()

View File

@ -35,15 +35,16 @@ type WebhookParams struct {
Components []MessageComponent `json:"components"` Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds,omitempty"` Embeds []*MessageEmbed `json:"embeds,omitempty"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"` AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
// NOTE: Works only for followup messages. // Only MessageFlagsSuppressEmbeds and MessageFlagsEphemeral can be set.
Flags uint64 `json:"flags,omitempty"` // MessageFlagsEphemeral can only be set when using Followup Message Create endpoint.
Flags MessageFlags `json:"flags,omitempty"`
} }
// WebhookEdit stores data for editing of a webhook message. // WebhookEdit stores data for editing of a webhook message.
type WebhookEdit struct { type WebhookEdit struct {
Content string `json:"content,omitempty"` Content *string `json:"content,omitempty"`
Components []MessageComponent `json:"components"` Components *[]MessageComponent `json:"components,omitempty"`
Embeds []*MessageEmbed `json:"embeds,omitempty"` Embeds *[]*MessageEmbed `json:"embeds,omitempty"`
Files []*File `json:"-"` Files []*File `json:"-"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"` AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
} }

View File

@ -77,7 +77,7 @@ func (s *Session) Open() error {
s.log(LogInformational, "connecting to gateway %s", s.gateway) s.log(LogInformational, "connecting to gateway %s", s.gateway)
header := http.Header{} header := http.Header{}
header.Add("accept-encoding", "zlib") header.Add("accept-encoding", "zlib")
s.wsConn, _, err = websocket.DefaultDialer.Dial(s.gateway, header) s.wsConn, _, err = s.Dialer.Dial(s.gateway, header)
if err != nil { if err != nil {
s.log(LogError, "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.gateway = "" // clear cached gateway

View File

@ -141,25 +141,7 @@ func (c *Compiler) Compile(node parser.Node) error {
if node.Token == token.LAnd || node.Token == token.LOr { if node.Token == token.LAnd || node.Token == token.LOr {
return c.compileLogical(node) return c.compileLogical(node)
} }
if node.Token == token.Less {
if err := c.Compile(node.RHS); err != nil {
return err
}
if err := c.Compile(node.LHS); err != nil {
return err
}
c.emit(node, parser.OpBinaryOp, int(token.Greater))
return nil
} else if node.Token == token.LessEq {
if err := c.Compile(node.RHS); err != nil {
return err
}
if err := c.Compile(node.LHS); err != nil {
return err
}
c.emit(node, parser.OpBinaryOp, int(token.GreaterEq))
return nil
}
if err := c.Compile(node.LHS); err != nil { if err := c.Compile(node.LHS); err != nil {
return err return err
} }
@ -182,6 +164,10 @@ func (c *Compiler) Compile(node parser.Node) error {
c.emit(node, parser.OpBinaryOp, int(token.Greater)) c.emit(node, parser.OpBinaryOp, int(token.Greater))
case token.GreaterEq: case token.GreaterEq:
c.emit(node, parser.OpBinaryOp, int(token.GreaterEq)) c.emit(node, parser.OpBinaryOp, int(token.GreaterEq))
case token.Less:
c.emit(node, parser.OpBinaryOp, int(token.Less))
case token.LessEq:
c.emit(node, parser.OpBinaryOp, int(token.LessEq))
case token.Equal: case token.Equal:
c.emit(node, parser.OpEqual) c.emit(node, parser.OpEqual)
case token.NotEqual: case token.NotEqual:

View File

@ -272,6 +272,7 @@ type CrossReference struct {
Container Container
Destination []byte // Destination is where the reference points to Destination []byte // Destination is where the reference points to
Suffix []byte // Potential citation suffix, i.e. (#myid, text)
} }
// Citation is a citation node. // Citation is a citation node.

View File

@ -11,7 +11,6 @@ import (
"strings" "strings"
"github.com/gomarkdown/markdown/ast" "github.com/gomarkdown/markdown/ast"
"github.com/gomarkdown/markdown/internal/valid"
"github.com/gomarkdown/markdown/parser" "github.com/gomarkdown/markdown/parser"
) )
@ -133,7 +132,9 @@ type Renderer struct {
// if > 0, will strip html tags in Out and Outs // if > 0, will strip html tags in Out and Outs
DisableTags int DisableTags int
// TODO: documentation // IsSafeURLOverride allows overriding the default URL matcher. URL is
// safe if the overriding function returns true. Can be used to extend
// the default list of safe URLs.
IsSafeURLOverride func(url []byte) bool IsSafeURLOverride func(url []byte) bool
sr *SPRenderer sr *SPRenderer
@ -216,6 +217,11 @@ func NewRenderer(opts RendererOptions) *Renderer {
} }
func isRelativeLink(link []byte) (yes bool) { func isRelativeLink(link []byte) (yes bool) {
// empty links considerd relative
if len(link) == 0 {
return true
}
// a tag begin with '#' // a tag begin with '#'
if link[0] == '#' { if link[0] == '#' {
return true return true
@ -245,6 +251,9 @@ func isRelativeLink(link []byte) (yes bool) {
} }
func (r *Renderer) addAbsPrefix(link []byte) []byte { func (r *Renderer) addAbsPrefix(link []byte) []byte {
if len(link) == 0 {
return link
}
if r.opts.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' { if r.opts.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' {
newDest := r.opts.AbsolutePrefix newDest := r.opts.AbsolutePrefix
if link[0] != '/' { if link[0] != '/' {
@ -291,7 +300,7 @@ func needSkipLink(r *Renderer, dest []byte) bool {
} }
isSafeURL := r.IsSafeURLOverride isSafeURL := r.IsSafeURLOverride
if isSafeURL == nil { if isSafeURL == nil {
isSafeURL = valid.IsSafeURL isSafeURL = parser.IsSafeURL
} }
return flags&Safelink != 0 && !isSafeURL(dest) && !isMailto(dest) return flags&Safelink != 0 && !isSafeURL(dest) && !isMailto(dest)
} }
@ -1269,33 +1278,6 @@ func slugify(in []byte) []byte {
return out[a : b+1] return out[a : b+1]
} }
// TODO: move to internal package
// isAlnum returns true if c is a digit or letter
// TODO: check when this is looking for ASCII alnum and when it should use unicode
func isAlnum(c byte) bool {
return (c >= '0' && c <= '9') || isLetter(c)
}
// isSpace returns true if c is a white-space charactr
func isSpace(c byte) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'
}
// isLetter returns true if c is ascii letter
func isLetter(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
// isPunctuation returns true if c is a punctuation symbol.
func isPunctuation(c byte) bool {
for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") {
if c == r {
return true
}
}
return false
}
// BlockAttrs takes a node and checks if it has block level attributes set. If so it // BlockAttrs takes a node and checks if it has block level attributes set. If so it
// will return a slice each containing a "key=value(s)" string. // will return a slice each containing a "key=value(s)" string.
func BlockAttrs(node ast.Node) []string { func BlockAttrs(node ast.Node) []string {

View File

@ -3,10 +3,18 @@ package html
import ( import (
"bytes" "bytes"
"io" "io"
"github.com/gomarkdown/markdown/parser"
) )
// SmartyPants rendering // SmartyPants rendering
var (
isSpace = parser.IsSpace
isAlnum = parser.IsAlnum
isPunctuation = parser.IsPunctuation
)
// SPRenderer is a struct containing state of a Smartypants renderer. // SPRenderer is a struct containing state of a Smartypants renderer.
type SPRenderer struct { type SPRenderer struct {
inSingleQuote bool inSingleQuote bool

View File

@ -1,59 +0,0 @@
package valid
import (
"bytes"
)
var URIs = [][]byte{
[]byte("http://"),
[]byte("https://"),
[]byte("ftp://"),
[]byte("mailto:"),
}
var Paths = [][]byte{
[]byte("/"),
[]byte("./"),
[]byte("../"),
}
// TODO: documentation
func IsSafeURL(url []byte) bool {
nLink := len(url)
for _, path := range Paths {
nPath := len(path)
linkPrefix := url[:nPath]
if nLink >= nPath && bytes.Equal(linkPrefix, path) {
if nLink == nPath {
return true
} else if isAlnum(url[nPath]) {
return true
}
}
}
for _, prefix := range URIs {
// TODO: handle unicode here
// case-insensitive prefix test
nPrefix := len(prefix)
if nLink > nPrefix {
linkPrefix := bytes.ToLower(url[:nPrefix])
if bytes.Equal(linkPrefix, prefix) && isAlnum(url[nPrefix]) {
return true
}
}
}
return false
}
// isAlnum returns true if c is a digit or letter
// TODO: check when this is looking for ASCII alnum and when it should use unicode
func isAlnum(c byte) bool {
return (c >= '0' && c <= '9') || isLetter(c)
}
// isLetter returns true if c is ascii letter
func isLetter(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}

View File

@ -909,18 +909,18 @@ func syntaxRange(data []byte, iout *int) (int, int) {
// strip all whitespace at the beginning and the end // strip all whitespace at the beginning and the end
// of the {} block // of the {} block
for syn > 0 && isSpace(data[syntaxStart]) { for syn > 0 && IsSpace(data[syntaxStart]) {
syntaxStart++ syntaxStart++
syn-- syn--
} }
for syn > 0 && isSpace(data[syntaxStart+syn-1]) { for syn > 0 && IsSpace(data[syntaxStart+syn-1]) {
syn-- syn--
} }
i++ i++
} else { } else {
for i < n && !isSpace(data[i]) { for i < n && !IsSpace(data[i]) {
syn++ syn++
i++ i++
} }
@ -1767,7 +1767,7 @@ func skipUntilChar(data []byte, i int, c byte) int {
func skipAlnum(data []byte, i int) int { func skipAlnum(data []byte, i int) int {
n := len(data) n := len(data)
for i < n && isAlnum(data[i]) { for i < n && IsAlnum(data[i]) {
i++ i++
} }
return i return i
@ -1775,7 +1775,7 @@ func skipAlnum(data []byte, i int) int {
func skipSpace(data []byte, i int) int { func skipSpace(data []byte, i int) int {
n := len(data) n := len(data)
for i < n && isSpace(data[i]) { for i < n && IsSpace(data[i]) {
i++ i++
} }
return i return i

View File

@ -58,7 +58,7 @@ func captionID(data []byte) (string, int) {
} }
// remains must be whitespace. // remains must be whitespace.
for l := k + 1; l < end; l++ { for l := k + 1; l < end; l++ {
if !isSpace(data[l]) { if !IsSpace(data[l]) {
return "", 0 return "", 0
} }
} }

View File

@ -6,7 +6,6 @@ import (
"strconv" "strconv"
"github.com/gomarkdown/markdown/ast" "github.com/gomarkdown/markdown/ast"
"github.com/gomarkdown/markdown/internal/valid"
) )
// Parsing of inline elements // Parsing of inline elements
@ -69,7 +68,7 @@ func emphasis(p *Parser, data []byte, offset int) (int, ast.Node) {
if n > 2 && data[1] != c { if n > 2 && data[1] != c {
// whitespace cannot follow an opening emphasis; // whitespace cannot follow an opening emphasis;
// strikethrough only takes two characters '~~' // strikethrough only takes two characters '~~'
if isSpace(data[1]) { if IsSpace(data[1]) {
return 0, nil return 0, nil
} }
if p.extensions&SuperSubscript != 0 && c == '~' { if p.extensions&SuperSubscript != 0 && c == '~' {
@ -81,7 +80,7 @@ func emphasis(p *Parser, data []byte, offset int) (int, ast.Node) {
} }
ret++ // we started with data[1:] above. ret++ // we started with data[1:] above.
for i := 1; i < ret; i++ { for i := 1; i < ret; i++ {
if isSpace(data[i]) && !isEscape(data, i) { if IsSpace(data[i]) && !isEscape(data, i) {
return 0, nil return 0, nil
} }
} }
@ -98,7 +97,7 @@ func emphasis(p *Parser, data []byte, offset int) (int, ast.Node) {
} }
if n > 3 && data[1] == c && data[2] != c { if n > 3 && data[1] == c && data[2] != c {
if isSpace(data[2]) { if IsSpace(data[2]) {
return 0, nil return 0, nil
} }
ret, node := helperDoubleEmphasis(p, data[2:], c) ret, node := helperDoubleEmphasis(p, data[2:], c)
@ -110,7 +109,7 @@ func emphasis(p *Parser, data []byte, offset int) (int, ast.Node) {
} }
if n > 4 && data[1] == c && data[2] == c && data[3] != c { if n > 4 && data[1] == c && data[2] == c && data[3] != c {
if c == '~' || isSpace(data[3]) { if c == '~' || IsSpace(data[3]) {
return 0, nil return 0, nil
} }
ret, node := helperTripleEmphasis(p, data, 3, c) ret, node := helperTripleEmphasis(p, data, 3, c)
@ -156,7 +155,7 @@ func codeSpan(p *Parser, data []byte, offset int) (int, ast.Node) {
if data[j] == '\n' { if data[j] == '\n' {
break break
} }
if !isSpace(data[j]) { if !IsSpace(data[j]) {
hasCharsAfterDelimiter = true hasCharsAfterDelimiter = true
} }
} }
@ -256,7 +255,7 @@ func maybeInlineFootnoteOrSuper(p *Parser, data []byte, offset int) (int, ast.No
return 0, nil return 0, nil
} }
for i := offset; i < offset+ret; i++ { for i := offset; i < offset+ret; i++ {
if isSpace(data[i]) && !isEscape(data, i) { if IsSpace(data[i]) && !isEscape(data, i) {
return 0, nil return 0, nil
} }
} }
@ -421,7 +420,7 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) {
// skip whitespace after title // skip whitespace after title
titleE = i - 1 titleE = i - 1
for titleE > titleB && isSpace(data[titleE]) { for titleE > titleB && IsSpace(data[titleE]) {
titleE-- titleE--
} }
@ -433,7 +432,7 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) {
} }
// remove whitespace at the end of the link // remove whitespace at the end of the link
for linkE > linkB && isSpace(data[linkE-1]) { for linkE > linkB && IsSpace(data[linkE-1]) {
linkE-- linkE--
} }
@ -602,9 +601,8 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) {
} }
// links need something to click on and somewhere to go // links need something to click on and somewhere to go
if len(uLink) == 0 || (t == linkNormal && txtE <= 1) { // [](http://bla) is legal in CommonMark, so allow txtE <=1 for linkNormal
return 0, nil // [bla]() is also legal in CommonMark, so allow empty uLink
}
} }
// call the relevant rendering function // call the relevant rendering function
@ -827,7 +825,9 @@ func linkEndsWithEntity(data []byte, linkEnd int) bool {
} }
// hasPrefixCaseInsensitive is a custom implementation of // hasPrefixCaseInsensitive is a custom implementation of
// strings.HasPrefix(strings.ToLower(s), prefix) //
// strings.HasPrefix(strings.ToLower(s), prefix)
//
// we rolled our own because ToLower pulls in a huge machinery of lowercasing // we rolled our own because ToLower pulls in a huge machinery of lowercasing
// anything from Unicode and that's very slow. Since this func will only be // anything from Unicode and that's very slow. Since this func will only be
// used on ASCII protocol prefixes, we can take shortcuts. // used on ASCII protocol prefixes, we can take shortcuts.
@ -889,7 +889,7 @@ func autoLink(p *Parser, data []byte, offset int) (int, ast.Node) {
// scan backward for a word boundary // scan backward for a word boundary
rewind := 0 rewind := 0
for offset-rewind > 0 && rewind <= 7 && isLetter(data[offset-rewind-1]) { for offset-rewind > 0 && rewind <= 7 && IsLetter(data[offset-rewind-1]) {
rewind++ rewind++
} }
if rewind > 6 { // longest supported protocol is "mailto" which has 6 letters if rewind > 6 { // longest supported protocol is "mailto" which has 6 letters
@ -901,7 +901,7 @@ func autoLink(p *Parser, data []byte, offset int) (int, ast.Node) {
isSafeURL := p.IsSafeURLOverride isSafeURL := p.IsSafeURLOverride
if isSafeURL == nil { if isSafeURL == nil {
isSafeURL = valid.IsSafeURL isSafeURL = IsSafeURL
} }
if !isSafeURL(data) { if !isSafeURL(data) {
return 0, nil return 0, nil
@ -996,7 +996,7 @@ func autoLink(p *Parser, data []byte, offset int) (int, ast.Node) {
} }
func isEndOfLink(char byte) bool { func isEndOfLink(char byte) bool {
return isSpace(char) || char == '<' return IsSpace(char) || char == '<'
} }
// return the length of the given tag, or 0 is it's not valid // return the length of the given tag, or 0 is it's not valid
@ -1018,7 +1018,7 @@ func tagLength(data []byte) (autolink autolinkType, end int) {
i = 1 i = 1
} }
if !isAlnum(data[i]) { if !IsAlnum(data[i]) {
return notAutolink, 0 return notAutolink, 0
} }
@ -1026,7 +1026,7 @@ func tagLength(data []byte) (autolink autolinkType, end int) {
autolink = notAutolink autolink = notAutolink
// try to find the beginning of an URI // try to find the beginning of an URI
for i < len(data) && (isAlnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-') { for i < len(data) && (IsAlnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-') {
i++ i++
} }
@ -1051,7 +1051,7 @@ func tagLength(data []byte) (autolink autolinkType, end int) {
for i < len(data) { for i < len(data) {
if data[i] == '\\' { if data[i] == '\\' {
i += 2 i += 2
} else if data[i] == '>' || data[i] == '\'' || data[i] == '"' || isSpace(data[i]) { } else if data[i] == '>' || data[i] == '\'' || data[i] == '"' || IsSpace(data[i]) {
break break
} else { } else {
i++ i++
@ -1083,7 +1083,7 @@ func isMailtoAutoLink(data []byte) int {
// address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' // address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@'
for i, c := range data { for i, c := range data {
if isAlnum(c) { if IsAlnum(c) {
continue continue
} }
@ -1204,10 +1204,10 @@ func helperEmphasis(p *Parser, data []byte, c byte) (int, ast.Node) {
continue continue
} }
if data[i] == c && !isSpace(data[i-1]) { if data[i] == c && !IsSpace(data[i-1]) {
if p.extensions&NoIntraEmphasis != 0 { if p.extensions&NoIntraEmphasis != 0 {
if !(i+1 == len(data) || isSpace(data[i+1]) || isPunctuation(data[i+1])) { if !(i+1 == len(data) || IsSpace(data[i+1]) || IsPunctuation(data[i+1])) {
continue continue
} }
} }
@ -1231,7 +1231,7 @@ func helperDoubleEmphasis(p *Parser, data []byte, c byte) (int, ast.Node) {
} }
i += length i += length
if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isSpace(data[i-1]) { if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !IsSpace(data[i-1]) {
var node ast.Node = &ast.Strong{} var node ast.Node = &ast.Strong{}
if c == '~' { if c == '~' {
node = &ast.Del{} node = &ast.Del{}
@ -1257,7 +1257,7 @@ func helperTripleEmphasis(p *Parser, data []byte, offset int, c byte) (int, ast.
i += length i += length
// skip whitespace preceded symbols // skip whitespace preceded symbols
if data[i] != c || isSpace(data[i-1]) { if data[i] != c || IsSpace(data[i-1]) {
continue continue
} }

View File

@ -84,7 +84,9 @@ type Parser struct {
// the bottom will be used to fill in the link details. // the bottom will be used to fill in the link details.
ReferenceOverride ReferenceOverrideFunc ReferenceOverride ReferenceOverrideFunc
// TODO: documentation // IsSafeURLOverride allows overriding the default URL matcher. URL is
// safe if the overriding function returns true. Can be used to extend
// the default list of safe URLs.
IsSafeURLOverride func(url []byte) bool IsSafeURLOverride func(url []byte) bool
Opts Options Opts Options
@ -390,35 +392,35 @@ func (p *Parser) parseRefsToAST() {
// //
// Consider this markdown with reference-style links: // Consider this markdown with reference-style links:
// //
// [link][ref] // [link][ref]
// //
// [ref]: /url/ "tooltip title" // [ref]: /url/ "tooltip title"
// //
// It will be ultimately converted to this HTML: // It will be ultimately converted to this HTML:
// //
// <p><a href=\"/url/\" title=\"title\">link</a></p> // <p><a href=\"/url/\" title=\"title\">link</a></p>
// //
// And a reference structure will be populated as follows: // And a reference structure will be populated as follows:
// //
// p.refs["ref"] = &reference{ // p.refs["ref"] = &reference{
// link: "/url/", // link: "/url/",
// title: "tooltip title", // title: "tooltip title",
// } // }
// //
// Alternatively, reference can contain information about a footnote. Consider // Alternatively, reference can contain information about a footnote. Consider
// this markdown: // this markdown:
// //
// Text needing a footnote.[^a] // Text needing a footnote.[^a]
// //
// [^a]: This is the note // [^a]: This is the note
// //
// A reference structure will be populated as follows: // A reference structure will be populated as follows:
// //
// p.refs["a"] = &reference{ // p.refs["a"] = &reference{
// link: "a", // link: "a",
// title: "This is the note", // title: "This is the note",
// noteID: <some positive int>, // noteID: <some positive int>,
// } // }
// //
// TODO: As you can see, it begs for splitting into two dedicated structures // TODO: As you can see, it begs for splitting into two dedicated structures
// for refs and for footnotes. // for refs and for footnotes.
@ -693,8 +695,8 @@ gatherLines:
return return
} }
// isPunctuation returns true if c is a punctuation symbol. // IsPunctuation returns true if c is a punctuation symbol.
func isPunctuation(c byte) bool { func IsPunctuation(c byte) bool {
for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") { for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") {
if c == r { if c == r {
return true return true
@ -703,20 +705,63 @@ func isPunctuation(c byte) bool {
return false return false
} }
// isSpace returns true if c is a white-space charactr // IsSpace returns true if c is a white-space charactr
func isSpace(c byte) bool { func IsSpace(c byte) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'
} }
// isLetter returns true if c is ascii letter // IsLetter returns true if c is ascii letter
func isLetter(c byte) bool { func IsLetter(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
} }
// isAlnum returns true if c is a digit or letter // IsAlnum returns true if c is a digit or letter
// TODO: check when this is looking for ASCII alnum and when it should use unicode // TODO: check when this is looking for ASCII alnum and when it should use unicode
func isAlnum(c byte) bool { func IsAlnum(c byte) bool {
return (c >= '0' && c <= '9') || isLetter(c) return (c >= '0' && c <= '9') || IsLetter(c)
}
var URIs = [][]byte{
[]byte("http://"),
[]byte("https://"),
[]byte("ftp://"),
[]byte("mailto:"),
}
var Paths = [][]byte{
[]byte("/"),
[]byte("./"),
[]byte("../"),
}
// IsSafeURL returns true if url starts with one of the valid schemes or is a relative path.
func IsSafeURL(url []byte) bool {
nLink := len(url)
for _, path := range Paths {
nPath := len(path)
linkPrefix := url[:nPath]
if nLink >= nPath && bytes.Equal(linkPrefix, path) {
if nLink == nPath {
return true
} else if IsAlnum(url[nPath]) {
return true
}
}
}
for _, prefix := range URIs {
// TODO: handle unicode here
// case-insensitive prefix test
nPrefix := len(prefix)
if nLink > nPrefix {
linkPrefix := bytes.ToLower(url[:nPrefix])
if bytes.Equal(linkPrefix, prefix) && IsAlnum(url[nPrefix]) {
return true
}
}
}
return false
} }
// TODO: this is not used // TODO: this is not used
@ -809,7 +854,7 @@ func slugify(in []byte) []byte {
sym := false sym := false
for _, ch := range in { for _, ch := range in {
if isAlnum(ch) { if IsAlnum(ch) {
sym = false sym = false
out = append(out, ch) out = append(out, ch)
} else if sym { } else if sym {

View File

@ -7,8 +7,8 @@ import (
"github.com/gomarkdown/markdown/ast" "github.com/gomarkdown/markdown/ast"
) )
// parse '(#r)', where r does not contain spaces. Or. // parse '(#r, text)', where r does not contain spaces, but text may (similar to a citation). Or. (!item) (!item,
// (!item) (!item, subitem), for an index, (!!item) signals primary. // subitem), for an index, (!!item) signals primary.
func maybeShortRefOrIndex(p *Parser, data []byte, offset int) (int, ast.Node) { func maybeShortRefOrIndex(p *Parser, data []byte, offset int) (int, ast.Node) {
if len(data[offset:]) < 4 { if len(data[offset:]) < 4 {
return 0, nil return 0, nil
@ -25,8 +25,8 @@ func maybeShortRefOrIndex(p *Parser, data []byte, offset int) (int, ast.Node) {
switch { switch {
case c == ')': case c == ')':
break Loop break Loop
case !isAlnum(c): case !IsAlnum(c):
if c == '_' || c == '-' || c == ':' { if c == '_' || c == '-' || c == ':' || c == ' ' || c == ',' {
i++ i++
continue continue
} }
@ -45,6 +45,21 @@ func maybeShortRefOrIndex(p *Parser, data []byte, offset int) (int, ast.Node) {
id := data[2:i] id := data[2:i]
node := &ast.CrossReference{} node := &ast.CrossReference{}
node.Destination = id node.Destination = id
if c := bytes.Index(id, []byte(",")); c > 0 {
idpart := id[:c]
suff := id[c+1:]
suff = bytes.TrimSpace(suff)
node.Destination = idpart
node.Suffix = suff
}
if bytes.Index(node.Destination, []byte(" ")) > 0 {
// no spaces allowed in id
return 0, nil
}
if bytes.Index(node.Destination, []byte(",")) > 0 {
// nor comma
return 0, nil
}
return i + 1, node return i + 1, node

View File

@ -1,5 +1,17 @@
# Changelog # Changelog
## v4.9.0 - 2022-09-04
**Security**
* Fix open redirect vulnerability in handlers serving static directories (e.Static, e.StaticFs, echo.StaticDirectoryHandler) [#2260](https://github.com/labstack/echo/pull/2260)
**Enhancements**
* Allow configuring ErrorHandler in CSRF middleware [#2257](https://github.com/labstack/echo/pull/2257)
* Replace HTTP method constants in tests with stdlib constants [#2247](https://github.com/labstack/echo/pull/2247)
## v4.8.0 - 2022-08-10 ## v4.8.0 - 2022-08-10
**Most notable things** **Most notable things**

View File

@ -1,33 +1,49 @@
//go:build !go1.16
// +build !go1.16
package echo package echo
import ( import (
"errors"
"io"
"io/fs"
"net/http" "net/http"
"os"
"path/filepath" "path/filepath"
) )
func (c *context) File(file string) (err error) { func (c *context) File(file string) error {
f, err := os.Open(file) return fsFile(c, file, c.echo.Filesystem)
}
// FileFS serves file from given file system.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (c *context) FileFS(file string, filesystem fs.FS) error {
return fsFile(c, file, filesystem)
}
func fsFile(c Context, file string, filesystem fs.FS) error {
f, err := filesystem.Open(file)
if err != nil { if err != nil {
return NotFoundHandler(c) return ErrNotFound
} }
defer f.Close() defer f.Close()
fi, _ := f.Stat() fi, _ := f.Stat()
if fi.IsDir() { if fi.IsDir() {
file = filepath.Join(file, indexPage) file = filepath.ToSlash(filepath.Join(file, indexPage)) // ToSlash is necessary for Windows. fs.Open and os.Open are different in that aspect.
f, err = os.Open(file) f, err = filesystem.Open(file)
if err != nil { if err != nil {
return NotFoundHandler(c) return ErrNotFound
} }
defer f.Close() defer f.Close()
if fi, err = f.Stat(); err != nil { if fi, err = f.Stat(); err != nil {
return return err
} }
} }
http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f) ff, ok := f.(io.ReadSeeker)
return if !ok {
return errors.New("file does not implement io.ReadSeeker")
}
http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), ff)
return nil
} }

View File

@ -1,52 +0,0 @@
//go:build go1.16
// +build go1.16
package echo
import (
"errors"
"io"
"io/fs"
"net/http"
"path/filepath"
)
func (c *context) File(file string) error {
return fsFile(c, file, c.echo.Filesystem)
}
// FileFS serves file from given file system.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (c *context) FileFS(file string, filesystem fs.FS) error {
return fsFile(c, file, filesystem)
}
func fsFile(c Context, file string, filesystem fs.FS) error {
f, err := filesystem.Open(file)
if err != nil {
return ErrNotFound
}
defer f.Close()
fi, _ := f.Stat()
if fi.IsDir() {
file = filepath.ToSlash(filepath.Join(file, indexPage)) // ToSlash is necessary for Windows. fs.Open and os.Open are different in that aspect.
f, err = filesystem.Open(file)
if err != nil {
return ErrNotFound
}
defer f.Close()
if fi, err = f.Stat(); err != nil {
return err
}
}
ff, ok := f.(io.ReadSeeker)
if !ok {
return errors.New("file does not implement io.ReadSeeker")
}
http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), ff)
return nil
}

View File

@ -248,7 +248,7 @@ const (
const ( const (
// Version of Echo // Version of Echo
Version = "4.8.0" Version = "4.9.0"
website = "https://echo.labstack.com" website = "https://echo.labstack.com"
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo // http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
banner = ` banner = `

View File

@ -1,62 +1,175 @@
//go:build !go1.16
// +build !go1.16
package echo package echo
import ( import (
"fmt"
"io/fs"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"strings"
) )
type filesystem struct { type filesystem struct {
// Filesystem is file system used by Static and File handlers to access files.
// Defaults to os.DirFS(".")
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
Filesystem fs.FS
} }
func createFilesystem() filesystem { func createFilesystem() filesystem {
return filesystem{} return filesystem{
} Filesystem: newDefaultFS(),
// Static registers a new route with path prefix to serve static files from the
// provided root directory.
func (e *Echo) Static(prefix, root string) *Route {
if root == "" {
root = "." // For security we want to restrict to CWD.
} }
return e.static(prefix, root, e.GET)
} }
func (common) static(prefix, root string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route) *Route { // Static registers a new route with path prefix to serve static files from the provided root directory.
h := func(c Context) error { func (e *Echo) Static(pathPrefix, fsRoot string) *Route {
p, err := url.PathUnescape(c.Param("*")) subFs := MustSubFS(e.Filesystem, fsRoot)
if err != nil { return e.Add(
return err http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(subFs, false),
)
}
// StaticFS registers a new route with path prefix to serve static files from the provided file system.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (e *Echo) StaticFS(pathPrefix string, filesystem fs.FS) *Route {
return e.Add(
http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(filesystem, false),
)
}
// StaticDirectoryHandler creates handler function to serve files from provided file system
// When disablePathUnescaping is set then file name from path is not unescaped and is served as is.
func StaticDirectoryHandler(fileSystem fs.FS, disablePathUnescaping bool) HandlerFunc {
return func(c Context) error {
p := c.Param("*")
if !disablePathUnescaping { // when router is already unescaping we do not want to do is twice
tmpPath, err := url.PathUnescape(p)
if err != nil {
return fmt.Errorf("failed to unescape path variable: %w", err)
}
p = tmpPath
} }
name := filepath.Join(root, filepath.Clean("/"+p)) // "/"+ for security // fs.FS.Open() already assumes that file names are relative to FS root path and considers name with prefix `/` as invalid
fi, err := os.Stat(name) name := filepath.ToSlash(filepath.Clean(strings.TrimPrefix(p, "/")))
fi, err := fs.Stat(fileSystem, name)
if err != nil { if err != nil {
// The access path does not exist return ErrNotFound
return NotFoundHandler(c)
} }
// If the request is for a directory and does not end with "/" // If the request is for a directory and does not end with "/"
p = c.Request().URL.Path // path must not be empty. p = c.Request().URL.Path // path must not be empty.
if fi.IsDir() && p[len(p)-1] != '/' { if fi.IsDir() && len(p) > 0 && p[len(p)-1] != '/' {
// Redirect to ends with "/" // Redirect to ends with "/"
return c.Redirect(http.StatusMovedPermanently, p+"/") return c.Redirect(http.StatusMovedPermanently, sanitizeURI(p+"/"))
} }
return c.File(name) return fsFile(c, name, fileSystem)
} }
// Handle added routes based on trailing slash: }
// /prefix => exact route "/prefix" + any route "/prefix/*"
// /prefix/ => only any route "/prefix/*" // FileFS registers a new route with path to serve file from the provided file system.
if prefix != "" { func (e *Echo) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
if prefix[len(prefix)-1] == '/' { return e.GET(path, StaticFileHandler(file, filesystem), m...)
// Only add any route for intentional trailing slash }
return get(prefix+"*", h)
} // StaticFileHandler creates handler function to serve file from provided file system
get(prefix, h) func StaticFileHandler(file string, filesystem fs.FS) HandlerFunc {
} return func(c Context) error {
return get(prefix+"/*", h) return fsFile(c, file, filesystem)
}
}
// defaultFS exists to preserve pre v4.7.0 behaviour where files were open by `os.Open`.
// v4.7 introduced `echo.Filesystem` field which is Go1.16+ `fs.Fs` interface.
// Difference between `os.Open` and `fs.Open` is that FS does not allow opening path that start with `.`, `..` or `/`
// etc. For example previously you could have `../images` in your application but `fs := os.DirFS("./")` would not
// allow you to use `fs.Open("../images")` and this would break all old applications that rely on being able to
// traverse up from current executable run path.
// NB: private because you really should use fs.FS implementation instances
type defaultFS struct {
prefix string
fs fs.FS
}
func newDefaultFS() *defaultFS {
dir, _ := os.Getwd()
return &defaultFS{
prefix: dir,
fs: nil,
}
}
func (fs defaultFS) Open(name string) (fs.File, error) {
if fs.fs == nil {
return os.Open(name)
}
return fs.fs.Open(name)
}
func subFS(currentFs fs.FS, root string) (fs.FS, error) {
root = filepath.ToSlash(filepath.Clean(root)) // note: fs.FS operates only with slashes. `ToSlash` is necessary for Windows
if dFS, ok := currentFs.(*defaultFS); ok {
// we need to make exception for `defaultFS` instances as it interprets root prefix differently from fs.FS.
// fs.Fs.Open does not like relative paths ("./", "../") and absolute paths at all but prior echo.Filesystem we
// were able to use paths like `./myfile.log`, `/etc/hosts` and these would work fine with `os.Open` but not with fs.Fs
if isRelativePath(root) {
root = filepath.Join(dFS.prefix, root)
}
return &defaultFS{
prefix: root,
fs: os.DirFS(root),
}, nil
}
return fs.Sub(currentFs, root)
}
func isRelativePath(path string) bool {
if path == "" {
return true
}
if path[0] == '/' {
return false
}
if runtime.GOOS == "windows" && strings.IndexByte(path, ':') != -1 {
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#file_and_directory_names
// https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats
return false
}
return true
}
// MustSubFS creates sub FS from current filesystem or panic on failure.
// Panic happens when `fsRoot` contains invalid path according to `fs.ValidPath` rules.
//
// MustSubFS is helpful when dealing with `embed.FS` because for example `//go:embed assets/images` embeds files with
// paths including `assets/images` as their prefix. In that case use `fs := echo.MustSubFS(fs, "rootDirectory") to
// create sub fs which uses necessary prefix for directory path.
func MustSubFS(currentFs fs.FS, fsRoot string) fs.FS {
subFs, err := subFS(currentFs, fsRoot)
if err != nil {
panic(fmt.Errorf("can not create sub FS, invalid root given, err: %w", err))
}
return subFs
}
func sanitizeURI(uri string) string {
// double slash `\\`, `//` or even `\/` is absolute uri for browsers and by redirecting request to that uri
// we are vulnerable to open redirect attack. so replace all slashes from the beginning with single slash
if len(uri) > 1 && (uri[0] == '\\' || uri[0] == '/') && (uri[1] == '\\' || uri[1] == '/') {
uri = "/" + strings.TrimLeft(uri, `/\`)
}
return uri
} }

View File

@ -1,169 +0,0 @@
//go:build go1.16
// +build go1.16
package echo
import (
"fmt"
"io/fs"
"net/http"
"net/url"
"os"
"path/filepath"
"runtime"
"strings"
)
type filesystem struct {
// Filesystem is file system used by Static and File handlers to access files.
// Defaults to os.DirFS(".")
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
Filesystem fs.FS
}
func createFilesystem() filesystem {
return filesystem{
Filesystem: newDefaultFS(),
}
}
// Static registers a new route with path prefix to serve static files from the provided root directory.
func (e *Echo) Static(pathPrefix, fsRoot string) *Route {
subFs := MustSubFS(e.Filesystem, fsRoot)
return e.Add(
http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(subFs, false),
)
}
// StaticFS registers a new route with path prefix to serve static files from the provided file system.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (e *Echo) StaticFS(pathPrefix string, filesystem fs.FS) *Route {
return e.Add(
http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(filesystem, false),
)
}
// StaticDirectoryHandler creates handler function to serve files from provided file system
// When disablePathUnescaping is set then file name from path is not unescaped and is served as is.
func StaticDirectoryHandler(fileSystem fs.FS, disablePathUnescaping bool) HandlerFunc {
return func(c Context) error {
p := c.Param("*")
if !disablePathUnescaping { // when router is already unescaping we do not want to do is twice
tmpPath, err := url.PathUnescape(p)
if err != nil {
return fmt.Errorf("failed to unescape path variable: %w", err)
}
p = tmpPath
}
// fs.FS.Open() already assumes that file names are relative to FS root path and considers name with prefix `/` as invalid
name := filepath.ToSlash(filepath.Clean(strings.TrimPrefix(p, "/")))
fi, err := fs.Stat(fileSystem, name)
if err != nil {
return ErrNotFound
}
// If the request is for a directory and does not end with "/"
p = c.Request().URL.Path // path must not be empty.
if fi.IsDir() && len(p) > 0 && p[len(p)-1] != '/' {
// Redirect to ends with "/"
return c.Redirect(http.StatusMovedPermanently, p+"/")
}
return fsFile(c, name, fileSystem)
}
}
// FileFS registers a new route with path to serve file from the provided file system.
func (e *Echo) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
return e.GET(path, StaticFileHandler(file, filesystem), m...)
}
// StaticFileHandler creates handler function to serve file from provided file system
func StaticFileHandler(file string, filesystem fs.FS) HandlerFunc {
return func(c Context) error {
return fsFile(c, file, filesystem)
}
}
// defaultFS exists to preserve pre v4.7.0 behaviour where files were open by `os.Open`.
// v4.7 introduced `echo.Filesystem` field which is Go1.16+ `fs.Fs` interface.
// Difference between `os.Open` and `fs.Open` is that FS does not allow opening path that start with `.`, `..` or `/`
// etc. For example previously you could have `../images` in your application but `fs := os.DirFS("./")` would not
// allow you to use `fs.Open("../images")` and this would break all old applications that rely on being able to
// traverse up from current executable run path.
// NB: private because you really should use fs.FS implementation instances
type defaultFS struct {
prefix string
fs fs.FS
}
func newDefaultFS() *defaultFS {
dir, _ := os.Getwd()
return &defaultFS{
prefix: dir,
fs: nil,
}
}
func (fs defaultFS) Open(name string) (fs.File, error) {
if fs.fs == nil {
return os.Open(name)
}
return fs.fs.Open(name)
}
func subFS(currentFs fs.FS, root string) (fs.FS, error) {
root = filepath.ToSlash(filepath.Clean(root)) // note: fs.FS operates only with slashes. `ToSlash` is necessary for Windows
if dFS, ok := currentFs.(*defaultFS); ok {
// we need to make exception for `defaultFS` instances as it interprets root prefix differently from fs.FS.
// fs.Fs.Open does not like relative paths ("./", "../") and absolute paths at all but prior echo.Filesystem we
// were able to use paths like `./myfile.log`, `/etc/hosts` and these would work fine with `os.Open` but not with fs.Fs
if isRelativePath(root) {
root = filepath.Join(dFS.prefix, root)
}
return &defaultFS{
prefix: root,
fs: os.DirFS(root),
}, nil
}
return fs.Sub(currentFs, root)
}
func isRelativePath(path string) bool {
if path == "" {
return true
}
if path[0] == '/' {
return false
}
if runtime.GOOS == "windows" && strings.IndexByte(path, ':') != -1 {
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#file_and_directory_names
// https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats
return false
}
return true
}
// MustSubFS creates sub FS from current filesystem or panic on failure.
// Panic happens when `fsRoot` contains invalid path according to `fs.ValidPath` rules.
//
// MustSubFS is helpful when dealing with `embed.FS` because for example `//go:embed assets/images` embeds files with
// paths including `assets/images` as their prefix. In that case use `fs := echo.MustSubFS(fs, "rootDirectory") to
// create sub fs which uses necessary prefix for directory path.
func MustSubFS(currentFs fs.FS, fsRoot string) fs.FS {
subFs, err := subFS(currentFs, fsRoot)
if err != nil {
panic(fmt.Errorf("can not create sub FS, invalid root given, err: %w", err))
}
return subFs
}

View File

@ -1,9 +1,30 @@
//go:build !go1.16
// +build !go1.16
package echo package echo
import (
"io/fs"
"net/http"
)
// Static implements `Echo#Static()` for sub-routes within the Group. // Static implements `Echo#Static()` for sub-routes within the Group.
func (g *Group) Static(prefix, root string) { func (g *Group) Static(pathPrefix, fsRoot string) {
g.static(prefix, root, g.GET) subFs := MustSubFS(g.echo.Filesystem, fsRoot)
g.StaticFS(pathPrefix, subFs)
}
// StaticFS implements `Echo#StaticFS()` for sub-routes within the Group.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (g *Group) StaticFS(pathPrefix string, filesystem fs.FS) {
g.Add(
http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(filesystem, false),
)
}
// FileFS implements `Echo#FileFS()` for sub-routes within the Group.
func (g *Group) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
return g.GET(path, StaticFileHandler(file, filesystem), m...)
} }

View File

@ -1,33 +0,0 @@
//go:build go1.16
// +build go1.16
package echo
import (
"io/fs"
"net/http"
)
// Static implements `Echo#Static()` for sub-routes within the Group.
func (g *Group) Static(pathPrefix, fsRoot string) {
subFs := MustSubFS(g.echo.Filesystem, fsRoot)
g.StaticFS(pathPrefix, subFs)
}
// StaticFS implements `Echo#StaticFS()` for sub-routes within the Group.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (g *Group) StaticFS(pathPrefix string, filesystem fs.FS) {
g.Add(
http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(filesystem, false),
)
}
// FileFS implements `Echo#FileFS()` for sub-routes within the Group.
func (g *Group) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
return g.GET(path, StaticFileHandler(file, filesystem), m...)
}

View File

@ -61,7 +61,13 @@ type (
// Indicates SameSite mode of the CSRF cookie. // Indicates SameSite mode of the CSRF cookie.
// Optional. Default value SameSiteDefaultMode. // Optional. Default value SameSiteDefaultMode.
CookieSameSite http.SameSite `yaml:"cookie_same_site"` CookieSameSite http.SameSite `yaml:"cookie_same_site"`
// ErrorHandler defines a function which is executed for returning custom errors.
ErrorHandler CSRFErrorHandler
} }
// CSRFErrorHandler is a function which is executed for creating custom errors.
CSRFErrorHandler func(err error, c echo.Context) error
) )
// ErrCSRFInvalid is returned when CSRF check fails // ErrCSRFInvalid is returned when CSRF check fails
@ -154,8 +160,9 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
lastTokenErr = ErrCSRFInvalid lastTokenErr = ErrCSRFInvalid
} }
} }
var finalErr error
if lastTokenErr != nil { if lastTokenErr != nil {
return lastTokenErr finalErr = lastTokenErr
} else if lastExtractorErr != nil { } else if lastExtractorErr != nil {
// ugly part to preserve backwards compatible errors. someone could rely on them // ugly part to preserve backwards compatible errors. someone could rely on them
if lastExtractorErr == errQueryExtractorValueMissing { if lastExtractorErr == errQueryExtractorValueMissing {
@ -167,7 +174,14 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
} else { } else {
lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, lastExtractorErr.Error()) lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, lastExtractorErr.Error())
} }
return lastExtractorErr finalErr = lastExtractorErr
}
if finalErr != nil {
if config.ErrorHandler != nil {
return config.ErrorHandler(finalErr, c)
}
return finalErr
} }
} }

View File

@ -47,7 +47,13 @@
<!-- do not edit anything in this "template" block, its auto-generated --> <!-- do not edit anything in this "template" block, its auto-generated -->
## :link: Table of Contents ## :link: Table of Contents
- []() - [Features](#features)
- [Installing](#installing)
- [Examples](#examples)
- [References](#references)
- [Support &amp; Assistance](#raising_hand_man-support--assistance)
- [Contributing](#handshake-contributing)
- [License](#balance_scale-license)
<!-- template:end:toc --> <!-- template:end:toc -->
## Features ## Features
@ -112,24 +118,24 @@ Working on a project and want to add it to the list? Submit a pull request!
<!-- do not edit anything in this "template" block, its auto-generated --> <!-- do not edit anything in this "template" block, its auto-generated -->
## :raising_hand_man: Support & Assistance ## :raising_hand_man: Support & Assistance
* :heart: Please review the [Code of Conduct](.github/CODE_OF_CONDUCT.md) for * :heart: Please review the [Code of Conduct](.github/CODE_OF_CONDUCT.md) for
guidelines on ensuring everyone has the best experience interacting with guidelines on ensuring everyone has the best experience interacting with
the community. the community.
* :raising_hand_man: Take a look at the [support](.github/SUPPORT.md) document on * :raising_hand_man: Take a look at the [support](.github/SUPPORT.md) document on
guidelines for tips on how to ask the right questions. guidelines for tips on how to ask the right questions.
* :lady_beetle: For all features/bugs/issues/questions/etc, [head over here](https://github.com/lrstanley/girc/issues/new/choose). * :lady_beetle: For all features/bugs/issues/questions/etc, [head over here](https://github.com/lrstanley/girc/issues/new/choose).
<!-- template:end:support --> <!-- template:end:support -->
<!-- template:begin:contributing --> <!-- template:begin:contributing -->
<!-- do not edit anything in this "template" block, its auto-generated --> <!-- do not edit anything in this "template" block, its auto-generated -->
## :handshake: Contributing ## :handshake: Contributing
* :heart: Please review the [Code of Conduct](.github/CODE_OF_CONDUCT.md) for guidelines * :heart: Please review the [Code of Conduct](.github/CODE_OF_CONDUCT.md) for guidelines
on ensuring everyone has the best experience interacting with the on ensuring everyone has the best experience interacting with the
community. community.
* :clipboard: Please review the [contributing](.github/CONTRIBUTING.md) doc for submitting * :clipboard: Please review the [contributing](.github/CONTRIBUTING.md) doc for submitting
issues/a guide on submitting pull requests and helping out. issues/a guide on submitting pull requests and helping out.
* :old_key: For anything security related, please review this repositories [security policy](https://github.com/lrstanley/girc/security/policy). * :old_key: For anything security related, please review this repositories [security policy](https://github.com/lrstanley/girc/security/policy).
<!-- template:end:contributing --> <!-- template:end:contributing -->
<!-- template:begin:license --> <!-- template:begin:license -->

File diff suppressed because it is too large Load Diff

View File

@ -358,6 +358,7 @@ message HistorySyncNotification {
FULL = 2; FULL = 2;
RECENT = 3; RECENT = 3;
PUSH_NAME = 4; PUSH_NAME = 4;
NON_BLOCKING_DATA = 5;
} }
optional bytes fileSha256 = 1; optional bytes fileSha256 = 1;
optional uint64 fileLength = 2; optional uint64 fileLength = 2;
@ -1014,6 +1015,7 @@ message SendPaymentMessage {
enum RmrSource { enum RmrSource {
FAVORITE_STICKER = 0; FAVORITE_STICKER = 0;
RECENT_STICKER = 1; RECENT_STICKER = 1;
RECENT_STICKER_INIT = 2;
} }
message RequestPhoneNumberMessage { message RequestPhoneNumberMessage {
optional ContextInfo contextInfo = 1; optional ContextInfo contextInfo = 1;
@ -1132,6 +1134,7 @@ message StickerMetadata {
optional string directPath = 8; optional string directPath = 8;
optional uint64 fileLength = 9; optional uint64 fileLength = 9;
optional float weight = 10; optional float weight = 10;
optional int64 lastStickerSentTs = 11;
} }
message Pushname { message Pushname {
@ -1140,7 +1143,7 @@ message Pushname {
} }
message PastParticipants { message PastParticipants {
required string groupJid = 1; optional string groupJid = 1;
repeated PastParticipant pastParticipants = 2; repeated PastParticipant pastParticipants = 2;
} }
@ -1149,9 +1152,9 @@ message PastParticipant {
LEFT = 0; LEFT = 0;
REMOVED = 1; REMOVED = 1;
} }
required string userJid = 1; optional string userJid = 1;
required LeaveReason leaveReason = 2; optional LeaveReason leaveReason = 2;
required uint64 leaveTs = 3; optional uint64 leaveTs = 3;
} }
enum MediaVisibility { enum MediaVisibility {
@ -1166,7 +1169,7 @@ message HistorySync {
FULL = 2; FULL = 2;
RECENT = 3; RECENT = 3;
PUSH_NAME = 4; PUSH_NAME = 4;
UNBLOCKING_DATA = 5; NON_BLOCKING_DATA = 5;
} }
required HistorySyncType syncType = 1; required HistorySyncType syncType = 1;
repeated Conversation conversations = 2; repeated Conversation conversations = 2;
@ -1297,6 +1300,7 @@ message MsgOpaqueData {
repeated PollOption pollOptions = 18; repeated PollOption pollOptions = 18;
optional uint32 pollSelectableOptionsCount = 20; optional uint32 pollSelectableOptionsCount = 20;
optional bytes messageSecret = 21; optional bytes messageSecret = 21;
optional string originalSelfAuthorJid = 51;
optional int64 senderTimestampMs = 22; optional int64 senderTimestampMs = 22;
optional string pollUpdateParentKey = 23; optional string pollUpdateParentKey = 23;
optional PollEncValue encPollVote = 24; optional PollEncValue encPollVote = 24;
@ -1481,6 +1485,10 @@ message SecurityNotificationSetting {
optional bool showNotification = 1; optional bool showNotification = 1;
} }
message RemoveRecentStickerAction {
optional int64 lastStickerSentTs = 1;
}
message RecentEmojiWeightsAction { message RecentEmojiWeightsAction {
repeated RecentEmojiWeight weights = 1; repeated RecentEmojiWeight weights = 1;
} }
@ -2006,6 +2014,8 @@ message WebMessageInfo {
COMMUNITY_PARTICIPANT_PROMOTE = 147; COMMUNITY_PARTICIPANT_PROMOTE = 147;
COMMUNITY_PARTICIPANT_DEMOTE = 148; COMMUNITY_PARTICIPANT_DEMOTE = 148;
COMMUNITY_PARENT_GROUP_DELETED = 149; COMMUNITY_PARENT_GROUP_DELETED = 149;
COMMUNITY_LINK_PARENT_GROUP_MEMBERSHIP_APPROVAL = 150;
GROUP_PARTICIPANT_JOINED_GROUP_AND_PARENT_GROUP = 151;
} }
enum Status { enum Status {
ERROR = 0; ERROR = 0;

View File

@ -74,7 +74,7 @@ func (vc WAVersionContainer) ProtoAppVersion() *waProto.ClientPayload_UserAgent_
} }
// waVersion is the WhatsApp web client version // waVersion is the WhatsApp web client version
var waVersion = WAVersionContainer{2, 2228, 12} var waVersion = WAVersionContainer{2, 2230, 10}
// waVersionHash is the md5 hash of a dot-separated waVersion // waVersionHash is the md5 hash of a dot-separated waVersion
var waVersionHash [16]byte var waVersionHash [16]byte

17
vendor/modules.txt vendored
View File

@ -55,10 +55,10 @@ github.com/av-elier/go-decimal-to-rational
# github.com/blang/semver v3.5.1+incompatible # github.com/blang/semver v3.5.1+incompatible
## explicit ## explicit
github.com/blang/semver github.com/blang/semver
# github.com/bwmarrin/discordgo v0.25.0 # github.com/bwmarrin/discordgo v0.26.1
## explicit; go 1.13 ## explicit; go 1.13
github.com/bwmarrin/discordgo github.com/bwmarrin/discordgo
# github.com/d5/tengo/v2 v2.12.1 # github.com/d5/tengo/v2 v2.12.2
## explicit; go 1.13 ## explicit; go 1.13
github.com/d5/tengo/v2 github.com/d5/tengo/v2
github.com/d5/tengo/v2/parser github.com/d5/tengo/v2/parser
@ -93,12 +93,11 @@ github.com/golang-jwt/jwt
## explicit; go 1.9 ## explicit; go 1.9
github.com/golang/protobuf/proto github.com/golang/protobuf/proto
github.com/golang/protobuf/protoc-gen-go/descriptor github.com/golang/protobuf/protoc-gen-go/descriptor
# github.com/gomarkdown/markdown v0.0.0-20220731190611-dcdaee8e7a53 # github.com/gomarkdown/markdown v0.0.0-20220830015526-01a3c37d6f50
## explicit; go 1.12 ## explicit; go 1.12
github.com/gomarkdown/markdown github.com/gomarkdown/markdown
github.com/gomarkdown/markdown/ast github.com/gomarkdown/markdown/ast
github.com/gomarkdown/markdown/html github.com/gomarkdown/markdown/html
github.com/gomarkdown/markdown/internal/valid
github.com/gomarkdown/markdown/parser github.com/gomarkdown/markdown/parser
# github.com/google/gops v0.3.25 # github.com/google/gops v0.3.25
## explicit; go 1.13 ## explicit; go 1.13
@ -199,7 +198,7 @@ github.com/klauspost/cpuid/v2
# github.com/kyokomi/emoji/v2 v2.2.10 # github.com/kyokomi/emoji/v2 v2.2.10
## explicit; go 1.14 ## explicit; go 1.14
github.com/kyokomi/emoji/v2 github.com/kyokomi/emoji/v2
# github.com/labstack/echo/v4 v4.8.0 # github.com/labstack/echo/v4 v4.9.0
## explicit; go 1.17 ## explicit; go 1.17
github.com/labstack/echo/v4 github.com/labstack/echo/v4
github.com/labstack/echo/v4/middleware github.com/labstack/echo/v4/middleware
@ -209,7 +208,7 @@ github.com/labstack/gommon/bytes
github.com/labstack/gommon/color github.com/labstack/gommon/color
github.com/labstack/gommon/log github.com/labstack/gommon/log
github.com/labstack/gommon/random github.com/labstack/gommon/random
# github.com/lrstanley/girc v0.0.0-20220812131643-56459d73b75a # github.com/lrstanley/girc v0.0.0-20220821023908-8e7df6d970f8
## explicit; go 1.18 ## explicit; go 1.18
github.com/lrstanley/girc github.com/lrstanley/girc
# github.com/magiconair/properties v1.8.6 # github.com/magiconair/properties v1.8.6
@ -514,7 +513,7 @@ go.mau.fi/libsignal/util/errorhelper
go.mau.fi/libsignal/util/keyhelper go.mau.fi/libsignal/util/keyhelper
go.mau.fi/libsignal/util/medium go.mau.fi/libsignal/util/medium
go.mau.fi/libsignal/util/optional go.mau.fi/libsignal/util/optional
# go.mau.fi/whatsmeow v0.0.0-20220804175245-31c5af44cb82 # go.mau.fi/whatsmeow v0.0.0-20220811191500-f650c10b0068
## explicit; go 1.17 ## explicit; go 1.17
go.mau.fi/whatsmeow go.mau.fi/whatsmeow
go.mau.fi/whatsmeow/appstate go.mau.fi/whatsmeow/appstate
@ -567,7 +566,7 @@ golang.org/x/crypto/scrypt
golang.org/x/crypto/ssh golang.org/x/crypto/ssh
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
golang.org/x/crypto/ssh/terminal golang.org/x/crypto/ssh/terminal
# golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 # golang.org/x/image v0.0.0-20220902085622-e7cb96979f69
## explicit; go 1.12 ## explicit; go 1.12
golang.org/x/image/riff golang.org/x/image/riff
golang.org/x/image/vp8 golang.org/x/image/vp8
@ -589,7 +588,7 @@ golang.org/x/net/http2/hpack
golang.org/x/net/idna golang.org/x/net/idna
golang.org/x/net/publicsuffix golang.org/x/net/publicsuffix
golang.org/x/net/websocket golang.org/x/net/websocket
# golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7 # golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
## explicit; go 1.17 ## explicit; go 1.17
golang.org/x/oauth2 golang.org/x/oauth2
golang.org/x/oauth2/clientcredentials golang.org/x/oauth2/clientcredentials