Update dependencies for 1.18.0 release (#1175)

This commit is contained in:
Wim 2020-07-18 17:27:41 +02:00 committed by GitHub
parent 3b6a8be07b
commit 23d8742f0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
174 changed files with 2158 additions and 2164 deletions

19
go.mod
View File

@ -6,12 +6,12 @@ require (
github.com/Jeffail/gabs v1.1.1 // indirect github.com/Jeffail/gabs v1.1.1 // indirect
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0 github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0
github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334 github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334
github.com/d5/tengo/v2 v2.4.2 github.com/d5/tengo/v2 v2.6.0
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/fsnotify/fsnotify v1.4.9 github.com/fsnotify/fsnotify v1.4.9
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81
github.com/gomarkdown/markdown v0.0.0-20200127000047-1813ea067497 github.com/gomarkdown/markdown v0.0.0-20200609195525-3f9352745725
github.com/google/gops v0.3.6 github.com/google/gops v0.3.10
github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect
github.com/gorilla/schema v1.1.0 github.com/gorilla/schema v1.1.0
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
@ -22,7 +22,7 @@ require (
github.com/labstack/echo/v4 v4.1.16 github.com/labstack/echo/v4 v4.1.16
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7 github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048 github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048
github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3 github.com/matterbridge/discordgo v0.21.2-0.20200718144317-01fe5db6c78d
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050 github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050
github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6 github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6
@ -45,15 +45,14 @@ require (
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98 github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98
github.com/sirupsen/logrus v1.6.0 github.com/sirupsen/logrus v1.6.0
github.com/slack-go/slack v0.6.4 github.com/slack-go/slack v0.6.5
github.com/spf13/viper v1.7.0 github.com/spf13/viper v1.7.0
github.com/stretchr/testify v1.5.1 github.com/stretchr/testify v1.5.1
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/writeas/go-strip-markdown v2.0.1+incompatible github.com/writeas/go-strip-markdown v2.0.1+incompatible
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
github.com/yaegashi/msgraph.go v0.1.2 github.com/yaegashi/msgraph.go v0.1.3
github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2 github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 golang.org/x/image v0.0.0-20200618115811-c13761719519
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gomod.garykim.dev/nc-talk v0.0.1 gomod.garykim.dev/nc-talk v0.0.1
gopkg.in/fsnotify.v1 v1.4.7 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect
@ -61,6 +60,4 @@ require (
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
) )
//replace github.com/bwmarrin/discordgo v0.20.2 => github.com/matterbridge/discordgo v0.18.1-0.20200109173909-ed873362fa43
go 1.13 go 1.13

74
go.sum
View File

@ -30,10 +30,9 @@ github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/g
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU= github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw= github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM= github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM=
github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58 h1:MkpmYfld/S8kXqTYI68DfL8/hHXjHogL120Dy00TIxc=
github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58/go.mod h1:YNfsMyWSs+h+PaYkxGeMVmVCX75Zj/pqdjbu12ciCYE= github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58/go.mod h1:YNfsMyWSs+h+PaYkxGeMVmVCX75Zj/pqdjbu12ciCYE=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@ -49,8 +48,8 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/d5/tengo/v2 v2.4.2 h1:Sj+v0CS8jtrZrXyJLzWof6QTnE6S5k3tYP0y6YVPGkw= github.com/d5/tengo/v2 v2.6.0 h1:D0cJtpiBzaLJ/Smv6nnUc/LIfO46oKwDx85NZtIRNRI=
github.com/d5/tengo/v2 v2.4.2/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8= github.com/d5/tengo/v2 v2.6.0/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8=
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=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -58,7 +57,6 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@ -67,10 +65,10 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible h1:i64CCJcSqkRIkm5OSdZQjZq84/gJsk2zNwHWIRYWlKE= github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81 h1:FdZThbRF0R+2qgyBl3KCVNWWBmKm68E+stT3rnQ02Ww=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81/go.mod h1:lDm2E64X4OjFdBUA4hlN4mEvbSitvhJdKw7rsA8KHgI=
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -82,18 +80,17 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gomarkdown/markdown v0.0.0-20200127000047-1813ea067497 h1:wJkj+x9gPYlDyM34C6r3SXPs270coWeh85wu1CsusDo= github.com/gomarkdown/markdown v0.0.0-20200609195525-3f9352745725 h1:X6sZdr+t2E2jwajTy/FfXbmAKPFTYxEq9hiFgzMiuPQ=
github.com/gomarkdown/markdown v0.0.0-20200127000047-1813ea067497/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU= github.com/gomarkdown/markdown v0.0.0-20200609195525-3f9352745725/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU=
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=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gops v0.3.6 h1:6akvbMlpZrEYOuoebn2kR+ZJekbZqJ28fJXTs84+8to= github.com/google/gops v0.3.10 h1:M2XZYgfUW+P7AOCLiu4CRb0rQfwnslLyB4B9Mp0vXmE=
github.com/google/gops v0.3.6/go.mod h1:RZ1rH95wsAGX4vMWKmqBOIWynmWisBf4QFdgT/k/xOI= github.com/google/gops v0.3.10/go.mod h1:38bMPVKFh+1X106CPpbLAWtZIR1+xwgzT9gew0kn6w4=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -107,9 +104,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGa
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY= github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@ -151,15 +146,11 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/keybase/go-keybase-chat-bot v0.0.0-20200505163032-5cacf52379da h1:LK+8uBG3kNikj664cjFt88RBmuGmonxkXv2rUVfbqz4= github.com/keybase/go-keybase-chat-bot v0.0.0-20200505163032-5cacf52379da h1:LK+8uBG3kNikj664cjFt88RBmuGmonxkXv2rUVfbqz4=
github.com/keybase/go-keybase-chat-bot v0.0.0-20200505163032-5cacf52379da/go.mod h1:xJA+X9ZVyT/irGldcb7q1XnJBq5F9s5H9h2L44Y+poY= github.com/keybase/go-keybase-chat-bot v0.0.0-20200505163032-5cacf52379da/go.mod h1:xJA+X9ZVyT/irGldcb7q1XnJBq5F9s5H9h2L44Y+poY=
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999 h1:2d+FLQbz4xRTi36DO1qYNUwfORax9XcQ0jhbO81Vago= github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -179,8 +170,8 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048 h1:B9HaistmV+MD8/33BXmZe1zPIn+RImAFVXNNSOrwU2E= github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048 h1:B9HaistmV+MD8/33BXmZe1zPIn+RImAFVXNNSOrwU2E=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A= github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3 h1:VP/DNRn2HtrVRN6+X3h4FDcQI2OOKT+88WUi21ZD1Kw= github.com/matterbridge/discordgo v0.21.2-0.20200718144317-01fe5db6c78d h1:NBckP4nw7qVspbt7cOZYsrOrEbq7tATdMjSjc1hW63A=
github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3/go.mod h1:5a1bHtG/38ofcx9cgwM5eTW/Pl4SpbQksNDnTRcGA2Y= github.com/matterbridge/discordgo v0.21.2-0.20200718144317-01fe5db6c78d/go.mod h1:411nZYv0UMMrtppR5glXop1foboJiFAowy+42U+Ahvw=
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible h1:oaOqwbg5HxHRxvAbd84ks0Okwoc1ISyUZ87EiVJFhGI= github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible h1:oaOqwbg5HxHRxvAbd84ks0Okwoc1ISyUZ87EiVJFhGI=
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible/go.mod h1:igE6rUAn3jai2wCdsjFHfhUoekjrFthoEjFObKKwSb4= github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible/go.mod h1:igE6rUAn3jai2wCdsjFHfhUoekjrFthoEjFObKKwSb4=
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050 h1:kWkP1lXpkvtoNL08jkP3XQH/zvDOEXJpdCJd/DlIvMw= github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050 h1:kWkP1lXpkvtoNL08jkP3XQH/zvDOEXJpdCJd/DlIvMw=
@ -280,15 +271,14 @@ github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 h1:Lx3BlDGFElJt4u/zK
github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1/go.mod h1:vt2jWY/3Qw1bIzle5thrJWucsLuuX9iUNnp20CqCciI= github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1/go.mod h1:vt2jWY/3Qw1bIzle5thrJWucsLuuX9iUNnp20CqCciI=
github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98 h1:sN07ff+PSRsUNhpSod4uGKAQ+Nc0FXsBPG9FmYMNg4w= github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98 h1:sN07ff+PSRsUNhpSod4uGKAQ+Nc0FXsBPG9FmYMNg4w=
github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98/go.mod h1:xkTgfD+WP+KR4HuG76oal25BBEeu5kJyi2EOsgiu/4Q= github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98/go.mod h1:xkTgfD+WP+KR4HuG76oal25BBEeu5kJyi2EOsgiu/4Q=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v2.20.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE= github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE=
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo= github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
github.com/slack-go/slack v0.6.4 h1:cxOqFgM5RW6mdEyDqAJutFk3qiORK9oHRKi5bPqkY9o= github.com/slack-go/slack v0.6.5 h1:IkDKtJ2IROJNoe3d6mW870/NRKvq2fhLB/Q5XmzWk00=
github.com/slack-go/slack v0.6.4/go.mod h1:sGRjv3w+ERAUMMMbldHObQPBcNSyVB7KLKYfnwUFBfw= github.com/slack-go/slack v0.6.5/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
@ -309,7 +299,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
@ -328,9 +317,11 @@ github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9p
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v1.0.0/go.mod h1:IoImgRak9i3zJyuxOKUP1v4UZd1tMoKkq/Cimt1uhCg=
github.com/yaegashi/msgraph.go v0.1.2 h1:83uVRQaj8YBsVqOUGj0WRwzxdgGF69jRpg5IQYaTvoY= github.com/yaegashi/msgraph.go v0.1.3 h1:xeknrGbPGqUVvjjtXGuxvesHLNJ6jEfiOtqJToZe0qw=
github.com/yaegashi/msgraph.go v0.1.2/go.mod h1:Lp39e9oo596G5FcmMKI0cXR3mg/QikSdabgZdbMqbAM= github.com/yaegashi/msgraph.go v0.1.3/go.mod h1:dpty8G9hMEC1xBQeXp6Z2hCXKalqczk2BLvK9me/TUU=
github.com/yaegashi/wtz.go v0.0.2/go.mod h1:nOLA5QXsmdkRxBkP5tljhua13ADHCKirLBrzPf4PEJc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2 h1:UQwvu7FjUEdVYofx0U6bsc5odNE7wa5TSA0fl559GcA= github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2 h1:UQwvu7FjUEdVYofx0U6bsc5odNE7wa5TSA0fl559GcA=
github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2/go.mod h1:0MsIttMJIF/8Y7x0XjonJP7K99t3sR6bjj4m5S4JmqU= github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2/go.mod h1:0MsIttMJIF/8Y7x0XjonJP7K99t3sR6bjj4m5S4JmqU=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@ -345,14 +336,15 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ= golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -360,8 +352,8 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -373,6 +365,7 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -402,8 +395,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20171017063910-8dbc5d05d6ed/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -424,8 +417,9 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@ -449,7 +443,11 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200529172331-a64b76657301/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomod.garykim.dev/nc-talk v0.0.1 h1:6mgjcAf5/HMkV0CFGeXVfYHG7FAUCQcGR8eg9oM6fCc= gomod.garykim.dev/nc-talk v0.0.1 h1:6mgjcAf5/HMkV0CFGeXVfYHG7FAUCQcGR8eg9oM6fCc=
gomod.garykim.dev/nc-talk v0.0.1/go.mod h1:0/Ksg0osAYmnWKs1OcCG+gBQ4HU1xiF1699g9B6jWZw= gomod.garykim.dev/nc-talk v0.0.1/go.mod h1:0/Ksg0osAYmnWKs1OcCG+gBQ4HU1xiF1699g9B6jWZw=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@ -458,7 +456,6 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
@ -493,7 +490,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -502,4 +498,4 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/goversion v1.0.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo= rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=

View File

@ -506,7 +506,11 @@ func (c *Compiler) Compile(node parser.Node) error {
return err return err
} }
} }
c.emit(node, parser.OpCall, len(node.Args)) ellipsis := 0
if node.Ellipsis.IsValid() {
ellipsis = 1
}
c.emit(node, parser.OpCall, len(node.Args), ellipsis)
case *parser.ImportExpr: case *parser.ImportExpr:
if node.ModuleName == "" { if node.ModuleName == "" {
return c.errorf(node, "empty module name") return c.errorf(node, "empty module name")
@ -526,7 +530,7 @@ func (c *Compiler) Compile(node parser.Node) error {
return err return err
} }
c.emit(node, parser.OpConstant, c.addConstant(compiled)) c.emit(node, parser.OpConstant, c.addConstant(compiled))
c.emit(node, parser.OpCall, 0) c.emit(node, parser.OpCall, 0, 0)
case Object: // builtin module case Object: // builtin module
c.emit(node, parser.OpConstant, c.addConstant(v)) c.emit(node, parser.OpConstant, c.addConstant(v))
default: default:
@ -556,7 +560,7 @@ func (c *Compiler) Compile(node parser.Node) error {
return err return err
} }
c.emit(node, parser.OpConstant, c.addConstant(compiled)) c.emit(node, parser.OpConstant, c.addConstant(compiled))
c.emit(node, parser.OpCall, 0) c.emit(node, parser.OpCall, 0, 0)
} else { } else {
return c.errorf(node, "module '%s' not found", node.ModuleName) return c.errorf(node, "module '%s' not found", node.ModuleName)
} }

View File

@ -1342,6 +1342,38 @@ func (o *String) BinaryOp(op token.Token, rhs Object) (Object, error) {
} }
return &String{Value: o.Value + rhsStr}, nil return &String{Value: o.Value + rhsStr}, nil
} }
case token.Less:
switch rhs := rhs.(type) {
case *String:
if o.Value < rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
}
case token.LessEq:
switch rhs := rhs.(type) {
case *String:
if o.Value <= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
}
case token.Greater:
switch rhs := rhs.(type) {
case *String:
if o.Value > rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
}
case token.GreaterEq:
switch rhs := rhs.(type) {
case *String:
if o.Value >= rhs.Value {
return TrueValue, nil
}
return FalseValue, nil
}
} }
return nil, ErrInvalidOperator return nil, ErrInvalidOperator
} }

View File

@ -114,6 +114,7 @@ type CallExpr struct {
Func Expr Func Expr
LParen Pos LParen Pos
Args []Expr Args []Expr
Ellipsis Pos
RParen Pos RParen Pos
} }
@ -134,6 +135,9 @@ func (e *CallExpr) String() string {
for _, e := range e.Args { for _, e := range e.Args {
args = append(args, e.String()) args = append(args, e.String())
} }
if len(args) > 0 && e.Ellipsis.IsValid() {
args[len(args)-1] = args[len(args)-1] + "..."
}
return e.Func.String() + "(" + strings.Join(args, ", ") + ")" return e.Func.String() + "(" + strings.Join(args, ", ") + ")"
} }

View File

@ -120,7 +120,7 @@ var OpcodeOperands = [...][]int{
OpImmutable: {}, OpImmutable: {},
OpIndex: {}, OpIndex: {},
OpSliceIndex: {}, OpSliceIndex: {},
OpCall: {1}, OpCall: {1, 1},
OpReturn: {1}, OpReturn: {1},
OpGetLocal: {1}, OpGetLocal: {1},
OpSetLocal: {1}, OpSetLocal: {1},

View File

@ -270,9 +270,13 @@ func (p *Parser) parseCall(x Expr) *CallExpr {
p.exprLevel++ p.exprLevel++
var list []Expr var list []Expr
for p.token != token.RParen && p.token != token.EOF { var ellipsis Pos
for p.token != token.RParen && p.token != token.EOF && !ellipsis.IsValid() {
list = append(list, p.parseExpr()) list = append(list, p.parseExpr())
if p.token == token.Ellipsis {
ellipsis = p.pos
p.next()
}
if !p.expectComma(token.RParen, "call argument") { if !p.expectComma(token.RParen, "call argument") {
break break
} }
@ -284,6 +288,7 @@ func (p *Parser) parseCall(x Expr) *CallExpr {
Func: x, Func: x,
LParen: lparen, LParen: lparen,
RParen: rparen, RParen: rparen,
Ellipsis: ellipsis,
Args: list, Args: list,
} }
} }

26
vendor/github.com/d5/tengo/v2/vm.go generated vendored
View File

@ -537,12 +537,36 @@ func (v *VM) run() {
} }
case parser.OpCall: case parser.OpCall:
numArgs := int(v.curInsts[v.ip+1]) numArgs := int(v.curInsts[v.ip+1])
v.ip++ spread := int(v.curInsts[v.ip+2])
v.ip += 2
value := v.stack[v.sp-1-numArgs] value := v.stack[v.sp-1-numArgs]
if !value.CanCall() { if !value.CanCall() {
v.err = fmt.Errorf("not callable: %s", value.TypeName()) v.err = fmt.Errorf("not callable: %s", value.TypeName())
return return
} }
if spread == 1 {
v.sp--
switch arr := v.stack[v.sp].(type) {
case *Array:
for _, item := range arr.Value {
v.stack[v.sp] = item
v.sp++
}
numArgs += len(arr.Value) - 1
case *ImmutableArray:
for _, item := range arr.Value {
v.stack[v.sp] = item
v.sp++
}
numArgs += len(arr.Value) - 1
default:
v.err = fmt.Errorf("not an array: %s", arr.TypeName())
return
}
}
if callee, ok := value.(*CompiledFunction); ok { if callee, ok := value.(*CompiledFunction); ok {
if callee.VarArgs { if callee.VarArgs {
// if the closure is variadic, // if the closure is variadic,

View File

@ -3,4 +3,6 @@ language: go
go: go:
- '1.10' - '1.10'
- '1.11' - '1.11'
- '1.12'
- '1.13'
- tip - tip

View File

@ -3,7 +3,7 @@
[![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) [![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api)
[![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api) [![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api)
All methods are fairly self explanatory, and reading the godoc page should All methods are fairly self explanatory, and reading the [godoc](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) page should
explain everything. If something isn't clear, open an issue or submit explain everything. If something isn't clear, open an issue or submit
a pull request. a pull request.
@ -63,7 +63,7 @@ func main() {
``` ```
There are more examples on the [wiki](https://github.com/go-telegram-bot-api/telegram-bot-api/wiki) There are more examples on the [wiki](https://github.com/go-telegram-bot-api/telegram-bot-api/wiki)
with detailed information on how to do many differen kinds of things. with detailed information on how to do many different kinds of things.
It's a great place to get started on using keyboards, commands, or other It's a great place to get started on using keyboards, commands, or other
kinds of reply markup. kinds of reply markup.

View File

@ -19,6 +19,10 @@ import (
"github.com/technoweenie/multipartstreamer" "github.com/technoweenie/multipartstreamer"
) )
type HttpClient interface {
Do(req *http.Request) (*http.Response, error)
}
// BotAPI allows you to interact with the Telegram Bot API. // BotAPI allows you to interact with the Telegram Bot API.
type BotAPI struct { type BotAPI struct {
Token string `json:"token"` Token string `json:"token"`
@ -26,27 +30,39 @@ type BotAPI struct {
Buffer int `json:"buffer"` Buffer int `json:"buffer"`
Self User `json:"-"` Self User `json:"-"`
Client *http.Client `json:"-"` Client HttpClient `json:"-"`
shutdownChannel chan interface{} shutdownChannel chan interface{}
apiEndpoint string
} }
// NewBotAPI creates a new BotAPI instance. // NewBotAPI creates a new BotAPI instance.
// //
// It requires a token, provided by @BotFather on Telegram. // It requires a token, provided by @BotFather on Telegram.
func NewBotAPI(token string) (*BotAPI, error) { func NewBotAPI(token string) (*BotAPI, error) {
return NewBotAPIWithClient(token, &http.Client{}) return NewBotAPIWithClient(token, APIEndpoint, &http.Client{})
}
// NewBotAPIWithAPIEndpoint creates a new BotAPI instance
// and allows you to pass API endpoint.
//
// It requires a token, provided by @BotFather on Telegram and API endpoint.
func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) {
return NewBotAPIWithClient(token, apiEndpoint, &http.Client{})
} }
// NewBotAPIWithClient creates a new BotAPI instance // NewBotAPIWithClient creates a new BotAPI instance
// and allows you to pass a http.Client. // and allows you to pass a http.Client.
// //
// It requires a token, provided by @BotFather on Telegram. // It requires a token, provided by @BotFather on Telegram and API endpoint.
func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) { func NewBotAPIWithClient(token, apiEndpoint string, client HttpClient) (*BotAPI, error) {
bot := &BotAPI{ bot := &BotAPI{
Token: token, Token: token,
Client: client, Client: client,
Buffer: 100, Buffer: 100,
shutdownChannel: make(chan interface{}), shutdownChannel: make(chan interface{}),
apiEndpoint: apiEndpoint,
} }
self, err := bot.GetMe() self, err := bot.GetMe()
@ -59,11 +75,21 @@ func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
return bot, nil return bot, nil
} }
func (b *BotAPI) SetAPIEndpoint(apiEndpoint string) {
b.apiEndpoint = apiEndpoint
}
// MakeRequest makes a request to a specific endpoint with our token. // MakeRequest makes a request to a specific endpoint with our token.
func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) { func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) {
method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint) method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
resp, err := bot.Client.PostForm(method, params) req, err := http.NewRequest("POST", method, strings.NewReader(params.Encode()))
if err != nil {
return APIResponse{}, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := bot.Client.Do(req)
if err != nil { if err != nil {
return APIResponse{}, err return APIResponse{}, err
} }
@ -84,7 +110,7 @@ func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse,
if apiResp.Parameters != nil { if apiResp.Parameters != nil {
parameters = *apiResp.Parameters parameters = *apiResp.Parameters
} }
return apiResp, Error{apiResp.Description, parameters} return apiResp, &Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters}
} }
return apiResp, nil return apiResp, nil
@ -186,7 +212,7 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna
return APIResponse{}, errors.New(ErrBadFileType) return APIResponse{}, errors.New(ErrBadFileType)
} }
method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint) method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
req, err := http.NewRequest("POST", method, nil) req, err := http.NewRequest("POST", method, nil)
if err != nil { if err != nil {
@ -430,7 +456,7 @@ func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
// RemoveWebhook unsets the webhook. // RemoveWebhook unsets the webhook.
func (bot *BotAPI) RemoveWebhook() (APIResponse, error) { func (bot *BotAPI) RemoveWebhook() (APIResponse, error) {
return bot.MakeRequest("setWebhook", url.Values{}) return bot.MakeRequest("deleteWebhook", url.Values{})
} }
// SetWebhook sets a webhook. // SetWebhook sets a webhook.
@ -487,6 +513,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
for { for {
select { select {
case <-bot.shutdownChannel: case <-bot.shutdownChannel:
close(ch)
return return
default: default:
} }
@ -966,3 +993,22 @@ func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, e
return bot.MakeRequest(config.method(), v) return bot.MakeRequest(config.method(), v)
} }
// GetStickerSet get a sticker set.
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
v, err := config.values()
if err != nil {
return StickerSet{}, err
}
bot.debugLog(config.method(), v, nil)
res, err := bot.MakeRequest(config.method(), v)
if err != nil {
return StickerSet{}, err
}
stickerSet := StickerSet{}
err = json.Unmarshal(res.Result, &stickerSet)
if err != nil {
return StickerSet{}, err
}
return stickerSet, nil
}

View File

@ -1262,3 +1262,18 @@ func (config DeleteChatPhotoConfig) values() (url.Values, error) {
return v, nil return v, nil
} }
// GetStickerSetConfig contains information for get sticker set.
type GetStickerSetConfig struct {
Name string
}
func (config GetStickerSetConfig) method() string {
return "getStickerSet"
}
func (config GetStickerSetConfig) values() (url.Values, error) {
v := url.Values{}
v.Add("name", config.Name)
return v, nil
}

View File

@ -0,0 +1,5 @@
module github.com/go-telegram-bot-api/telegram-bot-api
go 1.12
require github.com/technoweenie/multipartstreamer v1.0.1

View File

@ -0,0 +1,2 @@
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=

View File

@ -29,7 +29,8 @@ func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
// NewMessageToChannel creates a new Message that is sent to a channel // NewMessageToChannel creates a new Message that is sent to a channel
// by username. // by username.
// //
// username is the username of the channel, text is the message text. // username is the username of the channel, text is the message text,
// and the username should be in the form of `@username`.
func NewMessageToChannel(username string, text string) MessageConfig { func NewMessageToChannel(username string, text string) MessageConfig {
return MessageConfig{ return MessageConfig{
BaseChat: BaseChat{ BaseChat: BaseChat{
@ -604,6 +605,18 @@ func NewInlineQueryResultLocation(id, title string, latitude, longitude float64)
} }
} }
// NewInlineQueryResultVenue creates a new inline query venue.
func NewInlineQueryResultVenue(id, title, address string, latitude, longitude float64) InlineQueryResultVenue {
return InlineQueryResultVenue{
Type: "venue",
ID: id,
Title: title,
Address: address,
Latitude: latitude,
Longitude: longitude,
}
}
// NewEditMessageText allows you to edit the text of a message. // NewEditMessageText allows you to edit the text of a message.
func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig { func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig {
return EditMessageTextConfig{ return EditMessageTextConfig{

View File

@ -64,6 +64,9 @@ type User struct {
// It is normally a user's username, but falls back to a first/last // It is normally a user's username, but falls back to a first/last
// name as available. // name as available.
func (u *User) String() string { func (u *User) String() string {
if u == nil {
return ""
}
if u.UserName != "" { if u.UserName != "" {
return u.UserName return u.UserName
} }
@ -100,6 +103,7 @@ type Chat struct {
Photo *ChatPhoto `json:"photo"` Photo *ChatPhoto `json:"photo"`
Description string `json:"description,omitempty"` // optional Description string `json:"description,omitempty"` // optional
InviteLink string `json:"invite_link,omitempty"` // optional InviteLink string `json:"invite_link,omitempty"` // optional
PinnedMessage *Message `json:"pinned_message"` // optional
} }
// IsPrivate returns if the Chat is a private conversation. // IsPrivate returns if the Chat is a private conversation.
@ -142,6 +146,7 @@ type Message struct {
EditDate int `json:"edit_date"` // optional EditDate int `json:"edit_date"` // optional
Text string `json:"text"` // optional Text string `json:"text"` // optional
Entities *[]MessageEntity `json:"entities"` // optional Entities *[]MessageEntity `json:"entities"` // optional
CaptionEntities *[]MessageEntity `json:"caption_entities"` // optional
Audio *Audio `json:"audio"` // optional Audio *Audio `json:"audio"` // optional
Document *Document `json:"document"` // optional Document *Document `json:"document"` // optional
Animation *ChatAnimation `json:"animation"` // optional Animation *ChatAnimation `json:"animation"` // optional
@ -183,7 +188,7 @@ func (m *Message) IsCommand() bool {
} }
entity := (*m.Entities)[0] entity := (*m.Entities)[0]
return entity.Offset == 0 && entity.Type == "bot_command" return entity.Offset == 0 && entity.IsCommand()
} }
// Command checks if the message was a command and if it was, returns the // Command checks if the message was a command and if it was, returns the
@ -249,12 +254,62 @@ type MessageEntity struct {
} }
// ParseURL attempts to parse a URL contained within a MessageEntity. // ParseURL attempts to parse a URL contained within a MessageEntity.
func (entity MessageEntity) ParseURL() (*url.URL, error) { func (e MessageEntity) ParseURL() (*url.URL, error) {
if entity.URL == "" { if e.URL == "" {
return nil, errors.New(ErrBadURL) return nil, errors.New(ErrBadURL)
} }
return url.Parse(entity.URL) return url.Parse(e.URL)
}
// IsMention returns true if the type of the message entity is "mention" (@username).
func (e MessageEntity) IsMention() bool {
return e.Type == "mention"
}
// IsHashtag returns true if the type of the message entity is "hashtag".
func (e MessageEntity) IsHashtag() bool {
return e.Type == "hashtag"
}
// IsCommand returns true if the type of the message entity is "bot_command".
func (e MessageEntity) IsCommand() bool {
return e.Type == "bot_command"
}
// IsUrl returns true if the type of the message entity is "url".
func (e MessageEntity) IsUrl() bool {
return e.Type == "url"
}
// IsEmail returns true if the type of the message entity is "email".
func (e MessageEntity) IsEmail() bool {
return e.Type == "email"
}
// IsBold returns true if the type of the message entity is "bold" (bold text).
func (e MessageEntity) IsBold() bool {
return e.Type == "bold"
}
// IsItalic returns true if the type of the message entity is "italic" (italic text).
func (e MessageEntity) IsItalic() bool {
return e.Type == "italic"
}
// IsCode returns true if the type of the message entity is "code" (monowidth string).
func (e MessageEntity) IsCode() bool {
return e.Type == "code"
}
// IsPre returns true if the type of the message entity is "pre" (monowidth block).
func (e MessageEntity) IsPre() bool {
return e.Type == "pre"
}
// IsTextLink returns true if the type of the message entity is "text_link" (clickable text URL).
func (e MessageEntity) IsTextLink() bool {
return e.Type == "text_link"
} }
// PhotoSize contains information about photos. // PhotoSize contains information about photos.
@ -286,6 +341,7 @@ type Document struct {
// Sticker contains information about a sticker. // Sticker contains information about a sticker.
type Sticker struct { type Sticker struct {
FileUniqueID string `json:"file_unique_id"`
FileID string `json:"file_id"` FileID string `json:"file_id"`
Width int `json:"width"` Width int `json:"width"`
Height int `json:"height"` Height int `json:"height"`
@ -293,6 +349,15 @@ type Sticker struct {
Emoji string `json:"emoji"` // optional Emoji string `json:"emoji"` // optional
FileSize int `json:"file_size"` // optional FileSize int `json:"file_size"` // optional
SetName string `json:"set_name"` // optional SetName string `json:"set_name"` // optional
IsAnimated bool `json:"is_animated"` // optional
}
type StickerSet struct {
Name string `json:"name"`
Title string `json:"title"`
IsAnimated bool `json:"is_animated"`
ContainsMasks bool `json:"contains_masks"`
Stickers []Sticker `json:"stickers"`
} }
// ChatAnimation contains information about an animation. // ChatAnimation contains information about an animation.
@ -582,6 +647,7 @@ type InlineQueryResultPhoto struct {
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Caption string `json:"caption"` Caption string `json:"caption"`
ParseMode string `json:"parse_mode"`
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
InputMessageContent interface{} `json:"input_message_content,omitempty"` InputMessageContent interface{} `json:"input_message_content,omitempty"`
} }
@ -604,12 +670,12 @@ type InlineQueryResultGIF struct {
Type string `json:"type"` // required Type string `json:"type"` // required
ID string `json:"id"` // required ID string `json:"id"` // required
URL string `json:"gif_url"` // required URL string `json:"gif_url"` // required
Width int `json:"gif_width"` ThumbURL string `json:"thumb_url"` // required
Height int `json:"gif_height"` Width int `json:"gif_width,omitempty"`
Duration int `json:"gif_duration"` Height int `json:"gif_height,omitempty"`
ThumbURL string `json:"thumb_url"` Duration int `json:"gif_duration,omitempty"`
Title string `json:"title"` Title string `json:"title,omitempty"`
Caption string `json:"caption"` Caption string `json:"caption,omitempty"`
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
InputMessageContent interface{} `json:"input_message_content,omitempty"` InputMessageContent interface{} `json:"input_message_content,omitempty"`
} }
@ -775,6 +841,23 @@ type InlineQueryResultLocation struct {
ThumbHeight int `json:"thumb_height"` ThumbHeight int `json:"thumb_height"`
} }
// InlineQueryResultVenue is an inline query response venue.
type InlineQueryResultVenue struct {
Type string `json:"type"` // required
ID string `json:"id"` // required
Latitude float64 `json:"latitude"` // required
Longitude float64 `json:"longitude"` // required
Title string `json:"title"` // required
Address string `json:"address"` // required
FoursquareID string `json:"foursquare_id"`
FoursquareType string `json:"foursquare_type"`
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
InputMessageContent interface{} `json:"input_message_content,omitempty"`
ThumbURL string `json:"thumb_url"`
ThumbWidth int `json:"thumb_width"`
ThumbHeight int `json:"thumb_height"`
}
// InlineQueryResultGame is an inline query response game. // InlineQueryResultGame is an inline query response game.
type InlineQueryResultGame struct { type InlineQueryResultGame struct {
Type string `json:"type"` Type string `json:"type"`
@ -897,6 +980,7 @@ type PreCheckoutQuery struct {
// Error is an error containing extra information returned by the Telegram API. // Error is an error containing extra information returned by the Telegram API.
type Error struct { type Error struct {
Code int
Message string Message string
ResponseParameters ResponseParameters
} }

View File

@ -28,6 +28,7 @@ const (
Safelink // Only link to trusted protocols Safelink // Only link to trusted protocols
NofollowLinks // Only link with rel="nofollow" NofollowLinks // Only link with rel="nofollow"
NoreferrerLinks // Only link with rel="noreferrer" NoreferrerLinks // Only link with rel="noreferrer"
NoopenerLinks // Only link with rel="noopener"
HrefTargetBlank // Add a blank target HrefTargetBlank // Add a blank target
CompletePage // Generate a complete HTML page CompletePage // Generate a complete HTML page
UseXHTML // Generate XHTML output instead of HTML UseXHTML // Generate XHTML output instead of HTML
@ -295,6 +296,9 @@ func appendLinkAttrs(attrs []string, flags Flags, link []byte) []string {
if flags&NoreferrerLinks != 0 { if flags&NoreferrerLinks != 0 {
val = append(val, "noreferrer") val = append(val, "noreferrer")
} }
if flags&NoopenerLinks != 0 {
val = append(val, "noopener")
}
if flags&HrefTargetBlank != 0 { if flags&HrefTargetBlank != 0 {
attrs = append(attrs, `target="_blank"`) attrs = append(attrs, `target="_blank"`)
} }
@ -1110,7 +1114,9 @@ func (r *Renderer) writeTOC(w io.Writer, doc ast.Node) {
buf.WriteString("</a>") buf.WriteString("</a>")
return ast.GoToNext return ast.GoToNext
} }
if nodeData.HeadingID == "" {
nodeData.HeadingID = fmt.Sprintf("toc_%d", headingCount) nodeData.HeadingID = fmt.Sprintf("toc_%d", headingCount)
}
if nodeData.Level == tocLevel { if nodeData.Level == tocLevel {
buf.WriteString("</li>\n\n<li>") buf.WriteString("</li>\n\n<li>")
} else if nodeData.Level < tocLevel { } else if nodeData.Level < tocLevel {
@ -1126,7 +1132,7 @@ func (r *Renderer) writeTOC(w io.Writer, doc ast.Node) {
} }
} }
fmt.Fprintf(&buf, `<a href="#toc_%d">`, headingCount) fmt.Fprintf(&buf, `<a href="#%s">`, nodeData.HeadingID)
headingCount++ headingCount++
return ast.GoToNext return ast.GoToNext
} }

View File

@ -326,6 +326,7 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) {
i = skipSpace(data, i) i = skipSpace(data, i)
linkB := i linkB := i
brace := 0
// look for link end: ' " ) // look for link end: ' " )
findlinkend: findlinkend:
@ -334,7 +335,18 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) {
case data[i] == '\\': case data[i] == '\\':
i += 2 i += 2
case data[i] == ')' || data[i] == '\'' || data[i] == '"': case data[i] == '(':
brace++
i++
case data[i] == ')':
if brace <= 0 {
break findlinkend
}
brace--
i++
case data[i] == '\'' || data[i] == '"':
break findlinkend break findlinkend
default: default:
@ -352,19 +364,21 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) {
if data[i] == '\'' || data[i] == '"' { if data[i] == '\'' || data[i] == '"' {
i++ i++
titleB = i titleB = i
titleEndCharFound := false
findtitleend: findtitleend:
for i < len(data) { for i < len(data) {
switch { switch {
case data[i] == '\\': case data[i] == '\\':
i += 2
case data[i] == ')':
break findtitleend
default:
i++ i++
case data[i] == data[titleB-1]: // matching title delimiter
titleEndCharFound = true
case titleEndCharFound && data[i] == ')':
break findtitleend
} }
i++
} }
if i >= len(data) { if i >= len(data) {

View File

@ -20,12 +20,13 @@ import (
"runtime/pprof" "runtime/pprof"
"runtime/trace" "runtime/trace"
"strconv" "strconv"
"strings"
"sync" "sync"
"syscall"
"time" "time"
"github.com/google/gops/internal" "github.com/google/gops/internal"
"github.com/google/gops/signal" "github.com/google/gops/signal"
"github.com/kardianos/osext"
) )
const defaultAddr = "127.0.0.1:0" const defaultAddr = "127.0.0.1:0"
@ -116,18 +117,21 @@ func listen() {
for { for {
fd, err := listener.Accept() fd, err := listener.Accept()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "gops: %v", err) // No great way to check for this, see https://golang.org/issues/4373.
if !strings.Contains(err.Error(), "use of closed network connection") {
fmt.Fprintf(os.Stderr, "gops: %v\n", err)
}
if netErr, ok := err.(net.Error); ok && !netErr.Temporary() { if netErr, ok := err.(net.Error); ok && !netErr.Temporary() {
break break
} }
continue continue
} }
if _, err := fd.Read(buf); err != nil { if _, err := fd.Read(buf); err != nil {
fmt.Fprintf(os.Stderr, "gops: %v", err) fmt.Fprintf(os.Stderr, "gops: %v\n", err)
continue continue
} }
if err := handle(fd, buf); err != nil { if err := handle(fd, buf); err != nil {
fmt.Fprintf(os.Stderr, "gops: %v", err) fmt.Fprintf(os.Stderr, "gops: %v\n", err)
continue continue
} }
fd.Close() fd.Close()
@ -136,12 +140,16 @@ func listen() {
func gracefulShutdown() { func gracefulShutdown() {
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
gosignal.Notify(c, os.Interrupt) gosignal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func() { go func() {
// cleanup the socket on shutdown. // cleanup the socket on shutdown.
<-c sig := <-c
Close() Close()
os.Exit(1) ret := 1
if sig == syscall.SIGTERM {
ret = 0
}
os.Exit(ret)
}() }()
} }
@ -220,7 +228,7 @@ func handle(conn io.ReadWriter, msg []byte) error {
case signal.Version: case signal.Version:
fmt.Fprintf(conn, "%v\n", runtime.Version()) fmt.Fprintf(conn, "%v\n", runtime.Version())
case signal.HeapProfile: case signal.HeapProfile:
pprof.WriteHeapProfile(conn) return pprof.WriteHeapProfile(conn)
case signal.CPUProfile: case signal.CPUProfile:
if err := pprof.StartCPUProfile(conn); err != nil { if err := pprof.StartCPUProfile(conn); err != nil {
return err return err
@ -233,7 +241,7 @@ func handle(conn io.ReadWriter, msg []byte) error {
fmt.Fprintf(conn, "GOMAXPROCS: %v\n", runtime.GOMAXPROCS(0)) fmt.Fprintf(conn, "GOMAXPROCS: %v\n", runtime.GOMAXPROCS(0))
fmt.Fprintf(conn, "num CPU: %v\n", runtime.NumCPU()) fmt.Fprintf(conn, "num CPU: %v\n", runtime.NumCPU())
case signal.BinaryDump: case signal.BinaryDump:
path, err := osext.Executable() path, err := os.Executable()
if err != nil { if err != nil {
return err return err
} }
@ -246,7 +254,9 @@ func handle(conn io.ReadWriter, msg []byte) error {
_, err = bufio.NewReader(f).WriteTo(conn) _, err = bufio.NewReader(f).WriteTo(conn)
return err return err
case signal.Trace: case signal.Trace:
trace.Start(conn) if err := trace.Start(conn); err != nil {
return err
}
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
trace.Stop() trace.Stop()
case signal.SetGCPercent: case signal.SetGCPercent:

View File

@ -6,12 +6,12 @@ package internal
import ( import (
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"os/user" "os/user"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv"
"strings" "strings"
) )
@ -22,9 +22,18 @@ func ConfigDir() (string, error) {
return configDir, nil return configDir, nil
} }
if osUserConfigDir := getOSUserConfigDir(); osUserConfigDir != "" {
return filepath.Join(osUserConfigDir, "gops"), nil
}
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
return filepath.Join(os.Getenv("APPDATA"), "gops"), nil return filepath.Join(os.Getenv("APPDATA"), "gops"), nil
} }
if xdgConfigDir := os.Getenv("XDG_CONFIG_HOME"); xdgConfigDir != "" {
return filepath.Join(xdgConfigDir, "gops"), nil
}
homeDir := guessUnixHomeDir() homeDir := guessUnixHomeDir()
if homeDir == "" { if homeDir == "" {
return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty") return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty")
@ -45,7 +54,7 @@ func PIDFile(pid int) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return fmt.Sprintf("%s/%d", gopsdir, pid), nil return filepath.Join(gopsdir, strconv.Itoa(pid)), nil
} }
func GetPort(pid int) (string, error) { func GetPort(pid int) (string, error) {

View File

@ -0,0 +1,19 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.13
package internal
import (
"os"
)
func getOSUserConfigDir() string {
configDir, err := os.UserConfigDir()
if err != nil {
return ""
}
return configDir
}

View File

@ -0,0 +1,11 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.13
package internal
func getOSUserConfigDir() string {
return ""
}

View File

@ -1,27 +0,0 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,21 +0,0 @@
### Extensions to the "os" package.
[![GoDoc](https://godoc.org/github.com/kardianos/osext?status.svg)](https://godoc.org/github.com/kardianos/osext)
## Find the current Executable and ExecutableFolder.
As of go1.8 the Executable function may be found in `os`. The Executable function
in the std lib `os` package is used if available.
There is sometimes utility in finding the current executable file
that is running. This can be used for upgrading the current executable
or finding resources located relative to the executable file. Both
working directory and the os.Args[0] value are arbitrary and cannot
be relied on; os.Args[0] can be "faked".
Multi-platform and supports:
* Linux
* OS X
* Windows
* Plan 9
* BSDs.

View File

@ -1,33 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Extensions to the standard "os" package.
package osext // import "github.com/kardianos/osext"
import "path/filepath"
var cx, ce = executableClean()
func executableClean() (string, error) {
p, err := executable()
return filepath.Clean(p), err
}
// Executable returns an absolute path that can be used to
// re-invoke the current program.
// It may not be valid after the current program exits.
func Executable() (string, error) {
return cx, ce
}
// Returns same path as Executable, returns just the folder
// path. Excludes the executable name and any trailing slash.
func ExecutableFolder() (string, error) {
p, err := Executable()
if err != nil {
return "", err
}
return filepath.Dir(p), nil
}

View File

@ -1,9 +0,0 @@
//+build go1.8,!openbsd
package osext
import "os"
func executable() (string, error) {
return os.Executable()
}

View File

@ -1,22 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//+build !go1.8
package osext
import (
"os"
"strconv"
"syscall"
)
func executable() (string, error) {
f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text")
if err != nil {
return "", err
}
defer f.Close()
return syscall.Fd2path(int(f.Fd()))
}

View File

@ -1,36 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.8,android !go1.8,linux !go1.8,netbsd !go1.8,solaris !go1.8,dragonfly
package osext
import (
"errors"
"fmt"
"os"
"runtime"
"strings"
)
func executable() (string, error) {
switch runtime.GOOS {
case "linux", "android":
const deletedTag = " (deleted)"
execpath, err := os.Readlink("/proc/self/exe")
if err != nil {
return execpath, err
}
execpath = strings.TrimSuffix(execpath, deletedTag)
execpath = strings.TrimPrefix(execpath, deletedTag)
return execpath, nil
case "netbsd":
return os.Readlink("/proc/curproc/exe")
case "dragonfly":
return os.Readlink("/proc/curproc/file")
case "solaris":
return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid()))
}
return "", errors.New("ExecPath not implemented for " + runtime.GOOS)
}

View File

@ -1,126 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.8,darwin !go1.8,freebsd openbsd
package osext
import (
"os"
"os/exec"
"path/filepath"
"runtime"
"syscall"
"unsafe"
)
var initCwd, initCwdErr = os.Getwd()
func executable() (string, error) {
var mib [4]int32
switch runtime.GOOS {
case "freebsd":
mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
case "darwin":
mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1}
case "openbsd":
mib = [4]int32{1 /* CTL_KERN */, 55 /* KERN_PROC_ARGS */, int32(os.Getpid()), 1 /* KERN_PROC_ARGV */}
}
n := uintptr(0)
// Get length.
_, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
if errNum != 0 {
return "", errNum
}
if n == 0 { // This shouldn't happen.
return "", nil
}
buf := make([]byte, n)
_, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
if errNum != 0 {
return "", errNum
}
if n == 0 { // This shouldn't happen.
return "", nil
}
var execPath string
switch runtime.GOOS {
case "openbsd":
// buf now contains **argv, with pointers to each of the C-style
// NULL terminated arguments.
var args []string
argv := uintptr(unsafe.Pointer(&buf[0]))
Loop:
for {
argp := *(**[1 << 20]byte)(unsafe.Pointer(argv))
if argp == nil {
break
}
for i := 0; uintptr(i) < n; i++ {
// we don't want the full arguments list
if string(argp[i]) == " " {
break Loop
}
if argp[i] != 0 {
continue
}
args = append(args, string(argp[:i]))
n -= uintptr(i)
break
}
if n < unsafe.Sizeof(argv) {
break
}
argv += unsafe.Sizeof(argv)
n -= unsafe.Sizeof(argv)
}
execPath = args[0]
// There is no canonical way to get an executable path on
// OpenBSD, so check PATH in case we are called directly
if execPath[0] != '/' && execPath[0] != '.' {
execIsInPath, err := exec.LookPath(execPath)
if err == nil {
execPath = execIsInPath
}
}
default:
for i, v := range buf {
if v == 0 {
buf = buf[:i]
break
}
}
execPath = string(buf)
}
var err error
// execPath will not be empty due to above checks.
// Try to get the absolute path if the execPath is not rooted.
if execPath[0] != '/' {
execPath, err = getAbs(execPath)
if err != nil {
return execPath, err
}
}
// For darwin KERN_PROCARGS may return the path to a symlink rather than the
// actual executable.
if runtime.GOOS == "darwin" {
if execPath, err = filepath.EvalSymlinks(execPath); err != nil {
return execPath, err
}
}
return execPath, nil
}
func getAbs(execPath string) (string, error) {
if initCwdErr != nil {
return execPath, initCwdErr
}
// The execPath may begin with a "../" or a "./" so clean it first.
// Join the two paths, trailing and starting slashes undetermined, so use
// the generic Join function.
return filepath.Join(initCwd, filepath.Clean(execPath)), nil
}

View File

@ -1,36 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//+build !go1.8
package osext
import (
"syscall"
"unicode/utf16"
"unsafe"
)
var (
kernel = syscall.MustLoadDLL("kernel32.dll")
getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW")
)
// GetModuleFileName() with hModule = NULL
func executable() (exePath string, err error) {
return getModuleFileName()
}
func getModuleFileName() (string, error) {
var n uint32
b := make([]uint16, syscall.MAX_PATH)
size := uint32(len(b))
r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size))
n = uint32(r0)
if n == 0 {
return "", e1
}
return string(utf16.Decode(b[0:n])), nil
}

2
vendor/github.com/matterbridge/discordgo/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
# IDE-specific metadata
.idea/

View File

@ -1,8 +1,9 @@
language: go language: go
go: go:
- 1.9.x
- 1.10.x - 1.10.x
- 1.11.x - 1.11.x
- 1.12.x
- 1.13.x
install: install:
- go get github.com/bwmarrin/discordgo - go get github.com/bwmarrin/discordgo
- go get -v . - go get -v .

View File

@ -1,16 +1,16 @@
# DiscordGo # DiscordGo
[![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo) [![Go report](http://goreportcard.com/badge/bwmarrin/discordgo)](http://goreportcard.com/report/bwmarrin/discordgo) [![Build Status](https://travis-ci.org/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.org/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/0f1SbxBZjYoCtNPP) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discordapp.com/invite/discord-api) [![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo) [![Go report](http://goreportcard.com/badge/bwmarrin/discordgo)](http://goreportcard.com/report/bwmarrin/discordgo) [![Build Status](https://travis-ci.org/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.org/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/0f1SbxBZjYoCtNPP) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discord.com/invite/discord-api)
<img align="right" src="http://bwmarrin.github.io/discordgo/img/discordgo.png"> <img align="right" src="http://bwmarrin.github.io/discordgo/img/discordgo.png">
DiscordGo is a [Go](https://golang.org/) package that provides low level DiscordGo is a [Go](https://golang.org/) package that provides low level
bindings to the [Discord](https://discordapp.com/) chat client API. DiscordGo bindings to the [Discord](https://discord.com/) chat client API. DiscordGo
has nearly complete support for all of the Discord API endpoints, websocket has nearly complete support for all of the Discord API endpoints, websocket
interface, and voice interface. interface, and voice interface.
If you would like to help the DiscordGo package please use If you would like to help the DiscordGo package please use
[this link](https://discordapp.com/oauth2/authorize?client_id=173113690092994561&scope=bot) [this link](https://discord.com/oauth2/authorize?client_id=173113690092994561&scope=bot)
to add the official DiscordGo test bot **dgo** to your server. This provides to add the official DiscordGo test bot **dgo** to your server. This provides
indispensable help to this project. indispensable help to this project.

View File

@ -17,11 +17,12 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"runtime"
"time" "time"
) )
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/) // VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
const VERSION = "0.20.2" const VERSION = "0.21.1"
// ErrMFA will be risen by New when the user has 2FA. // ErrMFA will be risen by New when the user has 2FA.
var ErrMFA = errors.New("account has 2FA enabled") var ErrMFA = errors.New("account has 2FA enabled")
@ -30,10 +31,13 @@ var ErrMFA = errors.New("account has 2FA enabled")
// tasks if given enough information to do so. Currently you can pass zero // tasks if given enough information to do so. Currently you can pass zero
// arguments and it will return an empty Discord session. // arguments and it will return an empty Discord session.
// There are 3 ways to call New: // There are 3 ways to call New:
// With a single auth token - All requests will use the token blindly, // With a single auth token - All requests will use the token blindly
// (just tossing it into the HTTP Authorization header);
// no verification of the token will be done and requests may fail. // no verification of the token will be done and requests may fail.
// IF THE TOKEN IS FOR A BOT, IT MUST BE PREFIXED WITH `BOT ` // IF THE TOKEN IS FOR A BOT, IT MUST BE PREFIXED WITH `BOT `
// eg: `"Bot <token>"` // eg: `"Bot <token>"`
// IF IT IS AN OAUTH2 ACCESS TOKEN, IT MUST BE PREFIXED WITH `Bearer `
// eg: `"Bearer <token>"`
// With an email and password - Discord will sign in with the provided // With an email and password - Discord will sign in with the provided
// credentials. // credentials.
// With an email, password and auth token - Discord will verify the auth // With an email, password and auth token - Discord will verify the auth
@ -63,6 +67,15 @@ func New(args ...interface{}) (s *Session, err error) {
LastHeartbeatAck: time.Now().UTC(), LastHeartbeatAck: time.Now().UTC(),
} }
// Initilize the Identify Package with defaults
// These can be modified prior to calling Open()
s.Identify.Compress = true
s.Identify.LargeThreshold = 250
s.Identify.GuildSubscriptions = true
s.Identify.Properties.OS = runtime.GOOS
s.Identify.Properties.Browser = "DiscordGo v" + VERSION
s.Identify.Intents = MakeIntent(IntentsAllWithoutPrivileged)
// If no arguments are passed return the empty Session interface. // If no arguments are passed return the empty Session interface.
if args == nil { if args == nil {
return return
@ -94,7 +107,8 @@ func New(args ...interface{}) (s *Session, err error) {
// If third string exists, it must be an auth token. // If third string exists, it must be an auth token.
if len(v) > 2 { if len(v) > 2 {
s.Token = v[2] s.Identify.Token = v[2]
s.Token = v[2] // TODO: Remove, Deprecated - Kept for backwards compatibility.
} }
case string: case string:
@ -107,7 +121,8 @@ func New(args ...interface{}) (s *Session, err error) {
} else if pass == "" { } else if pass == "" {
pass = v pass = v
} else if s.Token == "" { } else if s.Token == "" {
s.Token = v s.Identify.Token = v
s.Token = v // TODO: Remove, Deprecated - Kept for backwards compatibility.
} else { } else {
err = fmt.Errorf("too many string parameters provided") err = fmt.Errorf("too many string parameters provided")
return return
@ -127,10 +142,12 @@ func New(args ...interface{}) (s *Session, err error) {
// Discord will verify it for free, or log the user in if it is // Discord will verify it for free, or log the user in if it is
// invalid. // invalid.
if pass == "" { if pass == "" {
s.Token = auth s.Identify.Token = auth
s.Token = auth // TODO: Remove, Deprecated - Kept for backwards compatibility.
} else { } else {
err = s.Login(auth, pass) err = s.Login(auth, pass)
if err != nil || s.Token == "" { // TODO: Remove last s.Token part, Deprecated - Kept for backwards compatibility.
if err != nil || s.Identify.Token == "" || s.Token == "" {
if s.MFA { if s.MFA {
err = ErrMFA err = ErrMFA
} else { } else {
@ -140,8 +157,5 @@ func New(args ...interface{}) (s *Session, err error) {
} }
} }
// The Session is now able to have RestAPI methods called on it.
// It is recommended that you now call Open() so that events will trigger.
return return
} }

View File

@ -18,12 +18,12 @@ var APIVersion = "6"
// Known Discord API Endpoints. // Known Discord API Endpoints.
var ( var (
EndpointStatus = "https://status.discordapp.com/api/v2/" EndpointStatus = "https://status.discord.com/api/v2/"
EndpointSm = EndpointStatus + "scheduled-maintenances/" EndpointSm = EndpointStatus + "scheduled-maintenances/"
EndpointSmActive = EndpointSm + "active.json" EndpointSmActive = EndpointSm + "active.json"
EndpointSmUpcoming = EndpointSm + "upcoming.json" EndpointSmUpcoming = EndpointSm + "upcoming.json"
EndpointDiscord = "https://discordapp.com/" EndpointDiscord = "https://discord.com/"
EndpointAPI = EndpointDiscord + "api/v" + APIVersion + "/" EndpointAPI = EndpointDiscord + "api/v" + APIVersion + "/"
EndpointGuilds = EndpointAPI + "guilds/" EndpointGuilds = EndpointAPI + "guilds/"
EndpointChannels = EndpointAPI + "channels/" EndpointChannels = EndpointAPI + "channels/"

View File

@ -110,7 +110,7 @@ func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() {
// }) // })
// //
// List of events can be found at this page, with corresponding names in the // List of events can be found at this page, with corresponding names in the
// library for each event: https://discordapp.com/developers/docs/topics/gateway#event-names // library for each event: https://discord.com/developers/docs/topics/gateway#event-names
// There are also synthetic events fired by the library internally which are // There are also synthetic events fired by the library internally which are
// available for handling, like Connect, Disconnect, and RateLimit. // available for handling, like Connect, Disconnect, and RateLimit.
// events.go contains all of the Discord WSAPI and synthetic events that can be handled. // events.go contains all of the Discord WSAPI and synthetic events that can be handled.

View File

@ -141,6 +141,9 @@ type GuildEmojisUpdate struct {
type GuildMembersChunk struct { type GuildMembersChunk struct {
GuildID string `json:"guild_id"` GuildID string `json:"guild_id"`
Members []*Member `json:"members"` Members []*Member `json:"members"`
ChunkIndex int `json:"chunk_index"`
ChunkCount int `json:"chunk_count"`
Presences []*Presence `json:"presences,omitempty"`
} }
// GuildIntegrationsUpdate is the data for a GuildIntegrationsUpdate event. // GuildIntegrationsUpdate is the data for a GuildIntegrationsUpdate event.
@ -169,6 +172,7 @@ type MessageUpdate struct {
// MessageDelete is the data for a MessageDelete event. // MessageDelete is the data for a MessageDelete event.
type MessageDelete struct { type MessageDelete struct {
*Message *Message
BeforeDelete *Message `json:"-"`
} }
// MessageReactionAdd is the data for a MessageReactionAdd event. // MessageReactionAdd is the data for a MessageReactionAdd event.

View File

@ -1,6 +1,8 @@
module github.com/matterbridge/discordgo module github.com/matterbridge/discordgo
require ( require (
github.com/gorilla/websocket v1.4.0 github.com/gorilla/websocket v1.4.2
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
) )
go 1.10

View File

@ -1,4 +1,10 @@
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -37,7 +37,7 @@ const (
// Logger can be used to replace the standard logging for discordgo // Logger can be used to replace the standard logging for discordgo
var Logger func(msgL, caller int, format string, a ...interface{}) var Logger func(msgL, caller int, format string, a ...interface{})
// msglog provides package wide logging consistancy for discordgo // msglog provides package wide logging consistency for discordgo
// the format, a... portion this command follows that of fmt.Printf // the format, a... portion this command follows that of fmt.Printf
// msgL : LogLevel of the message // msgL : LogLevel of the message
// caller : 1 + the number of callers away from the message source // caller : 1 + the number of callers away from the message source

View File

@ -63,7 +63,7 @@ type Message struct {
MentionRoles []string `json:"mention_roles"` MentionRoles []string `json:"mention_roles"`
// Whether the message is text-to-speech. // Whether the message is text-to-speech.
Tts bool `json:"tts"` TTS bool `json:"tts"`
// Whether the message mentions everyone. // Whether the message mentions everyone.
MentionEveryone bool `json:"mention_everyone"` MentionEveryone bool `json:"mention_everyone"`
@ -131,8 +131,9 @@ type File struct {
type MessageSend struct { type MessageSend struct {
Content string `json:"content,omitempty"` Content string `json:"content,omitempty"`
Embed *MessageEmbed `json:"embed,omitempty"` Embed *MessageEmbed `json:"embed,omitempty"`
Tts bool `json:"tts"` TTS bool `json:"tts"`
Files []*File `json:"-"` Files []*File `json:"-"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
// TODO: Remove this when compatibility is not required. // TODO: Remove this when compatibility is not required.
File *File `json:"-"` File *File `json:"-"`
@ -143,6 +144,7 @@ type MessageSend struct {
type MessageEdit struct { type MessageEdit struct {
Content *string `json:"content,omitempty"` Content *string `json:"content,omitempty"`
Embed *MessageEmbed `json:"embed,omitempty"` Embed *MessageEmbed `json:"embed,omitempty"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
ID string ID string
Channel string Channel string
@ -171,6 +173,42 @@ func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
return m return m
} }
// AllowedMentionType describes the types of mentions used
// in the MessageAllowedMentions type.
type AllowedMentionType string
// The types of mentions used in MessageAllowedMentions.
const (
AllowedMentionTypeRoles AllowedMentionType = "roles"
AllowedMentionTypeUsers AllowedMentionType = "users"
AllowedMentionTypeEveryone AllowedMentionType = "everyone"
)
// MessageAllowedMentions allows the user to specify which mentions
// Discord is allowed to parse in this message. This is useful when
// sending user input as a message, as it prevents unwanted mentions.
// If this type is used, all mentions must be explicitly whitelisted,
// either by putting an AllowedMentionType in the Parse slice
// (allowing all mentions of that type) or, in the case of roles and
// users, explicitly allowing those mentions on an ID-by-ID basis.
// For more information on this functionality, see:
// https://discordapp.com/developers/docs/resources/channel#allowed-mentions-object-allowed-mentions-reference
type MessageAllowedMentions struct {
// The mention types that are allowed to be parsed in this message.
// Please note that this is purposely **not** marked as omitempty,
// so if a zero-value MessageAllowedMentions object is provided no
// mentions will be allowed.
Parse []AllowedMentionType `json:"parse"`
// A list of role IDs to allow. This cannot be used when specifying
// AllowedMentionTypeRoles in the Parse slice.
Roles []string `json:"roles,omitempty"`
// A list of user IDs to allow. This cannot be used when specifying
// AllowedMentionTypeUsers in the Parse slice.
Users []string `json:"users,omitempty"`
}
// A MessageAttachment stores data for message attachments. // A MessageAttachment stores data for message attachments.
type MessageAttachment struct { type MessageAttachment struct {
ID string `json:"id"` ID string `json:"id"`

View File

@ -38,7 +38,7 @@ var (
ErrPruneDaysBounds = errors.New("the number of days should be more than or equal to 1") ErrPruneDaysBounds = errors.New("the number of days should be more than or equal to 1")
ErrGuildNoIcon = errors.New("guild does not have an icon set") ErrGuildNoIcon = errors.New("guild does not have an icon set")
ErrGuildNoSplash = errors.New("guild does not have a splash set") ErrGuildNoSplash = errors.New("guild does not have a splash set")
ErrUnauthorized = errors.New("HTTP request was unauthorized. This could be because the provided token was not a bot token. Please add \"Bot \" to the start of your token. https://discordapp.com/developers/docs/reference#authentication-example-bot-token-authorization-header") ErrUnauthorized = errors.New("HTTP request was unauthorized. This could be because the provided token was not a bot token. Please add \"Bot \" to the start of your token. https://discord.com/developers/docs/reference#authentication-example-bot-token-authorization-header")
) )
// Request is the same as RequestWithBucketID but the bucket id is the same as the urlStr // Request is the same as RequestWithBucketID but the bucket id is the same as the urlStr
@ -506,7 +506,7 @@ func (s *Session) UserChannelPermissions(userID, channelID string) (apermissions
} }
// Calculates the permissions for a member. // Calculates the permissions for a member.
// https://support.discordapp.com/hc/en-us/articles/206141927-How-is-the-permission-hierarchy-structured- // https://support.discord.com/hc/en-us/articles/206141927-How-is-the-permission-hierarchy-structured-
func memberPermissions(guild *Guild, channel *Channel, member *Member) (apermissions int) { func memberPermissions(guild *Guild, channel *Channel, member *Member) (apermissions int) {
userID := member.User.ID userID := member.User.ID
@ -583,14 +583,6 @@ func memberPermissions(guild *Guild, channel *Channel, member *Member) (apermiss
// Guild returns a Guild structure of a specific Guild. // Guild returns a Guild structure of a specific Guild.
// guildID : The ID of a Guild // guildID : The ID of a Guild
func (s *Session) Guild(guildID string) (st *Guild, err error) { func (s *Session) Guild(guildID string) (st *Guild, err error) {
if s.StateEnabled {
// Attempt to grab the guild from State first.
st, err = s.State.Guild(guildID)
if err == nil && !st.Unavailable {
return
}
}
body, err := s.RequestWithBucketID("GET", EndpointGuild(guildID), nil, EndpointGuild(guildID)) body, err := s.RequestWithBucketID("GET", EndpointGuild(guildID), nil, EndpointGuild(guildID))
if err != nil { if err != nil {
return return
@ -931,6 +923,8 @@ type GuildChannelCreateData struct {
Topic string `json:"topic,omitempty"` Topic string `json:"topic,omitempty"`
Bitrate int `json:"bitrate,omitempty"` Bitrate int `json:"bitrate,omitempty"`
UserLimit int `json:"user_limit,omitempty"` UserLimit int `json:"user_limit,omitempty"`
RateLimitPerUser int `json:"rate_limit_per_user,omitempty"`
Position int `json:"position,omitempty"`
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"` PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"`
ParentID string `json:"parent_id,omitempty"` ParentID string `json:"parent_id,omitempty"`
NSFW bool `json:"nsfw,omitempty"` NSFW bool `json:"nsfw,omitempty"`
@ -1593,7 +1587,7 @@ func (s *Session) ChannelMessageSendComplex(channelID string, data *MessageSend)
func (s *Session) ChannelMessageSendTTS(channelID string, content string) (*Message, error) { func (s *Session) ChannelMessageSendTTS(channelID string, content string) (*Message, error) {
return s.ChannelMessageSendComplex(channelID, &MessageSend{ return s.ChannelMessageSendComplex(channelID, &MessageSend{
Content: content, Content: content,
Tts: true, TTS: true,
}) })
} }
@ -2191,7 +2185,9 @@ func (s *Session) MessageReactionsRemoveAll(channelID, messageID string) error {
// messageID : The message ID. // messageID : The message ID.
// emojiID : Either the unicode emoji for the reaction, or a guild emoji identifier. // emojiID : Either the unicode emoji for the reaction, or a guild emoji identifier.
// limit : max number of users to return (max 100) // limit : max number of users to return (max 100)
func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit int) (st []*User, err error) { // beforeID : If provided all reactions returned will be before given ID.
// afterID : If provided all reactions returned will be after given ID.
func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit int, beforeID, afterID string) (st []*User, err error) {
// emoji such as #⃣ need to have # escaped // emoji such as #⃣ need to have # escaped
emojiID = strings.Replace(emojiID, "#", "%23", -1) emojiID = strings.Replace(emojiID, "#", "%23", -1)
uri := EndpointMessageReactions(channelID, messageID, emojiID) uri := EndpointMessageReactions(channelID, messageID, emojiID)
@ -2202,6 +2198,13 @@ func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit i
v.Set("limit", strconv.Itoa(limit)) v.Set("limit", strconv.Itoa(limit))
} }
if afterID != "" {
v.Set("after", afterID)
}
if beforeID != "" {
v.Set("before", beforeID)
}
if len(v) > 0 { if len(v) > 0 {
uri += "?" + v.Encode() uri += "?" + v.Encode()
} }

View File

@ -848,6 +848,12 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
err = s.MemberAdd(t.Members[i]) err = s.MemberAdd(t.Members[i])
} }
} }
if s.TrackPresences {
for _, p := range t.Presences {
err = s.PresenceAdd(t.GuildID, p)
}
}
case *GuildRoleCreate: case *GuildRoleCreate:
if s.TrackRoles { if s.TrackRoles {
err = s.RoleAdd(t.GuildID, t.Role) err = s.RoleAdd(t.GuildID, t.Role)
@ -893,6 +899,13 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
} }
case *MessageDelete: case *MessageDelete:
if s.MaxMessageCount != 0 { if s.MaxMessageCount != 0 {
var old *Message
old, err = s.Message(t.ChannelID, t.ID)
if err == nil {
oldCopy := *old
t.BeforeDelete = &oldCopy
}
err = s.MessageRemove(t.Message) err = s.MessageRemove(t.Message)
} }
case *MessageDeleteBulk: case *MessageDeleteBulk:

View File

@ -29,7 +29,9 @@ type Session struct {
// General configurable settings. // General configurable settings.
// Authentication token for this session // Authentication token for this session
// TODO: Remove Below, Deprecated, Use Identify struct
Token string Token string
MFA bool MFA bool
// Debug for printing JSON request/responses // Debug for printing JSON request/responses
@ -39,6 +41,11 @@ type Session struct {
// Should the session reconnect the websocket on errors. // Should the session reconnect the websocket on errors.
ShouldReconnectOnError bool ShouldReconnectOnError bool
// Identify is sent during initial handshake with the discord gateway.
// https://discord.com/developers/docs/topics/gateway#identify
Identify Identify
// TODO: Remove Below, Deprecated, Use Identify struct
// Should the session request compressed websocket data. // Should the session request compressed websocket data.
Compress bool Compress bool
@ -590,6 +597,7 @@ type Presence struct {
User *User `json:"user"` User *User `json:"user"`
Status Status `json:"status"` Status Status `json:"status"`
Game *Game `json:"game"` Game *Game `json:"game"`
Activities []*Game `json:"activities"`
Nick string `json:"nick"` Nick string `json:"nick"`
Roles []string `json:"roles"` Roles []string `json:"roles"`
Since *int `json:"since"` Since *int `json:"since"`
@ -604,6 +612,7 @@ const (
GameTypeStreaming GameTypeStreaming
GameTypeListening GameTypeListening
GameTypeWatching GameTypeWatching
GameTypeCustom
) )
// A Game struct holds the name of the "playing .." game for a user // A Game struct holds the name of the "playing .." game for a user
@ -687,7 +696,7 @@ type Settings struct {
RenderEmbeds bool `json:"render_embeds"` RenderEmbeds bool `json:"render_embeds"`
InlineEmbedMedia bool `json:"inline_embed_media"` InlineEmbedMedia bool `json:"inline_embed_media"`
InlineAttachmentMedia bool `json:"inline_attachment_media"` InlineAttachmentMedia bool `json:"inline_attachment_media"`
EnableTtsCommand bool `json:"enable_tts_command"` EnableTTSCommand bool `json:"enable_tts_command"`
MessageDisplayCompact bool `json:"message_display_compact"` MessageDisplayCompact bool `json:"message_display_compact"`
ShowCurrentGame bool `json:"show_current_game"` ShowCurrentGame bool `json:"show_current_game"`
ConvertEmoticons bool `json:"convert_emoticons"` ConvertEmoticons bool `json:"convert_emoticons"`
@ -909,8 +918,63 @@ type GatewayBotResponse struct {
Shards int `json:"shards"` Shards int `json:"shards"`
} }
// GatewayStatusUpdate is sent by the client to indicate a presence or status update
// https://discord.com/developers/docs/topics/gateway#update-status-gateway-status-update-structure
type GatewayStatusUpdate struct {
Since int `json:"since"`
Game Activity `json:"game"`
Status string `json:"status"`
AFK bool `json:"afk"`
}
// Activity defines the Activity sent with GatewayStatusUpdate
// https://discord.com/developers/docs/topics/gateway#activity-object
type Activity struct {
Name string
Type ActivityType
URL string
}
// ActivityType is the type of Activity (see ActivityType* consts) in the Activity struct
// https://discord.com/developers/docs/topics/gateway#activity-object-activity-types
type ActivityType int
// Valid ActivityType values
// https://discord.com/developers/docs/topics/gateway#activity-object-activity-types
const (
ActivityTypeGame GameType = iota
ActivityTypeStreaming
ActivityTypeListening
// ActivityTypeWatching // not valid in this use case?
ActivityTypeCustom = 4
)
// Identify is sent during initial handshake with the discord gateway.
// https://discord.com/developers/docs/topics/gateway#identify
type Identify struct {
Token string `json:"token"`
Properties IdentifyProperties `json:"properties"`
Compress bool `json:"compress"`
LargeThreshold int `json:"large_threshold"`
Shard *[2]int `json:"shard,omitempty"`
Presence GatewayStatusUpdate `json:"presence,omitempty"`
GuildSubscriptions bool `json:"guild_subscriptions"`
Intents *Intent `json:"intents,omitempty"`
}
// IdentifyProperties contains the "properties" portion of an Identify packet
// https://discord.com/developers/docs/topics/gateway#identify-identify-connection-properties
type IdentifyProperties struct {
OS string `json:"$os"`
Browser string `json:"$browser"`
Device string `json:"$device"`
Referer string `json:"$referer"`
ReferringDomain string `json:"$referring_domain"`
}
// Constants for the different bit offsets of text channel permissions // Constants for the different bit offsets of text channel permissions
const ( const (
// Deprecated: PermissionReadMessages has been replaced with PermissionViewChannel for text and voice channels
PermissionReadMessages = 1 << (iota + 10) PermissionReadMessages = 1 << (iota + 10)
PermissionSendMessages PermissionSendMessages
PermissionSendTTSMessages PermissionSendTTSMessages
@ -952,8 +1016,9 @@ const (
PermissionManageServer PermissionManageServer
PermissionAddReactions PermissionAddReactions
PermissionViewAuditLogs PermissionViewAuditLogs
PermissionViewChannel = 1 << (iota + 2)
PermissionAllText = PermissionReadMessages | PermissionAllText = PermissionViewChannel |
PermissionSendMessages | PermissionSendMessages |
PermissionSendTTSMessages | PermissionSendTTSMessages |
PermissionManageMessages | PermissionManageMessages |
@ -961,7 +1026,8 @@ const (
PermissionAttachFiles | PermissionAttachFiles |
PermissionReadMessageHistory | PermissionReadMessageHistory |
PermissionMentionEveryone PermissionMentionEveryone
PermissionAllVoice = PermissionVoiceConnect | PermissionAllVoice = PermissionViewChannel |
PermissionVoiceConnect |
PermissionVoiceSpeak | PermissionVoiceSpeak |
PermissionVoiceMuteMembers | PermissionVoiceMuteMembers |
PermissionVoiceDeafenMembers | PermissionVoiceDeafenMembers |
@ -1037,3 +1103,49 @@ const (
ErrCodeReactionBlocked = 90001 ErrCodeReactionBlocked = 90001
) )
// Intent is the type of a Gateway Intent
// https://discord.com/developers/docs/topics/gateway#gateway-intents
type Intent int
// Constants for the different bit offsets of intents
const (
IntentsGuilds Intent = 1 << iota
IntentsGuildMembers
IntentsGuildBans
IntentsGuildEmojis
IntentsGuildIntegrations
IntentsGuildWebhooks
IntentsGuildInvites
IntentsGuildVoiceStates
IntentsGuildPresences
IntentsGuildMessages
IntentsGuildMessageReactions
IntentsGuildMessageTyping
IntentsDirectMessages
IntentsDirectMessageReactions
IntentsDirectMessageTyping
IntentsAllWithoutPrivileged = IntentsGuilds |
IntentsGuildBans |
IntentsGuildEmojis |
IntentsGuildIntegrations |
IntentsGuildWebhooks |
IntentsGuildInvites |
IntentsGuildVoiceStates |
IntentsGuildMessages |
IntentsGuildMessageReactions |
IntentsGuildMessageTyping |
IntentsDirectMessages |
IntentsDirectMessageReactions |
IntentsDirectMessageTyping
IntentsAll = IntentsAllWithoutPrivileged |
IntentsGuildMembers |
IntentsGuildPresences
IntentsNone Intent = 0
)
// MakeIntent helps convert a gateway intent value for use in the Identify structure.
func MakeIntent(intents Intent) *Intent {
return &intents
}

View File

@ -12,6 +12,6 @@ func SnowflakeTimestamp(ID string) (t time.Time, err error) {
return return
} }
timestamp := (i >> 22) + 1420070400000 timestamp := (i >> 22) + 1420070400000
t = time.Unix(timestamp/1000, 0) t = time.Unix(0, timestamp*1000000)
return return
} }

View File

@ -346,6 +346,25 @@ func (v *VoiceConnection) wsListen(wsConn *websocket.Conn, close <-chan struct{}
for { for {
_, message, err := v.wsConn.ReadMessage() _, message, err := v.wsConn.ReadMessage()
if err != nil { if err != nil {
// 4014 indicates a manual disconnection by someone in the guild;
// we shouldn't reconnect.
if websocket.IsCloseError(err, 4014) {
v.log(LogInformational, "received 4014 manual disconnection")
// Abandon the voice WS connection
v.Lock()
v.wsConn = nil
v.Unlock()
v.session.Lock()
delete(v.session.VoiceConnections, v.GuildID)
v.session.Unlock()
v.Close()
return
}
// Detect if we have been closed manually. If a Close() has already // Detect if we have been closed manually. If a Close() has already
// happened, the websocket we are listening on will be different to the // happened, the websocket we are listening on will be different to the
// current session. // current session.

View File

@ -18,7 +18,6 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"runtime"
"sync/atomic" "sync/atomic"
"time" "time"
@ -47,7 +46,7 @@ type resumePacket struct {
} }
// Open creates a websocket connection to Discord. // Open creates a websocket connection to Discord.
// See: https://discordapp.com/developers/docs/topics/gateway#connecting // See: https://discord.com/developers/docs/topics/gateway#connecting
func (s *Session) Open() error { func (s *Session) Open() error {
s.log(LogInformational, "called") s.log(LogInformational, "called")
@ -80,7 +79,7 @@ func (s *Session) Open() error {
header.Add("accept-encoding", "zlib") header.Add("accept-encoding", "zlib")
s.wsConn, _, err = websocket.DefaultDialer.Dial(s.gateway, header) s.wsConn, _, err = websocket.DefaultDialer.Dial(s.gateway, header)
if err != nil { if err != nil {
s.log(LogWarning, "error connecting to gateway %s, %s", s.gateway, err) s.log(LogError, "error connecting to gateway %s, %s", s.gateway, err)
s.gateway = "" // clear cached gateway s.gateway = "" // clear cached gateway
s.wsConn = nil // Just to be safe. s.wsConn = nil // Just to be safe.
return err return err
@ -399,9 +398,10 @@ func (s *Session) UpdateStatusComplex(usd UpdateStatusData) (err error) {
} }
type requestGuildMembersData struct { type requestGuildMembersData struct {
GuildID string `json:"guild_id"` GuildIDs []string `json:"guild_id"`
Query string `json:"query"` Query string `json:"query"`
Limit int `json:"limit"` Limit int `json:"limit"`
Presences bool `json:"presences"`
} }
type requestGuildMembersOp struct { type requestGuildMembersOp struct {
@ -411,10 +411,39 @@ type requestGuildMembersOp struct {
// RequestGuildMembers requests guild members from the gateway // RequestGuildMembers requests guild members from the gateway
// The gateway responds with GuildMembersChunk events // The gateway responds with GuildMembersChunk events
// guildID : The ID of the guild to request members of // guildID : Single Guild ID to request members of
// query : String that username starts with, leave empty to return all members // query : String that username starts with, leave empty to return all members
// limit : Max number of items to return, or 0 to request all members matched // limit : Max number of items to return, or 0 to request all members matched
func (s *Session) RequestGuildMembers(guildID, query string, limit int) (err error) { // presences : Whether to request presences of guild members
func (s *Session) RequestGuildMembers(guildID string, query string, limit int, presences bool) (err error) {
data := requestGuildMembersData{
GuildIDs: []string{guildID},
Query: query,
Limit: limit,
Presences: presences,
}
err = s.requestGuildMembers(data)
return
}
// RequestGuildMembersBatch requests guild members from the gateway
// The gateway responds with GuildMembersChunk events
// guildID : Slice of guild IDs to request members of
// query : String that username starts with, leave empty to return all members
// limit : Max number of items to return, or 0 to request all members matched
// presences : Whether to request presences of guild members
func (s *Session) RequestGuildMembersBatch(guildIDs []string, query string, limit int, presences bool) (err error) {
data := requestGuildMembersData{
GuildIDs: guildIDs,
Query: query,
Limit: limit,
Presences: presences,
}
err = s.requestGuildMembers(data)
return
}
func (s *Session) requestGuildMembers(data requestGuildMembersData) (err error) {
s.log(LogInformational, "called") s.log(LogInformational, "called")
s.RLock() s.RLock()
@ -423,12 +452,6 @@ func (s *Session) RequestGuildMembers(guildID, query string, limit int) (err err
return ErrWSNotFound return ErrWSNotFound
} }
data := requestGuildMembersData{
GuildID: guildID,
Query: query,
Limit: limit,
}
s.wsMutex.Lock() s.wsMutex.Lock()
err = s.wsConn.WriteJSON(requestGuildMembersOp{8, data}) err = s.wsConn.WriteJSON(requestGuildMembersOp{8, data})
s.wsMutex.Unlock() s.wsMutex.Unlock()
@ -498,7 +521,7 @@ func (s *Session) onEvent(messageType int, message []byte) (*Event, error) {
// Must immediately disconnect from gateway and reconnect to new gateway. // Must immediately disconnect from gateway and reconnect to new gateway.
if e.Operation == 7 { if e.Operation == 7 {
s.log(LogInformational, "Closing and reconnecting in response to Op7") s.log(LogInformational, "Closing and reconnecting in response to Op7")
s.Close() s.CloseWithCode(websocket.CloseServiceRestart)
s.reconnect() s.reconnect()
return e, nil return e, nil
} }
@ -722,55 +745,42 @@ func (s *Session) onVoiceServerUpdate(st *VoiceServerUpdate) {
} }
} }
type identifyProperties struct {
OS string `json:"$os"`
Browser string `json:"$browser"`
Device string `json:"$device"`
Referer string `json:"$referer"`
ReferringDomain string `json:"$referring_domain"`
}
type identifyData struct {
Token string `json:"token"`
Properties identifyProperties `json:"properties"`
LargeThreshold int `json:"large_threshold"`
Compress bool `json:"compress"`
Shard *[2]int `json:"shard,omitempty"`
}
type identifyOp struct { type identifyOp struct {
Op int `json:"op"` Op int `json:"op"`
Data identifyData `json:"d"` Data Identify `json:"d"`
} }
// identify sends the identify packet to the gateway // identify sends the identify packet to the gateway
func (s *Session) identify() error { func (s *Session) identify() error {
s.log(LogDebug, "called")
properties := identifyProperties{runtime.GOOS, // TODO: This is a temporary block of code to help
"Discordgo v" + VERSION, // maintain backwards compatability
"", if s.Compress == false {
"", s.Identify.Compress = false
"",
} }
data := identifyData{s.Token, // TODO: This is a temporary block of code to help
properties, // maintain backwards compatability
250, if s.Token != "" && s.Identify.Token == "" {
s.Compress, s.Identify.Token = s.Token
nil,
} }
// TODO: Below block should be refactored so ShardID and ShardCount
// can be deprecated and their usage moved to the Session.Identify
// struct
if s.ShardCount > 1 { if s.ShardCount > 1 {
if s.ShardID >= s.ShardCount { if s.ShardID >= s.ShardCount {
return ErrWSShardBounds return ErrWSShardBounds
} }
data.Shard = &[2]int{s.ShardID, s.ShardCount} s.Identify.Shard = &[2]int{s.ShardID, s.ShardCount}
} }
op := identifyOp{2, data} // Send Identify packet to Discord
op := identifyOp{2, s.Identify}
s.log(LogDebug, "Identify Packet: \n%#v", op)
s.wsMutex.Lock() s.wsMutex.Lock()
err := s.wsConn.WriteJSON(op) err := s.wsConn.WriteJSON(op)
s.wsMutex.Unlock() s.wsMutex.Unlock()
@ -834,8 +844,15 @@ func (s *Session) reconnect() {
} }
// Close closes a websocket and stops all listening/heartbeat goroutines. // Close closes a websocket and stops all listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP
func (s *Session) Close() error {
return s.CloseWithCode(websocket.CloseNormalClosure)
}
// CloseWithCode closes a websocket using the provided closeCode and stops all
// listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP connections // TODO: Add support for Voice WS/UDP connections
func (s *Session) Close() (err error) { func (s *Session) CloseWithCode(closeCode int) (err error) {
s.log(LogInformational, "called") s.log(LogInformational, "called")
s.Lock() s.Lock()
@ -857,7 +874,7 @@ func (s *Session) Close() (err error) {
// To cleanly close a connection, a client should send a close // To cleanly close a connection, a client should send a close
// frame and wait for the server to close the connection. // frame and wait for the server to close the connection.
s.wsMutex.Lock() s.wsMutex.Lock()
err := s.wsConn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) err := s.wsConn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, ""))
s.wsMutex.Unlock() s.wsMutex.Unlock()
if err != nil { if err != nil {
s.log(LogInformational, "error closing websocket, %s", err) s.log(LogInformational, "error closing websocket, %s", err)

View File

@ -32,6 +32,8 @@ matrix:
script: go test -v -mod=vendor ./... script: go test -v -mod=vendor ./...
- go: "1.13.x" - go: "1.13.x"
script: go test -v -mod=vendor ./... script: go test -v -mod=vendor ./...
- go: "1.14.x"
script: go test -v -mod=vendor ./...
- go: "tip" - go: "tip"
script: go test -v -mod=vendor ./... script: go test -v -mod=vendor ./...

View File

@ -41,8 +41,11 @@ type BlockAction struct {
SelectedOption OptionBlockObject `json:"selected_option"` SelectedOption OptionBlockObject `json:"selected_option"`
SelectedOptions []OptionBlockObject `json:"selected_options"` SelectedOptions []OptionBlockObject `json:"selected_options"`
SelectedUser string `json:"selected_user"` SelectedUser string `json:"selected_user"`
SelectedUsers []string `json:"selected_users"`
SelectedChannel string `json:"selected_channel"` SelectedChannel string `json:"selected_channel"`
SelectedChannels []string `json:"selected_channels"`
SelectedConversation string `json:"selected_conversation"` SelectedConversation string `json:"selected_conversation"`
SelectedConversations []string `json:"selected_conversations"`
SelectedDate string `json:"selected_date"` SelectedDate string `json:"selected_date"`
InitialOption OptionBlockObject `json:"initial_option"` InitialOption OptionBlockObject `json:"initial_option"`
InitialUser string `json:"initial_user"` InitialUser string `json:"initial_user"`

View File

@ -2,6 +2,7 @@ package slack
import ( import (
"encoding/json" "encoding/json"
"fmt"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -172,10 +173,12 @@ func (b *BlockElements) UnmarshalJSON(data []byte) error {
blockElement = &DatePickerBlockElement{} blockElement = &DatePickerBlockElement{}
case "plain_text_input": case "plain_text_input":
blockElement = &PlainTextInputBlockElement{} blockElement = &PlainTextInputBlockElement{}
case "checkboxes":
blockElement = &CheckboxGroupsBlockElement{}
case "static_select", "external_select", "users_select", "conversations_select", "channels_select": case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
blockElement = &SelectBlockElement{} blockElement = &SelectBlockElement{}
default: default:
return errors.New("unsupported block element type") return fmt.Errorf("unsupported block element type %v", blockElementType)
} }
err = json.Unmarshal(r, blockElement) err = json.Unmarshal(r, blockElement)
@ -275,6 +278,12 @@ func (a *Accessory) UnmarshalJSON(data []byte) error {
return err return err
} }
a.MultiSelectElement = element.(*MultiSelectBlockElement) a.MultiSelectElement = element.(*MultiSelectBlockElement)
case "checkboxes":
element, err := unmarshalBlockElement(r, &CheckboxGroupsBlockElement{})
if err != nil {
return err
}
a.CheckboxGroupsBlockElement = element.(*CheckboxGroupsBlockElement)
default: default:
element, err := unmarshalBlockElement(r, &UnknownBlockElement{}) element, err := unmarshalBlockElement(r, &UnknownBlockElement{})
if err != nil { if err != nil {
@ -313,6 +322,9 @@ func toBlockElement(element *Accessory) BlockElement {
if element.RadioButtonsElement != nil { if element.RadioButtonsElement != nil {
return element.RadioButtonsElement return element.RadioButtonsElement
} }
if element.CheckboxGroupsBlockElement != nil {
return element.CheckboxGroupsBlockElement
}
if element.SelectElement != nil { if element.SelectElement != nil {
return element.SelectElement return element.SelectElement
} }

View File

@ -48,6 +48,7 @@ type Accessory struct {
RadioButtonsElement *RadioButtonsBlockElement RadioButtonsElement *RadioButtonsBlockElement
SelectElement *SelectBlockElement SelectElement *SelectBlockElement
MultiSelectElement *MultiSelectBlockElement MultiSelectElement *MultiSelectBlockElement
CheckboxGroupsBlockElement *CheckboxGroupsBlockElement
UnknownElement *UnknownBlockElement UnknownElement *UnknownBlockElement
} }
@ -70,6 +71,8 @@ func NewAccessory(element BlockElement) *Accessory {
return &Accessory{SelectElement: element.(*SelectBlockElement)} return &Accessory{SelectElement: element.(*SelectBlockElement)}
case *MultiSelectBlockElement: case *MultiSelectBlockElement:
return &Accessory{MultiSelectElement: element.(*MultiSelectBlockElement)} return &Accessory{MultiSelectElement: element.(*MultiSelectBlockElement)}
case *CheckboxGroupsBlockElement:
return &Accessory{CheckboxGroupsBlockElement: element.(*CheckboxGroupsBlockElement)}
default: default:
return &Accessory{UnknownElement: element.(*UnknownBlockElement)} return &Accessory{UnknownElement: element.(*UnknownBlockElement)}
} }
@ -152,9 +155,10 @@ func (s ButtonBlockElement) ElementType() MessageElementType {
return s.Type return s.Type
} }
// add styling to button object // WithStyling adds styling to the button object and returns the modified ButtonBlockElement
func (s *ButtonBlockElement) WithStyle(style Style) { func (s *ButtonBlockElement) WithStyle(style Style) *ButtonBlockElement {
s.Style = style s.Style = style
return s
} }
// NewButtonBlockElement returns an instance of a new button element to be used within a block // NewButtonBlockElement returns an instance of a new button element to be used within a block
@ -195,6 +199,8 @@ type SelectBlockElement struct {
InitialUser string `json:"initial_user,omitempty"` InitialUser string `json:"initial_user,omitempty"`
InitialConversation string `json:"initial_conversation,omitempty"` InitialConversation string `json:"initial_conversation,omitempty"`
InitialChannel string `json:"initial_channel,omitempty"` InitialChannel string `json:"initial_channel,omitempty"`
DefaultToCurrentConversation bool `json:"default_to_current_conversation,omitempty"`
ResponseURLEnabled bool `json:"response_url_enabled,omitempty"`
MinQueryLength *int `json:"min_query_length,omitempty"` MinQueryLength *int `json:"min_query_length,omitempty"`
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
} }
@ -315,7 +321,7 @@ func NewOverflowBlockElement(actionID string, options ...*OptionBlockObject) *Ov
// More Information: https://api.slack.com/reference/messaging/block-elements#datepicker // More Information: https://api.slack.com/reference/messaging/block-elements#datepicker
type DatePickerBlockElement struct { type DatePickerBlockElement struct {
Type MessageElementType `json:"type"` Type MessageElementType `json:"type"`
ActionID string `json:"action_id"` ActionID string `json:"action_id,omitempty"`
Placeholder *TextBlockObject `json:"placeholder,omitempty"` Placeholder *TextBlockObject `json:"placeholder,omitempty"`
InitialDate string `json:"initial_date,omitempty"` InitialDate string `json:"initial_date,omitempty"`
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
@ -341,7 +347,7 @@ func NewDatePickerBlockElement(actionID string) *DatePickerBlockElement {
// More Information: https://api.slack.com/reference/block-kit/block-elements#input // More Information: https://api.slack.com/reference/block-kit/block-elements#input
type PlainTextInputBlockElement struct { type PlainTextInputBlockElement struct {
Type MessageElementType `json:"type"` Type MessageElementType `json:"type"`
ActionID string `json:"action_id"` ActionID string `json:"action_id,omitempty"`
Placeholder *TextBlockObject `json:"placeholder,omitempty"` Placeholder *TextBlockObject `json:"placeholder,omitempty"`
InitialValue string `json:"initial_value,omitempty"` InitialValue string `json:"initial_value,omitempty"`
Multiline bool `json:"multiline,omitempty"` Multiline bool `json:"multiline,omitempty"`
@ -370,7 +376,7 @@ func NewPlainTextInputBlockElement(placeholder *TextBlockObject, actionID string
// More Information: https://api.slack.com/reference/block-kit/block-elements#checkboxes // More Information: https://api.slack.com/reference/block-kit/block-elements#checkboxes
type CheckboxGroupsBlockElement struct { type CheckboxGroupsBlockElement struct {
Type MessageElementType `json:"type"` Type MessageElementType `json:"type"`
ActionID string `json:"action_id"` ActionID string `json:"action_id,omitempty"`
Options []*OptionBlockObject `json:"options"` Options []*OptionBlockObject `json:"options"`
InitialOptions []*OptionBlockObject `json:"initial_options,omitempty"` InitialOptions []*OptionBlockObject `json:"initial_options,omitempty"`
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
@ -381,7 +387,7 @@ func (c CheckboxGroupsBlockElement) ElementType() MessageElementType {
return c.Type return c.Type
} }
// NewRadioButtonsBlockElement returns an instance of a radio block element // NewCheckboxGroupsBlockElement returns an instance of a radio block element
func NewCheckboxGroupsBlockElement(actionID string, options ...*OptionBlockObject) *CheckboxGroupsBlockElement { func NewCheckboxGroupsBlockElement(actionID string, options ...*OptionBlockObject) *CheckboxGroupsBlockElement {
return &CheckboxGroupsBlockElement{ return &CheckboxGroupsBlockElement{
Type: METCheckboxGroups, Type: METCheckboxGroups,
@ -396,7 +402,7 @@ func NewCheckboxGroupsBlockElement(actionID string, options ...*OptionBlockObjec
// More Information: https://api.slack.com/reference/block-kit/block-elements#radio // More Information: https://api.slack.com/reference/block-kit/block-elements#radio
type RadioButtonsBlockElement struct { type RadioButtonsBlockElement struct {
Type MessageElementType `json:"type"` Type MessageElementType `json:"type"`
ActionID string `json:"action_id"` ActionID string `json:"action_id,omitempty"`
Options []*OptionBlockObject `json:"options"` Options []*OptionBlockObject `json:"options"`
InitialOption *OptionBlockObject `json:"initial_option,omitempty"` InitialOption *OptionBlockObject `json:"initial_option,omitempty"`
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`

View File

@ -8,7 +8,7 @@ type ImageBlock struct {
ImageURL string `json:"image_url"` ImageURL string `json:"image_url"`
AltText string `json:"alt_text"` AltText string `json:"alt_text"`
BlockID string `json:"block_id,omitempty"` BlockID string `json:"block_id,omitempty"`
Title *TextBlockObject `json:"title"` Title *TextBlockObject `json:"title,omitempty"`
} }
// BlockType returns the type of the block // BlockType returns the type of the block

View File

@ -163,6 +163,7 @@ type ConfirmationBlockObject struct {
Text *TextBlockObject `json:"text"` Text *TextBlockObject `json:"text"`
Confirm *TextBlockObject `json:"confirm"` Confirm *TextBlockObject `json:"confirm"`
Deny *TextBlockObject `json:"deny"` Deny *TextBlockObject `json:"deny"`
Style Style `json:"style,omitempty"`
} }
// validateType enforces block objects for element and block parameters // validateType enforces block objects for element and block parameters
@ -170,6 +171,11 @@ func (s ConfirmationBlockObject) validateType() MessageObjectType {
return motConfirmation return motConfirmation
} }
// add styling to confirmation object
func (s *ConfirmationBlockObject) WithStyle(style Style) {
s.Style = style
}
// NewConfirmationBlockObject returns an instance of a new Confirmation Block Object // NewConfirmationBlockObject returns an instance of a new Confirmation Block Object
func NewConfirmationBlockObject(title, text, confirm, deny *TextBlockObject) *ConfirmationBlockObject { func NewConfirmationBlockObject(title, text, confirm, deny *TextBlockObject) *ConfirmationBlockObject {
return &ConfirmationBlockObject{ return &ConfirmationBlockObject{

View File

@ -1,8 +1,10 @@
package slack package slack
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -206,6 +208,15 @@ func (api *Client) SendMessageContext(ctx context.Context, channelID string, opt
return "", "", "", err return "", "", "", err
} }
if api.Debug() {
reqBody, err := ioutil.ReadAll(req.Body)
if err != nil {
return "", "", "", err
}
req.Body = ioutil.NopCloser(bytes.NewBuffer(reqBody))
api.Debugf("Sending request: %s", string(reqBody))
}
if err = doPost(ctx, api.httpclient, req, parser(&response), api); err != nil { if err = doPost(ctx, api.httpclient, req, parser(&response), api); err != nil {
return "", "", "", err return "", "", "", err
} }

View File

@ -1,9 +1,11 @@
module github.com/slack-go/slack module github.com/slack-go/slack
require ( require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-test/deep v1.0.4 github.com/go-test/deep v1.0.4
github.com/gorilla/websocket v1.2.0 github.com/gorilla/websocket v1.4.2
github.com/pkg/errors v0.8.0 github.com/pkg/errors v0.8.0
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2 github.com/stretchr/testify v1.2.2
) )

View File

@ -4,6 +4,8 @@ github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@ -61,6 +61,11 @@ type InteractionCallback struct {
type Container struct { type Container struct {
Type string `json:"type"` Type string `json:"type"`
ViewID string `json:"view_id"` ViewID string `json:"view_id"`
MessageTs string `json:"message_ts"`
AttachmentID json.Number `json:"attachment_id"`
ChannelID string `json:"channel_id"`
IsEphemeral bool `json:"is_ephemeral"`
IsAppUnfurl bool `json:"is_app_unfurl"`
} }
// ActionCallback is a convenience struct defined to allow dynamic unmarshalling of // ActionCallback is a convenience struct defined to allow dynamic unmarshalling of
@ -135,7 +140,7 @@ func (a *ActionCallbacks) UnmarshalJSON(data []byte) error {
} }
a.BlockActions = append(a.BlockActions, action.(*BlockAction)) a.BlockActions = append(a.BlockActions, action.(*BlockAction))
return nil continue
} }
action, err := unmarshalAction(r, &AttachmentAction{}) action, err := unmarshalAction(r, &AttachmentAction{})

View File

@ -78,10 +78,26 @@ func GetOAuthTokenContext(ctx context.Context, client httpClient, clientID, clie
return response.AccessToken, response.Scope, nil return response.AccessToken, response.Scope, nil
} }
// GetBotOAuthToken retrieves top-level and bot AccessToken - https://api.slack.com/legacy/oauth#bot_user_access_tokens
func GetBotOAuthToken(client httpClient, clientID, clientSecret, code, redirectURI string) (accessToken string, scope string, bot OAuthResponseBot, err error) {
return GetBotOAuthTokenContext(context.Background(), client, clientID, clientSecret, code, redirectURI)
}
// GetBotOAuthTokenContext retrieves top-level and bot AccessToken with a custom context
func GetBotOAuthTokenContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string) (accessToken string, scope string, bot OAuthResponseBot, err error) {
response, err := GetOAuthResponseContext(ctx, client, clientID, clientSecret, code, redirectURI)
if err != nil {
return "", "", OAuthResponseBot{}, err
}
return response.AccessToken, response.Scope, response.Bot, nil
}
// GetOAuthResponse retrieves OAuth response
func GetOAuthResponse(client httpClient, clientID, clientSecret, code, redirectURI string) (resp *OAuthResponse, err error) { func GetOAuthResponse(client httpClient, clientID, clientSecret, code, redirectURI string) (resp *OAuthResponse, err error) {
return GetOAuthResponseContext(context.Background(), client, clientID, clientSecret, code, redirectURI) return GetOAuthResponseContext(context.Background(), client, clientID, clientSecret, code, redirectURI)
} }
// GetOAuthResponseContext retrieves OAuth response with custom context
func GetOAuthResponseContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string) (resp *OAuthResponse, err error) { func GetOAuthResponseContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string) (resp *OAuthResponse, err error) {
values := url.Values{ values := url.Values{
"client_id": {clientID}, "client_id": {clientID},

View File

@ -14,6 +14,7 @@ type WebhookMessage struct {
Text string `json:"text,omitempty"` Text string `json:"text,omitempty"`
Attachments []Attachment `json:"attachments,omitempty"` Attachments []Attachment `json:"attachments,omitempty"`
Parse string `json:"parse,omitempty"` Parse string `json:"parse,omitempty"`
Blocks *Blocks `json:"blocks,omitempty"`
} }
func PostWebhook(url string, msg *WebhookMessage) error { func PostWebhook(url string, msg *WebhookMessage) error {

View File

@ -58,6 +58,32 @@ var scopes = []string{msauth.DefaultMSGraphScope}
... ...
``` ```
### Resource owner password credentials grant
- [OAuth 2.0 resource owner passowrd credentials grant flow]
```go
const (
tenantID = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
clientID = "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY"
clientSecret = "ZZZZZZZZZZZZZZZZZZZZZZZZ"
username = "user.name@your-domain.com"
password = "secure-password"
)
var scopes = []string{msauth.DefaultMSGraphScope}
ctx := context.Background()
m := msauth.NewManager()
ts, err := m.ResourceOwnerPasswordGrant(ctx, tenantID, clientID, clientSecret, username, password, scopes)
if err != nil {
log.Fatal(err)
}
httpClient := oauth2.NewClient(ctx, ts)
...
```
### Authorization code grant ### Authorization code grant
- [OAuth 2.0 authorization code grant flow] - [OAuth 2.0 authorization code grant flow]
@ -68,3 +94,4 @@ var scopes = []string{msauth.DefaultMSGraphScope}
[OAuth 2.0 device authorization grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code [OAuth 2.0 device authorization grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code
[OAuth 2.0 client credentials grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow [OAuth 2.0 client credentials grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
[OAuth 2.0 authorization code grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow [OAuth 2.0 authorization code grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
[OAuth 2.0 resource owner passowrd credentials grant flow]: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc

View File

@ -39,9 +39,10 @@ func (m *Manager) DeviceAuthorizationGrant(ctx context.Context, tenantID, client
Endpoint: endpoint, Endpoint: endpoint,
Scopes: scopes, Scopes: scopes,
} }
if t, ok := m.TokenCache[generateKey(tenantID, clientID)]; ok { if t, ok := m.GetToken(CacheKey(tenantID, clientID)); ok {
tt, err := config.TokenSource(ctx, t).Token() tt, err := config.TokenSource(ctx, t).Token()
if err == nil { if err == nil {
m.PutToken(CacheKey(tenantID, clientID), tt)
return config.TokenSource(ctx, tt), nil return config.TokenSource(ctx, tt), nil
} }
if _, ok := err.(*oauth2.RetrieveError); !ok { if _, ok := err.(*oauth2.RetrieveError); !ok {
@ -85,7 +86,7 @@ func (m *Manager) DeviceAuthorizationGrant(ctx context.Context, tenantID, client
time.Sleep(time.Second * time.Duration(interval)) time.Sleep(time.Second * time.Duration(interval))
token, err := m.requestToken(ctx, tenantID, clientID, values) token, err := m.requestToken(ctx, tenantID, clientID, values)
if err == nil { if err == nil {
m.Cache(tenantID, clientID, token) m.PutToken(CacheKey(tenantID, clientID), token)
return config.TokenSource(ctx, token), nil return config.TokenSource(ctx, token), nil
} }
tokenError, ok := err.(*TokenError) tokenError, ok := err.(*TokenError)

View File

@ -36,10 +36,6 @@ func (t *TokenError) Error() string {
return fmt.Sprintf("%s: %s", t.ErrorObject, t.ErrorDescription) return fmt.Sprintf("%s: %s", t.ErrorObject, t.ErrorDescription)
} }
func generateKey(tenantID, clientID string) string {
return fmt.Sprintf("%s:%s", tenantID, clientID)
}
func deviceCodeURL(tenantID string) string { func deviceCodeURL(tenantID string) string {
return fmt.Sprintf(endpointURLFormat, tenantID, "devicecode") return fmt.Sprintf(endpointURLFormat, tenantID, "devicecode")
} }
@ -65,6 +61,7 @@ func (e *tokenJSON) expiry() (t time.Time) {
// Manager is oauth2 token cache manager // Manager is oauth2 token cache manager
type Manager struct { type Manager struct {
mu sync.Mutex mu sync.Mutex
Dirty bool
TokenCache map[string]*oauth2.Token TokenCache map[string]*oauth2.Token
} }
@ -87,27 +84,64 @@ func (m *Manager) SaveBytes() ([]byte, error) {
return json.Marshal(m.TokenCache) return json.Marshal(m.TokenCache)
} }
// LoadFile loads token cache from file // LoadFile loads token cache from file with dirty state control
func (m *Manager) LoadFile(path string) error { func (m *Manager) LoadFile(path string) error {
b, err := ioutil.ReadFile(path) m.mu.Lock()
defer m.mu.Unlock()
b, err := ReadLocation(path)
if err != nil { if err != nil {
return err return err
} }
return m.LoadBytes(b) err = json.Unmarshal(b, &m.TokenCache)
if err != nil {
return err
}
m.Dirty = false
return nil
} }
// SaveFile saves token cache to file // SaveFile saves token cache to file with dirty state control
func (m *Manager) SaveFile(path string) error { func (m *Manager) SaveFile(path string) error {
b, err := m.SaveBytes() m.mu.Lock()
defer m.mu.Unlock()
if !m.Dirty {
return nil
}
b, err := json.Marshal(m.TokenCache)
if err != nil { if err != nil {
return err return err
} }
return ioutil.WriteFile(path, b, 0644) err = WriteLocation(path, b, 0644)
if err != nil {
return err
}
m.Dirty = false
return nil
} }
// Cache stores a token into token cache // CacheKey generates a token cache key from tenantID/clientID
func (m *Manager) Cache(tenantID, clientID string, token *oauth2.Token) { func CacheKey(tenantID, clientID string) string {
m.TokenCache[generateKey(tenantID, clientID)] = token return fmt.Sprintf("%s:%s", tenantID, clientID)
}
// GetToken gets a token from token cache
func (m *Manager) GetToken(cacheKey string) (*oauth2.Token, bool) {
m.mu.Lock()
defer m.mu.Unlock()
token, ok := m.TokenCache[cacheKey]
return token, ok
}
// PutToken puts a token into token cache
func (m *Manager) PutToken(cacheKey string, token *oauth2.Token) {
m.mu.Lock()
defer m.mu.Unlock()
oldToken, ok := m.TokenCache[cacheKey]
if ok && *oldToken == *token {
return
}
m.TokenCache[cacheKey] = token
m.Dirty = true
} }
// requestToken requests a token from the token endpoint // requestToken requests a token from the token endpoint

View File

@ -0,0 +1,26 @@
package msauth
import (
"context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/microsoft"
)
// ResourceOwnerPasswordGrant preforms OAuth 2.0 client resource owner password grant and returns a token.
func (m *Manager) ResourceOwnerPasswordGrant(ctx context.Context, tenantID, clientID, clientSecret, username, password string, scopes []string) (oauth2.TokenSource, error) {
endpoint := microsoft.AzureADEndpoint(tenantID)
endpoint.AuthStyle = oauth2.AuthStyleInParams
config := &oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
Endpoint: endpoint,
Scopes: scopes,
}
t, err := config.PasswordCredentialsToken(ctx, username, password)
if err != nil {
return nil, err
}
ts := config.TokenSource(ctx, t)
return ts, nil
}

View File

@ -0,0 +1,70 @@
package msauth
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
)
// ReadLocation reads data from file with path or URL
func ReadLocation(loc string) ([]byte, error) {
u, err := url.Parse(loc)
if err != nil {
return nil, err
}
switch u.Scheme {
case "", "file":
return ioutil.ReadFile(u.Path)
case "http", "https":
res, err := http.Get(loc)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s", res.Status)
}
b, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
return b, nil
}
return nil, fmt.Errorf("Unsupported location to load: %s", loc)
}
// WriteLocation writes data to file with path or URL
func WriteLocation(loc string, b []byte, m os.FileMode) error {
u, err := url.Parse(loc)
if err != nil {
return err
}
switch u.Scheme {
case "", "file":
return ioutil.WriteFile(u.Path, b, m)
case "http", "https":
if strings.HasSuffix(u.Host, ".blob.core.windows.net") {
// Azure Blob Storage URL with SAS assumed here
cli := &http.Client{}
req, err := http.NewRequest(http.MethodPut, loc, bytes.NewBuffer(b))
if err != nil {
return err
}
req.Header.Set("x-ms-blob-type", "BlockBlob")
res, err := cli.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
return fmt.Errorf("%s", res.Status)
}
return nil
}
}
return fmt.Errorf("Unsupported location to save: %s", loc)
}

View File

@ -102,9 +102,14 @@ func (a *AuthorizationError) Error() string {
for i, err := range a.Errors { for i, err := range a.Errors {
e[i] = err.Error() e[i] = err.Error()
} }
if a.Identifier != "" {
return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; ")) return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
} }
return fmt.Sprintf("acme: authorization error: %s", strings.Join(e, "; "))
}
// OrderError is returned from Client's order related methods. // OrderError is returned from Client's order related methods.
// It indicates the order is unusable and the clients should start over with // It indicates the order is unusable and the clients should start over with
// AuthorizeOrder. // AuthorizeOrder.
@ -407,6 +412,7 @@ type wireAuthz struct {
Wildcard bool Wildcard bool
Challenges []wireChallenge Challenges []wireChallenge
Combinations [][]int Combinations [][]int
Error *wireError
} }
func (z *wireAuthz) authorization(uri string) *Authorization { func (z *wireAuthz) authorization(uri string) *Authorization {
@ -430,11 +436,17 @@ func (z *wireAuthz) error(uri string) *AuthorizationError {
URI: uri, URI: uri,
Identifier: z.Identifier.Value, Identifier: z.Identifier.Value,
} }
if z.Error != nil {
err.Errors = append(err.Errors, z.Error.error(nil))
}
for _, raw := range z.Challenges { for _, raw := range z.Challenges {
if raw.Error != nil { if raw.Error != nil {
err.Errors = append(err.Errors, raw.Error.error(nil)) err.Errors = append(err.Errors, raw.Error.error(nil))
} }
} }
return err return err
} }

View File

@ -42,10 +42,14 @@ type Cipher struct {
// The last len bytes of buf are leftover key stream bytes from the previous // The last len bytes of buf are leftover key stream bytes from the previous
// XORKeyStream invocation. The size of buf depends on how many blocks are // XORKeyStream invocation. The size of buf depends on how many blocks are
// computed at a time. // computed at a time by xorKeyStreamBlocks.
buf [bufSize]byte buf [bufSize]byte
len int len int
// overflow is set when the counter overflowed, no more blocks can be
// generated, and the next XORKeyStream call should panic.
overflow bool
// The counter-independent results of the first round are cached after they // The counter-independent results of the first round are cached after they
// are computed the first time. // are computed the first time.
precompDone bool precompDone bool
@ -89,6 +93,7 @@ func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) {
return nil, errors.New("chacha20: wrong nonce size") return nil, errors.New("chacha20: wrong nonce size")
} }
key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint
c.key = [8]uint32{ c.key = [8]uint32{
binary.LittleEndian.Uint32(key[0:4]), binary.LittleEndian.Uint32(key[0:4]),
binary.LittleEndian.Uint32(key[4:8]), binary.LittleEndian.Uint32(key[4:8]),
@ -139,15 +144,18 @@ func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will // SetCounter sets the Cipher counter. The next invocation of XORKeyStream will
// behave as if (64 * counter) bytes had been encrypted so far. // behave as if (64 * counter) bytes had been encrypted so far.
// //
// To prevent accidental counter reuse, SetCounter panics if counter is // To prevent accidental counter reuse, SetCounter panics if counter is less
// less than the current value. // than the current value.
//
// Note that the execution time of XORKeyStream is not independent of the
// counter value.
func (s *Cipher) SetCounter(counter uint32) { func (s *Cipher) SetCounter(counter uint32) {
// Internally, s may buffer multiple blocks, which complicates this // Internally, s may buffer multiple blocks, which complicates this
// implementation slightly. When checking whether the counter has rolled // implementation slightly. When checking whether the counter has rolled
// back, we must use both s.counter and s.len to determine how many blocks // back, we must use both s.counter and s.len to determine how many blocks
// we have already output. // we have already output.
outputCounter := s.counter - uint32(s.len)/blockSize outputCounter := s.counter - uint32(s.len)/blockSize
if counter < outputCounter { if s.overflow || counter < outputCounter {
panic("chacha20: SetCounter attempted to rollback counter") panic("chacha20: SetCounter attempted to rollback counter")
} }
@ -196,34 +204,52 @@ func (s *Cipher) XORKeyStream(dst, src []byte) {
dst[i] = src[i] ^ b dst[i] = src[i] ^ b
} }
s.len -= len(keyStream) s.len -= len(keyStream)
src = src[len(keyStream):] dst, src = dst[len(keyStream):], src[len(keyStream):]
dst = dst[len(keyStream):] }
if len(src) == 0 {
return
} }
const blocksPerBuf = bufSize / blockSize // If we'd need to let the counter overflow and keep generating output,
numBufs := (uint64(len(src)) + bufSize - 1) / bufSize // panic immediately. If instead we'd only reach the last block, remember
if uint64(s.counter)+numBufs*blocksPerBuf >= 1<<32 { // not to generate any more output after the buffer is drained.
numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize
if s.overflow || uint64(s.counter)+numBlocks > 1<<32 {
panic("chacha20: counter overflow") panic("chacha20: counter overflow")
} else if uint64(s.counter)+numBlocks == 1<<32 {
s.overflow = true
} }
// xorKeyStreamBlocks implementations expect input lengths that are a // xorKeyStreamBlocks implementations expect input lengths that are a
// multiple of bufSize. Platform-specific ones process multiple blocks at a // multiple of bufSize. Platform-specific ones process multiple blocks at a
// time, so have bufSizes that are a multiple of blockSize. // time, so have bufSizes that are a multiple of blockSize.
rem := len(src) % bufSize full := len(src) - len(src)%bufSize
full := len(src) - rem
if full > 0 { if full > 0 {
s.xorKeyStreamBlocks(dst[:full], src[:full]) s.xorKeyStreamBlocks(dst[:full], src[:full])
} }
dst, src = dst[full:], src[full:]
// If using a multi-block xorKeyStreamBlocks would overflow, use the generic
// one that does one block at a time.
const blocksPerBuf = bufSize / blockSize
if uint64(s.counter)+blocksPerBuf > 1<<32 {
s.buf = [bufSize]byte{}
numBlocks := (len(src) + blockSize - 1) / blockSize
buf := s.buf[bufSize-numBlocks*blockSize:]
copy(buf, src)
s.xorKeyStreamBlocksGeneric(buf, buf)
s.len = len(buf) - copy(dst, buf)
return
}
// If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and // If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
// keep the leftover keystream for the next XORKeyStream invocation. // keep the leftover keystream for the next XORKeyStream invocation.
if rem > 0 { if len(src) > 0 {
s.buf = [bufSize]byte{} s.buf = [bufSize]byte{}
copy(s.buf[:], src[full:]) copy(s.buf[:], src)
s.xorKeyStreamBlocks(s.buf[:], s.buf[:]) s.xorKeyStreamBlocks(s.buf[:], s.buf[:])
s.len = bufSize - copy(dst[full:], s.buf[:]) s.len = bufSize - copy(dst, s.buf[:])
} }
} }
@ -260,7 +286,9 @@ func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
s.precompDone = true s.precompDone = true
} }
for i := 0; i < len(src); i += blockSize { // A condition of len(src) > 0 would be sufficient, but this also
// acts as a bounds check elimination hint.
for len(src) >= 64 && len(dst) >= 64 {
// The remainder of the first column round. // The remainder of the first column round.
fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter) fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter)
@ -285,49 +313,28 @@ func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
} }
// Finally, add back the initial state to generate the key stream. // Add back the initial state to generate the key stream, then
x0 += c0 // XOR the key stream with the source and write out the result.
x1 += c1 addXor(dst[0:4], src[0:4], x0, c0)
x2 += c2 addXor(dst[4:8], src[4:8], x1, c1)
x3 += c3 addXor(dst[8:12], src[8:12], x2, c2)
x4 += c4 addXor(dst[12:16], src[12:16], x3, c3)
x5 += c5 addXor(dst[16:20], src[16:20], x4, c4)
x6 += c6 addXor(dst[20:24], src[20:24], x5, c5)
x7 += c7 addXor(dst[24:28], src[24:28], x6, c6)
x8 += c8 addXor(dst[28:32], src[28:32], x7, c7)
x9 += c9 addXor(dst[32:36], src[32:36], x8, c8)
x10 += c10 addXor(dst[36:40], src[36:40], x9, c9)
x11 += c11 addXor(dst[40:44], src[40:44], x10, c10)
x12 += s.counter addXor(dst[44:48], src[44:48], x11, c11)
x13 += c13 addXor(dst[48:52], src[48:52], x12, s.counter)
x14 += c14 addXor(dst[52:56], src[52:56], x13, c13)
x15 += c15 addXor(dst[56:60], src[56:60], x14, c14)
addXor(dst[60:64], src[60:64], x15, c15)
s.counter += 1 s.counter += 1
if s.counter == 0 {
panic("chacha20: internal error: counter overflow")
}
in, out := src[i:], dst[i:] src, dst = src[blockSize:], dst[blockSize:]
in, out = in[:blockSize], out[:blockSize] // bounds check elimination hint
// XOR the key stream with the source and write out the result.
xor(out[0:], in[0:], x0)
xor(out[4:], in[4:], x1)
xor(out[8:], in[8:], x2)
xor(out[12:], in[12:], x3)
xor(out[16:], in[16:], x4)
xor(out[20:], in[20:], x5)
xor(out[24:], in[24:], x6)
xor(out[28:], in[28:], x7)
xor(out[32:], in[32:], x8)
xor(out[36:], in[36:], x9)
xor(out[40:], in[40:], x10)
xor(out[44:], in[44:], x11)
xor(out[48:], in[48:], x12)
xor(out[52:], in[52:], x13)
xor(out[56:], in[56:], x14)
xor(out[60:], in[60:], x15)
} }
} }

View File

@ -13,10 +13,10 @@ const unaligned = runtime.GOARCH == "386" ||
runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64le" ||
runtime.GOARCH == "s390x" runtime.GOARCH == "s390x"
// xor reads a little endian uint32 from src, XORs it with u and // addXor reads a little endian uint32 from src, XORs it with (a + b) and
// places the result in little endian byte order in dst. // places the result in little endian byte order in dst.
func xor(dst, src []byte, u uint32) { func addXor(dst, src []byte, a, b uint32) {
_, _ = src[3], dst[3] // eliminate bounds checks _, _ = src[3], dst[3] // bounds check elimination hint
if unaligned { if unaligned {
// The compiler should optimize this code into // The compiler should optimize this code into
// 32-bit unaligned little endian loads and stores. // 32-bit unaligned little endian loads and stores.
@ -27,15 +27,16 @@ func xor(dst, src []byte, u uint32) {
v |= uint32(src[1]) << 8 v |= uint32(src[1]) << 8
v |= uint32(src[2]) << 16 v |= uint32(src[2]) << 16
v |= uint32(src[3]) << 24 v |= uint32(src[3]) << 24
v ^= u v ^= a + b
dst[0] = byte(v) dst[0] = byte(v)
dst[1] = byte(v >> 8) dst[1] = byte(v >> 8)
dst[2] = byte(v >> 16) dst[2] = byte(v >> 16)
dst[3] = byte(v >> 24) dst[3] = byte(v >> 24)
} else { } else {
dst[0] = src[0] ^ byte(u) a += b
dst[1] = src[1] ^ byte(u>>8) dst[0] = src[0] ^ byte(a)
dst[2] = src[2] ^ byte(u>>16) dst[1] = src[1] ^ byte(a>>8)
dst[3] = src[3] ^ byte(u>>24) dst[2] = src[2] ^ byte(a>>16)
dst[3] = src[3] ^ byte(a>>24)
} }
} }

View File

@ -2,10 +2,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !amd64,!ppc64le gccgo purego // +build !amd64,!ppc64le,!s390x gccgo purego
package poly1305 package poly1305
type mac struct{ macGeneric } type mac struct{ macGeneric }
func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} }

View File

@ -26,7 +26,9 @@ const TagSize = 16
// 16-byte result into out. Authenticating two different messages with the same // 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will. // key allows an attacker to forge messages at will.
func Sum(out *[16]byte, m []byte, key *[32]byte) { func Sum(out *[16]byte, m []byte, key *[32]byte) {
sum(out, m, key) h := New(key)
h.Write(m)
h.Sum(out[:0])
} }
// Verify returns true if mac is a valid authenticator for m with the given key. // Verify returns true if mac is a valid authenticator for m with the given key.
@ -46,10 +48,9 @@ func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
// two different messages with the same key allows an attacker // two different messages with the same key allows an attacker
// to forge messages at will. // to forge messages at will.
func New(key *[32]byte) *MAC { func New(key *[32]byte) *MAC {
return &MAC{ m := &MAC{}
mac: newMAC(key), initialize(key, &m.macState)
finalized: false, return m
}
} }
// MAC is an io.Writer computing an authentication tag // MAC is an io.Writer computing an authentication tag
@ -58,7 +59,7 @@ func New(key *[32]byte) *MAC {
// MAC cannot be used like common hash.Hash implementations, // MAC cannot be used like common hash.Hash implementations,
// because using a poly1305 key twice breaks its security. // because using a poly1305 key twice breaks its security.
// Therefore writing data to a running MAC after calling // Therefore writing data to a running MAC after calling
// Sum causes it to panic. // Sum or Verify causes it to panic.
type MAC struct { type MAC struct {
mac // platform-dependent implementation mac // platform-dependent implementation
@ -71,10 +72,10 @@ func (h *MAC) Size() int { return TagSize }
// Write adds more data to the running message authentication code. // Write adds more data to the running message authentication code.
// It never returns an error. // It never returns an error.
// //
// It must not be called after the first call of Sum. // It must not be called after the first call of Sum or Verify.
func (h *MAC) Write(p []byte) (n int, err error) { func (h *MAC) Write(p []byte) (n int, err error) {
if h.finalized { if h.finalized {
panic("poly1305: write to MAC after Sum") panic("poly1305: write to MAC after Sum or Verify")
} }
return h.mac.Write(p) return h.mac.Write(p)
} }
@ -87,3 +88,12 @@ func (h *MAC) Sum(b []byte) []byte {
h.finalized = true h.finalized = true
return append(b, mac[:]...) return append(b, mac[:]...)
} }
// Verify returns whether the authenticator of all data written to
// the message authentication code matches the expected value.
func (h *MAC) Verify(expected []byte) bool {
var mac [TagSize]byte
h.mac.Sum(&mac)
h.finalized = true
return subtle.ConstantTimeCompare(expected, mac[:]) == 1
}

View File

@ -9,17 +9,6 @@ package poly1305
//go:noescape //go:noescape
func update(state *macState, msg []byte) func update(state *macState, msg []byte)
func sum(out *[16]byte, m []byte, key *[32]byte) {
h := newMAC(key)
h.Write(m)
h.Sum(out)
}
func newMAC(key *[32]byte) (h mac) {
initialize(key, &h.r, &h.s)
return
}
// mac is a wrapper for macGeneric that redirects calls that would have gone to // mac is a wrapper for macGeneric that redirects calls that would have gone to
// updateGeneric to update. // updateGeneric to update.
// //

View File

@ -31,16 +31,18 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
h.Sum(out) h.Sum(out)
} }
func newMACGeneric(key *[32]byte) (h macGeneric) { func newMACGeneric(key *[32]byte) macGeneric {
initialize(key, &h.r, &h.s) m := macGeneric{}
return initialize(key, &m.macState)
return m
} }
// macState holds numbers in saturated 64-bit little-endian limbs. That is, // macState holds numbers in saturated 64-bit little-endian limbs. That is,
// the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸. // the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸.
type macState struct { type macState struct {
// h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but // h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but
// can grow larger during and after rounds. // can grow larger during and after rounds. It must, however, remain below
// 2 * (2¹³⁰ - 5).
h [3]uint64 h [3]uint64
// r and s are the private key components. // r and s are the private key components.
r [2]uint64 r [2]uint64
@ -97,11 +99,12 @@ const (
rMask1 = 0x0FFFFFFC0FFFFFFC rMask1 = 0x0FFFFFFC0FFFFFFC
) )
func initialize(key *[32]byte, r, s *[2]uint64) { // initialize loads the 256-bit key into the two 128-bit secret values r and s.
r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0 func initialize(key *[32]byte, m *macState) {
r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1 m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0
s[0] = binary.LittleEndian.Uint64(key[16:24]) m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1
s[1] = binary.LittleEndian.Uint64(key[24:32]) m.s[0] = binary.LittleEndian.Uint64(key[16:24])
m.s[1] = binary.LittleEndian.Uint64(key[24:32])
} }
// uint128 holds a 128-bit number as two 64-bit limbs, for use with the // uint128 holds a 128-bit number as two 64-bit limbs, for use with the

View File

@ -1,13 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build s390x,!go1.11 !amd64,!s390x,!ppc64le gccgo purego
package poly1305
func sum(out *[TagSize]byte, msg []byte, key *[32]byte) {
h := newMAC(key)
h.Write(msg)
h.Sum(out)
}

View File

@ -9,17 +9,6 @@ package poly1305
//go:noescape //go:noescape
func update(state *macState, msg []byte) func update(state *macState, msg []byte)
func sum(out *[16]byte, m []byte, key *[32]byte) {
h := newMAC(key)
h.Write(m)
h.Sum(out)
}
func newMAC(key *[32]byte) (h mac) {
initialize(key, &h.r, &h.s)
return
}
// mac is a wrapper for macGeneric that redirects calls that would have gone to // mac is a wrapper for macGeneric that redirects calls that would have gone to
// updateGeneric to update. // updateGeneric to update.
// //

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build go1.11,!gccgo,!purego // +build !gccgo,!purego
package poly1305 package poly1305
@ -10,30 +10,66 @@ import (
"golang.org/x/sys/cpu" "golang.org/x/sys/cpu"
) )
// poly1305vx is an assembly implementation of Poly1305 that uses vector // updateVX is an assembly implementation of Poly1305 that uses vector
// instructions. It must only be called if the vector facility (vx) is // instructions. It must only be called if the vector facility (vx) is
// available. // available.
//go:noescape //go:noescape
func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]byte) func updateVX(state *macState, msg []byte)
// poly1305vmsl is an assembly implementation of Poly1305 that uses vector // mac is a replacement for macGeneric that uses a larger buffer and redirects
// instructions, including VMSL. It must only be called if the vector facility (vx) is // calls that would have gone to updateGeneric to updateVX if the vector
// available and if VMSL is supported. // facility is installed.
//go:noescape //
func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte) // A larger buffer is required for good performance because the vector
// implementation has a higher fixed cost per call than the generic
// implementation.
type mac struct {
macState
func sum(out *[16]byte, m []byte, key *[32]byte) { buffer [16 * TagSize]byte // size must be a multiple of block size (16)
offset int
}
func (h *mac) Write(p []byte) (int, error) {
nn := len(p)
if h.offset > 0 {
n := copy(h.buffer[h.offset:], p)
if h.offset+n < len(h.buffer) {
h.offset += n
return nn, nil
}
p = p[n:]
h.offset = 0
if cpu.S390X.HasVX { if cpu.S390X.HasVX {
var mPtr *byte updateVX(&h.macState, h.buffer[:])
if len(m) > 0 {
mPtr = &m[0]
}
if cpu.S390X.HasVXE && len(m) > 256 {
poly1305vmsl(out, mPtr, uint64(len(m)), key)
} else { } else {
poly1305vx(out, mPtr, uint64(len(m)), key) updateGeneric(&h.macState, h.buffer[:])
} }
}
tail := len(p) % len(h.buffer) // number of bytes to copy into buffer
body := len(p) - tail // number of bytes to process now
if body > 0 {
if cpu.S390X.HasVX {
updateVX(&h.macState, p[:body])
} else { } else {
sumGeneric(out, m, key) updateGeneric(&h.macState, p[:body])
} }
} }
h.offset = copy(h.buffer[:], p[body:]) // copy tail bytes - can be 0
return nn, nil
}
func (h *mac) Sum(out *[TagSize]byte) {
state := h.macState
remainder := h.buffer[:h.offset]
// Use the generic implementation if we have 2 or fewer blocks left
// to sum. The vector implementation has a higher startup time.
if cpu.S390X.HasVX && len(remainder) > 2*TagSize {
updateVX(&state, remainder)
} else if len(remainder) > 0 {
updateGeneric(&state, remainder)
}
finalize(out, &state.h, &state.s)
}

View File

@ -2,115 +2,187 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build go1.11,!gccgo,!purego // +build !gccgo,!purego
#include "textflag.h" #include "textflag.h"
// Implementation of Poly1305 using the vector facility (vx). // This implementation of Poly1305 uses the vector facility (vx)
// to process up to 2 blocks (32 bytes) per iteration using an
// algorithm based on the one described in:
//
// NEON crypto, Daniel J. Bernstein & Peter Schwabe
// https://cryptojedi.org/papers/neoncrypto-20120320.pdf
//
// This algorithm uses 5 26-bit limbs to represent a 130-bit
// value. These limbs are, for the most part, zero extended and
// placed into 64-bit vector register elements. Each vector
// register is 128-bits wide and so holds 2 of these elements.
// Using 26-bit limbs allows us plenty of headroom to accomodate
// accumulations before and after multiplication without
// overflowing either 32-bits (before multiplication) or 64-bits
// (after multiplication).
//
// In order to parallelise the operations required to calculate
// the sum we use two separate accumulators and then sum those
// in an extra final step. For compatibility with the generic
// implementation we perform this summation at the end of every
// updateVX call.
//
// To use two accumulators we must multiply the message blocks
// by r² rather than r. Only the final message block should be
// multiplied by r.
//
// Example:
//
// We want to calculate the sum (h) for a 64 byte message (m):
//
// h = m[0:16]r + m[16:32]r³ + m[32:48]r² + m[48:64]r
//
// To do this we split the calculation into the even indices
// and odd indices of the message. These form our SIMD 'lanes':
//
// h = m[ 0:16]r + m[32:48]r² + <- lane 0
// m[16:32]r³ + m[48:64]r <- lane 1
//
// To calculate this iteratively we refactor so that both lanes
// are written in terms of r² and r:
//
// h = (m[ 0:16]r² + m[32:48])r² + <- lane 0
// (m[16:32]r² + m[48:64])r <- lane 1
// ^ ^
// | coefficients for second iteration
// coefficients for first iteration
//
// So in this case we would have two iterations. In the first
// both lanes are multiplied by r². In the second only the
// first lane is multiplied by r² and the second lane is
// instead multiplied by r. This gives use the odd and even
// powers of r that we need from the original equation.
//
// Notation:
//
// h - accumulator
// r - key
// m - message
//
// [a, b] - SIMD register holding two 64-bit values
// [a, b, c, d] - SIMD register holding four 32-bit values
// x[n] - limb n of variable x with bit width i
//
// Limbs are expressed in little endian order, so for 26-bit
// limbs x[4] will be the most significant limb and x[0]
// will be the least significant limb.
// constants // masking constants
#define MOD26 V0 #define MOD24 V0 // [0x0000000000ffffff, 0x0000000000ffffff] - mask low 24-bits
#define EX0 V1 #define MOD26 V1 // [0x0000000003ffffff, 0x0000000003ffffff] - mask low 26-bits
#define EX1 V2
#define EX2 V3
// temporaries // expansion constants (see EXPAND macro)
#define T_0 V4 #define EX0 V2
#define T_1 V5 #define EX1 V3
#define T_2 V6 #define EX2 V4
#define T_3 V7
#define T_4 V8
// key (r) // key (r², r or 1 depending on context)
#define R_0 V9 #define R_0 V5
#define R_1 V10 #define R_1 V6
#define R_2 V11 #define R_2 V7
#define R_3 V12 #define R_3 V8
#define R_4 V13 #define R_4 V9
#define R5_1 V14
#define R5_2 V15
#define R5_3 V16
#define R5_4 V17
#define RSAVE_0 R5
#define RSAVE_1 R6
#define RSAVE_2 R7
#define RSAVE_3 R8
#define RSAVE_4 R9
#define R5SAVE_1 V28
#define R5SAVE_2 V29
#define R5SAVE_3 V30
#define R5SAVE_4 V31
// message block // precalculated coefficients (5r², 5r or 0 depending on context)
#define F_0 V18 #define R5_1 V10
#define F_1 V19 #define R5_2 V11
#define F_2 V20 #define R5_3 V12
#define F_3 V21 #define R5_4 V13
#define F_4 V22
// accumulator // message block (m)
#define H_0 V23 #define M_0 V14
#define H_1 V24 #define M_1 V15
#define H_2 V25 #define M_2 V16
#define H_3 V26 #define M_3 V17
#define H_4 V27 #define M_4 V18
GLOBL ·keyMask<>(SB), RODATA, $16 // accumulator (h)
DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f #define H_0 V19
DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f #define H_1 V20
#define H_2 V21
#define H_3 V22
#define H_4 V23
GLOBL ·bswapMask<>(SB), RODATA, $16 // temporary registers (for short-lived values)
DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908 #define T_0 V24
DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100 #define T_1 V25
#define T_2 V26
#define T_3 V27
#define T_4 V28
GLOBL ·constants<>(SB), RODATA, $64 GLOBL ·constants<>(SB), RODATA, $0x30
// MOD26
DATA ·constants<>+0(SB)/8, $0x3ffffff
DATA ·constants<>+8(SB)/8, $0x3ffffff
// EX0 // EX0
DATA ·constants<>+16(SB)/8, $0x0006050403020100 DATA ·constants<>+0x00(SB)/8, $0x0006050403020100
DATA ·constants<>+24(SB)/8, $0x1016151413121110 DATA ·constants<>+0x08(SB)/8, $0x1016151413121110
// EX1 // EX1
DATA ·constants<>+32(SB)/8, $0x060c0b0a09080706 DATA ·constants<>+0x10(SB)/8, $0x060c0b0a09080706
DATA ·constants<>+40(SB)/8, $0x161c1b1a19181716 DATA ·constants<>+0x18(SB)/8, $0x161c1b1a19181716
// EX2 // EX2
DATA ·constants<>+48(SB)/8, $0x0d0d0d0d0d0f0e0d DATA ·constants<>+0x20(SB)/8, $0x0d0d0d0d0d0f0e0d
DATA ·constants<>+56(SB)/8, $0x1d1d1d1d1d1f1e1d DATA ·constants<>+0x28(SB)/8, $0x1d1d1d1d1d1f1e1d
// h = (f*g) % (2**130-5) [partial reduction] // MULTIPLY multiplies each lane of f and g, partially reduced
// modulo 2¹³ - 5. The result, h, consists of partial products
// in each lane that need to be reduced further to produce the
// final result.
//
// h = (fg) % 2¹³ + (5fg) / 2¹³
//
// Note that the multiplication by 5 of the high bits is
// achieved by precalculating the multiplication of four of the
// g coefficients by 5. These are g51-g54.
#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \ #define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \
VMLOF f0, g0, h0 \ VMLOF f0, g0, h0 \
VMLOF f0, g1, h1 \
VMLOF f0, g2, h2 \
VMLOF f0, g3, h3 \ VMLOF f0, g3, h3 \
VMLOF f0, g1, h1 \
VMLOF f0, g4, h4 \ VMLOF f0, g4, h4 \
VMLOF f0, g2, h2 \
VMLOF f1, g54, T_0 \ VMLOF f1, g54, T_0 \
VMLOF f1, g0, T_1 \
VMLOF f1, g1, T_2 \
VMLOF f1, g2, T_3 \ VMLOF f1, g2, T_3 \
VMLOF f1, g0, T_1 \
VMLOF f1, g3, T_4 \ VMLOF f1, g3, T_4 \
VMLOF f1, g1, T_2 \
VMALOF f2, g53, h0, h0 \ VMALOF f2, g53, h0, h0 \
VMALOF f2, g54, h1, h1 \
VMALOF f2, g0, h2, h2 \
VMALOF f2, g1, h3, h3 \ VMALOF f2, g1, h3, h3 \
VMALOF f2, g54, h1, h1 \
VMALOF f2, g2, h4, h4 \ VMALOF f2, g2, h4, h4 \
VMALOF f2, g0, h2, h2 \
VMALOF f3, g52, T_0, T_0 \ VMALOF f3, g52, T_0, T_0 \
VMALOF f3, g53, T_1, T_1 \
VMALOF f3, g54, T_2, T_2 \
VMALOF f3, g0, T_3, T_3 \ VMALOF f3, g0, T_3, T_3 \
VMALOF f3, g53, T_1, T_1 \
VMALOF f3, g1, T_4, T_4 \ VMALOF f3, g1, T_4, T_4 \
VMALOF f3, g54, T_2, T_2 \
VMALOF f4, g51, h0, h0 \ VMALOF f4, g51, h0, h0 \
VMALOF f4, g52, h1, h1 \
VMALOF f4, g53, h2, h2 \
VMALOF f4, g54, h3, h3 \ VMALOF f4, g54, h3, h3 \
VMALOF f4, g52, h1, h1 \
VMALOF f4, g0, h4, h4 \ VMALOF f4, g0, h4, h4 \
VMALOF f4, g53, h2, h2 \
VAG T_0, h0, h0 \ VAG T_0, h0, h0 \
VAG T_1, h1, h1 \
VAG T_2, h2, h2 \
VAG T_3, h3, h3 \ VAG T_3, h3, h3 \
VAG T_4, h4, h4 VAG T_1, h1, h1 \
VAG T_4, h4, h4 \
VAG T_2, h2, h2
// carry h0->h1 h3->h4, h1->h2 h4->h0, h0->h1 h2->h3, h3->h4 // REDUCE performs the following carry operations in four
// stages, as specified in Bernstein & Schwabe:
//
// 1: h[0]->h[1] h[3]->h[4]
// 2: h[1]->h[2] h[4]->h[0]
// 3: h[0]->h[1] h[2]->h[3]
// 4: h[3]->h[4]
//
// The result is that all of the limbs are limited to 26-bits
// except for h[1] and h[4] which are limited to 27-bits.
//
// Note that although each limb is aligned at 26-bit intervals
// they may contain values that exceed 2² - 1, hence the need
// to carry the excess bits in each limb.
#define REDUCE(h0, h1, h2, h3, h4) \ #define REDUCE(h0, h1, h2, h3, h4) \
VESRLG $26, h0, T_0 \ VESRLG $26, h0, T_0 \
VESRLG $26, h3, T_1 \ VESRLG $26, h3, T_1 \
@ -136,144 +208,155 @@ DATA ·constants<>+56(SB)/8, $0x1d1d1d1d1d1f1e1d
VN MOD26, h3, h3 \ VN MOD26, h3, h3 \
VAG T_2, h4, h4 VAG T_2, h4, h4
// expand in0 into d[0] and in1 into d[1] // EXPAND splits the 128-bit little-endian values in0 and in1
// into 26-bit big-endian limbs and places the results into
// the first and second lane of d[0:4] respectively.
//
// The EX0, EX1 and EX2 constants are arrays of byte indices
// for permutation. The permutation both reverses the bytes
// in the input and ensures the bytes are copied into the
// destination limb ready to be shifted into their final
// position.
#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \ #define EXPAND(in0, in1, d0, d1, d2, d3, d4) \
VGBM $0x0707, d1 \ // d1=tmp
VPERM in0, in1, EX2, d4 \
VPERM in0, in1, EX0, d0 \ VPERM in0, in1, EX0, d0 \
VPERM in0, in1, EX1, d2 \ VPERM in0, in1, EX1, d2 \
VN d1, d4, d4 \ VPERM in0, in1, EX2, d4 \
VESRLG $26, d0, d1 \ VESRLG $26, d0, d1 \
VESRLG $30, d2, d3 \ VESRLG $30, d2, d3 \
VESRLG $4, d2, d2 \ VESRLG $4, d2, d2 \
VN MOD26, d0, d0 \ VN MOD26, d0, d0 \ // [in0[0], in1[0]]
VN MOD26, d1, d1 \ VN MOD26, d3, d3 \ // [in0[3], in1[3]]
VN MOD26, d2, d2 \ VN MOD26, d1, d1 \ // [in0[1], in1[1]]
VN MOD26, d3, d3 VN MOD24, d4, d4 \ // [in0[4], in1[4]]
VN MOD26, d2, d2 // [in0[2], in1[2]]
// pack h4:h0 into h1:h0 (no carry) // func updateVX(state *macState, msg []byte)
#define PACK(h0, h1, h2, h3, h4) \ TEXT ·updateVX(SB), NOSPLIT, $0
VESLG $26, h1, h1 \ MOVD state+0(FP), R1
VESLG $26, h3, h3 \ LMG msg+8(FP), R2, R3 // R2=msg_base, R3=msg_len
VO h0, h1, h0 \
VO h2, h3, h2 \
VESLG $4, h2, h2 \
VLEIB $7, $48, h1 \
VSLB h1, h2, h2 \
VO h0, h2, h0 \
VLEIB $7, $104, h1 \
VSLB h1, h4, h3 \
VO h3, h0, h0 \
VLEIB $7, $24, h1 \
VSRLB h1, h4, h1
// if h > 2**130-5 then h -= 2**130-5 // load EX0, EX1 and EX2
#define MOD(h0, h1, t0, t1, t2) \
VZERO t0 \
VLEIG $1, $5, t0 \
VACCQ h0, t0, t1 \
VAQ h0, t0, t0 \
VONE t2 \
VLEIG $1, $-4, t2 \
VAQ t2, t1, t1 \
VACCQ h1, t1, t1 \
VONE t2 \
VAQ t2, t1, t1 \
VN h0, t1, t2 \
VNC t0, t1, t1 \
VO t1, t2, h0
// func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]key)
TEXT ·poly1305vx(SB), $0-32
// This code processes up to 2 blocks (32 bytes) per iteration
// using the algorithm described in:
// NEON crypto, Daniel J. Bernstein & Peter Schwabe
// https://cryptojedi.org/papers/neoncrypto-20120320.pdf
LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key
// load MOD26, EX0, EX1 and EX2
MOVD $·constants<>(SB), R5 MOVD $·constants<>(SB), R5
VLM (R5), MOD26, EX2 VLM (R5), EX0, EX2
// setup r // generate masks
VL (R4), T_0 VGMG $(64-24), $63, MOD24 // [0x00ffffff, 0x00ffffff]
MOVD $·keyMask<>(SB), R6 VGMG $(64-26), $63, MOD26 // [0x03ffffff, 0x03ffffff]
VL (R6), T_1
VN T_0, T_1, T_0
EXPAND(T_0, T_0, R_0, R_1, R_2, R_3, R_4)
// setup r*5 // load h (accumulator) and r (key) from state
VLEIG $0, $5, T_0 VZERO T_1 // [0, 0]
VLEIG $1, $5, T_0 VL 0(R1), T_0 // [h[0], h[1]]
VLEG $0, 16(R1), T_1 // [h[2], 0]
VL 24(R1), T_2 // [r[0], r[1]]
VPDI $0, T_0, T_2, T_3 // [h[0], r[0]]
VPDI $5, T_0, T_2, T_4 // [h[1], r[1]]
// store r (for final block) // unpack h and r into 26-bit limbs
VMLOF T_0, R_1, R5SAVE_1 // note: h[2] may have the low 3 bits set, so h[4] is a 27-bit value
VMLOF T_0, R_2, R5SAVE_2 VN MOD26, T_3, H_0 // [h[0], r[0]]
VMLOF T_0, R_3, R5SAVE_3 VZERO H_1 // [0, 0]
VMLOF T_0, R_4, R5SAVE_4 VZERO H_3 // [0, 0]
VLGVG $0, R_0, RSAVE_0 VGMG $(64-12-14), $(63-12), T_0 // [0x03fff000, 0x03fff000] - 26-bit mask with low 12 bits masked out
VLGVG $0, R_1, RSAVE_1 VESLG $24, T_1, T_1 // [h[2]<<24, 0]
VLGVG $0, R_2, RSAVE_2 VERIMG $-26&63, T_3, MOD26, H_1 // [h[1], r[1]]
VLGVG $0, R_3, RSAVE_3 VESRLG $+52&63, T_3, H_2 // [h[2], r[2]] - low 12 bits only
VLGVG $0, R_4, RSAVE_4 VERIMG $-14&63, T_4, MOD26, H_3 // [h[1], r[1]]
VESRLG $40, T_4, H_4 // [h[4], r[4]] - low 24 bits only
VERIMG $+12&63, T_4, T_0, H_2 // [h[2], r[2]] - complete
VO T_1, H_4, H_4 // [h[4], r[4]] - complete
// skip r**2 calculation // replicate r across all 4 vector elements
VREPF $3, H_0, R_0 // [r[0], r[0], r[0], r[0]]
VREPF $3, H_1, R_1 // [r[1], r[1], r[1], r[1]]
VREPF $3, H_2, R_2 // [r[2], r[2], r[2], r[2]]
VREPF $3, H_3, R_3 // [r[3], r[3], r[3], r[3]]
VREPF $3, H_4, R_4 // [r[4], r[4], r[4], r[4]]
// zero out lane 1 of h
VLEIG $1, $0, H_0 // [h[0], 0]
VLEIG $1, $0, H_1 // [h[1], 0]
VLEIG $1, $0, H_2 // [h[2], 0]
VLEIG $1, $0, H_3 // [h[3], 0]
VLEIG $1, $0, H_4 // [h[4], 0]
// calculate 5r (ignore least significant limb)
VREPIF $5, T_0
VMLF T_0, R_1, R5_1 // [5r[1], 5r[1], 5r[1], 5r[1]]
VMLF T_0, R_2, R5_2 // [5r[2], 5r[2], 5r[2], 5r[2]]
VMLF T_0, R_3, R5_3 // [5r[3], 5r[3], 5r[3], 5r[3]]
VMLF T_0, R_4, R5_4 // [5r[4], 5r[4], 5r[4], 5r[4]]
// skip r² calculation if we are only calculating one block
CMPBLE R3, $16, skip CMPBLE R3, $16, skip
// calculate r**2 // calculate r²
MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5SAVE_1, R5SAVE_2, R5SAVE_3, R5SAVE_4, H_0, H_1, H_2, H_3, H_4) MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, M_0, M_1, M_2, M_3, M_4)
REDUCE(H_0, H_1, H_2, H_3, H_4) REDUCE(M_0, M_1, M_2, M_3, M_4)
VLEIG $0, $5, T_0 VGBM $0x0f0f, T_0
VLEIG $1, $5, T_0 VERIMG $0, M_0, T_0, R_0 // [r[0], r²[0], r[0], r²[0]]
VMLOF T_0, H_1, R5_1 VERIMG $0, M_1, T_0, R_1 // [r[1], r²[1], r[1], r²[1]]
VMLOF T_0, H_2, R5_2 VERIMG $0, M_2, T_0, R_2 // [r[2], r²[2], r[2], r²[2]]
VMLOF T_0, H_3, R5_3 VERIMG $0, M_3, T_0, R_3 // [r[3], r²[3], r[3], r²[3]]
VMLOF T_0, H_4, R5_4 VERIMG $0, M_4, T_0, R_4 // [r[4], r²[4], r[4], r²[4]]
VLR H_0, R_0
VLR H_1, R_1
VLR H_2, R_2
VLR H_3, R_3
VLR H_4, R_4
// initialize h // calculate 5r² (ignore least significant limb)
VZERO H_0 VREPIF $5, T_0
VZERO H_1 VMLF T_0, R_1, R5_1 // [5r[1], 5r²[1], 5r[1], 5r²[1]]
VZERO H_2 VMLF T_0, R_2, R5_2 // [5r[2], 5r²[2], 5r[2], 5r²[2]]
VZERO H_3 VMLF T_0, R_3, R5_3 // [5r[3], 5r²[3], 5r[3], 5r²[3]]
VZERO H_4 VMLF T_0, R_4, R5_4 // [5r[4], 5r²[4], 5r[4], 5r²[4]]
loop: loop:
CMPBLE R3, $32, b2 CMPBLE R3, $32, b2 // 2 or fewer blocks remaining, need to change key coefficients
// load next 2 blocks from message
VLM (R2), T_0, T_1 VLM (R2), T_0, T_1
// update message slice
SUB $32, R3 SUB $32, R3
MOVD $32(R2), R2 MOVD $32(R2), R2
EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
VLEIB $4, $1, F_4 // unpack message blocks into 26-bit big-endian limbs
VLEIB $12, $1, F_4 EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4)
// add 2¹² to each message block value
VLEIB $4, $1, M_4
VLEIB $12, $1, M_4
multiply: multiply:
VAG H_0, F_0, F_0 // accumulate the incoming message
VAG H_1, F_1, F_1 VAG H_0, M_0, M_0
VAG H_2, F_2, F_2 VAG H_3, M_3, M_3
VAG H_3, F_3, F_3 VAG H_1, M_1, M_1
VAG H_4, F_4, F_4 VAG H_4, M_4, M_4
MULTIPLY(F_0, F_1, F_2, F_3, F_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4) VAG H_2, M_2, M_2
// multiply the accumulator by the key coefficient
MULTIPLY(M_0, M_1, M_2, M_3, M_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4)
// carry and partially reduce the partial products
REDUCE(H_0, H_1, H_2, H_3, H_4) REDUCE(H_0, H_1, H_2, H_3, H_4)
CMPBNE R3, $0, loop CMPBNE R3, $0, loop
finish: finish:
// sum vectors // sum lane 0 and lane 1 and put the result in lane 1
VZERO T_0 VZERO T_0
VSUMQG H_0, T_0, H_0 VSUMQG H_0, T_0, H_0
VSUMQG H_1, T_0, H_1
VSUMQG H_2, T_0, H_2
VSUMQG H_3, T_0, H_3 VSUMQG H_3, T_0, H_3
VSUMQG H_1, T_0, H_1
VSUMQG H_4, T_0, H_4 VSUMQG H_4, T_0, H_4
VSUMQG H_2, T_0, H_2
// h may be >= 2*(2**130-5) so we need to reduce it again // reduce again after summation
// TODO(mundaym): there might be a more efficient way to do this
// now that we only have 1 active lane. For example, we could
// simultaneously pack the values as we reduce them.
REDUCE(H_0, H_1, H_2, H_3, H_4) REDUCE(H_0, H_1, H_2, H_3, H_4)
// carry h1->h4 // carry h[1] through to h[4] so that only h[4] can exceed 2² - 1
// TODO(mundaym): in testing this final carry was unnecessary.
// Needs a proof before it can be removed though.
VESRLG $26, H_1, T_1 VESRLG $26, H_1, T_1
VN MOD26, H_1, H_1 VN MOD26, H_1, H_1
VAQ T_1, H_2, H_2 VAQ T_1, H_2, H_2
@ -284,95 +367,137 @@ finish:
VN MOD26, H_3, H_3 VN MOD26, H_3, H_3
VAQ T_3, H_4, H_4 VAQ T_3, H_4, H_4
// h is now < 2*(2**130-5) // h is now < 2(2¹³ - 5)
// pack h into h1 (hi) and h0 (lo) // Pack each lane in h[0:4] into h[0:1].
PACK(H_0, H_1, H_2, H_3, H_4) VESLG $26, H_1, H_1
VESLG $26, H_3, H_3
// if h > 2**130-5 then h -= 2**130-5 VO H_0, H_1, H_0
MOD(H_0, H_1, T_0, T_1, T_2) VO H_2, H_3, H_2
VESLG $4, H_2, H_2
// h += s VLEIB $7, $48, H_1
MOVD $·bswapMask<>(SB), R5 VSLB H_1, H_2, H_2
VL (R5), T_1 VO H_0, H_2, H_0
VL 16(R4), T_0 VLEIB $7, $104, H_1
VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big) VSLB H_1, H_4, H_3
VAQ T_0, H_0, H_0 VO H_3, H_0, H_0
VPERM H_0, H_0, T_1, H_0 // reverse bytes (to little) VLEIB $7, $24, H_1
VST H_0, (R1) VSRLB H_1, H_4, H_1
// update state
VSTEG $1, H_0, 0(R1)
VSTEG $0, H_0, 8(R1)
VSTEG $1, H_1, 16(R1)
RET RET
b2: b2: // 2 or fewer blocks remaining
CMPBLE R3, $16, b1 CMPBLE R3, $16, b1
// 2 blocks remaining // Load the 2 remaining blocks (17-32 bytes remaining).
SUB $17, R3 MOVD $-17(R3), R0 // index of final byte to load modulo 16
VL (R2), T_0 VL (R2), T_0 // load full 16 byte block
VLL R3, 16(R2), T_1 VLL R0, 16(R2), T_1 // load final (possibly partial) block and pad with zeros to 16 bytes
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, T_1
EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
CMPBNE R3, $16, 2(PC)
VLEIB $12, $1, F_4
VLEIB $4, $1, F_4
// setup [r²,r] // The Poly1305 algorithm requires that a 1 bit be appended to
VLVGG $1, RSAVE_0, R_0 // each message block. If the final block is less than 16 bytes
VLVGG $1, RSAVE_1, R_1 // long then it is easiest to insert the 1 before the message
VLVGG $1, RSAVE_2, R_2 // block is split into 26-bit limbs. If, on the other hand, the
VLVGG $1, RSAVE_3, R_3 // final message block is 16 bytes long then we append the 1 bit
VLVGG $1, RSAVE_4, R_4 // after expansion as normal.
VPDI $0, R5_1, R5SAVE_1, R5_1 MOVBZ $1, R0
VPDI $0, R5_2, R5SAVE_2, R5_2 MOVD $-16(R3), R3 // index of byte in last block to insert 1 at (could be 16)
VPDI $0, R5_3, R5SAVE_3, R5_3 CMPBEQ R3, $16, 2(PC) // skip the insertion if the final block is 16 bytes long
VPDI $0, R5_4, R5SAVE_4, R5_4 VLVGB R3, R0, T_1 // insert 1 into the byte at index R3
// Split both blocks into 26-bit limbs in the appropriate lanes.
EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4)
// Append a 1 byte to the end of the second to last block.
VLEIB $4, $1, M_4
// Append a 1 byte to the end of the last block only if it is a
// full 16 byte block.
CMPBNE R3, $16, 2(PC)
VLEIB $12, $1, M_4
// Finally, set up the coefficients for the final multiplication.
// We have previously saved r and 5r in the 32-bit even indexes
// of the R_[0-4] and R5_[1-4] coefficient registers.
//
// We want lane 0 to be multiplied by r² so that can be kept the
// same. We want lane 1 to be multiplied by r so we need to move
// the saved r value into the 32-bit odd index in lane 1 by
// rotating the 64-bit lane by 32.
VGBM $0x00ff, T_0 // [0, 0xffffffffffffffff] - mask lane 1 only
VERIMG $32, R_0, T_0, R_0 // [_, r²[0], _, r[0]]
VERIMG $32, R_1, T_0, R_1 // [_, r²[1], _, r[1]]
VERIMG $32, R_2, T_0, R_2 // [_, r²[2], _, r[2]]
VERIMG $32, R_3, T_0, R_3 // [_, r²[3], _, r[3]]
VERIMG $32, R_4, T_0, R_4 // [_, r²[4], _, r[4]]
VERIMG $32, R5_1, T_0, R5_1 // [_, 5r²[1], _, 5r[1]]
VERIMG $32, R5_2, T_0, R5_2 // [_, 5r²[2], _, 5r[2]]
VERIMG $32, R5_3, T_0, R5_3 // [_, 5r²[3], _, 5r[3]]
VERIMG $32, R5_4, T_0, R5_4 // [_, 5r²[4], _, 5r[4]]
MOVD $0, R3 MOVD $0, R3
BR multiply BR multiply
skip: skip:
VZERO H_0
VZERO H_1
VZERO H_2
VZERO H_3
VZERO H_4
CMPBEQ R3, $0, finish CMPBEQ R3, $0, finish
b1: b1: // 1 block remaining
// 1 block remaining
SUB $1, R3 // Load the final block (1-16 bytes). This will be placed into
VLL R3, (R2), T_0 // lane 0.
ADD $1, R3 MOVD $-1(R3), R0
VLL R0, (R2), T_0 // pad to 16 bytes with zeros
// The Poly1305 algorithm requires that a 1 bit be appended to
// each message block. If the final block is less than 16 bytes
// long then it is easiest to insert the 1 before the message
// block is split into 26-bit limbs. If, on the other hand, the
// final message block is 16 bytes long then we append the 1 bit
// after expansion as normal.
MOVBZ $1, R0 MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC) CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, T_0 VLVGB R3, R0, T_0
VZERO T_1
EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
CMPBNE R3, $16, 2(PC)
VLEIB $4, $1, F_4
VLEIG $1, $1, R_0
VZERO R_1
VZERO R_2
VZERO R_3
VZERO R_4
VZERO R5_1
VZERO R5_2
VZERO R5_3
VZERO R5_4
// setup [r, 1] // Set the message block in lane 1 to the value 0 so that it
VLVGG $0, RSAVE_0, R_0 // can be accumulated without affecting the final result.
VLVGG $0, RSAVE_1, R_1 VZERO T_1
VLVGG $0, RSAVE_2, R_2
VLVGG $0, RSAVE_3, R_3 // Split the final message block into 26-bit limbs in lane 0.
VLVGG $0, RSAVE_4, R_4 // Lane 1 will be contain 0.
VPDI $0, R5SAVE_1, R5_1, R5_1 EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4)
VPDI $0, R5SAVE_2, R5_2, R5_2
VPDI $0, R5SAVE_3, R5_3, R5_3 // Append a 1 byte to the end of the last block only if it is a
VPDI $0, R5SAVE_4, R5_4, R5_4 // full 16 byte block.
CMPBNE R3, $16, 2(PC)
VLEIB $4, $1, M_4
// We have previously saved r and 5r in the 32-bit even indexes
// of the R_[0-4] and R5_[1-4] coefficient registers.
//
// We want lane 0 to be multiplied by r so we need to move the
// saved r value into the 32-bit odd index in lane 0. We want
// lane 1 to be set to the value 1. This makes multiplication
// a no-op. We do this by setting lane 1 in every register to 0
// and then just setting the 32-bit index 3 in R_0 to 1.
VZERO T_0
MOVD $0, R0
MOVD $0x10111213, R12
VLVGP R12, R0, T_1 // [_, 0x10111213, _, 0x00000000]
VPERM T_0, R_0, T_1, R_0 // [_, r[0], _, 0]
VPERM T_0, R_1, T_1, R_1 // [_, r[1], _, 0]
VPERM T_0, R_2, T_1, R_2 // [_, r[2], _, 0]
VPERM T_0, R_3, T_1, R_3 // [_, r[3], _, 0]
VPERM T_0, R_4, T_1, R_4 // [_, r[4], _, 0]
VPERM T_0, R5_1, T_1, R5_1 // [_, 5r[1], _, 0]
VPERM T_0, R5_2, T_1, R5_2 // [_, 5r[2], _, 0]
VPERM T_0, R5_3, T_1, R5_3 // [_, 5r[3], _, 0]
VPERM T_0, R5_4, T_1, R5_4 // [_, 5r[4], _, 0]
// Set the value of lane 1 to be 1.
VLEIF $3, $1, R_0 // [_, r[0], _, 1]
MOVD $0, R3 MOVD $0, R3
BR multiply BR multiply

View File

@ -1,909 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.11,!gccgo,!purego
#include "textflag.h"
// Implementation of Poly1305 using the vector facility (vx) and the VMSL instruction.
// constants
#define EX0 V1
#define EX1 V2
#define EX2 V3
// temporaries
#define T_0 V4
#define T_1 V5
#define T_2 V6
#define T_3 V7
#define T_4 V8
#define T_5 V9
#define T_6 V10
#define T_7 V11
#define T_8 V12
#define T_9 V13
#define T_10 V14
// r**2 & r**4
#define R_0 V15
#define R_1 V16
#define R_2 V17
#define R5_1 V18
#define R5_2 V19
// key (r)
#define RSAVE_0 R7
#define RSAVE_1 R8
#define RSAVE_2 R9
#define R5SAVE_1 R10
#define R5SAVE_2 R11
// message block
#define M0 V20
#define M1 V21
#define M2 V22
#define M3 V23
#define M4 V24
#define M5 V25
// accumulator
#define H0_0 V26
#define H1_0 V27
#define H2_0 V28
#define H0_1 V29
#define H1_1 V30
#define H2_1 V31
GLOBL ·keyMask<>(SB), RODATA, $16
DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f
DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f
GLOBL ·bswapMask<>(SB), RODATA, $16
DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908
DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100
GLOBL ·constants<>(SB), RODATA, $48
// EX0
DATA ·constants<>+0(SB)/8, $0x18191a1b1c1d1e1f
DATA ·constants<>+8(SB)/8, $0x0000050403020100
// EX1
DATA ·constants<>+16(SB)/8, $0x18191a1b1c1d1e1f
DATA ·constants<>+24(SB)/8, $0x00000a0908070605
// EX2
DATA ·constants<>+32(SB)/8, $0x18191a1b1c1d1e1f
DATA ·constants<>+40(SB)/8, $0x0000000f0e0d0c0b
GLOBL ·c<>(SB), RODATA, $48
// EX0
DATA ·c<>+0(SB)/8, $0x0000050403020100
DATA ·c<>+8(SB)/8, $0x0000151413121110
// EX1
DATA ·c<>+16(SB)/8, $0x00000a0908070605
DATA ·c<>+24(SB)/8, $0x00001a1918171615
// EX2
DATA ·c<>+32(SB)/8, $0x0000000f0e0d0c0b
DATA ·c<>+40(SB)/8, $0x0000001f1e1d1c1b
GLOBL ·reduce<>(SB), RODATA, $32
// 44 bit
DATA ·reduce<>+0(SB)/8, $0x0
DATA ·reduce<>+8(SB)/8, $0xfffffffffff
// 42 bit
DATA ·reduce<>+16(SB)/8, $0x0
DATA ·reduce<>+24(SB)/8, $0x3ffffffffff
// h = (f*g) % (2**130-5) [partial reduction]
// uses T_0...T_9 temporary registers
// input: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2
// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
// output: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2
#define MULTIPLY(m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) \
\ // Eliminate the dependency for the last 2 VMSLs
VMSLG m02_0, r_2, m4_2, m4_2 \
VMSLG m13_0, r_2, m5_2, m5_2 \ // 8 VMSLs pipelined
VMSLG m02_0, r_0, m4_0, m4_0 \
VMSLG m02_1, r5_2, V0, T_0 \
VMSLG m02_0, r_1, m4_1, m4_1 \
VMSLG m02_1, r_0, V0, T_1 \
VMSLG m02_1, r_1, V0, T_2 \
VMSLG m02_2, r5_1, V0, T_3 \
VMSLG m02_2, r5_2, V0, T_4 \
VMSLG m13_0, r_0, m5_0, m5_0 \
VMSLG m13_1, r5_2, V0, T_5 \
VMSLG m13_0, r_1, m5_1, m5_1 \
VMSLG m13_1, r_0, V0, T_6 \
VMSLG m13_1, r_1, V0, T_7 \
VMSLG m13_2, r5_1, V0, T_8 \
VMSLG m13_2, r5_2, V0, T_9 \
VMSLG m02_2, r_0, m4_2, m4_2 \
VMSLG m13_2, r_0, m5_2, m5_2 \
VAQ m4_0, T_0, m02_0 \
VAQ m4_1, T_1, m02_1 \
VAQ m5_0, T_5, m13_0 \
VAQ m5_1, T_6, m13_1 \
VAQ m02_0, T_3, m02_0 \
VAQ m02_1, T_4, m02_1 \
VAQ m13_0, T_8, m13_0 \
VAQ m13_1, T_9, m13_1 \
VAQ m4_2, T_2, m02_2 \
VAQ m5_2, T_7, m13_2 \
// SQUARE uses three limbs of r and r_2*5 to output square of r
// uses T_1, T_5 and T_7 temporary registers
// input: r_0, r_1, r_2, r5_2
// temp: TEMP0, TEMP1, TEMP2
// output: p0, p1, p2
#define SQUARE(r_0, r_1, r_2, r5_2, p0, p1, p2, TEMP0, TEMP1, TEMP2) \
VMSLG r_0, r_0, p0, p0 \
VMSLG r_1, r5_2, V0, TEMP0 \
VMSLG r_2, r5_2, p1, p1 \
VMSLG r_0, r_1, V0, TEMP1 \
VMSLG r_1, r_1, p2, p2 \
VMSLG r_0, r_2, V0, TEMP2 \
VAQ TEMP0, p0, p0 \
VAQ TEMP1, p1, p1 \
VAQ TEMP2, p2, p2 \
VAQ TEMP0, p0, p0 \
VAQ TEMP1, p1, p1 \
VAQ TEMP2, p2, p2 \
// carry h0->h1->h2->h0 || h3->h4->h5->h3
// uses T_2, T_4, T_5, T_7, T_8, T_9
// t6, t7, t8, t9, t10, t11
// input: h0, h1, h2, h3, h4, h5
// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11
// output: h0, h1, h2, h3, h4, h5
#define REDUCE(h0, h1, h2, h3, h4, h5, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) \
VLM (R12), t6, t7 \ // 44 and 42 bit clear mask
VLEIB $7, $0x28, t10 \ // 5 byte shift mask
VREPIB $4, t8 \ // 4 bit shift mask
VREPIB $2, t11 \ // 2 bit shift mask
VSRLB t10, h0, t0 \ // h0 byte shift
VSRLB t10, h1, t1 \ // h1 byte shift
VSRLB t10, h2, t2 \ // h2 byte shift
VSRLB t10, h3, t3 \ // h3 byte shift
VSRLB t10, h4, t4 \ // h4 byte shift
VSRLB t10, h5, t5 \ // h5 byte shift
VSRL t8, t0, t0 \ // h0 bit shift
VSRL t8, t1, t1 \ // h2 bit shift
VSRL t11, t2, t2 \ // h2 bit shift
VSRL t8, t3, t3 \ // h3 bit shift
VSRL t8, t4, t4 \ // h4 bit shift
VESLG $2, t2, t9 \ // h2 carry x5
VSRL t11, t5, t5 \ // h5 bit shift
VN t6, h0, h0 \ // h0 clear carry
VAQ t2, t9, t2 \ // h2 carry x5
VESLG $2, t5, t9 \ // h5 carry x5
VN t6, h1, h1 \ // h1 clear carry
VN t7, h2, h2 \ // h2 clear carry
VAQ t5, t9, t5 \ // h5 carry x5
VN t6, h3, h3 \ // h3 clear carry
VN t6, h4, h4 \ // h4 clear carry
VN t7, h5, h5 \ // h5 clear carry
VAQ t0, h1, h1 \ // h0->h1
VAQ t3, h4, h4 \ // h3->h4
VAQ t1, h2, h2 \ // h1->h2
VAQ t4, h5, h5 \ // h4->h5
VAQ t2, h0, h0 \ // h2->h0
VAQ t5, h3, h3 \ // h5->h3
VREPG $1, t6, t6 \ // 44 and 42 bit masks across both halves
VREPG $1, t7, t7 \
VSLDB $8, h0, h0, h0 \ // set up [h0/1/2, h3/4/5]
VSLDB $8, h1, h1, h1 \
VSLDB $8, h2, h2, h2 \
VO h0, h3, h3 \
VO h1, h4, h4 \
VO h2, h5, h5 \
VESRLG $44, h3, t0 \ // 44 bit shift right
VESRLG $44, h4, t1 \
VESRLG $42, h5, t2 \
VN t6, h3, h3 \ // clear carry bits
VN t6, h4, h4 \
VN t7, h5, h5 \
VESLG $2, t2, t9 \ // multiply carry by 5
VAQ t9, t2, t2 \
VAQ t0, h4, h4 \
VAQ t1, h5, h5 \
VAQ t2, h3, h3 \
// carry h0->h1->h2->h0
// input: h0, h1, h2
// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8
// output: h0, h1, h2
#define REDUCE2(h0, h1, h2, t0, t1, t2, t3, t4, t5, t6, t7, t8) \
VLEIB $7, $0x28, t3 \ // 5 byte shift mask
VREPIB $4, t4 \ // 4 bit shift mask
VREPIB $2, t7 \ // 2 bit shift mask
VGBM $0x003F, t5 \ // mask to clear carry bits
VSRLB t3, h0, t0 \
VSRLB t3, h1, t1 \
VSRLB t3, h2, t2 \
VESRLG $4, t5, t5 \ // 44 bit clear mask
VSRL t4, t0, t0 \
VSRL t4, t1, t1 \
VSRL t7, t2, t2 \
VESRLG $2, t5, t6 \ // 42 bit clear mask
VESLG $2, t2, t8 \
VAQ t8, t2, t2 \
VN t5, h0, h0 \
VN t5, h1, h1 \
VN t6, h2, h2 \
VAQ t0, h1, h1 \
VAQ t1, h2, h2 \
VAQ t2, h0, h0 \
VSRLB t3, h0, t0 \
VSRLB t3, h1, t1 \
VSRLB t3, h2, t2 \
VSRL t4, t0, t0 \
VSRL t4, t1, t1 \
VSRL t7, t2, t2 \
VN t5, h0, h0 \
VN t5, h1, h1 \
VESLG $2, t2, t8 \
VN t6, h2, h2 \
VAQ t0, h1, h1 \
VAQ t8, t2, t2 \
VAQ t1, h2, h2 \
VAQ t2, h0, h0 \
// expands two message blocks into the lower halfs of the d registers
// moves the contents of the d registers into upper halfs
// input: in1, in2, d0, d1, d2, d3, d4, d5
// temp: TEMP0, TEMP1, TEMP2, TEMP3
// output: d0, d1, d2, d3, d4, d5
#define EXPACC(in1, in2, d0, d1, d2, d3, d4, d5, TEMP0, TEMP1, TEMP2, TEMP3) \
VGBM $0xff3f, TEMP0 \
VGBM $0xff1f, TEMP1 \
VESLG $4, d1, TEMP2 \
VESLG $4, d4, TEMP3 \
VESRLG $4, TEMP0, TEMP0 \
VPERM in1, d0, EX0, d0 \
VPERM in2, d3, EX0, d3 \
VPERM in1, d2, EX2, d2 \
VPERM in2, d5, EX2, d5 \
VPERM in1, TEMP2, EX1, d1 \
VPERM in2, TEMP3, EX1, d4 \
VN TEMP0, d0, d0 \
VN TEMP0, d3, d3 \
VESRLG $4, d1, d1 \
VESRLG $4, d4, d4 \
VN TEMP1, d2, d2 \
VN TEMP1, d5, d5 \
VN TEMP0, d1, d1 \
VN TEMP0, d4, d4 \
// expands one message block into the lower halfs of the d registers
// moves the contents of the d registers into upper halfs
// input: in, d0, d1, d2
// temp: TEMP0, TEMP1, TEMP2
// output: d0, d1, d2
#define EXPACC2(in, d0, d1, d2, TEMP0, TEMP1, TEMP2) \
VGBM $0xff3f, TEMP0 \
VESLG $4, d1, TEMP2 \
VGBM $0xff1f, TEMP1 \
VPERM in, d0, EX0, d0 \
VESRLG $4, TEMP0, TEMP0 \
VPERM in, d2, EX2, d2 \
VPERM in, TEMP2, EX1, d1 \
VN TEMP0, d0, d0 \
VN TEMP1, d2, d2 \
VESRLG $4, d1, d1 \
VN TEMP0, d1, d1 \
// pack h2:h0 into h1:h0 (no carry)
// input: h0, h1, h2
// output: h0, h1, h2
#define PACK(h0, h1, h2) \
VMRLG h1, h2, h2 \ // copy h1 to upper half h2
VESLG $44, h1, h1 \ // shift limb 1 44 bits, leaving 20
VO h0, h1, h0 \ // combine h0 with 20 bits from limb 1
VESRLG $20, h2, h1 \ // put top 24 bits of limb 1 into h1
VLEIG $1, $0, h1 \ // clear h2 stuff from lower half of h1
VO h0, h1, h0 \ // h0 now has 88 bits (limb 0 and 1)
VLEIG $0, $0, h2 \ // clear upper half of h2
VESRLG $40, h2, h1 \ // h1 now has upper two bits of result
VLEIB $7, $88, h1 \ // for byte shift (11 bytes)
VSLB h1, h2, h2 \ // shift h2 11 bytes to the left
VO h0, h2, h0 \ // combine h0 with 20 bits from limb 1
VLEIG $0, $0, h1 \ // clear upper half of h1
// if h > 2**130-5 then h -= 2**130-5
// input: h0, h1
// temp: t0, t1, t2
// output: h0
#define MOD(h0, h1, t0, t1, t2) \
VZERO t0 \
VLEIG $1, $5, t0 \
VACCQ h0, t0, t1 \
VAQ h0, t0, t0 \
VONE t2 \
VLEIG $1, $-4, t2 \
VAQ t2, t1, t1 \
VACCQ h1, t1, t1 \
VONE t2 \
VAQ t2, t1, t1 \
VN h0, t1, t2 \
VNC t0, t1, t1 \
VO t1, t2, h0 \
// func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]key)
TEXT ·poly1305vmsl(SB), $0-32
// This code processes 6 + up to 4 blocks (32 bytes) per iteration
// using the algorithm described in:
// NEON crypto, Daniel J. Bernstein & Peter Schwabe
// https://cryptojedi.org/papers/neoncrypto-20120320.pdf
// And as moddified for VMSL as described in
// Accelerating Poly1305 Cryptographic Message Authentication on the z14
// O'Farrell et al, CASCON 2017, p48-55
// https://ibm.ent.box.com/s/jf9gedj0e9d2vjctfyh186shaztavnht
LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key
VZERO V0 // c
// load EX0, EX1 and EX2
MOVD $·constants<>(SB), R5
VLM (R5), EX0, EX2 // c
// setup r
VL (R4), T_0
MOVD $·keyMask<>(SB), R6
VL (R6), T_1
VN T_0, T_1, T_0
VZERO T_2 // limbs for r
VZERO T_3
VZERO T_4
EXPACC2(T_0, T_2, T_3, T_4, T_1, T_5, T_7)
// T_2, T_3, T_4: [0, r]
// setup r*20
VLEIG $0, $0, T_0
VLEIG $1, $20, T_0 // T_0: [0, 20]
VZERO T_5
VZERO T_6
VMSLG T_0, T_3, T_5, T_5
VMSLG T_0, T_4, T_6, T_6
// store r for final block in GR
VLGVG $1, T_2, RSAVE_0 // c
VLGVG $1, T_3, RSAVE_1 // c
VLGVG $1, T_4, RSAVE_2 // c
VLGVG $1, T_5, R5SAVE_1 // c
VLGVG $1, T_6, R5SAVE_2 // c
// initialize h
VZERO H0_0
VZERO H1_0
VZERO H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
// initialize pointer for reduce constants
MOVD $·reduce<>(SB), R12
// calculate r**2 and 20*(r**2)
VZERO R_0
VZERO R_1
VZERO R_2
SQUARE(T_2, T_3, T_4, T_6, R_0, R_1, R_2, T_1, T_5, T_7)
REDUCE2(R_0, R_1, R_2, M0, M1, M2, M3, M4, R5_1, R5_2, M5, T_1)
VZERO R5_1
VZERO R5_2
VMSLG T_0, R_1, R5_1, R5_1
VMSLG T_0, R_2, R5_2, R5_2
// skip r**4 calculation if 3 blocks or less
CMPBLE R3, $48, b4
// calculate r**4 and 20*(r**4)
VZERO T_8
VZERO T_9
VZERO T_10
SQUARE(R_0, R_1, R_2, R5_2, T_8, T_9, T_10, T_1, T_5, T_7)
REDUCE2(T_8, T_9, T_10, M0, M1, M2, M3, M4, T_2, T_3, M5, T_1)
VZERO T_2
VZERO T_3
VMSLG T_0, T_9, T_2, T_2
VMSLG T_0, T_10, T_3, T_3
// put r**2 to the right and r**4 to the left of R_0, R_1, R_2
VSLDB $8, T_8, T_8, T_8
VSLDB $8, T_9, T_9, T_9
VSLDB $8, T_10, T_10, T_10
VSLDB $8, T_2, T_2, T_2
VSLDB $8, T_3, T_3, T_3
VO T_8, R_0, R_0
VO T_9, R_1, R_1
VO T_10, R_2, R_2
VO T_2, R5_1, R5_1
VO T_3, R5_2, R5_2
CMPBLE R3, $80, load // less than or equal to 5 blocks in message
// 6(or 5+1) blocks
SUB $81, R3
VLM (R2), M0, M4
VLL R3, 80(R2), M5
ADD $1, R3
MOVBZ $1, R0
CMPBGE R3, $16, 2(PC)
VLVGB R3, R0, M5
MOVD $96(R2), R2
EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3)
EXPACC(M2, M3, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3)
VLEIB $2, $1, H2_0
VLEIB $2, $1, H2_1
VLEIB $10, $1, H2_0
VLEIB $10, $1, H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO T_4
VZERO T_10
EXPACC(M4, M5, M0, M1, M2, M3, T_4, T_10, T_0, T_1, T_2, T_3)
VLR T_4, M4
VLEIB $10, $1, M2
CMPBLT R3, $16, 2(PC)
VLEIB $10, $1, T_10
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
SUB $16, R3
CMPBLE R3, $0, square
load:
// load EX0, EX1 and EX2
MOVD $·c<>(SB), R5
VLM (R5), EX0, EX2
loop:
CMPBLE R3, $64, add // b4 // last 4 or less blocks left
// next 4 full blocks
VLM (R2), M2, M5
SUB $64, R3
MOVD $64(R2), R2
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, T_0, T_1, T_3, T_4, T_5, T_2, T_7, T_8, T_9)
// expacc in-lined to create [m2, m3] limbs
VGBM $0x3f3f, T_0 // 44 bit clear mask
VGBM $0x1f1f, T_1 // 40 bit clear mask
VPERM M2, M3, EX0, T_3
VESRLG $4, T_0, T_0 // 44 bit clear mask ready
VPERM M2, M3, EX1, T_4
VPERM M2, M3, EX2, T_5
VN T_0, T_3, T_3
VESRLG $4, T_4, T_4
VN T_1, T_5, T_5
VN T_0, T_4, T_4
VMRHG H0_1, T_3, H0_0
VMRHG H1_1, T_4, H1_0
VMRHG H2_1, T_5, H2_0
VMRLG H0_1, T_3, H0_1
VMRLG H1_1, T_4, H1_1
VMRLG H2_1, T_5, H2_1
VLEIB $10, $1, H2_0
VLEIB $10, $1, H2_1
VPERM M4, M5, EX0, T_3
VPERM M4, M5, EX1, T_4
VPERM M4, M5, EX2, T_5
VN T_0, T_3, T_3
VESRLG $4, T_4, T_4
VN T_1, T_5, T_5
VN T_0, T_4, T_4
VMRHG V0, T_3, M0
VMRHG V0, T_4, M1
VMRHG V0, T_5, M2
VMRLG V0, T_3, M3
VMRLG V0, T_4, M4
VMRLG V0, T_5, M5
VLEIB $10, $1, M2
VLEIB $10, $1, M5
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
CMPBNE R3, $0, loop
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
// load EX0, EX1, EX2
MOVD $·constants<>(SB), R5
VLM (R5), EX0, EX2
// sum vectors
VAQ H0_0, H0_1, H0_0
VAQ H1_0, H1_1, H1_0
VAQ H2_0, H2_1, H2_0
// h may be >= 2*(2**130-5) so we need to reduce it again
// M0...M4 are used as temps here
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
next: // carry h1->h2
VLEIB $7, $0x28, T_1
VREPIB $4, T_2
VGBM $0x003F, T_3
VESRLG $4, T_3
// byte shift
VSRLB T_1, H1_0, T_4
// bit shift
VSRL T_2, T_4, T_4
// clear h1 carry bits
VN T_3, H1_0, H1_0
// add carry
VAQ T_4, H2_0, H2_0
// h is now < 2*(2**130-5)
// pack h into h1 (hi) and h0 (lo)
PACK(H0_0, H1_0, H2_0)
// if h > 2**130-5 then h -= 2**130-5
MOD(H0_0, H1_0, T_0, T_1, T_2)
// h += s
MOVD $·bswapMask<>(SB), R5
VL (R5), T_1
VL 16(R4), T_0
VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big)
VAQ T_0, H0_0, H0_0
VPERM H0_0, H0_0, T_1, H0_0 // reverse bytes (to little)
VST H0_0, (R1)
RET
add:
// load EX0, EX1, EX2
MOVD $·constants<>(SB), R5
VLM (R5), EX0, EX2
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
CMPBLE R3, $64, b4
b4:
CMPBLE R3, $48, b3 // 3 blocks or less
// 4(3+1) blocks remaining
SUB $49, R3
VLM (R2), M0, M2
VLL R3, 48(R2), M3
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, M3
MOVD $64(R2), R2
EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3)
VLEIB $10, $1, H2_0
VLEIB $10, $1, H2_1
VZERO M0
VZERO M1
VZERO M4
VZERO M5
VZERO T_4
VZERO T_10
EXPACC(M2, M3, M0, M1, M4, M5, T_4, T_10, T_0, T_1, T_2, T_3)
VLR T_4, M2
VLEIB $10, $1, M4
CMPBNE R3, $16, 2(PC)
VLEIB $10, $1, T_10
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M4, M5, M2, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
SUB $16, R3
CMPBLE R3, $0, square // this condition must always hold true!
b3:
CMPBLE R3, $32, b2
// 3 blocks remaining
// setup [r²,r]
VSLDB $8, R_0, R_0, R_0
VSLDB $8, R_1, R_1, R_1
VSLDB $8, R_2, R_2, R_2
VSLDB $8, R5_1, R5_1, R5_1
VSLDB $8, R5_2, R5_2, R5_2
VLVGG $1, RSAVE_0, R_0
VLVGG $1, RSAVE_1, R_1
VLVGG $1, RSAVE_2, R_2
VLVGG $1, R5SAVE_1, R5_1
VLVGG $1, R5SAVE_2, R5_2
// setup [h0, h1]
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
VO H0_1, H0_0, H0_0
VO H1_1, H1_0, H1_0
VO H2_1, H2_0, H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
// H*[r**2, r]
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, T_10, M5)
SUB $33, R3
VLM (R2), M0, M1
VLL R3, 32(R2), M2
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, M2
// H += m0
VZERO T_1
VZERO T_2
VZERO T_3
EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6)
VLEIB $10, $1, T_3
VAG H0_0, T_1, H0_0
VAG H1_0, T_2, H1_0
VAG H2_0, T_3, H2_0
VZERO M0
VZERO M3
VZERO M4
VZERO M5
VZERO T_10
// (H+m0)*r
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M3, M4, M5, V0, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_10, H0_1, H1_1, H2_1, T_9)
// H += m1
VZERO V0
VZERO T_1
VZERO T_2
VZERO T_3
EXPACC2(M1, T_1, T_2, T_3, T_4, T_5, T_6)
VLEIB $10, $1, T_3
VAQ H0_0, T_1, H0_0
VAQ H1_0, T_2, H1_0
VAQ H2_0, T_3, H2_0
REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10)
// [H, m2] * [r**2, r]
EXPACC2(M2, H0_0, H1_0, H2_0, T_1, T_2, T_3)
CMPBNE R3, $16, 2(PC)
VLEIB $10, $1, H2_0
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, M5, T_10)
SUB $16, R3
CMPBLE R3, $0, next // this condition must always hold true!
b2:
CMPBLE R3, $16, b1
// 2 blocks remaining
// setup [r²,r]
VSLDB $8, R_0, R_0, R_0
VSLDB $8, R_1, R_1, R_1
VSLDB $8, R_2, R_2, R_2
VSLDB $8, R5_1, R5_1, R5_1
VSLDB $8, R5_2, R5_2, R5_2
VLVGG $1, RSAVE_0, R_0
VLVGG $1, RSAVE_1, R_1
VLVGG $1, RSAVE_2, R_2
VLVGG $1, R5SAVE_1, R5_1
VLVGG $1, R5SAVE_2, R5_2
// setup [h0, h1]
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
VO H0_1, H0_0, H0_0
VO H1_1, H1_0, H1_0
VO H2_1, H2_0, H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
// H*[r**2, r]
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
// move h to the left and 0s at the right
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
// get message blocks and append 1 to start
SUB $17, R3
VL (R2), M0
VLL R3, 16(R2), M1
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, M1
VZERO T_6
VZERO T_7
VZERO T_8
EXPACC2(M0, T_6, T_7, T_8, T_1, T_2, T_3)
EXPACC2(M1, T_6, T_7, T_8, T_1, T_2, T_3)
VLEIB $2, $1, T_8
CMPBNE R3, $16, 2(PC)
VLEIB $10, $1, T_8
// add [m0, m1] to h
VAG H0_0, T_6, H0_0
VAG H1_0, T_7, H1_0
VAG H2_0, T_8, H2_0
VZERO M2
VZERO M3
VZERO M4
VZERO M5
VZERO T_10
VZERO M0
// at this point R_0 .. R5_2 look like [r**2, r]
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M2, M3, M4, M5, T_10, M0, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M2, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10)
SUB $16, R3, R3
CMPBLE R3, $0, next
b1:
CMPBLE R3, $0, next
// 1 block remaining
// setup [r²,r]
VSLDB $8, R_0, R_0, R_0
VSLDB $8, R_1, R_1, R_1
VSLDB $8, R_2, R_2, R_2
VSLDB $8, R5_1, R5_1, R5_1
VSLDB $8, R5_2, R5_2, R5_2
VLVGG $1, RSAVE_0, R_0
VLVGG $1, RSAVE_1, R_1
VLVGG $1, RSAVE_2, R_2
VLVGG $1, R5SAVE_1, R5_1
VLVGG $1, R5SAVE_2, R5_2
// setup [h0, h1]
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
VO H0_1, H0_0, H0_0
VO H1_1, H1_0, H1_0
VO H2_1, H2_0, H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
// H*[r**2, r]
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
// set up [0, m0] limbs
SUB $1, R3
VLL R3, (R2), M0
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, M0
VZERO T_1
VZERO T_2
VZERO T_3
EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6)// limbs: [0, m]
CMPBNE R3, $16, 2(PC)
VLEIB $10, $1, T_3
// h+m0
VAQ H0_0, T_1, H0_0
VAQ H1_0, T_2, H1_0
VAQ H2_0, T_3, H2_0
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
BR next
square:
// setup [r²,r]
VSLDB $8, R_0, R_0, R_0
VSLDB $8, R_1, R_1, R_1
VSLDB $8, R_2, R_2, R_2
VSLDB $8, R5_1, R5_1, R5_1
VSLDB $8, R5_2, R5_2, R5_2
VLVGG $1, RSAVE_0, R_0
VLVGG $1, RSAVE_1, R_1
VLVGG $1, RSAVE_2, R_2
VLVGG $1, R5SAVE_1, R5_1
VLVGG $1, R5SAVE_2, R5_2
// setup [h0, h1]
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
VO H0_1, H0_0, H0_0
VO H1_1, H1_0, H1_0
VO H2_1, H2_0, H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
// (h0*r**2) + (h1*r)
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
BR next

View File

@ -414,8 +414,8 @@ func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
return nil return nil
} }
// SignCert sets c.SignatureKey to the authority's public key and stores a // SignCert signs the certificate with an authority, setting the Nonce,
// Signature, by authority, in the certificate. // SignatureKey, and Signature fields.
func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
c.Nonce = make([]byte, 32) c.Nonce = make([]byte, 32)
if _, err := io.ReadFull(rand, c.Nonce); err != nil { if _, err := io.ReadFull(rand, c.Nonce); err != nil {

View File

@ -119,7 +119,7 @@ var cipherModes = map[string]*cipherMode{
chacha20Poly1305ID: {64, 0, newChaCha20Cipher}, chacha20Poly1305ID: {64, 0, newChaCha20Cipher},
// CBC mode is insecure and so is not included in the default config. // CBC mode is insecure and so is not included in the default config.
// (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely // (See https://www.ieee-security.org/TC/SP2013/papers/4977a526.pdf). If absolutely
// needed, it's possible to specify a custom Config to enable it. // needed, it's possible to specify a custom Config to enable it.
// You should expect that an active attacker can recover plaintext if // You should expect that an active attacker can recover plaintext if
// you do. // you do.

View File

@ -36,7 +36,7 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
// during the authentication phase the client first attempts the "none" method // during the authentication phase the client first attempts the "none" method
// then any untried methods suggested by the server. // then any untried methods suggested by the server.
tried := make(map[string]bool) var tried []string
var lastMethods []string var lastMethods []string
sessionID := c.transport.getSessionID() sessionID := c.transport.getSessionID()
@ -49,7 +49,9 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
// success // success
return nil return nil
} else if ok == authFailure { } else if ok == authFailure {
tried[auth.method()] = true if m := auth.method(); !contains(tried, m) {
tried = append(tried, m)
}
} }
if methods == nil { if methods == nil {
methods = lastMethods methods = lastMethods
@ -61,7 +63,7 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
findNext: findNext:
for _, a := range config.Auth { for _, a := range config.Auth {
candidateMethod := a.method() candidateMethod := a.method()
if tried[candidateMethod] { if contains(tried, candidateMethod) {
continue continue
} }
for _, meth := range methods { for _, meth := range methods {
@ -72,16 +74,16 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
} }
} }
} }
return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried)) return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried)
} }
func keys(m map[string]bool) []string { func contains(list []string, e string) bool {
s := make([]string, 0, len(m)) for _, s := range list {
if s == e {
for key := range m { return true
s = append(s, key)
} }
return s }
return false
} }
// An AuthMethod represents an instance of an RFC 4252 authentication method. // An AuthMethod represents an instance of an RFC 4252 authentication method.

View File

@ -572,7 +572,7 @@ func (gex *dhGEXSHA) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, e
return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil
} }
func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
// Send GexRequest // Send GexRequest
kexDHGexRequest := kexDHGexRequestMsg{ kexDHGexRequest := kexDHGexRequestMsg{
MinBits: dhGroupExchangeMinimumBits, MinBits: dhGroupExchangeMinimumBits,
@ -677,7 +677,7 @@ func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshak
// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256. // Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
// //
// This is a minimal implementation to satisfy the automated tests. // This is a minimal implementation to satisfy the automated tests.
func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
// Receive GexRequest // Receive GexRequest
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {

View File

@ -1246,15 +1246,23 @@ func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc {
} }
key, iv := k[:32], k[32:] key, iv := k[:32], k[32:]
if cipherName != "aes256-ctr" {
return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q", cipherName, "aes256-ctr")
}
c, err := aes.NewCipher(key) c, err := aes.NewCipher(key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
switch cipherName {
case "aes256-ctr":
ctr := cipher.NewCTR(c, iv) ctr := cipher.NewCTR(c, iv)
ctr.XORKeyStream(privKeyBlock, privKeyBlock) ctr.XORKeyStream(privKeyBlock, privKeyBlock)
case "aes256-cbc":
if len(privKeyBlock)%c.BlockSize() != 0 {
return nil, fmt.Errorf("ssh: invalid encrypted private key length, not a multiple of the block size")
}
cbc := cipher.NewCBCDecrypter(c, iv)
cbc.CryptBlocks(privKeyBlock, privKeyBlock)
default:
return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q or %q", cipherName, "aes256-ctr", "aes256-cbc")
}
return privKeyBlock, nil return privKeyBlock, nil
} }

View File

@ -240,7 +240,7 @@ func (m *mux) onePacket() error {
id := binary.BigEndian.Uint32(packet[1:]) id := binary.BigEndian.Uint32(packet[1:])
ch := m.chanList.getChan(id) ch := m.chanList.getChan(id)
if ch == nil { if ch == nil {
return fmt.Errorf("ssh: invalid channel %d", id) return m.handleUnknownChannelPacket(id, packet)
} }
return ch.handlePacket(packet) return ch.handlePacket(packet)
@ -328,3 +328,24 @@ func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) {
return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg) return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg)
} }
} }
func (m *mux) handleUnknownChannelPacket(id uint32, packet []byte) error {
msg, err := decode(packet)
if err != nil {
return err
}
switch msg := msg.(type) {
// RFC 4254 section 5.4 says unrecognized channel requests should
// receive a failure response.
case *channelRequestMsg:
if msg.WantReply {
return m.sendMessage(channelRequestFailureMsg{
PeersID: msg.PeersID,
})
}
return nil
default:
return fmt.Errorf("ssh: invalid channel %d", id)
}
}

View File

@ -113,6 +113,7 @@ func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
} }
const ( const (
keyCtrlC = 3
keyCtrlD = 4 keyCtrlD = 4
keyCtrlU = 21 keyCtrlU = 21
keyEnter = '\r' keyEnter = '\r'
@ -151,8 +152,12 @@ func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
switch b[0] { switch b[0] {
case 1: // ^A case 1: // ^A
return keyHome, b[1:] return keyHome, b[1:]
case 2: // ^B
return keyLeft, b[1:]
case 5: // ^E case 5: // ^E
return keyEnd, b[1:] return keyEnd, b[1:]
case 6: // ^F
return keyRight, b[1:]
case 8: // ^H case 8: // ^H
return keyBackspace, b[1:] return keyBackspace, b[1:]
case 11: // ^K case 11: // ^K
@ -738,6 +743,9 @@ func (t *Terminal) readLine() (line string, err error) {
return "", io.EOF return "", io.EOF
} }
} }
if key == keyCtrlC {
return "", io.EOF
}
if key == keyPasteStart { if key == keyPasteStart {
t.pasteActive = true t.pasteActive = true
if len(t.line) == 0 { if len(t.line) == 0 {

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build aix,ppc64 // +build aix
package cpu package cpu

27
vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Recreate a getsystemcfg syscall handler instead of
// using the one provided by x/sys/unix to avoid having
// the dependency between them. (See golang.org/issue/32102)
// Morever, this file will be used during the building of
// gccgo's libgo and thus must not used a CGo method.
// +build aix
// +build gccgo
package cpu
import (
"syscall"
)
//extern getsystemcfg
func gccgoGetsystemcfg(label uint32) (r uint64)
func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) {
r1 = uintptr(gccgoGetsystemcfg(uint32(label)))
e1 = syscall.GetErrno()
return
}

View File

@ -0,0 +1,30 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package unsafeheader contains header declarations for the Go runtime's
// slice and string implementations.
//
// This package allows x/sys to use types equivalent to
// reflect.SliceHeader and reflect.StringHeader without introducing
// a dependency on the (relatively heavy) "reflect" package.
package unsafeheader
import (
"unsafe"
)
// Slice is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may change in a later release.
type Slice struct {
Data unsafe.Pointer
Len int
Cap int
}
// String is the runtime representation of a string.
// It cannot be used safely or portably and its representation may change in a later release.
type String struct {
Data unsafe.Pointer
Len int
}

View File

@ -89,7 +89,7 @@ constants.
Adding new syscall numbers is mostly done by running the build on a sufficiently Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you make need to update the new build system). However, depending on the OS, you may need to update the
parsing in mksysnum. parsing in mksysnum.
### mksyscall.go ### mksyscall.go
@ -163,7 +163,7 @@ The merge is performed in the following steps:
## Generated files ## Generated files
### `zerror_${GOOS}_${GOARCH}.go` ### `zerrors_${GOOS}_${GOARCH}.go`
A file containing all of the system's generated error numbers, error strings, A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by `mkerrors.sh` (see above). signal numbers, and constants. Generated by `mkerrors.sh` (see above).

View File

@ -187,6 +187,7 @@ struct ltchars {
#include <sys/select.h> #include <sys/select.h>
#include <sys/signalfd.h> #include <sys/signalfd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/timerfd.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/xattr.h> #include <sys/xattr.h>
#include <linux/bpf.h> #include <linux/bpf.h>
@ -200,6 +201,7 @@ struct ltchars {
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/fscrypt.h> #include <linux/fscrypt.h>
#include <linux/fsverity.h>
#include <linux/genetlink.h> #include <linux/genetlink.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/icmpv6.h> #include <linux/icmpv6.h>
@ -479,12 +481,13 @@ ccflags="$@"
$2 ~ /^(MS|MNT|UMOUNT)_/ || $2 ~ /^(MS|MNT|UMOUNT)_/ ||
$2 ~ /^NS_GET_/ || $2 ~ /^NS_GET_/ ||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ || $2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT)_/ || $2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|TFD)_/ ||
$2 ~ /^KEXEC_/ || $2 ~ /^KEXEC_/ ||
$2 ~ /^LINUX_REBOOT_CMD_/ || $2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ || $2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
$2 ~ /^MODULE_INIT_/ || $2 ~ /^MODULE_INIT_/ ||
$2 !~ "NLA_TYPE_MASK" && $2 !~ "NLA_TYPE_MASK" &&
$2 !~ /^RTC_VL_(ACCURACY|BACKUP|DATA)/ &&
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ || $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ ||
$2 ~ /^SIOC/ || $2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ || $2 ~ /^TIOC/ ||
@ -506,7 +509,8 @@ ccflags="$@"
$2 ~ /^CAP_/ || $2 ~ /^CAP_/ ||
$2 ~ /^ALG_/ || $2 ~ /^ALG_/ ||
$2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE)/ || $2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE)/ ||
$2 ~ /^FS_IOC_.*ENCRYPTION/ || $2 ~ /^FS_IOC_.*(ENCRYPTION|VERITY|GETFLAGS)/ ||
$2 ~ /^FS_VERITY_/ ||
$2 ~ /^FSCRYPT_/ || $2 ~ /^FSCRYPT_/ ||
$2 ~ /^GRND_/ || $2 ~ /^GRND_/ ||
$2 ~ /^RND/ || $2 ~ /^RND/ ||

View File

@ -6,7 +6,11 @@
package unix package unix
import "unsafe" import (
"unsafe"
"golang.org/x/sys/internal/unsafeheader"
)
//sys closedir(dir uintptr) (err error) //sys closedir(dir uintptr) (err error)
//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) //sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
@ -71,6 +75,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
cnt++ cnt++
continue continue
} }
reclen := int(entry.Reclen) reclen := int(entry.Reclen)
if reclen > len(buf) { if reclen > len(buf) {
// Not enough room. Return for now. // Not enough room. Return for now.
@ -79,13 +84,15 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// restarting is O(n^2) in the length of the directory. Oh well. // restarting is O(n^2) in the length of the directory. Oh well.
break break
} }
// Copy entry into return buffer. // Copy entry into return buffer.
s := struct { var s []byte
ptr unsafe.Pointer hdr := (*unsafeheader.Slice)(unsafe.Pointer(&s))
siz int hdr.Data = unsafe.Pointer(&entry)
cap int hdr.Cap = reclen
}{ptr: unsafe.Pointer(&entry), siz: reclen, cap: reclen} hdr.Len = reclen
copy(buf, *(*[]byte)(unsafe.Pointer(&s))) copy(buf, s)
buf = buf[reclen:] buf = buf[reclen:]
n += reclen n += reclen
cnt++ cnt++

View File

@ -423,6 +423,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sysnb Getrlimit(which int, lim *Rlimit) (err error) //sysnb Getrlimit(which int, lim *Rlimit) (err error)
//sysnb Getrusage(who int, rusage *Rusage) (err error) //sysnb Getrusage(who int, rusage *Rusage) (err error)
//sysnb Getsid(pid int) (sid int, err error) //sysnb Getsid(pid int) (sid int, err error)
//sysnb Gettimeofday(tp *Timeval) (err error)
//sysnb Getuid() (uid int) //sysnb Getuid() (uid int)
//sysnb Issetugid() (tainted bool) //sysnb Issetugid() (tainted bool)
//sys Kqueue() (fd int, err error) //sys Kqueue() (fd int, err error)

View File

@ -20,17 +20,6 @@ func setTimeval(sec, usec int64) Timeval {
return Timeval{Sec: int32(sec), Usec: int32(usec)} return Timeval{Sec: int32(sec), Usec: int32(usec)}
} }
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = int32(sec)
tv.Usec = int32(usec)
return err
}
func SetKevent(k *Kevent_t, fd, mode, flags int) { func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint32(fd) k.Ident = uint32(fd)
k.Filter = int16(mode) k.Filter = int16(mode)

View File

@ -20,17 +20,6 @@ func setTimeval(sec, usec int64) Timeval {
return Timeval{Sec: sec, Usec: int32(usec)} return Timeval{Sec: sec, Usec: int32(usec)}
} }
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = sec
tv.Usec = usec
return err
}
func SetKevent(k *Kevent_t, fd, mode, flags int) { func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint64(fd) k.Ident = uint64(fd)
k.Filter = int16(mode) k.Filter = int16(mode)

View File

@ -20,17 +20,6 @@ func setTimeval(sec, usec int64) Timeval {
return Timeval{Sec: int32(sec), Usec: int32(usec)} return Timeval{Sec: int32(sec), Usec: int32(usec)}
} }
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = int32(sec)
tv.Usec = int32(usec)
return err
}
func SetKevent(k *Kevent_t, fd, mode, flags int) { func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint32(fd) k.Ident = uint32(fd)
k.Filter = int16(mode) k.Filter = int16(mode)

View File

@ -22,17 +22,6 @@ func setTimeval(sec, usec int64) Timeval {
return Timeval{Sec: sec, Usec: int32(usec)} return Timeval{Sec: sec, Usec: int32(usec)}
} }
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = sec
tv.Usec = usec
return err
}
func SetKevent(k *Kevent_t, fd, mode, flags int) { func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint64(fd) k.Ident = uint64(fd)
k.Filter = int16(mode) k.Filter = int16(mode)

View File

@ -1633,6 +1633,15 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sys CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) //sys CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
//sys DeleteModule(name string, flags int) (err error) //sys DeleteModule(name string, flags int) (err error)
//sys Dup(oldfd int) (fd int, err error) //sys Dup(oldfd int) (fd int, err error)
func Dup2(oldfd, newfd int) error {
// Android O and newer blocks dup2; riscv and arm64 don't implement dup2.
if runtime.GOOS == "android" || runtime.GOARCH == "riscv64" || runtime.GOARCH == "arm64" {
return Dup3(oldfd, newfd, 0)
}
return dup2(oldfd, newfd)
}
//sys Dup3(oldfd int, newfd int, flags int) (err error) //sys Dup3(oldfd int, newfd int, flags int) (err error)
//sysnb EpollCreate1(flag int) (fd int, err error) //sysnb EpollCreate1(flag int) (fd int, err error)
//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) //sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
@ -1757,6 +1766,9 @@ func Signalfd(fd int, sigmask *Sigset_t, flags int) (newfd int, err error) {
//sys Syncfs(fd int) (err error) //sys Syncfs(fd int) (err error)
//sysnb Sysinfo(info *Sysinfo_t) (err error) //sysnb Sysinfo(info *Sysinfo_t) (err error)
//sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error) //sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error)
//sysnb TimerfdCreate(clockid int, flags int) (fd int, err error)
//sysnb TimerfdGettime(fd int, currValue *ItimerSpec) (err error)
//sysnb TimerfdSettime(fd int, flags int, newValue *ItimerSpec, oldValue *ItimerSpec) (err error)
//sysnb Tgkill(tgid int, tid int, sig syscall.Signal) (err error) //sysnb Tgkill(tgid int, tid int, sig syscall.Signal) (err error)
//sysnb Times(tms *Tms) (ticks uintptr, err error) //sysnb Times(tms *Tms) (ticks uintptr, err error)
//sysnb Umask(mask int) (oldmask int) //sysnb Umask(mask int) (oldmask int)
@ -2178,7 +2190,6 @@ func Klogset(typ int, arg int) (err error) {
// TimerGetoverrun // TimerGetoverrun
// TimerGettime // TimerGettime
// TimerSettime // TimerSettime
// Timerfd
// Tkill (obsolete) // Tkill (obsolete)
// Tuxcall // Tuxcall
// Umount2 // Umount2

View File

@ -49,7 +49,7 @@ func Pipe2(p []int, flags int) (err error) {
// 64-bit file system and 32-bit uid calls // 64-bit file system and 32-bit uid calls
// (386 default is 32-bit file system and 16-bit uid). // (386 default is 32-bit file system and 16-bit uid).
//sys Dup2(oldfd int, newfd int) (err error) //sys dup2(oldfd int, newfd int) (err error)
//sysnb EpollCreate(size int) (fd int, err error) //sysnb EpollCreate(size int) (fd int, err error)
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64 //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64

View File

@ -6,7 +6,7 @@
package unix package unix
//sys Dup2(oldfd int, newfd int) (err error) //sys dup2(oldfd int, newfd int) (err error)
//sysnb EpollCreate(size int) (fd int, err error) //sysnb EpollCreate(size int) (fd int, err error)
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64

View File

@ -80,7 +80,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
// 64-bit file system and 32-bit uid calls // 64-bit file system and 32-bit uid calls
// (16-bit uid calls are not always supported in newer kernels) // (16-bit uid calls are not always supported in newer kernels)
//sys Dup2(oldfd int, newfd int) (err error) //sys dup2(oldfd int, newfd int) (err error)
//sysnb EpollCreate(size int) (fd int, err error) //sysnb EpollCreate(size int) (fd int, err error)
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32 //sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32

View File

@ -25,7 +25,7 @@ func EpollCreate(size int) (fd int, err error) {
//sysnb Getegid() (egid int) //sysnb Getegid() (egid int)
//sysnb Geteuid() (euid int) //sysnb Geteuid() (euid int)
//sysnb Getgid() (gid int) //sysnb Getgid() (gid int)
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) //sysnb getrlimit(resource int, rlim *Rlimit) (err error)
//sysnb Getuid() (uid int) //sysnb Getuid() (uid int)
//sys Listen(s int, n int) (err error) //sys Listen(s int, n int) (err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
@ -47,7 +47,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
//sysnb Setregid(rgid int, egid int) (err error) //sysnb Setregid(rgid int, egid int) (err error)
//sysnb Setresgid(rgid int, egid int, sgid int) (err error) //sysnb Setresgid(rgid int, egid int, sgid int) (err error)
//sysnb Setresuid(ruid int, euid int, suid int) (err error) //sysnb Setresuid(ruid int, euid int, suid int) (err error)
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) //sysnb setrlimit(resource int, rlim *Rlimit) (err error)
//sysnb Setreuid(ruid int, euid int) (err error) //sysnb Setreuid(ruid int, euid int) (err error)
//sys Shutdown(fd int, how int) (err error) //sys Shutdown(fd int, how int) (err error)
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
@ -168,6 +168,24 @@ func Pipe2(p []int, flags int) (err error) {
return return
} }
// Getrlimit prefers the prlimit64 system call. See issue 38604.
func Getrlimit(resource int, rlim *Rlimit) error {
err := prlimit(0, resource, nil, rlim)
if err != ENOSYS {
return err
}
return getrlimit(resource, rlim)
}
// Setrlimit prefers the prlimit64 system call. See issue 38604.
func Setrlimit(resource int, rlim *Rlimit) error {
err := prlimit(0, resource, rlim, nil)
if err != ENOSYS {
return err
}
return setrlimit(resource, rlim)
}
func (r *PtraceRegs) PC() uint64 { return r.Pc } func (r *PtraceRegs) PC() uint64 { return r.Pc }
func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc } func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc }
@ -192,9 +210,9 @@ func InotifyInit() (fd int, err error) {
return InotifyInit1(0) return InotifyInit1(0)
} }
func Dup2(oldfd int, newfd int) (err error) { // dup2 exists because func Dup3 in syscall_linux.go references
return Dup3(oldfd, newfd, 0) // it in an unreachable path. dup2 isn't available on arm64.
} func dup2(oldfd int, newfd int) error
func Pause() error { func Pause() error {
_, err := ppoll(nil, 0, nil, nil) _, err := ppoll(nil, 0, nil, nil)

View File

@ -7,7 +7,7 @@
package unix package unix
//sys Dup2(oldfd int, newfd int) (err error) //sys dup2(oldfd int, newfd int) (err error)
//sysnb EpollCreate(size int) (fd int, err error) //sysnb EpollCreate(size int) (fd int, err error)
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64

Some files were not shown because too many files have changed in this diff Show More