summaryrefslogtreecommitdiffstats
path: root/vendor
diff options
context:
space:
mode:
Diffstat (limited to 'vendor')
-rw-r--r--vendor/github.com/bwmarrin/discordgo/.travis.yml (renamed from vendor/github.com/matterbridge/discordgo/.travis.yml)6
-rw-r--r--vendor/github.com/bwmarrin/discordgo/LICENSE (renamed from vendor/github.com/matterbridge/discordgo/LICENSE)0
-rw-r--r--vendor/github.com/bwmarrin/discordgo/README.md (renamed from vendor/github.com/matterbridge/discordgo/README.md)20
-rw-r--r--vendor/github.com/bwmarrin/discordgo/discord.go (renamed from vendor/github.com/matterbridge/discordgo/discord.go)6
-rw-r--r--vendor/github.com/bwmarrin/discordgo/endpoints.go (renamed from vendor/github.com/matterbridge/discordgo/endpoints.go)28
-rw-r--r--vendor/github.com/bwmarrin/discordgo/event.go (renamed from vendor/github.com/matterbridge/discordgo/event.go)11
-rw-r--r--vendor/github.com/bwmarrin/discordgo/eventhandlers.go (renamed from vendor/github.com/matterbridge/discordgo/eventhandlers.go)24
-rw-r--r--vendor/github.com/bwmarrin/discordgo/events.go (renamed from vendor/github.com/matterbridge/discordgo/events.go)9
-rw-r--r--vendor/github.com/bwmarrin/discordgo/go.mod6
-rw-r--r--vendor/github.com/bwmarrin/discordgo/go.sum4
-rw-r--r--vendor/github.com/bwmarrin/discordgo/logging.go (renamed from vendor/github.com/matterbridge/discordgo/logging.go)0
-rw-r--r--vendor/github.com/bwmarrin/discordgo/message.go (renamed from vendor/github.com/matterbridge/discordgo/message.go)67
-rw-r--r--vendor/github.com/bwmarrin/discordgo/mkdocs.yml (renamed from vendor/github.com/matterbridge/discordgo/mkdocs.yml)0
-rw-r--r--vendor/github.com/bwmarrin/discordgo/oauth2.go (renamed from vendor/github.com/matterbridge/discordgo/oauth2.go)0
-rw-r--r--vendor/github.com/bwmarrin/discordgo/ratelimit.go (renamed from vendor/github.com/matterbridge/discordgo/ratelimit.go)0
-rw-r--r--vendor/github.com/bwmarrin/discordgo/restapi.go (renamed from vendor/github.com/matterbridge/discordgo/restapi.go)233
-rw-r--r--vendor/github.com/bwmarrin/discordgo/state.go (renamed from vendor/github.com/matterbridge/discordgo/state.go)29
-rw-r--r--vendor/github.com/bwmarrin/discordgo/structs.go (renamed from vendor/github.com/matterbridge/discordgo/structs.go)439
-rw-r--r--vendor/github.com/bwmarrin/discordgo/types.go (renamed from vendor/github.com/matterbridge/discordgo/types.go)3
-rw-r--r--vendor/github.com/bwmarrin/discordgo/user.go69
-rw-r--r--vendor/github.com/bwmarrin/discordgo/voice.go (renamed from vendor/github.com/matterbridge/discordgo/voice.go)10
-rw-r--r--vendor/github.com/bwmarrin/discordgo/wsapi.go (renamed from vendor/github.com/matterbridge/discordgo/wsapi.go)99
-rw-r--r--vendor/github.com/gorilla/websocket/.gitignore2
-rw-r--r--vendor/github.com/gorilla/websocket/.travis.yml10
-rw-r--r--vendor/github.com/gorilla/websocket/AUTHORS1
-rw-r--r--vendor/github.com/gorilla/websocket/README.md2
-rw-r--r--vendor/github.com/gorilla/websocket/client.go243
-rw-r--r--vendor/github.com/gorilla/websocket/conn.go170
-rw-r--r--vendor/github.com/gorilla/websocket/conn_read_legacy.go21
-rw-r--r--vendor/github.com/gorilla/websocket/conn_write.go (renamed from vendor/github.com/gorilla/websocket/conn_read.go)15
-rw-r--r--vendor/github.com/gorilla/websocket/conn_write_legacy.go18
-rw-r--r--vendor/github.com/gorilla/websocket/doc.go56
-rw-r--r--vendor/github.com/gorilla/websocket/json.go11
-rw-r--r--vendor/github.com/gorilla/websocket/mask.go1
-rw-r--r--vendor/github.com/gorilla/websocket/prepared.go1
-rw-r--r--vendor/github.com/gorilla/websocket/proxy.go77
-rw-r--r--vendor/github.com/gorilla/websocket/server.go136
-rw-r--r--vendor/github.com/gorilla/websocket/trace.go19
-rw-r--r--vendor/github.com/gorilla/websocket/trace_17.go12
-rw-r--r--vendor/github.com/gorilla/websocket/util.go35
-rw-r--r--vendor/github.com/gorilla/websocket/x_net_proxy.go473
-rw-r--r--vendor/github.com/matterbridge/discordgo/user.go47
-rw-r--r--vendor/golang.org/x/crypto/acme/acme.go435
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/autocert.go361
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/cache.go6
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/listener.go7
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/renewal.go45
-rw-r--r--vendor/golang.org/x/crypto/acme/http.go281
-rw-r--r--vendor/golang.org/x/crypto/acme/types.go8
-rw-r--r--vendor/golang.org/x/crypto/ed25519/ed25519.go60
-rw-r--r--vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go22
-rw-r--r--vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go426
-rw-r--r--vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go16
-rw-r--r--vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go30
-rw-r--r--vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s283
-rw-r--r--vendor/golang.org/x/crypto/internal/chacha20/xor.go43
-rw-r--r--vendor/golang.org/x/crypto/internal/subtle/aliasing.go32
-rw-r--r--vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go35
-rw-r--r--vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go9
-rw-r--r--vendor/golang.org/x/crypto/poly1305/sum_noasm.go14
-rw-r--r--vendor/golang.org/x/crypto/poly1305/sum_ref.go10
-rw-r--r--vendor/golang.org/x/crypto/poly1305/sum_s390x.go49
-rw-r--r--vendor/golang.org/x/crypto/poly1305/sum_s390x.s400
-rw-r--r--vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s931
-rw-r--r--vendor/golang.org/x/crypto/ssh/certs.go16
-rw-r--r--vendor/golang.org/x/crypto/ssh/cipher.go43
-rw-r--r--vendor/golang.org/x/crypto/ssh/client.go6
-rw-r--r--vendor/golang.org/x/crypto/ssh/keys.go98
-rw-r--r--vendor/golang.org/x/crypto/ssh/server.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/streamlocal.go1
-rw-r--r--vendor/golang.org/x/crypto/ssh/tcpip.go9
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util.go4
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go40
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util_windows.go4
-rw-r--r--vendor/modules.txt13
75 files changed, 4936 insertions, 1216 deletions
diff --git a/vendor/github.com/matterbridge/discordgo/.travis.yml b/vendor/github.com/bwmarrin/discordgo/.travis.yml
index fe626fcf..2656ae53 100644
--- a/vendor/github.com/matterbridge/discordgo/.travis.yml
+++ b/vendor/github.com/bwmarrin/discordgo/.travis.yml
@@ -1,12 +1,12 @@
language: go
go:
- - 1.7.x
- - 1.8.x
- 1.9.x
+ - 1.10.x
+ - 1.11.x
install:
- go get github.com/bwmarrin/discordgo
- go get -v .
- - go get -v github.com/golang/lint/golint
+ - go get -v golang.org/x/lint/golint
script:
- diff <(gofmt -d .) <(echo -n)
- go vet -x ./...
diff --git a/vendor/github.com/matterbridge/discordgo/LICENSE b/vendor/github.com/bwmarrin/discordgo/LICENSE
index 8d062ea5..8d062ea5 100644
--- a/vendor/github.com/matterbridge/discordgo/LICENSE
+++ b/vendor/github.com/bwmarrin/discordgo/LICENSE
diff --git a/vendor/github.com/matterbridge/discordgo/README.md b/vendor/github.com/bwmarrin/discordgo/README.md
index acc72bf1..cb5a6659 100644
--- a/vendor/github.com/matterbridge/discordgo/README.md
+++ b/vendor/github.com/bwmarrin/discordgo/README.md
@@ -1,4 +1,4 @@
-# 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://discord.gg/0SBTUU1wZTWT6sqd)
@@ -15,11 +15,11 @@ to add the official DiscordGo test bot **dgo** to your server. This provides
indispensable help to this project.
* See [dgVoice](https://github.com/bwmarrin/dgvoice) package for an example of
-additional voice helper functions and features for DiscordGo
+additional voice helper functions and features for DiscordGo.
* See [dca](https://github.com/bwmarrin/dca) for an **experimental** stand alone
tool that wraps `ffmpeg` to create opus encoded audio appropriate for use with
-Discord (and DiscordGo)
+Discord (and DiscordGo).
**For help with this package or general Go discussion, please join the [Discord
Gophers](https://discord.gg/0f1SbxBZjYq9jLBk) chat server.**
@@ -39,9 +39,9 @@ the breaking changes get documented before pushing to master.
*So, what should you use?*
-If you can accept the constant changing nature of *develop* then it is the
+If you can accept the constant changing nature of *develop*, it is the
recommended branch to use. Otherwise, if you want to tail behind development
-slightly and have a more stable package with documented releases then use *master*
+slightly and have a more stable package with documented releases, use *master*.
### Installing
@@ -96,10 +96,10 @@ that information in a nice format.
## Examples
Below is a list of examples and other projects using DiscordGo. Please submit
-an issue if you would like your project added or removed from this list
+an issue if you would like your project added or removed from this list.
-- [DiscordGo Examples](https://github.com/bwmarrin/discordgo/tree/master/examples) A collection of example programs written with DiscordGo
-- [Awesome DiscordGo](https://github.com/bwmarrin/discordgo/wiki/Awesome-DiscordGo) A curated list of high quality projects using DiscordGo
+- [DiscordGo Examples](https://github.com/bwmarrin/discordgo/tree/master/examples) - A collection of example programs written with DiscordGo
+- [Awesome DiscordGo](https://github.com/bwmarrin/discordgo/wiki/Awesome-DiscordGo) - A curated list of high quality projects using DiscordGo
## Troubleshooting
For help with common problems please reference the
@@ -114,7 +114,7 @@ Contributions are very welcomed, however please follow the below guidelines.
discussed.
- Fork the develop branch and make your changes.
- Try to match current naming conventions as closely as possible.
-- This package is intended to be a low level direct mapping of the Discord API
+- This package is intended to be a low level direct mapping of the Discord API,
so please avoid adding enhancements outside of that scope without first
discussing it.
- Create a Pull Request with your changes against the develop branch.
@@ -127,4 +127,4 @@ comparison and list of other Discord API libraries.
## Special Thanks
-[Chris Rhodes](https://github.com/iopred) - For the DiscordGo logo and tons of PRs
+[Chris Rhodes](https://github.com/iopred) - For the DiscordGo logo and tons of PRs.
diff --git a/vendor/github.com/matterbridge/discordgo/discord.go b/vendor/github.com/bwmarrin/discordgo/discord.go
index 99fda30b..cdac67fe 100644
--- a/vendor/github.com/matterbridge/discordgo/discord.go
+++ b/vendor/github.com/bwmarrin/discordgo/discord.go
@@ -6,8 +6,8 @@
// license that can be found in the LICENSE file.
// This file contains high level helper functions and easy entry points for the
-// entire discordgo package. These functions are beling developed and are very
-// experimental at this point. They will most likley change so please use the
+// entire discordgo package. These functions are being developed and are very
+// experimental at this point. They will most likely change so please use the
// low level functions if that's a problem.
// Package discordgo provides Discord binding for Go
@@ -21,7 +21,7 @@ import (
)
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
-const VERSION = "0.18.0"
+const VERSION = "0.19.0"
// ErrMFA will be risen by New when the user has 2FA.
var ErrMFA = errors.New("account has 2FA enabled")
diff --git a/vendor/github.com/matterbridge/discordgo/endpoints.go b/vendor/github.com/bwmarrin/discordgo/endpoints.go
index 335e224d..b9619089 100644
--- a/vendor/github.com/matterbridge/discordgo/endpoints.go
+++ b/vendor/github.com/bwmarrin/discordgo/endpoints.go
@@ -11,6 +11,8 @@
package discordgo
+import "strconv"
+
// APIVersion is the Discord API version used for the REST and Websocket API.
var APIVersion = "6"
@@ -61,14 +63,18 @@ var (
EndpointUser = func(uID string) string { return EndpointUsers + uID }
EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" }
- EndpointUserSettings = func(uID string) string { return EndpointUsers + uID + "/settings" }
- EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
- EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
- EndpointUserGuildSettings = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID + "/settings" }
- EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
- EndpointUserDevices = func(uID string) string { return EndpointUsers + uID + "/devices" }
- EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
- EndpointUserNotes = func(uID string) string { return EndpointUsers + "@me/notes/" + uID }
+ EndpointDefaultUserAvatar = func(uDiscriminator string) string {
+ uDiscriminatorInt, _ := strconv.Atoi(uDiscriminator)
+ return EndpointCDN + "embed/avatars/" + strconv.Itoa(uDiscriminatorInt%5) + ".png"
+ }
+ EndpointUserSettings = func(uID string) string { return EndpointUsers + uID + "/settings" }
+ EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
+ EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
+ EndpointUserGuildSettings = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID + "/settings" }
+ EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
+ EndpointUserDevices = func(uID string) string { return EndpointUsers + uID + "/devices" }
+ EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
+ EndpointUserNotes = func(uID string) string { return EndpointUsers + "@me/notes/" + uID }
EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
EndpointGuildChannels = func(gID string) string { return EndpointGuilds + gID + "/channels" }
@@ -88,6 +94,9 @@ var (
EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" }
EndpointGuildSplash = func(gID, hash string) string { return EndpointCDNSplashes + gID + "/" + hash + ".png" }
EndpointGuildWebhooks = func(gID string) string { return EndpointGuilds + gID + "/webhooks" }
+ EndpointGuildAuditLogs = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" }
+ EndpointGuildEmojis = func(gID string) string { return EndpointGuilds + gID + "/emojis" }
+ EndpointGuildEmoji = func(gID, eID string) string { return EndpointGuilds + gID + "/emojis/" + eID }
EndpointChannel = func(cID string) string { return EndpointChannels + cID }
EndpointChannelPermissions = func(cID string) string { return EndpointChannels + cID + "/permissions" }
@@ -127,7 +136,8 @@ var (
EndpointIntegrationsJoin = func(iID string) string { return EndpointAPI + "integrations/" + iID + "/join" }
- EndpointEmoji = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".png" }
+ EndpointEmoji = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".png" }
+ EndpointEmojiAnimated = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".gif" }
EndpointOauth2 = EndpointAPI + "oauth2/"
EndpointApplications = EndpointOauth2 + "applications"
diff --git a/vendor/github.com/matterbridge/discordgo/event.go b/vendor/github.com/bwmarrin/discordgo/event.go
index bba396cb..97cc00a2 100644
--- a/vendor/github.com/matterbridge/discordgo/event.go
+++ b/vendor/github.com/bwmarrin/discordgo/event.go
@@ -98,7 +98,9 @@ func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() {
// AddHandler allows you to add an event handler that will be fired anytime
// the Discord WSAPI event that matches the function fires.
-// events.go contains all the Discord WSAPI events that can be fired.
+// The first parameter is a *Session, and the second parameter is a pointer
+// to a struct corresponding to the event for which you want to listen.
+//
// eg:
// Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
// })
@@ -106,6 +108,13 @@ func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() {
// or:
// Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
// })
+//
+// 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
+// There are also synthetic events fired by the library internally which are
+// available for handling, like Connect, Disconnect, and RateLimit.
+// events.go contains all of the Discord WSAPI and synthetic events that can be handled.
+//
// The return value of this method is a function, that when called will remove the
// event handler.
func (s *Session) AddHandler(handler interface{}) func() {
diff --git a/vendor/github.com/matterbridge/discordgo/eventhandlers.go b/vendor/github.com/bwmarrin/discordgo/eventhandlers.go
index 5cc157de..d2b9a98b 100644
--- a/vendor/github.com/matterbridge/discordgo/eventhandlers.go
+++ b/vendor/github.com/bwmarrin/discordgo/eventhandlers.go
@@ -50,6 +50,7 @@ const (
userUpdateEventType = "USER_UPDATE"
voiceServerUpdateEventType = "VOICE_SERVER_UPDATE"
voiceStateUpdateEventType = "VOICE_STATE_UPDATE"
+ webhooksUpdateEventType = "WEBHOOKS_UPDATE"
)
// channelCreateEventHandler is an event handler for ChannelCreate events.
@@ -892,6 +893,26 @@ func (eh voiceStateUpdateEventHandler) Handle(s *Session, i interface{}) {
}
}
+// webhooksUpdateEventHandler is an event handler for WebhooksUpdate events.
+type webhooksUpdateEventHandler func(*Session, *WebhooksUpdate)
+
+// Type returns the event type for WebhooksUpdate events.
+func (eh webhooksUpdateEventHandler) Type() string {
+ return webhooksUpdateEventType
+}
+
+// New returns a new instance of WebhooksUpdate.
+func (eh webhooksUpdateEventHandler) New() interface{} {
+ return &WebhooksUpdate{}
+}
+
+// Handle is the handler for WebhooksUpdate events.
+func (eh webhooksUpdateEventHandler) Handle(s *Session, i interface{}) {
+ if t, ok := i.(*WebhooksUpdate); ok {
+ eh(s, t)
+ }
+}
+
func handlerForInterface(handler interface{}) EventHandler {
switch v := handler.(type) {
case func(*Session, interface{}):
@@ -982,6 +1003,8 @@ func handlerForInterface(handler interface{}) EventHandler {
return voiceServerUpdateEventHandler(v)
case func(*Session, *VoiceStateUpdate):
return voiceStateUpdateEventHandler(v)
+ case func(*Session, *WebhooksUpdate):
+ return webhooksUpdateEventHandler(v)
}
return nil
@@ -1027,4 +1050,5 @@ func init() {
registerInterfaceProvider(userUpdateEventHandler(nil))
registerInterfaceProvider(voiceServerUpdateEventHandler(nil))
registerInterfaceProvider(voiceStateUpdateEventHandler(nil))
+ registerInterfaceProvider(webhooksUpdateEventHandler(nil))
}
diff --git a/vendor/github.com/matterbridge/discordgo/events.go b/vendor/github.com/bwmarrin/discordgo/events.go
index c78fbdd2..c4fb5205 100644
--- a/vendor/github.com/matterbridge/discordgo/events.go
+++ b/vendor/github.com/bwmarrin/discordgo/events.go
@@ -70,6 +70,7 @@ type ChannelDelete struct {
type ChannelPinsUpdate struct {
LastPinTimestamp string `json:"last_pin_timestamp"`
ChannelID string `json:"channel_id"`
+ GuildID string `json:"guild_id,omitempty"`
}
// GuildCreate is the data for a GuildCreate event.
@@ -212,6 +213,7 @@ type RelationshipRemove struct {
type TypingStart struct {
UserID string `json:"user_id"`
ChannelID string `json:"channel_id"`
+ GuildID string `json:"guild_id,omitempty"`
Timestamp int `json:"timestamp"`
}
@@ -250,4 +252,11 @@ type VoiceStateUpdate struct {
type MessageDeleteBulk struct {
Messages []string `json:"ids"`
ChannelID string `json:"channel_id"`
+ GuildID string `json:"guild_id"`
+}
+
+// WebhooksUpdate is the data for a WebhooksUpdate event
+type WebhooksUpdate struct {
+ GuildID string `json:"guild_id"`
+ ChannelID string `json:"channel_id"`
}
diff --git a/vendor/github.com/bwmarrin/discordgo/go.mod b/vendor/github.com/bwmarrin/discordgo/go.mod
new file mode 100644
index 00000000..2ff88680
--- /dev/null
+++ b/vendor/github.com/bwmarrin/discordgo/go.mod
@@ -0,0 +1,6 @@
+module github.com/bwmarrin/discordgo
+
+require (
+ github.com/gorilla/websocket v1.4.0
+ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16
+)
diff --git a/vendor/github.com/bwmarrin/discordgo/go.sum b/vendor/github.com/bwmarrin/discordgo/go.sum
new file mode 100644
index 00000000..a86b0501
--- /dev/null
+++ b/vendor/github.com/bwmarrin/discordgo/go.sum
@@ -0,0 +1,4 @@
+github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
+golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
diff --git a/vendor/github.com/matterbridge/discordgo/logging.go b/vendor/github.com/bwmarrin/discordgo/logging.go
index 6460b35b..6460b35b 100644
--- a/vendor/github.com/matterbridge/discordgo/logging.go
+++ b/vendor/github.com/bwmarrin/discordgo/logging.go
diff --git a/vendor/github.com/matterbridge/discordgo/message.go b/vendor/github.com/bwmarrin/discordgo/message.go
index 4fd468fd..2b609920 100644
--- a/vendor/github.com/matterbridge/discordgo/message.go
+++ b/vendor/github.com/bwmarrin/discordgo/message.go
@@ -32,20 +32,59 @@ const (
// A Message stores all data related to a specific Discord message.
type Message struct {
- ID string `json:"id"`
- ChannelID string `json:"channel_id"`
- Content string `json:"content"`
- Timestamp Timestamp `json:"timestamp"`
- EditedTimestamp Timestamp `json:"edited_timestamp"`
- MentionRoles []string `json:"mention_roles"`
- Tts bool `json:"tts"`
- MentionEveryone bool `json:"mention_everyone"`
- Author *User `json:"author"`
- Attachments []*MessageAttachment `json:"attachments"`
- Embeds []*MessageEmbed `json:"embeds"`
- Mentions []*User `json:"mentions"`
- Reactions []*MessageReactions `json:"reactions"`
- Type MessageType `json:"type"`
+ // The ID of the message.
+ ID string `json:"id"`
+
+ // The ID of the channel in which the message was sent.
+ ChannelID string `json:"channel_id"`
+
+ // The ID of the guild in which the message was sent.
+ GuildID string `json:"guild_id,omitempty"`
+
+ // The content of the message.
+ Content string `json:"content"`
+
+ // The time at which the messsage was sent.
+ // CAUTION: this field may be removed in a
+ // future API version; it is safer to calculate
+ // the creation time via the ID.
+ Timestamp Timestamp `json:"timestamp"`
+
+ // The time at which the last edit of the message
+ // occurred, if it has been edited.
+ EditedTimestamp Timestamp `json:"edited_timestamp"`
+
+ // The roles mentioned in the message.
+ MentionRoles []string `json:"mention_roles"`
+
+ // Whether the message is text-to-speech.
+ Tts bool `json:"tts"`
+
+ // Whether the message mentions everyone.
+ MentionEveryone bool `json:"mention_everyone"`
+
+ // The author of the message. This is not guaranteed to be a
+ // valid user (webhook-sent messages do not possess a full author).
+ Author *User `json:"author"`
+
+ // A list of attachments present in the message.
+ Attachments []*MessageAttachment `json:"attachments"`
+
+ // A list of embeds present in the message. Multiple
+ // embeds can currently only be sent by webhooks.
+ Embeds []*MessageEmbed `json:"embeds"`
+
+ // A list of users mentioned in the message.
+ Mentions []*User `json:"mentions"`
+
+ // A list of reactions to the message.
+ Reactions []*MessageReactions `json:"reactions"`
+
+ // The type of the message.
+ Type MessageType `json:"type"`
+
+ // The webhook ID of the message, if it was generated by a webhook
+ WebhookID string `json:"webhook_id"`
}
// File stores info about files you e.g. send in messages.
diff --git a/vendor/github.com/matterbridge/discordgo/mkdocs.yml b/vendor/github.com/bwmarrin/discordgo/mkdocs.yml
index 3ee8eb37..3ee8eb37 100644
--- a/vendor/github.com/matterbridge/discordgo/mkdocs.yml
+++ b/vendor/github.com/bwmarrin/discordgo/mkdocs.yml
diff --git a/vendor/github.com/matterbridge/discordgo/oauth2.go b/vendor/github.com/bwmarrin/discordgo/oauth2.go
index 108b32fe..108b32fe 100644
--- a/vendor/github.com/matterbridge/discordgo/oauth2.go
+++ b/vendor/github.com/bwmarrin/discordgo/oauth2.go
diff --git a/vendor/github.com/matterbridge/discordgo/ratelimit.go b/vendor/github.com/bwmarrin/discordgo/ratelimit.go
index dc48c924..dc48c924 100644
--- a/vendor/github.com/matterbridge/discordgo/ratelimit.go
+++ b/vendor/github.com/bwmarrin/discordgo/ratelimit.go
diff --git a/vendor/github.com/matterbridge/discordgo/restapi.go b/vendor/github.com/bwmarrin/discordgo/restapi.go
index 5dc0467f..84a2a31e 100644
--- a/vendor/github.com/matterbridge/discordgo/restapi.go
+++ b/vendor/github.com/bwmarrin/discordgo/restapi.go
@@ -38,6 +38,7 @@ var (
ErrPruneDaysBounds = errors.New("the number of days should be more than or equal to 1")
ErrGuildNoIcon = errors.New("guild does not have an icon set")
ErrGuildNoSplash = errors.New("guild does not have a splash set")
+ ErrUnauthorized = errors.New("HTTP request was unauthorized. This could be because the provided token was not a bot token. Please add \"Bot \" to the start of your token. https://discordapp.com/developers/docs/reference#authentication-example-bot-token-authorization-header")
)
// Request is the same as RequestWithBucketID but the bucket id is the same as the urlStr
@@ -89,7 +90,7 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
req.Header.Set("Content-Type", contentType)
// TODO: Make a configurable static variable.
- req.Header.Set("User-Agent", fmt.Sprintf("DiscordBot (https://github.com/bwmarrin/discordgo, v%s)", VERSION))
+ req.Header.Set("User-Agent", "DiscordBot (https://github.com/bwmarrin/discordgo, v"+VERSION+")")
if s.Debug {
for k, v := range req.Header {
@@ -129,13 +130,9 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
}
switch resp.StatusCode {
-
case http.StatusOK:
case http.StatusCreated:
case http.StatusNoContent:
-
- // TODO check for 401 response, invalidate token if we get one.
-
case http.StatusBadGateway:
// Retry sending request if possible
if sequence < s.MaxRestRetries {
@@ -145,7 +142,6 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
} else {
err = fmt.Errorf("Exceeded Max retries HTTP %s, %s", resp.Status, response)
}
-
case 429: // TOO MANY REQUESTS - Rate limiting
rl := TooManyRequests{}
err = json.Unmarshal(response, &rl)
@@ -161,7 +157,12 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
// this method can cause longer delays than required
response, err = s.RequestWithLockedBucket(method, urlStr, contentType, b, s.Ratelimiter.LockBucketObject(bucket), sequence)
-
+ case http.StatusUnauthorized:
+ if strings.Index(s.Token, "Bot ") != 0 {
+ s.log(LogInformational, ErrUnauthorized.Error())
+ err = ErrUnauthorized
+ }
+ fallthrough
default: // Error condition
err = newRestError(req, resp, response)
}
@@ -249,7 +250,7 @@ func (s *Session) Register(username string) (token string, err error) {
// even use.
func (s *Session) Logout() (err error) {
- // _, err = s.Request("POST", LOGOUT, fmt.Sprintf(`{"token": "%s"}`, s.Token))
+ // _, err = s.Request("POST", LOGOUT, `{"token": "` + s.Token + `"}`)
if s.Token == "" {
return
@@ -361,6 +362,21 @@ func (s *Session) UserUpdateStatus(status Status) (st *Settings, err error) {
return
}
+// UserConnections returns the user's connections
+func (s *Session) UserConnections() (conn []*UserConnection, err error) {
+ response, err := s.RequestWithBucketID("GET", EndpointUserConnections("@me"), nil, EndpointUserConnections("@me"))
+ if err != nil {
+ return nil, err
+ }
+
+ err = unmarshal(response, &conn)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
// UserChannels returns an array of Channel structures for all private
// channels.
func (s *Session) UserChannels() (st []*Channel, err error) {
@@ -412,7 +428,7 @@ func (s *Session) UserGuilds(limit int, beforeID, afterID string) (st []*UserGui
uri := EndpointUserGuilds("@me")
if len(v) > 0 {
- uri = fmt.Sprintf("%s?%s", uri, v.Encode())
+ uri += "?" + v.Encode()
}
body, err := s.RequestWithBucketID("GET", uri, nil, EndpointUserGuilds(""))
@@ -565,7 +581,7 @@ 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 {
+ if err == nil && !st.Unavailable {
return
}
}
@@ -735,7 +751,7 @@ func (s *Session) GuildMembers(guildID string, after string, limit int) (st []*M
}
if len(v) > 0 {
- uri = fmt.Sprintf("%s?%s", uri, v.Encode())
+ uri += "?" + v.Encode()
}
body, err := s.RequestWithBucketID("GET", uri, nil, EndpointGuildMembers(guildID))
@@ -761,6 +777,32 @@ func (s *Session) GuildMember(guildID, userID string) (st *Member, err error) {
return
}
+// GuildMemberAdd force joins a user to the guild.
+// accessToken : Valid access_token for the user.
+// guildID : The ID of a Guild.
+// userID : The ID of a User.
+// nick : Value to set users nickname to
+// roles : A list of role ID's to set on the member.
+// mute : If the user is muted.
+// deaf : If the user is deafened.
+func (s *Session) GuildMemberAdd(accessToken, guildID, userID, nick string, roles []string, mute, deaf bool) (err error) {
+
+ data := struct {
+ AccessToken string `json:"access_token"`
+ Nick string `json:"nick,omitempty"`
+ Roles []string `json:"roles,omitempty"`
+ Mute bool `json:"mute,omitempty"`
+ Deaf bool `json:"deaf,omitempty"`
+ }{accessToken, nick, roles, mute, deaf}
+
+ _, err = s.RequestWithBucketID("PUT", EndpointGuildMember(guildID, userID), data, EndpointGuildMember(guildID, ""))
+ if err != nil {
+ return err
+ }
+
+ return err
+}
+
// GuildMemberDelete removes the given user from the given guild.
// guildID : The ID of a Guild.
// userID : The ID of a User
@@ -877,17 +919,22 @@ func (s *Session) GuildChannels(guildID string) (st []*Channel, err error) {
return
}
-// GuildChannelCreate creates a new channel in the given guild
-// guildID : The ID of a Guild.
-// name : Name of the channel (2-100 chars length)
-// ctype : Tpye of the channel (voice or text)
-func (s *Session) GuildChannelCreate(guildID, name, ctype string) (st *Channel, err error) {
-
- data := struct {
- Name string `json:"name"`
- Type string `json:"type"`
- }{name, ctype}
+// GuildChannelCreateData is provided to GuildChannelCreateComplex
+type GuildChannelCreateData struct {
+ Name string `json:"name"`
+ Type ChannelType `json:"type"`
+ Topic string `json:"topic,omitempty"`
+ Bitrate int `json:"bitrate,omitempty"`
+ UserLimit int `json:"user_limit,omitempty"`
+ PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"`
+ ParentID string `json:"parent_id,omitempty"`
+ NSFW bool `json:"nsfw,omitempty"`
+}
+// GuildChannelCreateComplex creates a new channel in the given guild
+// guildID : The ID of a Guild
+// data : A data struct describing the new Channel, Name and Type are mandatory, other fields depending on the type
+func (s *Session) GuildChannelCreateComplex(guildID string, data GuildChannelCreateData) (st *Channel, err error) {
body, err := s.RequestWithBucketID("POST", EndpointGuildChannels(guildID), data, EndpointGuildChannels(guildID))
if err != nil {
return
@@ -897,12 +944,33 @@ func (s *Session) GuildChannelCreate(guildID, name, ctype string) (st *Channel,
return
}
+// GuildChannelCreate creates a new channel in the given guild
+// guildID : The ID of a Guild.
+// name : Name of the channel (2-100 chars length)
+// ctype : Type of the channel
+func (s *Session) GuildChannelCreate(guildID, name string, ctype ChannelType) (st *Channel, err error) {
+ return s.GuildChannelCreateComplex(guildID, GuildChannelCreateData{
+ Name: name,
+ Type: ctype,
+ })
+}
+
// GuildChannelsReorder updates the order of channels in a guild
// guildID : The ID of a Guild.
// channels : Updated channels.
func (s *Session) GuildChannelsReorder(guildID string, channels []*Channel) (err error) {
- _, err = s.RequestWithBucketID("PATCH", EndpointGuildChannels(guildID), channels, EndpointGuildChannels(guildID))
+ data := make([]struct {
+ ID string `json:"id"`
+ Position int `json:"position"`
+ }, len(channels))
+
+ for i, c := range channels {
+ data[i].ID = c.ID
+ data[i].Position = c.Position
+ }
+
+ _, err = s.RequestWithBucketID("PATCH", EndpointGuildChannels(guildID), data, EndpointGuildChannels(guildID))
return
}
@@ -1021,7 +1089,7 @@ func (s *Session) GuildPruneCount(guildID string, days uint32) (count uint32, er
Pruned uint32 `json:"pruned"`
}{}
- uri := EndpointGuildPrune(guildID) + fmt.Sprintf("?days=%d", days)
+ uri := EndpointGuildPrune(guildID) + "?days=" + strconv.FormatUint(uint64(days), 10)
body, err := s.RequestWithBucketID("GET", uri, nil, EndpointGuildPrune(guildID))
if err != nil {
return
@@ -1075,7 +1143,7 @@ func (s *Session) GuildPrune(guildID string, days uint32) (count uint32, err err
// GuildIntegrations returns an array of Integrations for a guild.
// guildID : The ID of a Guild.
-func (s *Session) GuildIntegrations(guildID string) (st []*GuildIntegration, err error) {
+func (s *Session) GuildIntegrations(guildID string) (st []*Integration, err error) {
body, err := s.RequestWithBucketID("GET", EndpointGuildIntegrations(guildID), nil, EndpointGuildIntegrations(guildID))
if err != nil {
@@ -1206,6 +1274,94 @@ func (s *Session) GuildEmbedEdit(guildID string, enabled bool, channelID string)
return
}
+// GuildAuditLog returns the audit log for a Guild.
+// guildID : The ID of a Guild.
+// userID : If provided the log will be filtered for the given ID.
+// beforeID : If provided all log entries returned will be before the given ID.
+// actionType : If provided the log will be filtered for the given Action Type.
+// limit : The number messages that can be returned. (default 50, min 1, max 100)
+func (s *Session) GuildAuditLog(guildID, userID, beforeID string, actionType, limit int) (st *GuildAuditLog, err error) {
+
+ uri := EndpointGuildAuditLogs(guildID)
+
+ v := url.Values{}
+ if userID != "" {
+ v.Set("user_id", userID)
+ }
+ if beforeID != "" {
+ v.Set("before", beforeID)
+ }
+ if actionType > 0 {
+ v.Set("action_type", strconv.Itoa(actionType))
+ }
+ if limit > 0 {
+ v.Set("limit", strconv.Itoa(limit))
+ }
+ if len(v) > 0 {
+ uri = fmt.Sprintf("%s?%s", uri, v.Encode())
+ }
+
+ body, err := s.RequestWithBucketID("GET", uri, nil, EndpointGuildAuditLogs(guildID))
+ if err != nil {
+ return
+ }
+
+ err = unmarshal(body, &st)
+ return
+}
+
+// GuildEmojiCreate creates a new emoji
+// guildID : The ID of a Guild.
+// name : The Name of the Emoji.
+// image : The base64 encoded emoji image, has to be smaller than 256KB.
+// roles : The roles for which this emoji will be whitelisted, can be nil.
+func (s *Session) GuildEmojiCreate(guildID, name, image string, roles []string) (emoji *Emoji, err error) {
+
+ data := struct {
+ Name string `json:"name"`
+ Image string `json:"image"`
+ Roles []string `json:"roles,omitempty"`
+ }{name, image, roles}
+
+ body, err := s.RequestWithBucketID("POST", EndpointGuildEmojis(guildID), data, EndpointGuildEmojis(guildID))
+ if err != nil {
+ return
+ }
+
+ err = unmarshal(body, &emoji)
+ return
+}
+
+// GuildEmojiEdit modifies an emoji
+// guildID : The ID of a Guild.
+// emojiID : The ID of an Emoji.
+// name : The Name of the Emoji.
+// roles : The roles for which this emoji will be whitelisted, can be nil.
+func (s *Session) GuildEmojiEdit(guildID, emojiID, name string, roles []string) (emoji *Emoji, err error) {
+
+ data := struct {
+ Name string `json:"name"`
+ Roles []string `json:"roles,omitempty"`
+ }{name, roles}
+
+ body, err := s.RequestWithBucketID("PATCH", EndpointGuildEmoji(guildID, emojiID), data, EndpointGuildEmojis(guildID))
+ if err != nil {
+ return
+ }
+
+ err = unmarshal(body, &emoji)
+ return
+}
+
+// GuildEmojiDelete deletes an Emoji.
+// guildID : The ID of a Guild.
+// emojiID : The ID of an Emoji.
+func (s *Session) GuildEmojiDelete(guildID, emojiID string) (err error) {
+
+ _, err = s.RequestWithBucketID("DELETE", EndpointGuildEmoji(guildID, emojiID), nil, EndpointGuildEmojis(guildID))
+ return
+}
+
// ------------------------------------------------------------------------------------------------
// Functions specific to Discord Channels
// ------------------------------------------------------------------------------------------------
@@ -1291,7 +1447,7 @@ func (s *Session) ChannelMessages(channelID string, limit int, beforeID, afterID
v.Set("around", aroundID)
}
if len(v) > 0 {
- uri = fmt.Sprintf("%s?%s", uri, v.Encode())
+ uri += "?" + v.Encode()
}
body, err := s.RequestWithBucketID("GET", uri, nil, EndpointChannelMessages(channelID))
@@ -1586,7 +1742,8 @@ func (s *Session) ChannelInviteCreate(channelID string, i Invite) (st *Invite, e
MaxAge int `json:"max_age"`
MaxUses int `json:"max_uses"`
Temporary bool `json:"temporary"`
- }{i.MaxAge, i.MaxUses, i.Temporary}
+ Unique bool `json:"unique"`
+ }{i.MaxAge, i.MaxUses, i.Temporary, i.Unique}
body, err := s.RequestWithBucketID("POST", EndpointChannelInvites(channelID), data, EndpointChannelInvites(channelID))
if err != nil {
@@ -1638,6 +1795,19 @@ func (s *Session) Invite(inviteID string) (st *Invite, err error) {
return
}
+// InviteWithCounts returns an Invite structure of the given invite including approximate member counts
+// inviteID : The invite code
+func (s *Session) InviteWithCounts(inviteID string) (st *Invite, err error) {
+
+ body, err := s.RequestWithBucketID("GET", EndpointInvite(inviteID)+"?with_counts=true", nil, EndpointInvite(""))
+ if err != nil {
+ return
+ }
+
+ err = unmarshal(body, &st)
+ return
+}
+
// InviteDelete deletes an existing invite
// inviteID : the code of an invite
func (s *Session) InviteDelete(inviteID string) (st *Invite, err error) {
@@ -1830,12 +2000,13 @@ func (s *Session) WebhookWithToken(webhookID, token string) (st *Webhook, err er
// webhookID: The ID of a webhook.
// name : The name of the webhook.
// avatar : The avatar of the webhook.
-func (s *Session) WebhookEdit(webhookID, name, avatar string) (st *Role, err error) {
+func (s *Session) WebhookEdit(webhookID, name, avatar, channelID string) (st *Role, err error) {
data := struct {
- Name string `json:"name,omitempty"`
- Avatar string `json:"avatar,omitempty"`
- }{name, avatar}
+ Name string `json:"name,omitempty"`
+ Avatar string `json:"avatar,omitempty"`
+ ChannelID string `json:"channel_id,omitempty"`
+ }{name, avatar, channelID}
body, err := s.RequestWithBucketID("PATCH", EndpointWebhook(webhookID), data, EndpointWebhooks)
if err != nil {
@@ -1956,7 +2127,7 @@ func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit i
}
if len(v) > 0 {
- uri = fmt.Sprintf("%s?%s", uri, v.Encode())
+ uri += "?" + v.Encode()
}
body, err := s.RequestWithBucketID("GET", uri, nil, EndpointMessageReaction(channelID, "", "", ""))
diff --git a/vendor/github.com/matterbridge/discordgo/state.go b/vendor/github.com/bwmarrin/discordgo/state.go
index 8158708b..e6f08c73 100644
--- a/vendor/github.com/matterbridge/discordgo/state.go
+++ b/vendor/github.com/bwmarrin/discordgo/state.go
@@ -32,6 +32,7 @@ type State struct {
sync.RWMutex
Ready
+ // MaxMessageCount represents how many messages per channel the state will store.
MaxMessageCount int
TrackChannels bool
TrackEmojis bool
@@ -98,6 +99,9 @@ func (s *State) GuildAdd(guild *Guild) error {
if g, ok := s.guildMap[guild.ID]; ok {
// We are about to replace `g` in the state with `guild`, but first we need to
// make sure we preserve any fields that the `guild` doesn't contain from `g`.
+ if guild.MemberCount == 0 {
+ guild.MemberCount = g.MemberCount
+ }
if guild.Roles == nil {
guild.Roles = g.Roles
}
@@ -299,7 +303,12 @@ func (s *State) MemberAdd(member *Member) error {
members[member.User.ID] = member
guild.Members = append(guild.Members, member)
} else {
- *m = *member // Update the actual data, which will also update the member pointer in the slice
+ // We are about to replace `m` in the state with `member`, but first we need to
+ // make sure we preserve any fields that the `member` doesn't contain from `m`.
+ if member.JoinedAt == "" {
+ member.JoinedAt = m.JoinedAt
+ }
+ *m = *member
}
return nil
@@ -607,7 +616,7 @@ func (s *State) EmojisAdd(guildID string, emojis []*Emoji) error {
// MessageAdd adds a message to the current world state, or updates it if it exists.
// If the channel cannot be found, the message is discarded.
-// Messages are kept in state up to s.MaxMessageCount
+// Messages are kept in state up to s.MaxMessageCount per channel.
func (s *State) MessageAdd(message *Message) error {
if s == nil {
return ErrNilState
@@ -805,6 +814,14 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
case *GuildDelete:
err = s.GuildRemove(t.Guild)
case *GuildMemberAdd:
+ // Updates the MemberCount of the guild.
+ guild, err := s.Guild(t.Member.GuildID)
+ if err != nil {
+ return err
+ }
+ guild.MemberCount++
+
+ // Caches member if tracking is enabled.
if s.TrackMembers {
err = s.MemberAdd(t.Member)
}
@@ -813,6 +830,14 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
err = s.MemberAdd(t.Member)
}
case *GuildMemberRemove:
+ // Updates the MemberCount of the guild.
+ guild, err := s.Guild(t.Member.GuildID)
+ if err != nil {
+ return err
+ }
+ guild.MemberCount--
+
+ // Removes member from the cache if tracking is enabled.
if s.TrackMembers {
err = s.MemberRemove(t.Member)
}
diff --git a/vendor/github.com/matterbridge/discordgo/structs.go b/vendor/github.com/bwmarrin/discordgo/structs.go
index 19d2bad7..4465ec52 100644
--- a/vendor/github.com/matterbridge/discordgo/structs.go
+++ b/vendor/github.com/bwmarrin/discordgo/structs.go
@@ -13,6 +13,7 @@ package discordgo
import (
"encoding/json"
+ "fmt"
"net/http"
"sync"
"time"
@@ -84,6 +85,9 @@ type Session struct {
// Stores the last HeartbeatAck that was recieved (in UTC)
LastHeartbeatAck time.Time
+ // Stores the last Heartbeat sent (in UTC)
+ LastHeartbeatSent time.Time
+
// used to deal with rate limits
Ratelimiter *RateLimiter
@@ -111,6 +115,37 @@ type Session struct {
wsMutex sync.Mutex
}
+// UserConnection is a Connection returned from the UserConnections endpoint
+type UserConnection struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ Revoked bool `json:"revoked"`
+ Integrations []*Integration `json:"integrations"`
+}
+
+// Integration stores integration information
+type Integration struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ Enabled bool `json:"enabled"`
+ Syncing bool `json:"syncing"`
+ RoleID string `json:"role_id"`
+ ExpireBehavior int `json:"expire_behavior"`
+ ExpireGracePeriod int `json:"expire_grace_period"`
+ User *User `json:"user"`
+ Account IntegrationAccount `json:"account"`
+ SyncedAt Timestamp `json:"synced_at"`
+}
+
+// IntegrationAccount is integration account information
+// sent by the UserConnections endpoint
+type IntegrationAccount struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+}
+
// A VoiceRegion stores data for a specific voice region server.
type VoiceRegion struct {
ID string `json:"id"`
@@ -145,6 +180,10 @@ type Invite struct {
Revoked bool `json:"revoked"`
Temporary bool `json:"temporary"`
Unique bool `json:"unique"`
+
+ // will only be filled when using InviteWithCounts
+ ApproximatePresenceCount int `json:"approximate_presence_count"`
+ ApproximateMemberCount int `json:"approximate_member_count"`
}
// ChannelType is the type of a Channel
@@ -161,22 +200,61 @@ const (
// A Channel holds all data related to an individual Discord channel.
type Channel struct {
- ID string `json:"id"`
- GuildID string `json:"guild_id"`
- Name string `json:"name"`
- Topic string `json:"topic"`
- Type ChannelType `json:"type"`
- LastMessageID string `json:"last_message_id"`
- NSFW bool `json:"nsfw"`
- Position int `json:"position"`
- Bitrate int `json:"bitrate"`
- Recipients []*User `json:"recipients"`
- Messages []*Message `json:"-"`
+ // The ID of the channel.
+ ID string `json:"id"`
+
+ // The ID of the guild to which the channel belongs, if it is in a guild.
+ // Else, this ID is empty (e.g. DM channels).
+ GuildID string `json:"guild_id"`
+
+ // The name of the channel.
+ Name string `json:"name"`
+
+ // The topic of the channel.
+ Topic string `json:"topic"`
+
+ // The type of the channel.
+ Type ChannelType `json:"type"`
+
+ // The ID of the last message sent in the channel. This is not
+ // guaranteed to be an ID of a valid message.
+ LastMessageID string `json:"last_message_id"`
+
+ // Whether the channel is marked as NSFW.
+ NSFW bool `json:"nsfw"`
+
+ // Icon of the group DM channel.
+ Icon string `json:"icon"`
+
+ // The position of the channel, used for sorting in client.
+ Position int `json:"position"`
+
+ // The bitrate of the channel, if it is a voice channel.
+ Bitrate int `json:"bitrate"`
+
+ // The recipients of the channel. This is only populated in DM channels.
+ Recipients []*User `json:"recipients"`
+
+ // The messages in the channel. This is only present in state-cached channels,
+ // and State.MaxMessageCount must be non-zero.
+ Messages []*Message `json:"-"`
+
+ // A list of permission overwrites present for the channel.
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites"`
- ParentID string `json:"parent_id"`
+
+ // The user limit of the voice channel.
+ UserLimit int `json:"user_limit"`
+
+ // The ID of the parent channel, if the channel is under a category
+ ParentID string `json:"parent_id"`
+}
+
+// Mention returns a string which mentions the channel
+func (c *Channel) Mention() string {
+ return fmt.Sprintf("<#%s>", c.ID)
}
-// A ChannelEdit holds Channel Feild data for a channel edit.
+// A ChannelEdit holds Channel Field data for a channel edit.
type ChannelEdit struct {
Name string `json:"name,omitempty"`
Topic string `json:"topic,omitempty"`
@@ -186,6 +264,7 @@ type ChannelEdit struct {
UserLimit int `json:"user_limit,omitempty"`
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"`
ParentID string `json:"parent_id,omitempty"`
+ RateLimitPerUser int `json:"rate_limit_per_user,omitempty"`
}
// A PermissionOverwrite holds permission overwrite data for a Channel
@@ -206,6 +285,19 @@ type Emoji struct {
Animated bool `json:"animated"`
}
+// MessageFormat returns a correctly formatted Emoji for use in Message content and embeds
+func (e *Emoji) MessageFormat() string {
+ if e.ID != "" && e.Name != "" {
+ if e.Animated {
+ return "<a:" + e.APIName() + ">"
+ }
+
+ return "<:" + e.APIName() + ">"
+ }
+
+ return e.APIName()
+}
+
// APIName returns an correctly formatted API name for use in the MessageReactions endpoints.
func (e *Emoji) APIName() string {
if e.ID != "" && e.Name != "" {
@@ -228,31 +320,129 @@ const (
VerificationLevelHigh
)
+// ExplicitContentFilterLevel type definition
+type ExplicitContentFilterLevel int
+
+// Constants for ExplicitContentFilterLevel levels from 0 to 2 inclusive
+const (
+ ExplicitContentFilterDisabled ExplicitContentFilterLevel = iota
+ ExplicitContentFilterMembersWithoutRoles
+ ExplicitContentFilterAllMembers
+)
+
+// MfaLevel type definition
+type MfaLevel int
+
+// Constants for MfaLevel levels from 0 to 1 inclusive
+const (
+ MfaLevelNone MfaLevel = iota
+ MfaLevelElevated
+)
+
// A Guild holds all data related to a specific Discord Guild. Guilds are also
// sometimes referred to as Servers in the Discord client.
type Guild struct {
- ID string `json:"id"`
- Name string `json:"name"`
- Icon string `json:"icon"`
- Region string `json:"region"`
- AfkChannelID string `json:"afk_channel_id"`
- EmbedChannelID string `json:"embed_channel_id"`
- OwnerID string `json:"owner_id"`
- JoinedAt Timestamp `json:"joined_at"`
- Splash string `json:"splash"`
- AfkTimeout int `json:"afk_timeout"`
- MemberCount int `json:"member_count"`
- VerificationLevel VerificationLevel `json:"verification_level"`
- EmbedEnabled bool `json:"embed_enabled"`
- Large bool `json:"large"` // ??
- DefaultMessageNotifications int `json:"default_message_notifications"`
- Roles []*Role `json:"roles"`
- Emojis []*Emoji `json:"emojis"`
- Members []*Member `json:"members"`
- Presences []*Presence `json:"presences"`
- Channels []*Channel `json:"channels"`
- VoiceStates []*VoiceState `json:"voice_states"`
- Unavailable bool `json:"unavailable"`
+ // The ID of the guild.
+ ID string `json:"id"`
+
+ // The name of the guild. (2–100 characters)
+ Name string `json:"name"`
+
+ // The hash of the guild's icon. Use Session.GuildIcon
+ // to retrieve the icon itself.
+ Icon string `json:"icon"`
+
+ // The voice region of the guild.
+ Region string `json:"region"`
+
+ // The ID of the AFK voice channel.
+ AfkChannelID string `json:"afk_channel_id"`
+
+ // The ID of the embed channel ID, used for embed widgets.
+ EmbedChannelID string `json:"embed_channel_id"`
+
+ // The user ID of the owner of the guild.
+ OwnerID string `json:"owner_id"`
+
+ // The time at which the current user joined the guild.
+ // This field is only present in GUILD_CREATE events and websocket
+ // update events, and thus is only present in state-cached guilds.
+ JoinedAt Timestamp `json:"joined_at"`
+
+ // The hash of the guild's splash.
+ Splash string `json:"splash"`
+
+ // The timeout, in seconds, before a user is considered AFK in voice.
+ AfkTimeout int `json:"afk_timeout"`
+
+ // The number of members in the guild.
+ // This field is only present in GUILD_CREATE events and websocket
+ // update events, and thus is only present in state-cached guilds.
+ MemberCount int `json:"member_count"`
+
+ // The verification level required for the guild.
+ VerificationLevel VerificationLevel `json:"verification_level"`
+
+ // Whether the guild has embedding enabled.
+ EmbedEnabled bool `json:"embed_enabled"`
+
+ // Whether the guild is considered large. This is
+ // determined by a member threshold in the identify packet,
+ // and is currently hard-coded at 250 members in the library.
+ Large bool `json:"large"`
+
+ // The default message notification setting for the guild.
+ // 0 == all messages, 1 == mentions only.
+ DefaultMessageNotifications int `json:"default_message_notifications"`
+
+ // A list of roles in the guild.
+ Roles []*Role `json:"roles"`
+
+ // A list of the custom emojis present in the guild.
+ Emojis []*Emoji `json:"emojis"`
+
+ // A list of the members in the guild.
+ // This field is only present in GUILD_CREATE events and websocket
+ // update events, and thus is only present in state-cached guilds.
+ Members []*Member `json:"members"`
+
+ // A list of partial presence objects for members in the guild.
+ // This field is only present in GUILD_CREATE events and websocket
+ // update events, and thus is only present in state-cached guilds.
+ Presences []*Presence `json:"presences"`
+
+ // A list of channels in the guild.
+ // This field is only present in GUILD_CREATE events and websocket
+ // update events, and thus is only present in state-cached guilds.
+ Channels []*Channel `json:"channels"`
+
+ // A list of voice states for the guild.
+ // This field is only present in GUILD_CREATE events and websocket
+ // update events, and thus is only present in state-cached guilds.
+ VoiceStates []*VoiceState `json:"voice_states"`
+
+ // Whether this guild is currently unavailable (most likely due to outage).
+ // This field is only present in GUILD_CREATE events and websocket
+ // update events, and thus is only present in state-cached guilds.
+ Unavailable bool `json:"unavailable"`
+
+ // The explicit content filter level
+ ExplicitContentFilter ExplicitContentFilterLevel `json:"explicit_content_filter"`
+
+ // The list of enabled guild features
+ Features []string `json:"features"`
+
+ // Required MFA level for the guild
+ MfaLevel MfaLevel `json:"mfa_level"`
+
+ // Whether or not the Server Widget is enabled
+ WidgetEnabled bool `json:"widget_enabled"`
+
+ // The Channel ID for the Server Widget
+ WidgetChannelID string `json:"widget_channel_id"`
+
+ // The Channel ID to which system messages are sent (eg join and leave messages)
+ SystemChannelID string `json:"system_channel_id"`
}
// A UserGuild holds a brief version of a Guild
@@ -279,14 +469,37 @@ type GuildParams struct {
// A Role stores information about Discord guild member roles.
type Role struct {
- ID string `json:"id"`
- Name string `json:"name"`
- Managed bool `json:"managed"`
- Mentionable bool `json:"mentionable"`
- Hoist bool `json:"hoist"`
- Color int `json:"color"`
- Position int `json:"position"`
- Permissions int `json:"permissions"`
+ // The ID of the role.
+ ID string `json:"id"`
+
+ // The name of the role.
+ Name string `json:"name"`
+
+ // Whether this role is managed by an integration, and
+ // thus cannot be manually added to, or taken from, members.
+ Managed bool `json:"managed"`
+
+ // Whether this role is mentionable.
+ Mentionable bool `json:"mentionable"`
+
+ // Whether this role is hoisted (shows up separately in member list).
+ Hoist bool `json:"hoist"`
+
+ // The hex color of this role.
+ Color int `json:"color"`
+
+ // The position of this role in the guild's role hierarchy.
+ Position int `json:"position"`
+
+ // The permissions of the role on the guild (doesn't include channel overrides).
+ // This is a combination of bit masks; the presence of a certain permission can
+ // be checked by performing a bitwise AND between this int and the permission.
+ Permissions int `json:"permissions"`
+}
+
+// Mention returns a string which mentions the role
+func (r *Role) Mention() string {
+ return fmt.Sprintf("<@&%s>", r.ID)
}
// Roles are a collection of Role
@@ -334,6 +547,8 @@ type GameType int
const (
GameTypeGame GameType = iota
GameTypeStreaming
+ GameTypeListening
+ GameTypeWatching
)
// A Game struct holds the name of the "playing .." game for a user
@@ -379,15 +594,34 @@ type Assets struct {
SmallText string `json:"small_text,omitempty"`
}
-// A Member stores user information for Guild members.
+// A Member stores user information for Guild members. A guild
+// member represents a certain user's presence in a guild.
type Member struct {
- GuildID string `json:"guild_id"`
- JoinedAt string `json:"joined_at"`
- Nick string `json:"nick"`
- Deaf bool `json:"deaf"`
- Mute bool `json:"mute"`
- User *User `json:"user"`
- Roles []string `json:"roles"`
+ // The guild ID on which the member exists.
+ GuildID string `json:"guild_id"`
+
+ // The time at which the member joined the guild, in ISO8601.
+ JoinedAt Timestamp `json:"joined_at"`
+
+ // The nickname of the member, if they have one.
+ Nick string `json:"nick"`
+
+ // Whether the member is deafened at a guild level.
+ Deaf bool `json:"deaf"`
+
+ // Whether the member is muted at a guild level.
+ Mute bool `json:"mute"`
+
+ // The underlying user on which the member is based.
+ User *User `json:"user"`
+
+ // A list of IDs of the roles which are possessed by the member.
+ Roles []string `json:"roles"`
+}
+
+// Mention creates a member mention
+func (m *Member) Mention() string {
+ return "<@!" + m.User.ID + ">"
}
// A Settings stores data for a specific users Discord client settings.
@@ -467,33 +701,88 @@ type GuildBan struct {
User *User `json:"user"`
}
-// A GuildIntegration stores data for a guild integration.
-type GuildIntegration struct {
- ID string `json:"id"`
- Name string `json:"name"`
- Type string `json:"type"`
- Enabled bool `json:"enabled"`
- Syncing bool `json:"syncing"`
- RoleID string `json:"role_id"`
- ExpireBehavior int `json:"expire_behavior"`
- ExpireGracePeriod int `json:"expire_grace_period"`
- User *User `json:"user"`
- Account *GuildIntegrationAccount `json:"account"`
- SyncedAt int `json:"synced_at"`
-}
-
-// A GuildIntegrationAccount stores data for a guild integration account.
-type GuildIntegrationAccount struct {
- ID string `json:"id"`
- Name string `json:"name"`
-}
-
// A GuildEmbed stores data for a guild embed.
type GuildEmbed struct {
Enabled bool `json:"enabled"`
ChannelID string `json:"channel_id"`
}
+// A GuildAuditLog stores data for a guild audit log.
+type GuildAuditLog struct {
+ Webhooks []struct {
+ ChannelID string `json:"channel_id"`
+ GuildID string `json:"guild_id"`
+ ID string `json:"id"`
+ Avatar string `json:"avatar"`
+ Name string `json:"name"`
+ } `json:"webhooks,omitempty"`
+ Users []struct {
+ Username string `json:"username"`
+ Discriminator string `json:"discriminator"`
+ Bot bool `json:"bot"`
+ ID string `json:"id"`
+ Avatar string `json:"avatar"`
+ } `json:"users,omitempty"`
+ AuditLogEntries []struct {
+ TargetID string `json:"target_id"`
+ Changes []struct {
+ NewValue interface{} `json:"new_value"`
+ OldValue interface{} `json:"old_value"`
+ Key string `json:"key"`
+ } `json:"changes,omitempty"`
+ UserID string `json:"user_id"`
+ ID string `json:"id"`
+ ActionType int `json:"action_type"`
+ Options struct {
+ DeleteMembersDay string `json:"delete_member_days"`
+ MembersRemoved string `json:"members_removed"`
+ ChannelID string `json:"channel_id"`
+ Count string `json:"count"`
+ ID string `json:"id"`
+ Type string `json:"type"`
+ RoleName string `json:"role_name"`
+ } `json:"options,omitempty"`
+ Reason string `json:"reason"`
+ } `json:"audit_log_entries"`
+}
+
+// Block contains Discord Audit Log Action Types
+const (
+ AuditLogActionGuildUpdate = 1
+
+ AuditLogActionChannelCreate = 10
+ AuditLogActionChannelUpdate = 11
+ AuditLogActionChannelDelete = 12
+ AuditLogActionChannelOverwriteCreate = 13
+ AuditLogActionChannelOverwriteUpdate = 14
+ AuditLogActionChannelOverwriteDelete = 15
+
+ AuditLogActionMemberKick = 20
+ AuditLogActionMemberPrune = 21
+ AuditLogActionMemberBanAdd = 22
+ AuditLogActionMemberBanRemove = 23
+ AuditLogActionMemberUpdate = 24
+ AuditLogActionMemberRoleUpdate = 25
+
+ AuditLogActionRoleCreate = 30
+ AuditLogActionRoleUpdate = 31
+ AuditLogActionRoleDelete = 32
+
+ AuditLogActionInviteCreate = 40
+ AuditLogActionInviteUpdate = 41
+ AuditLogActionInviteDelete = 42
+
+ AuditLogActionWebhookCreate = 50
+ AuditLogActionWebhookUpdate = 51
+ AuditLogActionWebhookDelete = 52
+
+ AuditLogActionEmojiCreate = 60
+ AuditLogActionEmojiUpdate = 61
+ AuditLogActionEmojiDelete = 62
+
+ AuditLogActionMessageDelete = 72
+)
+
// A UserGuildSettingsChannelOverride stores data for a channel override for a users guild settings.
type UserGuildSettingsChannelOverride struct {
Muted bool `json:"muted"`
@@ -553,6 +842,7 @@ type MessageReaction struct {
MessageID string `json:"message_id"`
Emoji Emoji `json:"emoji"`
ChannelID string `json:"channel_id"`
+ GuildID string `json:"guild_id,omitempty"`
}
// GatewayBotResponse stores the data for the gateway/bot response
@@ -629,7 +919,9 @@ const (
PermissionKickMembers |
PermissionBanMembers |
PermissionManageServer |
- PermissionAdministrator
+ PermissionAdministrator |
+ PermissionManageWebhooks |
+ PermissionManageEmojis
)
// Block contains Discord JSON Error Response codes
@@ -648,6 +940,7 @@ const (
ErrCodeUnknownToken = 10012
ErrCodeUnknownUser = 10013
ErrCodeUnknownEmoji = 10014
+ ErrCodeUnknownWebhook = 10015
ErrCodeBotsCannotUseEndpoint = 20001
ErrCodeOnlyBotsCanUseEndpoint = 20002
diff --git a/vendor/github.com/matterbridge/discordgo/types.go b/vendor/github.com/bwmarrin/discordgo/types.go
index 780b6bb9..c0ce0131 100644
--- a/vendor/github.com/matterbridge/discordgo/types.go
+++ b/vendor/github.com/bwmarrin/discordgo/types.go
@@ -11,7 +11,6 @@ package discordgo
import (
"encoding/json"
- "fmt"
"net/http"
"time"
)
@@ -54,5 +53,5 @@ func newRestError(req *http.Request, resp *http.Response, body []byte) *RESTErro
}
func (r RESTError) Error() string {
- return fmt.Sprintf("HTTP %s, %s", r.Response.Status, r.ResponseBody)
+ return "HTTP " + r.Response.Status + ", " + string(r.ResponseBody)
}
diff --git a/vendor/github.com/bwmarrin/discordgo/user.go b/vendor/github.com/bwmarrin/discordgo/user.go
new file mode 100644
index 00000000..a9af31a9
--- /dev/null
+++ b/vendor/github.com/bwmarrin/discordgo/user.go
@@ -0,0 +1,69 @@
+package discordgo
+
+import "strings"
+
+// A User stores all data for an individual Discord user.
+type User struct {
+ // The ID of the user.
+ ID string `json:"id"`
+
+ // The email of the user. This is only present when
+ // the application possesses the email scope for the user.
+ Email string `json:"email"`
+
+ // The user's username.
+ Username string `json:"username"`
+
+ // The hash of the user's avatar. Use Session.UserAvatar
+ // to retrieve the avatar itself.
+ Avatar string `json:"avatar"`
+
+ // The user's chosen language option.
+ Locale string `json:"locale"`
+
+ // The discriminator of the user (4 numbers after name).
+ Discriminator string `json:"discriminator"`
+
+ // The token of the user. This is only present for
+ // the user represented by the current session.
+ Token string `json:"token"`
+
+ // Whether the user's email is verified.
+ Verified bool `json:"verified"`
+
+ // Whether the user has multi-factor authentication enabled.
+ MFAEnabled bool `json:"mfa_enabled"`
+
+ // Whether the user is a bot.
+ Bot bool `json:"bot"`
+}
+
+// String returns a unique identifier of the form username#discriminator
+func (u *User) String() string {
+ return u.Username + "#" + u.Discriminator
+}
+
+// Mention return a string which mentions the user
+func (u *User) Mention() string {
+ return "<@" + u.ID + ">"
+}
+
+// AvatarURL returns a URL to the user's avatar.
+// size: The size of the user's avatar as a power of two
+// if size is an empty string, no size parameter will
+// be added to the URL.
+func (u *User) AvatarURL(size string) string {
+ var URL string
+ if u.Avatar == "" {
+ URL = EndpointDefaultUserAvatar(u.Discriminator)
+ } else if strings.HasPrefix(u.Avatar, "a_") {
+ URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
+ } else {
+ URL = EndpointUserAvatar(u.ID, u.Avatar)
+ }
+
+ if size != "" {
+ return URL + "?size=" + size
+ }
+ return URL
+}
diff --git a/vendor/github.com/matterbridge/discordgo/voice.go b/vendor/github.com/bwmarrin/discordgo/voice.go
index 3bbf6212..aa630b12 100644
--- a/vendor/github.com/matterbridge/discordgo/voice.go
+++ b/vendor/github.com/bwmarrin/discordgo/voice.go
@@ -14,6 +14,7 @@ import (
"encoding/json"
"fmt"
"net"
+ "strconv"
"strings"
"sync"
"time"
@@ -103,7 +104,7 @@ func (v *VoiceConnection) Speaking(b bool) (err error) {
defer v.Unlock()
if err != nil {
v.speaking = false
- v.log(LogError, "Speaking() write json error:", err)
+ v.log(LogError, "Speaking() write json error, %s", err)
return
}
@@ -135,7 +136,6 @@ func (v *VoiceConnection) ChangeChannel(channelID string, mute, deaf bool) (err
// Disconnect disconnects from this voice channel and closes the websocket
// and udp connections to Discord.
-// !!! NOTE !!! this function may be removed in favour of ChannelVoiceLeave
func (v *VoiceConnection) Disconnect() (err error) {
// Send a OP4 with a nil channel to disconnect
@@ -180,7 +180,7 @@ func (v *VoiceConnection) Close() {
v.log(LogInformational, "closing udp")
err := v.udpConn.Close()
if err != nil {
- v.log(LogError, "error closing udp connection: ", err)
+ v.log(LogError, "error closing udp connection, %s", err)
}
v.udpConn = nil
}
@@ -299,7 +299,7 @@ func (v *VoiceConnection) open() (err error) {
}
// Connect to VoiceConnection Websocket
- vg := fmt.Sprintf("wss://%s", strings.TrimSuffix(v.endpoint, ":80"))
+ vg := "wss://" + strings.TrimSuffix(v.endpoint, ":80")
v.log(LogInformational, "connecting to voice endpoint %s", vg)
v.wsConn, _, err = websocket.DefaultDialer.Dial(vg, nil)
if err != nil {
@@ -542,7 +542,7 @@ func (v *VoiceConnection) udpOpen() (err error) {
return fmt.Errorf("empty endpoint")
}
- host := fmt.Sprintf("%s:%d", strings.TrimSuffix(v.endpoint, ":80"), v.op2.Port)
+ host := strings.TrimSuffix(v.endpoint, ":80") + ":" + strconv.Itoa(v.op2.Port)
addr, err := net.ResolveUDPAddr("udp", host)
if err != nil {
v.log(LogWarning, "error resolving udp host %s, %s", host, err)
diff --git a/vendor/github.com/matterbridge/discordgo/wsapi.go b/vendor/github.com/bwmarrin/discordgo/wsapi.go
index de66f693..8ecaaa77 100644
--- a/vendor/github.com/matterbridge/discordgo/wsapi.go
+++ b/vendor/github.com/bwmarrin/discordgo/wsapi.go
@@ -86,6 +86,10 @@ func (s *Session) Open() error {
return err
}
+ s.wsConn.SetCloseHandler(func(code int, text string) error {
+ return nil
+ })
+
defer func() {
// because of this, all code below must set err to the error
// when exiting with an error :) Maybe someone has a better
@@ -263,6 +267,13 @@ type helloOp struct {
// FailedHeartbeatAcks is the Number of heartbeat intervals to wait until forcing a connection restart.
const FailedHeartbeatAcks time.Duration = 5 * time.Millisecond
+// HeartbeatLatency returns the latency between heartbeat acknowledgement and heartbeat send.
+func (s *Session) HeartbeatLatency() time.Duration {
+
+ return s.LastHeartbeatAck.Sub(s.LastHeartbeatSent)
+
+}
+
// heartbeat sends regular heartbeats to Discord so it knows the client
// is still connected. If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds.
@@ -283,8 +294,9 @@ func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}
last := s.LastHeartbeatAck
s.RUnlock()
sequence := atomic.LoadInt64(s.sequence)
- s.log(LogInformational, "sending gateway websocket heartbeat seq %d", sequence)
+ s.log(LogDebug, "sending gateway websocket heartbeat seq %d", sequence)
s.wsMutex.Lock()
+ s.LastHeartbeatSent = time.Now().UTC()
err = wsConn.WriteJSON(heartbeatOp{1, sequence})
s.wsMutex.Unlock()
if err != nil || time.Now().UTC().Sub(last) > (heartbeatIntervalMsec*FailedHeartbeatAcks) {
@@ -323,16 +335,8 @@ type updateStatusOp struct {
Data UpdateStatusData `json:"d"`
}
-// UpdateStreamingStatus is used to update the user's streaming status.
-// If idle>0 then set status to idle.
-// If game!="" then set game.
-// If game!="" and url!="" then set the status type to streaming with the URL set.
-// if otherwise, set status to active, and no game.
-func (s *Session) UpdateStreamingStatus(idle int, game string, url string) (err error) {
-
- s.log(LogInformational, "called")
-
- usd := UpdateStatusData{
+func newUpdateStatusData(idle int, gameType GameType, game, url string) *UpdateStatusData {
+ usd := &UpdateStatusData{
Status: "online",
}
@@ -341,10 +345,6 @@ func (s *Session) UpdateStreamingStatus(idle int, game string, url string) (err
}
if game != "" {
- gameType := GameTypeGame
- if url != "" {
- gameType = GameTypeStreaming
- }
usd.Game = &Game{
Name: game,
Type: gameType,
@@ -352,7 +352,35 @@ func (s *Session) UpdateStreamingStatus(idle int, game string, url string) (err
}
}
- return s.UpdateStatusComplex(usd)
+ return usd
+}
+
+// UpdateStatus is used to update the user's status.
+// If idle>0 then set status to idle.
+// If game!="" then set game.
+// if otherwise, set status to active, and no game.
+func (s *Session) UpdateStatus(idle int, game string) (err error) {
+ return s.UpdateStatusComplex(*newUpdateStatusData(idle, GameTypeGame, game, ""))
+}
+
+// UpdateStreamingStatus is used to update the user's streaming status.
+// If idle>0 then set status to idle.
+// If game!="" then set game.
+// If game!="" and url!="" then set the status type to streaming with the URL set.
+// if otherwise, set status to active, and no game.
+func (s *Session) UpdateStreamingStatus(idle int, game string, url string) (err error) {
+ gameType := GameTypeGame
+ if url != "" {
+ gameType = GameTypeStreaming
+ }
+ return s.UpdateStatusComplex(*newUpdateStatusData(idle, gameType, game, url))
+}
+
+// UpdateListeningStatus is used to set the user to "Listening to..."
+// If game!="" then set to what user is listening to
+// Else, set user to active and no game.
+func (s *Session) UpdateListeningStatus(game string) (err error) {
+ return s.UpdateStatusComplex(*newUpdateStatusData(0, GameTypeListening, game, ""))
}
// UpdateStatusComplex allows for sending the raw status update data untouched by discordgo.
@@ -371,14 +399,6 @@ func (s *Session) UpdateStatusComplex(usd UpdateStatusData) (err error) {
return
}
-// UpdateStatus is used to update the user's status.
-// If idle>0 then set status to idle.
-// If game!="" then set game.
-// if otherwise, set status to active, and no game.
-func (s *Session) UpdateStatus(idle int, game string) (err error) {
- return s.UpdateStreamingStatus(idle, game, "")
-}
-
type requestGuildMembersData struct {
GuildID string `json:"guild_id"`
Query string `json:"query"`
@@ -508,7 +528,7 @@ func (s *Session) onEvent(messageType int, message []byte) (*Event, error) {
s.Lock()
s.LastHeartbeatAck = time.Now().UTC()
s.Unlock()
- s.log(LogInformational, "got heartbeat ACK")
+ s.log(LogDebug, "got heartbeat ACK")
return e, nil
}
@@ -615,6 +635,30 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi
return
}
+// ChannelVoiceJoinManual initiates a voice session to a voice channel, but does not complete it.
+//
+// This should only be used when the VoiceServerUpdate will be intercepted and used elsewhere.
+//
+// gID : Guild ID of the channel to join.
+// cID : Channel ID of the channel to join.
+// mute : If true, you will be set to muted upon joining.
+// deaf : If true, you will be set to deafened upon joining.
+func (s *Session) ChannelVoiceJoinManual(gID, cID string, mute, deaf bool) (err error) {
+
+ s.log(LogInformational, "called")
+
+ // Send the request to Discord that we want to join the voice channel
+ data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
+ s.wsMutex.Lock()
+ err = s.wsConn.WriteJSON(data)
+ s.wsMutex.Unlock()
+ if err != nil {
+ return
+ }
+
+ return
+}
+
// onVoiceStateUpdate handles Voice State Update events on the data websocket.
func (s *Session) onVoiceStateUpdate(st *VoiceStateUpdate) {
@@ -732,11 +776,8 @@ func (s *Session) identify() error {
s.wsMutex.Lock()
err := s.wsConn.WriteJSON(op)
s.wsMutex.Unlock()
- if err != nil {
- return err
- }
- return nil
+ return err
}
func (s *Session) reconnect() {
diff --git a/vendor/github.com/gorilla/websocket/.gitignore b/vendor/github.com/gorilla/websocket/.gitignore
index ac710204..cd3fcd1e 100644
--- a/vendor/github.com/gorilla/websocket/.gitignore
+++ b/vendor/github.com/gorilla/websocket/.gitignore
@@ -22,4 +22,4 @@ _testmain.go
*.exe
.idea/
-*.iml \ No newline at end of file
+*.iml
diff --git a/vendor/github.com/gorilla/websocket/.travis.yml b/vendor/github.com/gorilla/websocket/.travis.yml
index 3d8d29cf..a49db51c 100644
--- a/vendor/github.com/gorilla/websocket/.travis.yml
+++ b/vendor/github.com/gorilla/websocket/.travis.yml
@@ -3,11 +3,11 @@ sudo: false
matrix:
include:
- - go: 1.4
- - go: 1.5
- - go: 1.6
- - go: 1.7
- - go: 1.8
+ - go: 1.7.x
+ - go: 1.8.x
+ - go: 1.9.x
+ - go: 1.10.x
+ - go: 1.11.x
- go: tip
allow_failures:
- go: tip
diff --git a/vendor/github.com/gorilla/websocket/AUTHORS b/vendor/github.com/gorilla/websocket/AUTHORS
index b003eca0..1931f400 100644
--- a/vendor/github.com/gorilla/websocket/AUTHORS
+++ b/vendor/github.com/gorilla/websocket/AUTHORS
@@ -4,5 +4,6 @@
# Please keep the list sorted.
Gary Burd <gary@beagledreams.com>
+Google LLC (https://opensource.google.com/)
Joachim Bauch <mail@joachim-bauch.de>
diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md
index 33c3d2be..20e391f8 100644
--- a/vendor/github.com/gorilla/websocket/README.md
+++ b/vendor/github.com/gorilla/websocket/README.md
@@ -51,7 +51,7 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn
<tr><td>Write message using io.WriteCloser</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextWriter">Yes</a></td><td>No, see note 3</td></tr>
</table>
-Notes:
+Notes:
1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html).
2. The application can get the type of a received data message by implementing
diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go
index 43a87c75..2e32fd50 100644
--- a/vendor/github.com/gorilla/websocket/client.go
+++ b/vendor/github.com/gorilla/websocket/client.go
@@ -5,15 +5,15 @@
package websocket
import (
- "bufio"
"bytes"
+ "context"
"crypto/tls"
- "encoding/base64"
"errors"
"io"
"io/ioutil"
"net"
"net/http"
+ "net/http/httptrace"
"net/url"
"strings"
"time"
@@ -53,6 +53,10 @@ type Dialer struct {
// NetDial is nil, net.Dial is used.
NetDial func(network, addr string) (net.Conn, error)
+ // NetDialContext specifies the dial function for creating TCP connections. If
+ // NetDialContext is nil, net.DialContext is used.
+ NetDialContext func(ctx context.Context, network, addr string) (net.Conn, error)
+
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
// request is aborted with the provided error.
@@ -71,6 +75,17 @@ type Dialer struct {
// do not limit the size of the messages that can be sent or received.
ReadBufferSize, WriteBufferSize int
+ // WriteBufferPool is a pool of buffers for write operations. If the value
+ // is not set, then write buffers are allocated to the connection for the
+ // lifetime of the connection.
+ //
+ // A pool is most useful when the application has a modest volume of writes
+ // across a large number of connections.
+ //
+ // Applications should use a single pool for each unique value of
+ // WriteBufferSize.
+ WriteBufferPool BufferPool
+
// Subprotocols specifies the client's requested subprotocols.
Subprotocols []string
@@ -86,52 +101,13 @@ type Dialer struct {
Jar http.CookieJar
}
-var errMalformedURL = errors.New("malformed ws or wss URL")
-
-// parseURL parses the URL.
-//
-// This function is a replacement for the standard library url.Parse function.
-// In Go 1.4 and earlier, url.Parse loses information from the path.
-func parseURL(s string) (*url.URL, error) {
- // From the RFC:
- //
- // ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
- // wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]
- var u url.URL
- switch {
- case strings.HasPrefix(s, "ws://"):
- u.Scheme = "ws"
- s = s[len("ws://"):]
- case strings.HasPrefix(s, "wss://"):
- u.Scheme = "wss"
- s = s[len("wss://"):]
- default:
- return nil, errMalformedURL
- }
-
- if i := strings.Index(s, "?"); i >= 0 {
- u.RawQuery = s[i+1:]
- s = s[:i]
- }
-
- if i := strings.Index(s, "/"); i >= 0 {
- u.Opaque = s[i:]
- s = s[:i]
- } else {
- u.Opaque = "/"
- }
-
- u.Host = s
-
- if strings.Contains(u.Host, "@") {
- // Don't bother parsing user information because user information is
- // not allowed in websocket URIs.
- return nil, errMalformedURL
- }
-
- return &u, nil
+// Dial creates a new client connection by calling DialContext with a background context.
+func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
+ return d.DialContext(context.Background(), urlStr, requestHeader)
}
+var errMalformedURL = errors.New("malformed ws or wss URL")
+
func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
hostPort = u.Host
hostNoPort = u.Host
@@ -150,26 +126,29 @@ func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
return hostPort, hostNoPort
}
-// DefaultDialer is a dialer with all fields set to the default zero values.
+// DefaultDialer is a dialer with all fields set to the default values.
var DefaultDialer = &Dialer{
- Proxy: http.ProxyFromEnvironment,
+ Proxy: http.ProxyFromEnvironment,
+ HandshakeTimeout: 45 * time.Second,
}
-// Dial creates a new client connection. Use requestHeader to specify the
+// nilDialer is dialer to use when receiver is nil.
+var nilDialer = *DefaultDialer
+
+// DialContext creates a new client connection. Use requestHeader to specify the
// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie).
// Use the response.Header to get the selected subprotocol
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
//
+// The context will be used in the request and in the Dialer
+//
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
// non-nil *http.Response so that callers can handle redirects, authentication,
// etcetera. The response body may not contain the entire response and does not
// need to be closed by the application.
-func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
-
+func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
if d == nil {
- d = &Dialer{
- Proxy: http.ProxyFromEnvironment,
- }
+ d = &nilDialer
}
challengeKey, err := generateChallengeKey()
@@ -177,7 +156,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
return nil, nil, err
}
- u, err := parseURL(urlStr)
+ u, err := url.Parse(urlStr)
if err != nil {
return nil, nil, err
}
@@ -205,6 +184,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
Header: make(http.Header),
Host: u.Host,
}
+ req = req.WithContext(ctx)
// Set the cookies present in the cookie jar of the dialer
if d.Jar != nil {
@@ -237,45 +217,83 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
k == "Sec-Websocket-Extensions" ||
(k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
+ case k == "Sec-Websocket-Protocol":
+ req.Header["Sec-WebSocket-Protocol"] = vs
default:
req.Header[k] = vs
}
}
if d.EnableCompression {
- req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover")
+ req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"}
}
- hostPort, hostNoPort := hostPortNoPort(u)
-
- var proxyURL *url.URL
- // Check wether the proxy method has been configured
- if d.Proxy != nil {
- proxyURL, err = d.Proxy(req)
- }
- if err != nil {
- return nil, nil, err
+ if d.HandshakeTimeout != 0 {
+ var cancel func()
+ ctx, cancel = context.WithTimeout(ctx, d.HandshakeTimeout)
+ defer cancel()
}
- var targetHostPort string
- if proxyURL != nil {
- targetHostPort, _ = hostPortNoPort(proxyURL)
+ // Get network dial function.
+ var netDial func(network, add string) (net.Conn, error)
+
+ if d.NetDialContext != nil {
+ netDial = func(network, addr string) (net.Conn, error) {
+ return d.NetDialContext(ctx, network, addr)
+ }
+ } else if d.NetDial != nil {
+ netDial = d.NetDial
} else {
- targetHostPort = hostPort
+ netDialer := &net.Dialer{}
+ netDial = func(network, addr string) (net.Conn, error) {
+ return netDialer.DialContext(ctx, network, addr)
+ }
}
- var deadline time.Time
- if d.HandshakeTimeout != 0 {
- deadline = time.Now().Add(d.HandshakeTimeout)
+ // If needed, wrap the dial function to set the connection deadline.
+ if deadline, ok := ctx.Deadline(); ok {
+ forwardDial := netDial
+ netDial = func(network, addr string) (net.Conn, error) {
+ c, err := forwardDial(network, addr)
+ if err != nil {
+ return nil, err
+ }
+ err = c.SetDeadline(deadline)
+ if err != nil {
+ c.Close()
+ return nil, err
+ }
+ return c, nil
+ }
}
- netDial := d.NetDial
- if netDial == nil {
- netDialer := &net.Dialer{Deadline: deadline}
- netDial = netDialer.Dial
+ // If needed, wrap the dial function to connect through a proxy.
+ if d.Proxy != nil {
+ proxyURL, err := d.Proxy(req)
+ if err != nil {
+ return nil, nil, err
+ }
+ if proxyURL != nil {
+ dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial))
+ if err != nil {
+ return nil, nil, err
+ }
+ netDial = dialer.Dial
+ }
+ }
+
+ hostPort, hostNoPort := hostPortNoPort(u)
+ trace := httptrace.ContextClientTrace(ctx)
+ if trace != nil && trace.GetConn != nil {
+ trace.GetConn(hostPort)
}
- netConn, err := netDial("tcp", targetHostPort)
+ netConn, err := netDial("tcp", hostPort)
+ if trace != nil && trace.GotConn != nil {
+ trace.GotConn(httptrace.GotConnInfo{
+ Conn: netConn,
+ })
+ }
if err != nil {
return nil, nil, err
}
@@ -286,42 +304,6 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
}
}()
- if err := netConn.SetDeadline(deadline); err != nil {
- return nil, nil, err
- }
-
- if proxyURL != nil {
- connectHeader := make(http.Header)
- if user := proxyURL.User; user != nil {
- proxyUser := user.Username()
- if proxyPassword, passwordSet := user.Password(); passwordSet {
- credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
- connectHeader.Set("Proxy-Authorization", "Basic "+credential)
- }
- }
- connectReq := &http.Request{
- Method: "CONNECT",
- URL: &url.URL{Opaque: hostPort},
- Host: hostPort,
- Header: connectHeader,
- }
-
- connectReq.Write(netConn)
-
- // Read response.
- // Okay to use and discard buffered reader here, because
- // TLS server will not speak until spoken to.
- br := bufio.NewReader(netConn)
- resp, err := http.ReadResponse(br, connectReq)
- if err != nil {
- return nil, nil, err
- }
- if resp.StatusCode != 200 {
- f := strings.SplitN(resp.Status, " ", 2)
- return nil, nil, errors.New(f[1])
- }
- }
-
if u.Scheme == "https" {
cfg := cloneTLSConfig(d.TLSClientConfig)
if cfg.ServerName == "" {
@@ -329,22 +311,31 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
}
tlsConn := tls.Client(netConn, cfg)
netConn = tlsConn
- if err := tlsConn.Handshake(); err != nil {
- return nil, nil, err
+
+ var err error
+ if trace != nil {
+ err = doHandshakeWithTrace(trace, tlsConn, cfg)
+ } else {
+ err = doHandshake(tlsConn, cfg)
}
- if !cfg.InsecureSkipVerify {
- if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
- return nil, nil, err
- }
+
+ if err != nil {
+ return nil, nil, err
}
}
- conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize)
+ conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize, d.WriteBufferPool, nil, nil)
if err := req.Write(netConn); err != nil {
return nil, nil, err
}
+ if trace != nil && trace.GotFirstResponseByte != nil {
+ if peek, err := conn.br.Peek(1); err == nil && len(peek) == 1 {
+ trace.GotFirstResponseByte()
+ }
+ }
+
resp, err := http.ReadResponse(conn.br, req)
if err != nil {
return nil, nil, err
@@ -390,3 +381,15 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
netConn = nil // to avoid close in defer.
return conn, resp, nil
}
+
+func doHandshake(tlsConn *tls.Conn, cfg *tls.Config) error {
+ if err := tlsConn.Handshake(); err != nil {
+ return err
+ }
+ if !cfg.InsecureSkipVerify {
+ if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go
index 97e1dbac..d2a21c14 100644
--- a/vendor/github.com/gorilla/websocket/conn.go
+++ b/vendor/github.com/gorilla/websocket/conn.go
@@ -76,7 +76,7 @@ const (
// is UTF-8 encoded text.
PingMessage = 9
- // PongMessage denotes a ping control message. The optional message payload
+ // PongMessage denotes a pong control message. The optional message payload
// is UTF-8 encoded text.
PongMessage = 10
)
@@ -100,9 +100,8 @@ func (e *netError) Error() string { return e.msg }
func (e *netError) Temporary() bool { return e.temporary }
func (e *netError) Timeout() bool { return e.timeout }
-// CloseError represents close frame.
+// CloseError represents a close message.
type CloseError struct {
-
// Code is defined in RFC 6455, section 11.7.
Code int
@@ -224,6 +223,20 @@ func isValidReceivedCloseCode(code int) bool {
return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999)
}
+// BufferPool represents a pool of buffers. The *sync.Pool type satisfies this
+// interface. The type of the value stored in a pool is not specified.
+type BufferPool interface {
+ // Get gets a value from the pool or returns nil if the pool is empty.
+ Get() interface{}
+ // Put adds a value to the pool.
+ Put(interface{})
+}
+
+// writePoolData is the type added to the write buffer pool. This wrapper is
+// used to prevent applications from peeking at and depending on the values
+// added to the pool.
+type writePoolData struct{ buf []byte }
+
// The Conn type represents a WebSocket connection.
type Conn struct {
conn net.Conn
@@ -233,6 +246,8 @@ type Conn struct {
// Write fields
mu chan bool // used as mutex to protect write to conn
writeBuf []byte // frame is constructed in this buffer.
+ writePool BufferPool
+ writeBufSize int
writeDeadline time.Time
writer io.WriteCloser // the current writer returned to the application
isWriting bool // for best-effort concurrent write detection
@@ -264,64 +279,29 @@ type Conn struct {
newDecompressionReader func(io.Reader) io.ReadCloser
}
-func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn {
- return newConnBRW(conn, isServer, readBufferSize, writeBufferSize, nil)
-}
-
-type writeHook struct {
- p []byte
-}
-
-func (wh *writeHook) Write(p []byte) (int, error) {
- wh.p = p
- return len(p), nil
-}
-
-func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, brw *bufio.ReadWriter) *Conn {
- mu := make(chan bool, 1)
- mu <- true
+func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, writeBufferPool BufferPool, br *bufio.Reader, writeBuf []byte) *Conn {
- var br *bufio.Reader
- if readBufferSize == 0 && brw != nil && brw.Reader != nil {
- // Reuse the supplied bufio.Reader if the buffer has a useful size.
- // This code assumes that peek on a reader returns
- // bufio.Reader.buf[:0].
- brw.Reader.Reset(conn)
- if p, err := brw.Reader.Peek(0); err == nil && cap(p) >= 256 {
- br = brw.Reader
- }
- }
if br == nil {
if readBufferSize == 0 {
readBufferSize = defaultReadBufferSize
- }
- if readBufferSize < maxControlFramePayloadSize {
+ } else if readBufferSize < maxControlFramePayloadSize {
+ // must be large enough for control frame
readBufferSize = maxControlFramePayloadSize
}
br = bufio.NewReaderSize(conn, readBufferSize)
}
- var writeBuf []byte
- if writeBufferSize == 0 && brw != nil && brw.Writer != nil {
- // Use the bufio.Writer's buffer if the buffer has a useful size. This
- // code assumes that bufio.Writer.buf[:1] is passed to the
- // bufio.Writer's underlying writer.
- var wh writeHook
- brw.Writer.Reset(&wh)
- brw.Writer.WriteByte(0)
- brw.Flush()
- if cap(wh.p) >= maxFrameHeaderSize+256 {
- writeBuf = wh.p[:cap(wh.p)]
- }
+ if writeBufferSize <= 0 {
+ writeBufferSize = defaultWriteBufferSize
}
+ writeBufferSize += maxFrameHeaderSize
- if writeBuf == nil {
- if writeBufferSize == 0 {
- writeBufferSize = defaultWriteBufferSize
- }
- writeBuf = make([]byte, writeBufferSize+maxFrameHeaderSize)
+ if writeBuf == nil && writeBufferPool == nil {
+ writeBuf = make([]byte, writeBufferSize)
}
+ mu := make(chan bool, 1)
+ mu <- true
c := &Conn{
isServer: isServer,
br: br,
@@ -329,6 +309,8 @@ func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize in
mu: mu,
readFinal: true,
writeBuf: writeBuf,
+ writePool: writeBufferPool,
+ writeBufSize: writeBufferSize,
enableWriteCompression: true,
compressionLevel: defaultCompressionLevel,
}
@@ -343,7 +325,8 @@ func (c *Conn) Subprotocol() string {
return c.subprotocol
}
-// Close closes the underlying network connection without sending or waiting for a close frame.
+// Close closes the underlying network connection without sending or waiting
+// for a close message.
func (c *Conn) Close() error {
return c.conn.Close()
}
@@ -370,7 +353,16 @@ func (c *Conn) writeFatal(err error) error {
return err
}
-func (c *Conn) write(frameType int, deadline time.Time, bufs ...[]byte) error {
+func (c *Conn) read(n int) ([]byte, error) {
+ p, err := c.br.Peek(n)
+ if err == io.EOF {
+ err = errUnexpectedEOF
+ }
+ c.br.Discard(len(p))
+ return p, err
+}
+
+func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error {
<-c.mu
defer func() { c.mu <- true }()
@@ -382,15 +374,14 @@ func (c *Conn) write(frameType int, deadline time.Time, bufs ...[]byte) error {
}
c.conn.SetWriteDeadline(deadline)
- for _, buf := range bufs {
- if len(buf) > 0 {
- _, err := c.conn.Write(buf)
- if err != nil {
- return c.writeFatal(err)
- }
- }
+ if len(buf1) == 0 {
+ _, err = c.conn.Write(buf0)
+ } else {
+ err = c.writeBufs(buf0, buf1)
+ }
+ if err != nil {
+ return c.writeFatal(err)
}
-
if frameType == CloseMessage {
c.writeFatal(ErrCloseSent)
}
@@ -476,7 +467,19 @@ func (c *Conn) prepWrite(messageType int) error {
c.writeErrMu.Lock()
err := c.writeErr
c.writeErrMu.Unlock()
- return err
+ if err != nil {
+ return err
+ }
+
+ if c.writeBuf == nil {
+ wpd, ok := c.writePool.Get().(writePoolData)
+ if ok {
+ c.writeBuf = wpd.buf
+ } else {
+ c.writeBuf = make([]byte, c.writeBufSize)
+ }
+ }
+ return nil
}
// NextWriter returns a writer for the next message to send. The writer's Close
@@ -484,6 +487,9 @@ func (c *Conn) prepWrite(messageType int) error {
//
// There can be at most one open writer on a connection. NextWriter closes the
// previous writer if the application has not already done so.
+//
+// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and
+// PongMessage) are supported.
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
if err := c.prepWrite(messageType); err != nil {
return nil, err
@@ -599,6 +605,10 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
if final {
c.writer = nil
+ if c.writePool != nil {
+ c.writePool.Put(writePoolData{buf: c.writeBuf})
+ c.writeBuf = nil
+ }
return nil
}
@@ -764,7 +774,6 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
// Read methods
func (c *Conn) advanceFrame() (int, error) {
-
// 1. Skip remainder of previous frame.
if c.readRemaining > 0 {
@@ -1033,7 +1042,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
}
// SetReadLimit sets the maximum size for a message read from the peer. If a
-// message exceeds the limit, the connection sends a close frame to the peer
+// message exceeds the limit, the connection sends a close message to the peer
// and returns ErrReadLimit to the application.
func (c *Conn) SetReadLimit(limit int64) {
c.readLimit = limit
@@ -1046,24 +1055,22 @@ func (c *Conn) CloseHandler() func(code int, text string) error {
// SetCloseHandler sets the handler for close messages received from the peer.
// The code argument to h is the received close code or CloseNoStatusReceived
-// if the close message is empty. The default close handler sends a close frame
-// back to the peer.
+// if the close message is empty. The default close handler sends a close
+// message back to the peer.
//
-// The application must read the connection to process close messages as
-// described in the section on Control Frames above.
+// The handler function is called from the NextReader, ReadMessage and message
+// reader Read methods. The application must read the connection to process
+// close messages as described in the section on Control Messages above.
//
-// The connection read methods return a CloseError when a close frame is
+// The connection read methods return a CloseError when a close message is
// received. Most applications should handle close messages as part of their
// normal error handling. Applications should only set a close handler when the
-// application must perform some action before sending a close frame back to
+// application must perform some action before sending a close message back to
// the peer.
func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
if h == nil {
h = func(code int, text string) error {
- message := []byte{}
- if code != CloseNoStatusReceived {
- message = FormatCloseMessage(code, "")
- }
+ message := FormatCloseMessage(code, "")
c.WriteControl(CloseMessage, message, time.Now().Add(writeWait))
return nil
}
@@ -1077,11 +1084,12 @@ func (c *Conn) PingHandler() func(appData string) error {
}
// SetPingHandler sets the handler for ping messages received from the peer.
-// The appData argument to h is the PING frame application data. The default
+// The appData argument to h is the PING message application data. The default
// ping handler sends a pong to the peer.
//
-// The application must read the connection to process ping messages as
-// described in the section on Control Frames above.
+// The handler function is called from the NextReader, ReadMessage and message
+// reader Read methods. The application must read the connection to process
+// ping messages as described in the section on Control Messages above.
func (c *Conn) SetPingHandler(h func(appData string) error) {
if h == nil {
h = func(message string) error {
@@ -1103,11 +1111,12 @@ func (c *Conn) PongHandler() func(appData string) error {
}
// SetPongHandler sets the handler for pong messages received from the peer.
-// The appData argument to h is the PONG frame application data. The default
+// The appData argument to h is the PONG message application data. The default
// pong handler does nothing.
//
-// The application must read the connection to process ping messages as
-// described in the section on Control Frames above.
+// The handler function is called from the NextReader, ReadMessage and message
+// reader Read methods. The application must read the connection to process
+// pong messages as described in the section on Control Messages above.
func (c *Conn) SetPongHandler(h func(appData string) error) {
if h == nil {
h = func(string) error { return nil }
@@ -1141,7 +1150,14 @@ func (c *Conn) SetCompressionLevel(level int) error {
}
// FormatCloseMessage formats closeCode and text as a WebSocket close message.
+// An empty message is returned for code CloseNoStatusReceived.
func FormatCloseMessage(closeCode int, text string) []byte {
+ if closeCode == CloseNoStatusReceived {
+ // Return empty message because it's illegal to send
+ // CloseNoStatusReceived. Return non-nil value in case application
+ // checks for nil.
+ return []byte{}
+ }
buf := make([]byte, 2+len(text))
binary.BigEndian.PutUint16(buf, uint16(closeCode))
copy(buf[2:], text)
diff --git a/vendor/github.com/gorilla/websocket/conn_read_legacy.go b/vendor/github.com/gorilla/websocket/conn_read_legacy.go
deleted file mode 100644
index 018541cf..00000000
--- a/vendor/github.com/gorilla/websocket/conn_read_legacy.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 The Gorilla WebSocket 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.5
-
-package websocket
-
-import "io"
-
-func (c *Conn) read(n int) ([]byte, error) {
- p, err := c.br.Peek(n)
- if err == io.EOF {
- err = errUnexpectedEOF
- }
- if len(p) > 0 {
- // advance over the bytes just read
- io.ReadFull(c.br, p)
- }
- return p, err
-}
diff --git a/vendor/github.com/gorilla/websocket/conn_read.go b/vendor/github.com/gorilla/websocket/conn_write.go
index 1ea15059..a509a21f 100644
--- a/vendor/github.com/gorilla/websocket/conn_read.go
+++ b/vendor/github.com/gorilla/websocket/conn_write.go
@@ -2,17 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build go1.5
+// +build go1.8
package websocket
-import "io"
+import "net"
-func (c *Conn) read(n int) ([]byte, error) {
- p, err := c.br.Peek(n)
- if err == io.EOF {
- err = errUnexpectedEOF
- }
- c.br.Discard(len(p))
- return p, err
+func (c *Conn) writeBufs(bufs ...[]byte) error {
+ b := net.Buffers(bufs)
+ _, err := b.WriteTo(c.conn)
+ return err
}
diff --git a/vendor/github.com/gorilla/websocket/conn_write_legacy.go b/vendor/github.com/gorilla/websocket/conn_write_legacy.go
new file mode 100644
index 00000000..37edaff5
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/conn_write_legacy.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Gorilla WebSocket 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 websocket
+
+func (c *Conn) writeBufs(bufs ...[]byte) error {
+ for _, buf := range bufs {
+ if len(buf) > 0 {
+ if _, err := c.conn.Write(buf); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go
index e291a952..dcce1a63 100644
--- a/vendor/github.com/gorilla/websocket/doc.go
+++ b/vendor/github.com/gorilla/websocket/doc.go
@@ -6,9 +6,8 @@
//
// Overview
//
-// The Conn type represents a WebSocket connection. A server application uses
-// the Upgrade function from an Upgrader object with a HTTP request handler
-// to get a pointer to a Conn:
+// The Conn type represents a WebSocket connection. A server application calls
+// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn:
//
// var upgrader = websocket.Upgrader{
// ReadBufferSize: 1024,
@@ -31,10 +30,12 @@
// for {
// messageType, p, err := conn.ReadMessage()
// if err != nil {
+// log.Println(err)
// return
// }
-// if err = conn.WriteMessage(messageType, p); err != nil {
-// return err
+// if err := conn.WriteMessage(messageType, p); err != nil {
+// log.Println(err)
+// return
// }
// }
//
@@ -85,20 +86,26 @@
// and pong. Call the connection WriteControl, WriteMessage or NextWriter
// methods to send a control message to the peer.
//
-// Connections handle received close messages by sending a close message to the
-// peer and returning a *CloseError from the the NextReader, ReadMessage or the
-// message Read method.
+// Connections handle received close messages by calling the handler function
+// set with the SetCloseHandler method and by returning a *CloseError from the
+// NextReader, ReadMessage or the message Read method. The default close
+// handler sends a close message to the peer.
//
-// Connections handle received ping and pong messages by invoking callback
-// functions set with SetPingHandler and SetPongHandler methods. The callback
-// functions are called from the NextReader, ReadMessage and the message Read
-// methods.
+// Connections handle received ping messages by calling the handler function
+// set with the SetPingHandler method. The default ping handler sends a pong
+// message to the peer.
//
-// The default ping handler sends a pong to the peer. The application's reading
-// goroutine can block for a short time while the handler writes the pong data
-// to the connection.
+// Connections handle received pong messages by calling the handler function
+// set with the SetPongHandler method. The default pong handler does nothing.
+// If an application sends ping messages, then the application should set a
+// pong handler to receive the corresponding pong.
//
-// The application must read the connection to process ping, pong and close
+// The control message handler functions are called from the NextReader,
+// ReadMessage and message reader Read methods. The default close and ping
+// handlers can block these methods for a short time when the handler writes to
+// the connection.
+//
+// The application must read the connection to process close, ping and pong
// messages sent from the peer. If the application is not otherwise interested
// in messages from the peer, then the application should start a goroutine to
// read and discard messages from the peer. A simple example is:
@@ -137,19 +144,12 @@
// method fails the WebSocket handshake with HTTP status 403.
//
// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
-// the handshake if the Origin request header is present and not equal to the
-// Host request header.
-//
-// An application can allow connections from any origin by specifying a
-// function that always returns true:
-//
-// var upgrader = websocket.Upgrader{
-// CheckOrigin: func(r *http.Request) bool { return true },
-// }
+// the handshake if the Origin request header is present and the Origin host is
+// not equal to the Host request header.
//
-// The deprecated Upgrade function does not enforce an origin policy. It's the
-// application's responsibility to check the Origin header before calling
-// Upgrade.
+// The deprecated package-level Upgrade function does not perform origin
+// checking. The application is responsible for checking the Origin header
+// before calling the Upgrade function.
//
// Compression EXPERIMENTAL
//
diff --git a/vendor/github.com/gorilla/websocket/json.go b/vendor/github.com/gorilla/websocket/json.go
index 4f0e3687..dc2c1f64 100644
--- a/vendor/github.com/gorilla/websocket/json.go
+++ b/vendor/github.com/gorilla/websocket/json.go
@@ -9,12 +9,14 @@ import (
"io"
)
-// WriteJSON is deprecated, use c.WriteJSON instead.
+// WriteJSON writes the JSON encoding of v as a message.
+//
+// Deprecated: Use c.WriteJSON instead.
func WriteJSON(c *Conn, v interface{}) error {
return c.WriteJSON(v)
}
-// WriteJSON writes the JSON encoding of v to the connection.
+// WriteJSON writes the JSON encoding of v as a message.
//
// See the documentation for encoding/json Marshal for details about the
// conversion of Go values to JSON.
@@ -31,7 +33,10 @@ func (c *Conn) WriteJSON(v interface{}) error {
return err2
}
-// ReadJSON is deprecated, use c.ReadJSON instead.
+// ReadJSON reads the next JSON-encoded message from the connection and stores
+// it in the value pointed to by v.
+//
+// Deprecated: Use c.ReadJSON instead.
func ReadJSON(c *Conn, v interface{}) error {
return c.ReadJSON(v)
}
diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go
index 6a88bbc7..577fce9e 100644
--- a/vendor/github.com/gorilla/websocket/mask.go
+++ b/vendor/github.com/gorilla/websocket/mask.go
@@ -11,7 +11,6 @@ import "unsafe"
const wordSize = int(unsafe.Sizeof(uintptr(0)))
func maskBytes(key [4]byte, pos int, b []byte) int {
-
// Mask one byte at a time for small buffers.
if len(b) < 2*wordSize {
for i := range b {
diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go
index 1efffbd1..74ec565d 100644
--- a/vendor/github.com/gorilla/websocket/prepared.go
+++ b/vendor/github.com/gorilla/websocket/prepared.go
@@ -19,7 +19,6 @@ import (
type PreparedMessage struct {
messageType int
data []byte
- err error
mu sync.Mutex
frames map[prepareKey]*preparedFrame
}
diff --git a/vendor/github.com/gorilla/websocket/proxy.go b/vendor/github.com/gorilla/websocket/proxy.go
new file mode 100644
index 00000000..bf2478e4
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/proxy.go
@@ -0,0 +1,77 @@
+// Copyright 2017 The Gorilla WebSocket 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 websocket
+
+import (
+ "bufio"
+ "encoding/base64"
+ "errors"
+ "net"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+type netDialerFunc func(network, addr string) (net.Conn, error)
+
+func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
+ return fn(network, addr)
+}
+
+func init() {
+ proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) {
+ return &httpProxyDialer{proxyURL: proxyURL, fowardDial: forwardDialer.Dial}, nil
+ })
+}
+
+type httpProxyDialer struct {
+ proxyURL *url.URL
+ fowardDial func(network, addr string) (net.Conn, error)
+}
+
+func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
+ hostPort, _ := hostPortNoPort(hpd.proxyURL)
+ conn, err := hpd.fowardDial(network, hostPort)
+ if err != nil {
+ return nil, err
+ }
+
+ connectHeader := make(http.Header)
+ if user := hpd.proxyURL.User; user != nil {
+ proxyUser := user.Username()
+ if proxyPassword, passwordSet := user.Password(); passwordSet {
+ credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
+ connectHeader.Set("Proxy-Authorization", "Basic "+credential)
+ }
+ }
+
+ connectReq := &http.Request{
+ Method: "CONNECT",
+ URL: &url.URL{Opaque: addr},
+ Host: addr,
+ Header: connectHeader,
+ }
+
+ if err := connectReq.Write(conn); err != nil {
+ conn.Close()
+ return nil, err
+ }
+
+ // Read response. It's OK to use and discard buffered reader here becaue
+ // the remote server does not speak until spoken to.
+ br := bufio.NewReader(conn)
+ resp, err := http.ReadResponse(br, connectReq)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+
+ if resp.StatusCode != 200 {
+ conn.Close()
+ f := strings.SplitN(resp.Status, " ", 2)
+ return nil, errors.New(f[1])
+ }
+ return conn, nil
+}
diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go
index 3495e0f1..a761824b 100644
--- a/vendor/github.com/gorilla/websocket/server.go
+++ b/vendor/github.com/gorilla/websocket/server.go
@@ -7,7 +7,7 @@ package websocket
import (
"bufio"
"errors"
- "net"
+ "io"
"net/http"
"net/url"
"strings"
@@ -33,10 +33,23 @@ type Upgrader struct {
// or received.
ReadBufferSize, WriteBufferSize int
+ // WriteBufferPool is a pool of buffers for write operations. If the value
+ // is not set, then write buffers are allocated to the connection for the
+ // lifetime of the connection.
+ //
+ // A pool is most useful when the application has a modest volume of writes
+ // across a large number of connections.
+ //
+ // Applications should use a single pool for each unique value of
+ // WriteBufferSize.
+ WriteBufferPool BufferPool
+
// Subprotocols specifies the server's supported protocols in order of
- // preference. If this field is set, then the Upgrade method negotiates a
+ // preference. If this field is not nil, then the Upgrade method negotiates a
// subprotocol by selecting the first match in this list with a protocol
- // requested by the client.
+ // requested by the client. If there's no match, then no protocol is
+ // negotiated (the Sec-Websocket-Protocol header is not included in the
+ // handshake response).
Subprotocols []string
// Error specifies the function for generating HTTP error responses. If Error
@@ -44,8 +57,12 @@ type Upgrader struct {
Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
// CheckOrigin returns true if the request Origin header is acceptable. If
- // CheckOrigin is nil, the host in the Origin header must not be set or
- // must match the host of the request.
+ // CheckOrigin is nil, then a safe default is used: return false if the
+ // Origin request header is present and the origin host is not equal to
+ // request Host header.
+ //
+ // A CheckOrigin function should carefully validate the request origin to
+ // prevent cross-site request forgery.
CheckOrigin func(r *http.Request) bool
// EnableCompression specify if the server should attempt to negotiate per
@@ -76,7 +93,7 @@ func checkSameOrigin(r *http.Request) bool {
if err != nil {
return false
}
- return u.Host == r.Host
+ return equalASCIIFold(u.Host, r.Host)
}
func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
@@ -99,42 +116,44 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header
//
// The responseHeader is included in the response to the client's upgrade
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
-// application negotiated subprotocol (Sec-Websocket-Protocol).
+// application negotiated subprotocol (Sec-WebSocket-Protocol).
//
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
// response.
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
- if r.Method != "GET" {
- return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: not a websocket handshake: request method is not GET")
- }
-
- if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
- return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-Websocket-Extensions' headers are unsupported")
- }
+ const badHandshake = "websocket: the client is not using the websocket protocol: "
if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'upgrade' token not found in 'Connection' header")
+ return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header")
}
if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'websocket' token not found in 'Upgrade' header")
+ return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header")
+ }
+
+ if r.Method != "GET" {
+ return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET")
}
if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
}
+ if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
+ return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported")
+ }
+
checkOrigin := u.CheckOrigin
if checkOrigin == nil {
checkOrigin = checkSameOrigin
}
if !checkOrigin(r) {
- return u.returnError(w, r, http.StatusForbidden, "websocket: 'Origin' header value not allowed")
+ return u.returnError(w, r, http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin")
}
challengeKey := r.Header.Get("Sec-Websocket-Key")
if challengeKey == "" {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-Websocket-Key' header is missing or blank")
+ return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-WebSocket-Key' header is missing or blank")
}
subprotocol := u.selectSubprotocol(r, responseHeader)
@@ -151,17 +170,12 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
}
}
- var (
- netConn net.Conn
- err error
- )
-
h, ok := w.(http.Hijacker)
if !ok {
return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
}
var brw *bufio.ReadWriter
- netConn, brw, err = h.Hijack()
+ netConn, brw, err := h.Hijack()
if err != nil {
return u.returnError(w, r, http.StatusInternalServerError, err.Error())
}
@@ -171,7 +185,21 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
return nil, errors.New("websocket: client sent data before handshake is complete")
}
- c := newConnBRW(netConn, true, u.ReadBufferSize, u.WriteBufferSize, brw)
+ var br *bufio.Reader
+ if u.ReadBufferSize == 0 && bufioReaderSize(netConn, brw.Reader) > 256 {
+ // Reuse hijacked buffered reader as connection reader.
+ br = brw.Reader
+ }
+
+ buf := bufioWriterBuffer(netConn, brw.Writer)
+
+ var writeBuf []byte
+ if u.WriteBufferPool == nil && u.WriteBufferSize == 0 && len(buf) >= maxFrameHeaderSize+256 {
+ // Reuse hijacked write buffer as connection buffer.
+ writeBuf = buf
+ }
+
+ c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf)
c.subprotocol = subprotocol
if compress {
@@ -179,17 +207,23 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
c.newDecompressionReader = decompressNoContextTakeover
}
- p := c.writeBuf[:0]
+ // Use larger of hijacked buffer and connection write buffer for header.
+ p := buf
+ if len(c.writeBuf) > len(p) {
+ p = c.writeBuf
+ }
+ p = p[:0]
+
p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
p = append(p, computeAcceptKey(challengeKey)...)
p = append(p, "\r\n"...)
if c.subprotocol != "" {
- p = append(p, "Sec-Websocket-Protocol: "...)
+ p = append(p, "Sec-WebSocket-Protocol: "...)
p = append(p, c.subprotocol...)
p = append(p, "\r\n"...)
}
if compress {
- p = append(p, "Sec-Websocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
+ p = append(p, "Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
}
for k, vs := range responseHeader {
if k == "Sec-Websocket-Protocol" {
@@ -230,13 +264,14 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
//
-// This function is deprecated, use websocket.Upgrader instead.
+// Deprecated: Use websocket.Upgrader instead.
//
-// The application is responsible for checking the request origin before
-// calling Upgrade. An example implementation of the same origin policy is:
+// Upgrade does not perform origin checking. The application is responsible for
+// checking the Origin header before calling Upgrade. An example implementation
+// of the same origin policy check is:
//
// if req.Header.Get("Origin") != "http://"+req.Host {
-// http.Error(w, "Origin not allowed", 403)
+// http.Error(w, "Origin not allowed", http.StatusForbidden)
// return
// }
//
@@ -289,3 +324,40 @@ func IsWebSocketUpgrade(r *http.Request) bool {
return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
tokenListContainsValue(r.Header, "Upgrade", "websocket")
}
+
+// bufioReaderSize size returns the size of a bufio.Reader.
+func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int {
+ // This code assumes that peek on a reset reader returns
+ // bufio.Reader.buf[:0].
+ // TODO: Use bufio.Reader.Size() after Go 1.10
+ br.Reset(originalReader)
+ if p, err := br.Peek(0); err == nil {
+ return cap(p)
+ }
+ return 0
+}
+
+// writeHook is an io.Writer that records the last slice passed to it vio
+// io.Writer.Write.
+type writeHook struct {
+ p []byte
+}
+
+func (wh *writeHook) Write(p []byte) (int, error) {
+ wh.p = p
+ return len(p), nil
+}
+
+// bufioWriterBuffer grabs the buffer from a bufio.Writer.
+func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte {
+ // This code assumes that bufio.Writer.buf[:1] is passed to the
+ // bufio.Writer's underlying writer.
+ var wh writeHook
+ bw.Reset(&wh)
+ bw.WriteByte(0)
+ bw.Flush()
+
+ bw.Reset(originalWriter)
+
+ return wh.p[:cap(wh.p)]
+}
diff --git a/vendor/github.com/gorilla/websocket/trace.go b/vendor/github.com/gorilla/websocket/trace.go
new file mode 100644
index 00000000..834f122a
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/trace.go
@@ -0,0 +1,19 @@
+// +build go1.8
+
+package websocket
+
+import (
+ "crypto/tls"
+ "net/http/httptrace"
+)
+
+func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
+ if trace.TLSHandshakeStart != nil {
+ trace.TLSHandshakeStart()
+ }
+ err := doHandshake(tlsConn, cfg)
+ if trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(tlsConn.ConnectionState(), err)
+ }
+ return err
+}
diff --git a/vendor/github.com/gorilla/websocket/trace_17.go b/vendor/github.com/gorilla/websocket/trace_17.go
new file mode 100644
index 00000000..77d05a0b
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/trace_17.go
@@ -0,0 +1,12 @@
+// +build !go1.8
+
+package websocket
+
+import (
+ "crypto/tls"
+ "net/http/httptrace"
+)
+
+func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
+ return doHandshake(tlsConn, cfg)
+}
diff --git a/vendor/github.com/gorilla/websocket/util.go b/vendor/github.com/gorilla/websocket/util.go
index 9a4908df..354001e1 100644
--- a/vendor/github.com/gorilla/websocket/util.go
+++ b/vendor/github.com/gorilla/websocket/util.go
@@ -11,6 +11,7 @@ import (
"io"
"net/http"
"strings"
+ "unicode/utf8"
)
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
@@ -111,14 +112,14 @@ func nextTokenOrQuoted(s string) (value string, rest string) {
case escape:
escape = false
p[j] = b
- j += 1
+ j++
case b == '\\':
escape = true
case b == '"':
return string(p[:j]), s[i+1:]
default:
p[j] = b
- j += 1
+ j++
}
}
return "", ""
@@ -127,8 +128,31 @@ func nextTokenOrQuoted(s string) (value string, rest string) {
return "", ""
}
+// equalASCIIFold returns true if s is equal to t with ASCII case folding.
+func equalASCIIFold(s, t string) bool {
+ for s != "" && t != "" {
+ sr, size := utf8.DecodeRuneInString(s)
+ s = s[size:]
+ tr, size := utf8.DecodeRuneInString(t)
+ t = t[size:]
+ if sr == tr {
+ continue
+ }
+ if 'A' <= sr && sr <= 'Z' {
+ sr = sr + 'a' - 'A'
+ }
+ if 'A' <= tr && tr <= 'Z' {
+ tr = tr + 'a' - 'A'
+ }
+ if sr != tr {
+ return false
+ }
+ }
+ return s == t
+}
+
// tokenListContainsValue returns true if the 1#token header with the given
-// name contains token.
+// name contains a token equal to value with ASCII case folding.
func tokenListContainsValue(header http.Header, name string, value string) bool {
headers:
for _, s := range header[name] {
@@ -142,7 +166,7 @@ headers:
if s != "" && s[0] != ',' {
continue headers
}
- if strings.EqualFold(t, value) {
+ if equalASCIIFold(t, value) {
return true
}
if s == "" {
@@ -154,9 +178,8 @@ headers:
return false
}
-// parseExtensiosn parses WebSocket extensions from a header.
+// parseExtensions parses WebSocket extensions from a header.
func parseExtensions(header http.Header) []map[string]string {
-
// From RFC 6455:
//
// Sec-WebSocket-Extensions = extension-list
diff --git a/vendor/github.com/gorilla/websocket/x_net_proxy.go b/vendor/github.com/gorilla/websocket/x_net_proxy.go
new file mode 100644
index 00000000..2e668f6b
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/x_net_proxy.go
@@ -0,0 +1,473 @@
+// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
+//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy
+
+// Package proxy provides support for a variety of protocols to proxy network
+// data.
+//
+
+package websocket
+
+import (
+ "errors"
+ "io"
+ "net"
+ "net/url"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+type proxy_direct struct{}
+
+// Direct is a direct proxy: one that makes network connections directly.
+var proxy_Direct = proxy_direct{}
+
+func (proxy_direct) Dial(network, addr string) (net.Conn, error) {
+ return net.Dial(network, addr)
+}
+
+// A PerHost directs connections to a default Dialer unless the host name
+// requested matches one of a number of exceptions.
+type proxy_PerHost struct {
+ def, bypass proxy_Dialer
+
+ bypassNetworks []*net.IPNet
+ bypassIPs []net.IP
+ bypassZones []string
+ bypassHosts []string
+}
+
+// NewPerHost returns a PerHost Dialer that directs connections to either
+// defaultDialer or bypass, depending on whether the connection matches one of
+// the configured rules.
+func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost {
+ return &proxy_PerHost{
+ def: defaultDialer,
+ bypass: bypass,
+ }
+}
+
+// Dial connects to the address addr on the given network through either
+// defaultDialer or bypass.
+func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) {
+ host, _, err := net.SplitHostPort(addr)
+ if err != nil {
+ return nil, err
+ }
+
+ return p.dialerForRequest(host).Dial(network, addr)
+}
+
+func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer {
+ if ip := net.ParseIP(host); ip != nil {
+ for _, net := range p.bypassNetworks {
+ if net.Contains(ip) {
+ return p.bypass
+ }
+ }
+ for _, bypassIP := range p.bypassIPs {
+ if bypassIP.Equal(ip) {
+ return p.bypass
+ }
+ }
+ return p.def
+ }
+
+ for _, zone := range p.bypassZones {
+ if strings.HasSuffix(host, zone) {
+ return p.bypass
+ }
+ if host == zone[1:] {
+ // For a zone ".example.com", we match "example.com"
+ // too.
+ return p.bypass
+ }
+ }
+ for _, bypassHost := range p.bypassHosts {
+ if bypassHost == host {
+ return p.bypass
+ }
+ }
+ return p.def
+}
+
+// AddFromString parses a string that contains comma-separated values
+// specifying hosts that should use the bypass proxy. Each value is either an
+// IP address, a CIDR range, a zone (*.example.com) or a host name
+// (localhost). A best effort is made to parse the string and errors are
+// ignored.
+func (p *proxy_PerHost) AddFromString(s string) {
+ hosts := strings.Split(s, ",")
+ for _, host := range hosts {
+ host = strings.TrimSpace(host)
+ if len(host) == 0 {
+ continue
+ }
+ if strings.Contains(host, "/") {
+ // We assume that it's a CIDR address like 127.0.0.0/8
+ if _, net, err := net.ParseCIDR(host); err == nil {
+ p.AddNetwork(net)
+ }
+ continue
+ }
+ if ip := net.ParseIP(host); ip != nil {
+ p.AddIP(ip)
+ continue
+ }
+ if strings.HasPrefix(host, "*.") {
+ p.AddZone(host[1:])
+ continue
+ }
+ p.AddHost(host)
+ }
+}
+
+// AddIP specifies an IP address that will use the bypass proxy. Note that
+// this will only take effect if a literal IP address is dialed. A connection
+// to a named host will never match an IP.
+func (p *proxy_PerHost) AddIP(ip net.IP) {
+ p.bypassIPs = append(p.bypassIPs, ip)
+}
+
+// AddNetwork specifies an IP range that will use the bypass proxy. Note that
+// this will only take effect if a literal IP address is dialed. A connection
+// to a named host will never match.
+func (p *proxy_PerHost) AddNetwork(net *net.IPNet) {
+ p.bypassNetworks = append(p.bypassNetworks, net)
+}
+
+// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
+// "example.com" matches "example.com" and all of its subdomains.
+func (p *proxy_PerHost) AddZone(zone string) {
+ if strings.HasSuffix(zone, ".") {
+ zone = zone[:len(zone)-1]
+ }
+ if !strings.HasPrefix(zone, ".") {
+ zone = "." + zone
+ }
+ p.bypassZones = append(p.bypassZones, zone)
+}
+
+// AddHost specifies a host name that will use the bypass proxy.
+func (p *proxy_PerHost) AddHost(host string) {
+ if strings.HasSuffix(host, ".") {
+ host = host[:len(host)-1]
+ }
+ p.bypassHosts = append(p.bypassHosts, host)
+}
+
+// A Dialer is a means to establish a connection.
+type proxy_Dialer interface {
+ // Dial connects to the given address via the proxy.
+ Dial(network, addr string) (c net.Conn, err error)
+}
+
+// Auth contains authentication parameters that specific Dialers may require.
+type proxy_Auth struct {
+ User, Password string
+}
+
+// FromEnvironment returns the dialer specified by the proxy related variables in
+// the environment.
+func proxy_FromEnvironment() proxy_Dialer {
+ allProxy := proxy_allProxyEnv.Get()
+ if len(allProxy) == 0 {
+ return proxy_Direct
+ }
+
+ proxyURL, err := url.Parse(allProxy)
+ if err != nil {
+ return proxy_Direct
+ }
+ proxy, err := proxy_FromURL(proxyURL, proxy_Direct)
+ if err != nil {
+ return proxy_Direct
+ }
+
+ noProxy := proxy_noProxyEnv.Get()
+ if len(noProxy) == 0 {
+ return proxy
+ }
+
+ perHost := proxy_NewPerHost(proxy, proxy_Direct)
+ perHost.AddFromString(noProxy)
+ return perHost
+}
+
+// proxySchemes is a map from URL schemes to a function that creates a Dialer
+// from a URL with such a scheme.
+var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)
+
+// RegisterDialerType takes a URL scheme and a function to generate Dialers from
+// a URL with that scheme and a forwarding Dialer. Registered schemes are used
+// by FromURL.
+func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) {
+ if proxy_proxySchemes == nil {
+ proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error))
+ }
+ proxy_proxySchemes[scheme] = f
+}
+
+// FromURL returns a Dialer given a URL specification and an underlying
+// Dialer for it to make network requests.
+func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) {
+ var auth *proxy_Auth
+ if u.User != nil {
+ auth = new(proxy_Auth)
+ auth.User = u.User.Username()
+ if p, ok := u.User.Password(); ok {
+ auth.Password = p
+ }
+ }
+
+ switch u.Scheme {
+ case "socks5":
+ return proxy_SOCKS5("tcp", u.Host, auth, forward)
+ }
+
+ // If the scheme doesn't match any of the built-in schemes, see if it
+ // was registered by another package.
+ if proxy_proxySchemes != nil {
+ if f, ok := proxy_proxySchemes[u.Scheme]; ok {
+ return f(u, forward)
+ }
+ }
+
+ return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
+}
+
+var (
+ proxy_allProxyEnv = &proxy_envOnce{
+ names: []string{"ALL_PROXY", "all_proxy"},
+ }
+ proxy_noProxyEnv = &proxy_envOnce{
+ names: []string{"NO_PROXY", "no_proxy"},
+ }
+)
+
+// envOnce looks up an environment variable (optionally by multiple
+// names) once. It mitigates expensive lookups on some platforms
+// (e.g. Windows).
+// (Borrowed from net/http/transport.go)
+type proxy_envOnce struct {
+ names []string
+ once sync.Once
+ val string
+}
+
+func (e *proxy_envOnce) Get() string {
+ e.once.Do(e.init)
+ return e.val
+}
+
+func (e *proxy_envOnce) init() {
+ for _, n := range e.names {
+ e.val = os.Getenv(n)
+ if e.val != "" {
+ return
+ }
+ }
+}
+
+// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
+// with an optional username and password. See RFC 1928 and RFC 1929.
+func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) {
+ s := &proxy_socks5{
+ network: network,
+ addr: addr,
+ forward: forward,
+ }
+ if auth != nil {
+ s.user = auth.User
+ s.password = auth.Password
+ }
+
+ return s, nil
+}
+
+type proxy_socks5 struct {
+ user, password string
+ network, addr string
+ forward proxy_Dialer
+}
+
+const proxy_socks5Version = 5
+
+const (
+ proxy_socks5AuthNone = 0
+ proxy_socks5AuthPassword = 2
+)
+
+const proxy_socks5Connect = 1
+
+const (
+ proxy_socks5IP4 = 1
+ proxy_socks5Domain = 3
+ proxy_socks5IP6 = 4
+)
+
+var proxy_socks5Errors = []string{
+ "",
+ "general failure",
+ "connection forbidden",
+ "network unreachable",
+ "host unreachable",
+ "connection refused",
+ "TTL expired",
+ "command not supported",
+ "address type not supported",
+}
+
+// Dial connects to the address addr on the given network via the SOCKS5 proxy.
+func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) {
+ switch network {
+ case "tcp", "tcp6", "tcp4":
+ default:
+ return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
+ }
+
+ conn, err := s.forward.Dial(s.network, s.addr)
+ if err != nil {
+ return nil, err
+ }
+ if err := s.connect(conn, addr); err != nil {
+ conn.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// connect takes an existing connection to a socks5 proxy server,
+// and commands the server to extend that connection to target,
+// which must be a canonical address with a host and port.
+func (s *proxy_socks5) connect(conn net.Conn, target string) error {
+ host, portStr, err := net.SplitHostPort(target)
+ if err != nil {
+ return err
+ }
+
+ port, err := strconv.Atoi(portStr)
+ if err != nil {
+ return errors.New("proxy: failed to parse port number: " + portStr)
+ }
+ if port < 1 || port > 0xffff {
+ return errors.New("proxy: port number out of range: " + portStr)
+ }
+
+ // the size here is just an estimate
+ buf := make([]byte, 0, 6+len(host))
+
+ buf = append(buf, proxy_socks5Version)
+ if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
+ buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword)
+ } else {
+ buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone)
+ }
+
+ if _, err := conn.Write(buf); err != nil {
+ return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ if _, err := io.ReadFull(conn, buf[:2]); err != nil {
+ return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+ if buf[0] != 5 {
+ return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
+ }
+ if buf[1] == 0xff {
+ return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
+ }
+
+ // See RFC 1929
+ if buf[1] == proxy_socks5AuthPassword {
+ buf = buf[:0]
+ buf = append(buf, 1 /* password protocol version */)
+ buf = append(buf, uint8(len(s.user)))
+ buf = append(buf, s.user...)
+ buf = append(buf, uint8(len(s.password)))
+ buf = append(buf, s.password...)
+
+ if _, err := conn.Write(buf); err != nil {
+ return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ if _, err := io.ReadFull(conn, buf[:2]); err != nil {
+ return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ if buf[1] != 0 {
+ return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
+ }
+ }
+
+ buf = buf[:0]
+ buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */)
+
+ if ip := net.ParseIP(host); ip != nil {
+ if ip4 := ip.To4(); ip4 != nil {
+ buf = append(buf, proxy_socks5IP4)
+ ip = ip4
+ } else {
+ buf = append(buf, proxy_socks5IP6)
+ }
+ buf = append(buf, ip...)
+ } else {
+ if len(host) > 255 {
+ return errors.New("proxy: destination host name too long: " + host)
+ }
+ buf = append(buf, proxy_socks5Domain)
+ buf = append(buf, byte(len(host)))
+ buf = append(buf, host...)
+ }
+ buf = append(buf, byte(port>>8), byte(port))
+
+ if _, err := conn.Write(buf); err != nil {
+ return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ if _, err := io.ReadFull(conn, buf[:4]); err != nil {
+ return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ failure := "unknown error"
+ if int(buf[1]) < len(proxy_socks5Errors) {
+ failure = proxy_socks5Errors[buf[1]]
+ }
+
+ if len(failure) > 0 {
+ return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
+ }
+
+ bytesToDiscard := 0
+ switch buf[3] {
+ case proxy_socks5IP4:
+ bytesToDiscard = net.IPv4len
+ case proxy_socks5IP6:
+ bytesToDiscard = net.IPv6len
+ case proxy_socks5Domain:
+ _, err := io.ReadFull(conn, buf[:1])
+ if err != nil {
+ return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+ bytesToDiscard = int(buf[0])
+ default:
+ return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
+ }
+
+ if cap(buf) < bytesToDiscard {
+ buf = make([]byte, bytesToDiscard)
+ } else {
+ buf = buf[:bytesToDiscard]
+ }
+ if _, err := io.ReadFull(conn, buf); err != nil {
+ return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ // Also need to discard the port number
+ if _, err := io.ReadFull(conn, buf[:2]); err != nil {
+ return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/matterbridge/discordgo/user.go b/vendor/github.com/matterbridge/discordgo/user.go
deleted file mode 100644
index a710f286..00000000
--- a/vendor/github.com/matterbridge/discordgo/user.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package discordgo
-
-import (
- "fmt"
- "strings"
-)
-
-// A User stores all data for an individual Discord user.
-type User struct {
- ID string `json:"id"`
- Email string `json:"email"`
- Username string `json:"username"`
- Avatar string `json:"avatar"`
- Discriminator string `json:"discriminator"`
- Token string `json:"token"`
- Verified bool `json:"verified"`
- MFAEnabled bool `json:"mfa_enabled"`
- Bot bool `json:"bot"`
-}
-
-// String returns a unique identifier of the form username#discriminator
-func (u *User) String() string {
- return fmt.Sprintf("%s#%s", u.Username, u.Discriminator)
-}
-
-// Mention return a string which mentions the user
-func (u *User) Mention() string {
- return fmt.Sprintf("<@%s>", u.ID)
-}
-
-// AvatarURL returns a URL to the user's avatar.
-// size: The size of the user's avatar as a power of two
-// if size is an empty string, no size parameter will
-// be added to the URL.
-func (u *User) AvatarURL(size string) string {
- var URL string
- if strings.HasPrefix(u.Avatar, "a_") {
- URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
- } else {
- URL = EndpointUserAvatar(u.ID, u.Avatar)
- }
-
- if size != "" {
- return URL + "?size=" + size
- }
- return URL
-}
diff --git a/vendor/golang.org/x/crypto/acme/acme.go b/vendor/golang.org/x/crypto/acme/acme.go
index 1f4fb69e..7df64764 100644
--- a/vendor/golang.org/x/crypto/acme/acme.go
+++ b/vendor/golang.org/x/crypto/acme/acme.go
@@ -14,7 +14,6 @@
package acme
import (
- "bytes"
"context"
"crypto"
"crypto/ecdsa"
@@ -23,6 +22,8 @@ import (
"crypto/sha256"
"crypto/tls"
"crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
"encoding/base64"
"encoding/hex"
"encoding/json"
@@ -33,14 +34,26 @@ import (
"io/ioutil"
"math/big"
"net/http"
- "strconv"
"strings"
"sync"
"time"
)
-// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
-const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
+const (
+ // LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
+ LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
+
+ // ALPNProto is the ALPN protocol name used by a CA server when validating
+ // tls-alpn-01 challenges.
+ //
+ // Package users must ensure their servers can negotiate the ACME ALPN in
+ // order for tls-alpn-01 challenge verifications to succeed.
+ // See the crypto/tls package's Config.NextProtos field.
+ ALPNProto = "acme-tls/1"
+)
+
+// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge.
+var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1}
const (
maxChainLen = 5 // max depth and breadth of a certificate chain
@@ -76,6 +89,22 @@ type Client struct {
// will have no effect.
DirectoryURL string
+ // RetryBackoff computes the duration after which the nth retry of a failed request
+ // should occur. The value of n for the first call on failure is 1.
+ // The values of r and resp are the request and response of the last failed attempt.
+ // If the returned value is negative or zero, no more retries are done and an error
+ // is returned to the caller of the original method.
+ //
+ // Requests which result in a 4xx client error are not retried,
+ // except for 400 Bad Request due to "bad nonce" errors and 429 Too Many Requests.
+ //
+ // If RetryBackoff is nil, a truncated exponential backoff algorithm
+ // with the ceiling of 10 seconds is used, where each subsequent retry n
+ // is done after either ("Retry-After" + jitter) or (2^n seconds + jitter),
+ // preferring the former if "Retry-After" header is found in the resp.
+ // The jitter is a random value up to 1 second.
+ RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration
+
dirMu sync.Mutex // guards writes to dir
dir *Directory // cached result of Client's Discover method
@@ -99,15 +128,12 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
if dirURL == "" {
dirURL = LetsEncryptURL
}
- res, err := c.get(ctx, dirURL)
+ res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK))
if err != nil {
return Directory{}, err
}
defer res.Body.Close()
c.addNonce(res.Header)
- if res.StatusCode != http.StatusOK {
- return Directory{}, responseError(res)
- }
var v struct {
Reg string `json:"new-reg"`
@@ -166,14 +192,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
req.NotAfter = now.Add(exp).Format(time.RFC3339)
}
- res, err := c.retryPostJWS(ctx, c.Key, c.dir.CertURL, req)
+ res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, "", err
}
defer res.Body.Close()
- if res.StatusCode != http.StatusCreated {
- return nil, "", responseError(res)
- }
curl := res.Header.Get("Location") // cert permanent URL
if res.ContentLength == 0 {
@@ -196,26 +219,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
// Callers are encouraged to parse the returned value to ensure the certificate is valid
// and has expected features.
func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
- for {
- res, err := c.get(ctx, url)
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- if res.StatusCode == http.StatusOK {
- return c.responseCert(ctx, res, bundle)
- }
- if res.StatusCode > 299 {
- return nil, responseError(res)
- }
- d := retryAfter(res.Header.Get("Retry-After"), 3*time.Second)
- select {
- case <-time.After(d):
- // retry
- case <-ctx.Done():
- return nil, ctx.Err()
- }
+ res, err := c.get(ctx, url, wantStatus(http.StatusOK))
+ if err != nil {
+ return nil, err
}
+ return c.responseCert(ctx, res, bundle)
}
// RevokeCert revokes a previously issued certificate cert, provided in DER format.
@@ -241,14 +249,11 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte,
if key == nil {
key = c.Key
}
- res, err := c.retryPostJWS(ctx, key, c.dir.RevokeURL, body)
+ res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK))
if err != nil {
return err
}
defer res.Body.Close()
- if res.StatusCode != http.StatusOK {
- return responseError(res)
- }
return nil
}
@@ -329,14 +334,11 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
Resource: "new-authz",
Identifier: authzID{Type: "dns", Value: domain},
}
- res, err := c.retryPostJWS(ctx, c.Key, c.dir.AuthzURL, req)
+ res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, err
}
defer res.Body.Close()
- if res.StatusCode != http.StatusCreated {
- return nil, responseError(res)
- }
var v wireAuthz
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
@@ -353,14 +355,11 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
// If a caller needs to poll an authorization until its status is final,
// see the WaitAuthorization method.
func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
- res, err := c.get(ctx, url)
+ res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
defer res.Body.Close()
- if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
- return nil, responseError(res)
- }
var v wireAuthz
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid response: %v", err)
@@ -387,14 +386,11 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
Status: "deactivated",
Delete: true,
}
- res, err := c.retryPostJWS(ctx, c.Key, url, req)
+ res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK))
if err != nil {
return err
}
defer res.Body.Close()
- if res.StatusCode != http.StatusOK {
- return responseError(res)
- }
return nil
}
@@ -406,44 +402,42 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
// In all other cases WaitAuthorization returns an error.
// If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
- sleep := sleeper(ctx)
for {
- res, err := c.get(ctx, url)
+ res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
- if res.StatusCode >= 400 && res.StatusCode <= 499 {
- // Non-retriable error. For instance, Let's Encrypt may return 404 Not Found
- // when requesting an expired authorization.
- defer res.Body.Close()
- return nil, responseError(res)
- }
- retry := res.Header.Get("Retry-After")
- if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
- res.Body.Close()
- if err := sleep(retry, 1); err != nil {
- return nil, err
- }
- continue
- }
var raw wireAuthz
err = json.NewDecoder(res.Body).Decode(&raw)
res.Body.Close()
- if err != nil {
- if err := sleep(retry, 0); err != nil {
- return nil, err
- }
- continue
- }
- if raw.Status == StatusValid {
+ switch {
+ case err != nil:
+ // Skip and retry.
+ case raw.Status == StatusValid:
return raw.authorization(url), nil
- }
- if raw.Status == StatusInvalid {
+ case raw.Status == StatusInvalid:
return nil, raw.error(url)
}
- if err := sleep(retry, 0); err != nil {
- return nil, err
+
+ // Exponential backoff is implemented in c.get above.
+ // This is just to prevent continuously hitting the CA
+ // while waiting for a final authorization status.
+ d := retryAfter(res.Header.Get("Retry-After"))
+ if d == 0 {
+ // Given that the fastest challenges TLS-SNI and HTTP-01
+ // require a CA to make at least 1 network round trip
+ // and most likely persist a challenge state,
+ // this default delay seems reasonable.
+ d = time.Second
+ }
+ t := time.NewTimer(d)
+ select {
+ case <-ctx.Done():
+ t.Stop()
+ return nil, ctx.Err()
+ case <-t.C:
+ // Retry.
}
}
}
@@ -452,14 +446,11 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
//
// A client typically polls a challenge status using this method.
func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
- res, err := c.get(ctx, url)
+ res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
defer res.Body.Close()
- if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
- return nil, responseError(res)
- }
v := wireChallenge{URI: url}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid response: %v", err)
@@ -486,16 +477,14 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error
Type: chal.Type,
Auth: auth,
}
- res, err := c.retryPostJWS(ctx, c.Key, chal.URI, req)
+ res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus(
+ http.StatusOK, // according to the spec
+ http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md)
+ ))
if err != nil {
return nil, err
}
defer res.Body.Close()
- // Note: the protocol specifies 200 as the expected response code, but
- // letsencrypt seems to be returning 202.
- if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
- return nil, responseError(res)
- }
var v wireChallenge
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
@@ -552,7 +541,7 @@ func (c *Client) HTTP01ChallengePath(token string) string {
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
//
// The returned certificate is valid for the next 24 hours and must be presented only when
-// the server name of the client hello matches exactly the returned name value.
+// the server name of the TLS ClientHello matches exactly the returned name value.
func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
ka, err := keyAuth(c.Key.Public(), token)
if err != nil {
@@ -579,7 +568,7 @@ func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tl
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
//
// The returned certificate is valid for the next 24 hours and must be presented only when
-// the server name in the client hello matches exactly the returned name value.
+// the server name in the TLS ClientHello matches exactly the returned name value.
func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
b := sha256.Sum256([]byte(token))
h := hex.EncodeToString(b[:])
@@ -600,6 +589,52 @@ func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tl
return cert, sanA, nil
}
+// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response.
+// Servers can present the certificate to validate the challenge and prove control
+// over a domain name. For more details on TLS-ALPN-01 see
+// https://tools.ietf.org/html/draft-shoemaker-acme-tls-alpn-00#section-3
+//
+// The token argument is a Challenge.Token value.
+// If a WithKey option is provided, its private part signs the returned cert,
+// and the public part is used to specify the signee.
+// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
+//
+// The returned certificate is valid for the next 24 hours and must be presented only when
+// the server name in the TLS ClientHello matches the domain, and the special acme-tls/1 ALPN protocol
+// has been specified.
+func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) (cert tls.Certificate, err error) {
+ ka, err := keyAuth(c.Key.Public(), token)
+ if err != nil {
+ return tls.Certificate{}, err
+ }
+ shasum := sha256.Sum256([]byte(ka))
+ extValue, err := asn1.Marshal(shasum[:])
+ if err != nil {
+ return tls.Certificate{}, err
+ }
+ acmeExtension := pkix.Extension{
+ Id: idPeACMEIdentifierV1,
+ Critical: true,
+ Value: extValue,
+ }
+
+ tmpl := defaultTLSChallengeCertTemplate()
+
+ var newOpt []CertOption
+ for _, o := range opt {
+ switch o := o.(type) {
+ case *certOptTemplate:
+ t := *(*x509.Certificate)(o) // shallow copy is ok
+ tmpl = &t
+ default:
+ newOpt = append(newOpt, o)
+ }
+ }
+ tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension)
+ newOpt = append(newOpt, WithTemplate(tmpl))
+ return tlsChallengeCert([]string{domain}, newOpt)
+}
+
// doReg sends all types of registration requests.
// The type of request is identified by typ argument, which is a "resource"
// in the ACME spec terms.
@@ -619,14 +654,15 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
req.Contact = acct.Contact
req.Agreement = acct.AgreedTerms
}
- res, err := c.retryPostJWS(ctx, c.Key, url, req)
+ res, err := c.post(ctx, c.Key, url, req, wantStatus(
+ http.StatusOK, // updates and deletes
+ http.StatusCreated, // new account creation
+ http.StatusAccepted, // Let's Encrypt divergent implementation
+ ))
if err != nil {
return nil, err
}
defer res.Body.Close()
- if res.StatusCode < 200 || res.StatusCode > 299 {
- return nil, responseError(res)
- }
var v struct {
Contact []string
@@ -656,59 +692,6 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
}, nil
}
-// retryPostJWS will retry calls to postJWS if there is a badNonce error,
-// clearing the stored nonces after each error.
-// If the response was 4XX-5XX, then responseError is called on the body,
-// the body is closed, and the error returned.
-func (c *Client) retryPostJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
- sleep := sleeper(ctx)
- for {
- res, err := c.postJWS(ctx, key, url, body)
- if err != nil {
- return nil, err
- }
- // handle errors 4XX-5XX with responseError
- if res.StatusCode >= 400 && res.StatusCode <= 599 {
- err := responseError(res)
- res.Body.Close()
- // according to spec badNonce is urn:ietf:params:acme:error:badNonce
- // however, acme servers in the wild return their version of the error
- // https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4
- if ae, ok := err.(*Error); ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") {
- // clear any nonces that we might've stored that might now be
- // considered bad
- c.clearNonces()
- retry := res.Header.Get("Retry-After")
- if err := sleep(retry, 1); err != nil {
- return nil, err
- }
- continue
- }
- return nil, err
- }
- return res, nil
- }
-}
-
-// postJWS signs the body with the given key and POSTs it to the provided url.
-// The body argument must be JSON-serializable.
-func (c *Client) postJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
- nonce, err := c.popNonce(ctx, url)
- if err != nil {
- return nil, err
- }
- b, err := jwsEncodeJSON(body, key, nonce)
- if err != nil {
- return nil, err
- }
- res, err := c.post(ctx, url, "application/jose+json", bytes.NewReader(b))
- if err != nil {
- return nil, err
- }
- c.addNonce(res.Header)
- return res, nil
-}
-
// popNonce returns a nonce value previously stored with c.addNonce
// or fetches a fresh one from the given URL.
func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
@@ -749,58 +732,12 @@ func (c *Client) addNonce(h http.Header) {
c.nonces[v] = struct{}{}
}
-func (c *Client) httpClient() *http.Client {
- if c.HTTPClient != nil {
- return c.HTTPClient
- }
- return http.DefaultClient
-}
-
-func (c *Client) get(ctx context.Context, urlStr string) (*http.Response, error) {
- req, err := http.NewRequest("GET", urlStr, nil)
- if err != nil {
- return nil, err
- }
- return c.do(ctx, req)
-}
-
-func (c *Client) head(ctx context.Context, urlStr string) (*http.Response, error) {
- req, err := http.NewRequest("HEAD", urlStr, nil)
- if err != nil {
- return nil, err
- }
- return c.do(ctx, req)
-}
-
-func (c *Client) post(ctx context.Context, urlStr, contentType string, body io.Reader) (*http.Response, error) {
- req, err := http.NewRequest("POST", urlStr, body)
- if err != nil {
- return nil, err
- }
- req.Header.Set("Content-Type", contentType)
- return c.do(ctx, req)
-}
-
-func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) {
- res, err := c.httpClient().Do(req.WithContext(ctx))
+func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) {
+ r, err := http.NewRequest("HEAD", url, nil)
if err != nil {
- select {
- case <-ctx.Done():
- // Prefer the unadorned context error.
- // (The acme package had tests assuming this, previously from ctxhttp's
- // behavior, predating net/http supporting contexts natively)
- // TODO(bradfitz): reconsider this in the future. But for now this
- // requires no test updates.
- return nil, ctx.Err()
- default:
- return nil, err
- }
+ return "", err
}
- return res, nil
-}
-
-func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) {
- resp, err := c.head(ctx, url)
+ resp, err := c.doNoRetry(ctx, r)
if err != nil {
return "", err
}
@@ -852,24 +789,6 @@ func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bo
return cert, nil
}
-// responseError creates an error of Error type from resp.
-func responseError(resp *http.Response) error {
- // don't care if ReadAll returns an error:
- // json.Unmarshal will fail in that case anyway
- b, _ := ioutil.ReadAll(resp.Body)
- e := &wireError{Status: resp.StatusCode}
- if err := json.Unmarshal(b, e); err != nil {
- // this is not a regular error response:
- // populate detail with anything we received,
- // e.Status will already contain HTTP response code value
- e.Detail = string(b)
- if e.Detail == "" {
- e.Detail = resp.Status
- }
- }
- return e.error(resp.Header)
-}
-
// chainCert fetches CA certificate chain recursively by following "up" links.
// Each recursive call increments the depth by 1, resulting in an error
// if the recursion level reaches maxChainLen.
@@ -880,14 +799,11 @@ func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte
return nil, errors.New("acme: certificate chain is too deep")
}
- res, err := c.get(ctx, url)
+ res, err := c.get(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
- if res.StatusCode != http.StatusOK {
- return nil, responseError(res)
- }
b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
if err != nil {
return nil, err
@@ -932,65 +848,6 @@ func linkHeader(h http.Header, rel string) []string {
return links
}
-// sleeper returns a function that accepts the Retry-After HTTP header value
-// and an increment that's used with backoff to increasingly sleep on
-// consecutive calls until the context is done. If the Retry-After header
-// cannot be parsed, then backoff is used with a maximum sleep time of 10
-// seconds.
-func sleeper(ctx context.Context) func(ra string, inc int) error {
- var count int
- return func(ra string, inc int) error {
- count += inc
- d := backoff(count, 10*time.Second)
- d = retryAfter(ra, d)
- wakeup := time.NewTimer(d)
- defer wakeup.Stop()
- select {
- case <-ctx.Done():
- return ctx.Err()
- case <-wakeup.C:
- return nil
- }
- }
-}
-
-// retryAfter parses a Retry-After HTTP header value,
-// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
-// It returns d if v cannot be parsed.
-func retryAfter(v string, d time.Duration) time.Duration {
- if i, err := strconv.Atoi(v); err == nil {
- return time.Duration(i) * time.Second
- }
- t, err := http.ParseTime(v)
- if err != nil {
- return d
- }
- return t.Sub(timeNow())
-}
-
-// backoff computes a duration after which an n+1 retry iteration should occur
-// using truncated exponential backoff algorithm.
-//
-// The n argument is always bounded between 0 and 30.
-// The max argument defines upper bound for the returned value.
-func backoff(n int, max time.Duration) time.Duration {
- if n < 0 {
- n = 0
- }
- if n > 30 {
- n = 30
- }
- var d time.Duration
- if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
- d = time.Duration(x.Int64()) * time.Millisecond
- }
- d += time.Duration(1<<uint(n)) * time.Second
- if d > max {
- return max
- }
- return d
-}
-
// keyAuth generates a key authorization string for a given token.
func keyAuth(pub crypto.PublicKey, token string) (string, error) {
th, err := JWKThumbprint(pub)
@@ -1000,15 +857,25 @@ func keyAuth(pub crypto.PublicKey, token string) (string, error) {
return fmt.Sprintf("%s.%s", token, th), nil
}
+// defaultTLSChallengeCertTemplate is a template used to create challenge certs for TLS challenges.
+func defaultTLSChallengeCertTemplate() *x509.Certificate {
+ return &x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ NotBefore: time.Now(),
+ NotAfter: time.Now().Add(24 * time.Hour),
+ BasicConstraintsValid: true,
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ }
+}
+
// tlsChallengeCert creates a temporary certificate for TLS-SNI challenges
// with the given SANs and auto-generated public/private key pair.
// The Subject Common Name is set to the first SAN to aid debugging.
// To create a cert with a custom key pair, specify WithKey option.
func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
- var (
- key crypto.Signer
- tmpl *x509.Certificate
- )
+ var key crypto.Signer
+ tmpl := defaultTLSChallengeCertTemplate()
for _, o := range opt {
switch o := o.(type) {
case *certOptKey:
@@ -1017,7 +884,7 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
}
key = o.key
case *certOptTemplate:
- var t = *(*x509.Certificate)(o) // shallow copy is ok
+ t := *(*x509.Certificate)(o) // shallow copy is ok
tmpl = &t
default:
// package's fault, if we let this happen:
@@ -1030,16 +897,6 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
return tls.Certificate{}, err
}
}
- if tmpl == nil {
- tmpl = &x509.Certificate{
- SerialNumber: big.NewInt(1),
- NotBefore: time.Now(),
- NotAfter: time.Now().Add(24 * time.Hour),
- BasicConstraintsValid: true,
- KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
- ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
- }
- }
tmpl.DNSNames = san
if len(san) > 0 {
tmpl.Subject.CommonName = san[0]
diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
index 263b2913..a50d9bfc 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
@@ -44,7 +44,7 @@ var createCertRetryAfter = time.Minute
var pseudoRand *lockedMathRand
func init() {
- src := mathrand.NewSource(timeNow().UnixNano())
+ src := mathrand.NewSource(time.Now().UnixNano())
pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
}
@@ -69,7 +69,7 @@ func HostWhitelist(hosts ...string) HostPolicy {
}
return func(_ context.Context, host string) error {
if !whitelist[host] {
- return errors.New("acme/autocert: host not configured")
+ return fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host)
}
return nil
}
@@ -81,9 +81,9 @@ func defaultHostPolicy(context.Context, string) error {
}
// Manager is a stateful certificate manager built on top of acme.Client.
-// It obtains and refreshes certificates automatically using "tls-sni-01",
-// "tls-sni-02" and "http-01" challenge types, as well as providing them
-// to a TLS server via tls.Config.
+// It obtains and refreshes certificates automatically using "tls-alpn-01",
+// "tls-sni-01", "tls-sni-02" and "http-01" challenge types,
+// as well as providing them to a TLS server via tls.Config.
//
// You must specify a cache implementation, such as DirCache,
// to reuse obtained certificates across program restarts.
@@ -98,11 +98,11 @@ type Manager struct {
// To always accept the terms, the callers can use AcceptTOS.
Prompt func(tosURL string) bool
- // Cache optionally stores and retrieves previously-obtained certificates.
- // If nil, certs will only be cached for the lifetime of the Manager.
+ // Cache optionally stores and retrieves previously-obtained certificates
+ // and other state. If nil, certs will only be cached for the lifetime of
+ // the Manager. Multiple Managers can share the same Cache.
//
- // Manager passes the Cache certificates data encoded in PEM, with private/public
- // parts combined in a single Cache.Put call, private key first.
+ // Using a persistent Cache, such as DirCache, is strongly recommended.
Cache Cache
// HostPolicy controls which domains the Manager will attempt
@@ -127,8 +127,10 @@ type Manager struct {
// Client is used to perform low-level operations, such as account registration
// and requesting new certificates.
+ //
// If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL
- // directory endpoint and a newly-generated ECDSA P-256 key.
+ // as directory endpoint. If the Client.Key is nil, a new ECDSA P-256 key is
+ // generated and, if Cache is not nil, stored in cache.
//
// Mutating the field after the first call of GetCertificate method will have no effect.
Client *acme.Client
@@ -140,22 +142,30 @@ type Manager struct {
// If the Client's account key is already registered, Email is not used.
Email string
- // ForceRSA makes the Manager generate certificates with 2048-bit RSA keys.
+ // ForceRSA used to make the Manager generate RSA certificates. It is now ignored.
//
- // If false, a default is used. Currently the default
- // is EC-based keys using the P-256 curve.
+ // Deprecated: the Manager will request the correct type of certificate based
+ // on what each client supports.
ForceRSA bool
+ // ExtraExtensions are used when generating a new CSR (Certificate Request),
+ // thus allowing customization of the resulting certificate.
+ // For instance, TLS Feature Extension (RFC 7633) can be used
+ // to prevent an OCSP downgrade attack.
+ //
+ // The field value is passed to crypto/x509.CreateCertificateRequest
+ // in the template's ExtraExtensions field as is.
+ ExtraExtensions []pkix.Extension
+
clientMu sync.Mutex
client *acme.Client // initialized by acmeClient method
stateMu sync.Mutex
- state map[string]*certState // keyed by domain name
+ state map[certKey]*certState
// renewal tracks the set of domains currently running renewal timers.
- // It is keyed by domain name.
renewalMu sync.Mutex
- renewal map[string]*domainRenewal
+ renewal map[certKey]*domainRenewal
// tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens.
tokensMu sync.RWMutex
@@ -167,21 +177,60 @@ type Manager struct {
// to be provisioned.
// The entries are stored for the duration of the authorization flow.
httpTokens map[string][]byte
- // certTokens contains temporary certificates for tls-sni challenges
+ // certTokens contains temporary certificates for tls-sni and tls-alpn challenges
// and is keyed by token domain name, which matches server name of ClientHello.
- // Keys always have ".acme.invalid" suffix.
+ // Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names
+ // for tls-alpn.
// The entries are stored for the duration of the authorization flow.
certTokens map[string]*tls.Certificate
+ // nowFunc, if not nil, returns the current time. This may be set for
+ // testing purposes.
+ nowFunc func() time.Time
+}
+
+// certKey is the key by which certificates are tracked in state, renewal and cache.
+type certKey struct {
+ domain string // without trailing dot
+ isRSA bool // RSA cert for legacy clients (as opposed to default ECDSA)
+ isToken bool // tls-based challenge token cert; key type is undefined regardless of isRSA
+}
+
+func (c certKey) String() string {
+ if c.isToken {
+ return c.domain + "+token"
+ }
+ if c.isRSA {
+ return c.domain + "+rsa"
+ }
+ return c.domain
+}
+
+// TLSConfig creates a new TLS config suitable for net/http.Server servers,
+// supporting HTTP/2 and the tls-alpn-01 ACME challenge type.
+func (m *Manager) TLSConfig() *tls.Config {
+ return &tls.Config{
+ GetCertificate: m.GetCertificate,
+ NextProtos: []string{
+ "h2", "http/1.1", // enable HTTP/2
+ acme.ALPNProto, // enable tls-alpn ACME challenges
+ },
+ }
}
// GetCertificate implements the tls.Config.GetCertificate hook.
// It provides a TLS certificate for hello.ServerName host, including answering
-// *.acme.invalid (TLS-SNI) challenges. All other fields of hello are ignored.
+// tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges.
+// All other fields of hello are ignored.
//
// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation.
// The error is propagated back to the caller of GetCertificate and is user-visible.
// This does not affect cached certs. See HostPolicy field description for more details.
+//
+// If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will
+// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler
+// for http-01. (The tls-sni-* challenges have been deprecated by popular ACME providers
+// due to security issues in the ecosystem.)
func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
if m.Prompt == nil {
return nil, errors.New("acme/autocert: Manager.Prompt not set")
@@ -194,7 +243,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
if !strings.Contains(strings.Trim(name, "."), ".") {
return nil, errors.New("acme/autocert: server name component count invalid")
}
- if strings.ContainsAny(name, `/\`) {
+ if strings.ContainsAny(name, `+/\`) {
return nil, errors.New("acme/autocert: server name contains invalid character")
}
@@ -203,14 +252,17 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
- // check whether this is a token cert requested for TLS-SNI challenge
- if strings.HasSuffix(name, ".acme.invalid") {
+ // Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge.
+ if wantsTokenCert(hello) {
m.tokensMu.RLock()
defer m.tokensMu.RUnlock()
+ // It's ok to use the same token cert key for both tls-sni and tls-alpn
+ // because there's always at most 1 token cert per on-going domain authorization.
+ // See m.verify for details.
if cert := m.certTokens[name]; cert != nil {
return cert, nil
}
- if cert, err := m.cacheGet(ctx, name); err == nil {
+ if cert, err := m.cacheGet(ctx, certKey{domain: name, isToken: true}); err == nil {
return cert, nil
}
// TODO: cache error results?
@@ -218,8 +270,11 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
}
// regular domain
- name = strings.TrimSuffix(name, ".") // golang.org/issue/18114
- cert, err := m.cert(ctx, name)
+ ck := certKey{
+ domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114
+ isRSA: !supportsECDSA(hello),
+ }
+ cert, err := m.cert(ctx, ck)
if err == nil {
return cert, nil
}
@@ -231,14 +286,71 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
if err := m.hostPolicy()(ctx, name); err != nil {
return nil, err
}
- cert, err = m.createCert(ctx, name)
+ cert, err = m.createCert(ctx, ck)
if err != nil {
return nil, err
}
- m.cachePut(ctx, name, cert)
+ m.cachePut(ctx, ck, cert)
return cert, nil
}
+// wantsTokenCert reports whether a TLS request with SNI is made by a CA server
+// for a challenge verification.
+func wantsTokenCert(hello *tls.ClientHelloInfo) bool {
+ // tls-alpn-01
+ if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto {
+ return true
+ }
+ // tls-sni-xx
+ return strings.HasSuffix(hello.ServerName, ".acme.invalid")
+}
+
+func supportsECDSA(hello *tls.ClientHelloInfo) bool {
+ // The "signature_algorithms" extension, if present, limits the key exchange
+ // algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1.
+ if hello.SignatureSchemes != nil {
+ ecdsaOK := false
+ schemeLoop:
+ for _, scheme := range hello.SignatureSchemes {
+ const tlsECDSAWithSHA1 tls.SignatureScheme = 0x0203 // constant added in Go 1.10
+ switch scheme {
+ case tlsECDSAWithSHA1, tls.ECDSAWithP256AndSHA256,
+ tls.ECDSAWithP384AndSHA384, tls.ECDSAWithP521AndSHA512:
+ ecdsaOK = true
+ break schemeLoop
+ }
+ }
+ if !ecdsaOK {
+ return false
+ }
+ }
+ if hello.SupportedCurves != nil {
+ ecdsaOK := false
+ for _, curve := range hello.SupportedCurves {
+ if curve == tls.CurveP256 {
+ ecdsaOK = true
+ break
+ }
+ }
+ if !ecdsaOK {
+ return false
+ }
+ }
+ for _, suite := range hello.CipherSuites {
+ switch suite {
+ case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
+ return true
+ }
+ }
+ return false
+}
+
// HTTPHandler configures the Manager to provision ACME "http-01" challenge responses.
// It returns an http.Handler that responds to the challenges and must be
// running on port 80. If it receives a request that is not an ACME challenge,
@@ -252,8 +364,8 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
// Because the fallback handler is run with unencrypted port 80 requests,
// the fallback should not serve TLS-only requests.
//
-// If HTTPHandler is never called, the Manager will only use TLS SNI
-// challenges for domain verification.
+// If HTTPHandler is never called, the Manager will only use the "tls-alpn-01"
+// challenge for domain verification.
func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler {
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
@@ -304,16 +416,16 @@ func stripPort(hostport string) string {
// cert returns an existing certificate either from m.state or cache.
// If a certificate is found in cache but not in m.state, the latter will be filled
// with the cached value.
-func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, error) {
+func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
m.stateMu.Lock()
- if s, ok := m.state[name]; ok {
+ if s, ok := m.state[ck]; ok {
m.stateMu.Unlock()
s.RLock()
defer s.RUnlock()
return s.tlscert()
}
defer m.stateMu.Unlock()
- cert, err := m.cacheGet(ctx, name)
+ cert, err := m.cacheGet(ctx, ck)
if err != nil {
return nil, err
}
@@ -322,25 +434,25 @@ func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, erro
return nil, errors.New("acme/autocert: private key cannot sign")
}
if m.state == nil {
- m.state = make(map[string]*certState)
+ m.state = make(map[certKey]*certState)
}
s := &certState{
key: signer,
cert: cert.Certificate,
leaf: cert.Leaf,
}
- m.state[name] = s
- go m.renew(name, s.key, s.leaf.NotAfter)
+ m.state[ck] = s
+ go m.renew(ck, s.key, s.leaf.NotAfter)
return cert, nil
}
// cacheGet always returns a valid certificate, or an error otherwise.
-// If a cached certficate exists but is not valid, ErrCacheMiss is returned.
-func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate, error) {
+// If a cached certificate exists but is not valid, ErrCacheMiss is returned.
+func (m *Manager) cacheGet(ctx context.Context, ck certKey) (*tls.Certificate, error) {
if m.Cache == nil {
return nil, ErrCacheMiss
}
- data, err := m.Cache.Get(ctx, domain)
+ data, err := m.Cache.Get(ctx, ck.String())
if err != nil {
return nil, err
}
@@ -371,7 +483,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate
}
// verify and create TLS cert
- leaf, err := validCert(domain, pubDER, privKey)
+ leaf, err := validCert(ck, pubDER, privKey, m.now())
if err != nil {
return nil, ErrCacheMiss
}
@@ -383,7 +495,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate
return tlscert, nil
}
-func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Certificate) error {
+func (m *Manager) cachePut(ctx context.Context, ck certKey, tlscert *tls.Certificate) error {
if m.Cache == nil {
return nil
}
@@ -415,7 +527,7 @@ func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Cert
}
}
- return m.Cache.Put(ctx, domain, buf.Bytes())
+ return m.Cache.Put(ctx, ck.String(), buf.Bytes())
}
func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
@@ -432,9 +544,9 @@ func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
//
// If the domain is already being verified, it waits for the existing verification to complete.
// Either way, createCert blocks for the duration of the whole process.
-func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certificate, error) {
+func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
// TODO: maybe rewrite this whole piece using sync.Once
- state, err := m.certState(domain)
+ state, err := m.certState(ck)
if err != nil {
return nil, err
}
@@ -452,44 +564,44 @@ func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certifica
defer state.Unlock()
state.locked = false
- der, leaf, err := m.authorizedCert(ctx, state.key, domain)
+ der, leaf, err := m.authorizedCert(ctx, state.key, ck)
if err != nil {
// Remove the failed state after some time,
// making the manager call createCert again on the following TLS hello.
time.AfterFunc(createCertRetryAfter, func() {
- defer testDidRemoveState(domain)
+ defer testDidRemoveState(ck)
m.stateMu.Lock()
defer m.stateMu.Unlock()
// Verify the state hasn't changed and it's still invalid
// before deleting.
- s, ok := m.state[domain]
+ s, ok := m.state[ck]
if !ok {
return
}
- if _, err := validCert(domain, s.cert, s.key); err == nil {
+ if _, err := validCert(ck, s.cert, s.key, m.now()); err == nil {
return
}
- delete(m.state, domain)
+ delete(m.state, ck)
})
return nil, err
}
state.cert = der
state.leaf = leaf
- go m.renew(domain, state.key, state.leaf.NotAfter)
+ go m.renew(ck, state.key, state.leaf.NotAfter)
return state.tlscert()
}
// certState returns a new or existing certState.
// If a new certState is returned, state.exist is false and the state is locked.
// The returned error is non-nil only in the case where a new state could not be created.
-func (m *Manager) certState(domain string) (*certState, error) {
+func (m *Manager) certState(ck certKey) (*certState, error) {
m.stateMu.Lock()
defer m.stateMu.Unlock()
if m.state == nil {
- m.state = make(map[string]*certState)
+ m.state = make(map[certKey]*certState)
}
// existing state
- if state, ok := m.state[domain]; ok {
+ if state, ok := m.state[ck]; ok {
return state, nil
}
@@ -498,7 +610,7 @@ func (m *Manager) certState(domain string) (*certState, error) {
err error
key crypto.Signer
)
- if m.ForceRSA {
+ if ck.isRSA {
key, err = rsa.GenerateKey(rand.Reader, 2048)
} else {
key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
@@ -512,22 +624,22 @@ func (m *Manager) certState(domain string) (*certState, error) {
locked: true,
}
state.Lock() // will be unlocked by m.certState caller
- m.state[domain] = state
+ m.state[ck] = state
return state, nil
}
// authorizedCert starts the domain ownership verification process and requests a new cert upon success.
// The key argument is the certificate private key.
-func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
+func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) {
client, err := m.acmeClient(ctx)
if err != nil {
return nil, nil, err
}
- if err := m.verify(ctx, client, domain); err != nil {
+ if err := m.verify(ctx, client, ck.domain); err != nil {
return nil, nil, err
}
- csr, err := certRequest(key, domain)
+ csr, err := certRequest(key, ck.domain, m.ExtraExtensions)
if err != nil {
return nil, nil, err
}
@@ -535,25 +647,55 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain
if err != nil {
return nil, nil, err
}
- leaf, err = validCert(domain, der, key)
+ leaf, err = validCert(ck, der, key, m.now())
if err != nil {
return nil, nil, err
}
return der, leaf, nil
}
+// revokePendingAuthz revokes all authorizations idenfied by the elements of uri slice.
+// It ignores revocation errors.
+func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) {
+ client, err := m.acmeClient(ctx)
+ if err != nil {
+ return
+ }
+ for _, u := range uri {
+ client.RevokeAuthorization(ctx, u)
+ }
+}
+
// verify runs the identifier (domain) authorization flow
// using each applicable ACME challenge type.
func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error {
// The list of challenge types we'll try to fulfill
// in this specific order.
- challengeTypes := []string{"tls-sni-02", "tls-sni-01"}
+ challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"}
m.tokensMu.RLock()
if m.tryHTTP01 {
challengeTypes = append(challengeTypes, "http-01")
}
m.tokensMu.RUnlock()
+ // Keep track of pending authzs and revoke the ones that did not validate.
+ pendingAuthzs := make(map[string]bool)
+ defer func() {
+ var uri []string
+ for k, pending := range pendingAuthzs {
+ if pending {
+ uri = append(uri, k)
+ }
+ }
+ if len(uri) > 0 {
+ // Use "detached" background context.
+ // The revocations need not happen in the current verification flow.
+ go m.revokePendingAuthz(context.Background(), uri)
+ }
+ }()
+
+ // errs accumulates challenge failure errors, printed if all fail
+ errs := make(map[*acme.Challenge]error)
var nextTyp int // challengeType index of the next challenge type to try
for {
// Start domain authorization and get the challenge.
@@ -570,6 +712,8 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI)
}
+ pendingAuthzs[authz.URI] = true
+
// Pick the next preferred challenge.
var chal *acme.Challenge
for chal == nil && nextTyp < len(challengeTypes) {
@@ -577,28 +721,44 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
nextTyp++
}
if chal == nil {
- return fmt.Errorf("acme/autocert: unable to authorize %q; tried %q", domain, challengeTypes)
+ errorMsg := fmt.Sprintf("acme/autocert: unable to authorize %q", domain)
+ for chal, err := range errs {
+ errorMsg += fmt.Sprintf("; challenge %q failed with error: %v", chal.Type, err)
+ }
+ return errors.New(errorMsg)
}
- cleanup, err := m.fulfill(ctx, client, chal)
+ cleanup, err := m.fulfill(ctx, client, chal, domain)
if err != nil {
+ errs[chal] = err
continue
}
defer cleanup()
if _, err := client.Accept(ctx, chal); err != nil {
+ errs[chal] = err
continue
}
// A challenge is fulfilled and accepted: wait for the CA to validate.
- if _, err := client.WaitAuthorization(ctx, authz.URI); err == nil {
- return nil
+ if _, err := client.WaitAuthorization(ctx, authz.URI); err != nil {
+ errs[chal] = err
+ continue
}
+ delete(pendingAuthzs, authz.URI)
+ return nil
}
}
// fulfill provisions a response to the challenge chal.
// The cleanup is non-nil only if provisioning succeeded.
-func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge) (cleanup func(), err error) {
+func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge, domain string) (cleanup func(), err error) {
switch chal.Type {
+ case "tls-alpn-01":
+ cert, err := client.TLSALPN01ChallengeCert(chal.Token, domain)
+ if err != nil {
+ return nil, err
+ }
+ m.putCertToken(ctx, domain, &cert)
+ return func() { go m.deleteCertToken(domain) }, nil
case "tls-sni-01":
cert, name, err := client.TLSSNI01ChallengeCert(chal.Token)
if err != nil {
@@ -634,8 +794,8 @@ func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge {
return nil
}
-// putCertToken stores the cert under the named key in both m.certTokens map
-// and m.Cache.
+// putCertToken stores the token certificate with the specified name
+// in both m.certTokens map and m.Cache.
func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) {
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
@@ -643,17 +803,18 @@ func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certi
m.certTokens = make(map[string]*tls.Certificate)
}
m.certTokens[name] = cert
- m.cachePut(ctx, name, cert)
+ m.cachePut(ctx, certKey{domain: name, isToken: true}, cert)
}
-// deleteCertToken removes the token certificate for the specified domain name
+// deleteCertToken removes the token certificate with the specified name
// from both m.certTokens map and m.Cache.
func (m *Manager) deleteCertToken(name string) {
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
delete(m.certTokens, name)
if m.Cache != nil {
- m.Cache.Delete(context.Background(), name)
+ ck := certKey{domain: name, isToken: true}
+ m.Cache.Delete(context.Background(), ck.String())
}
}
@@ -704,7 +865,7 @@ func (m *Manager) deleteHTTPToken(tokenPath string) {
// httpTokenCacheKey returns a key at which an http-01 token value may be stored
// in the Manager's optional Cache.
func httpTokenCacheKey(tokenPath string) string {
- return "http-01-" + path.Base(tokenPath)
+ return path.Base(tokenPath) + "+http-01"
}
// renew starts a cert renewal timer loop, one per domain.
@@ -715,18 +876,18 @@ func httpTokenCacheKey(tokenPath string) string {
//
// The key argument is a certificate private key.
// The exp argument is the cert expiration time (NotAfter).
-func (m *Manager) renew(domain string, key crypto.Signer, exp time.Time) {
+func (m *Manager) renew(ck certKey, key crypto.Signer, exp time.Time) {
m.renewalMu.Lock()
defer m.renewalMu.Unlock()
- if m.renewal[domain] != nil {
+ if m.renewal[ck] != nil {
// another goroutine is already on it
return
}
if m.renewal == nil {
- m.renewal = make(map[string]*domainRenewal)
+ m.renewal = make(map[certKey]*domainRenewal)
}
- dr := &domainRenewal{m: m, domain: domain, key: key}
- m.renewal[domain] = dr
+ dr := &domainRenewal{m: m, ck: ck, key: key}
+ m.renewal[ck] = dr
dr.start(exp)
}
@@ -742,7 +903,10 @@ func (m *Manager) stopRenew() {
}
func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
- const keyName = "acme_account.key"
+ const keyName = "acme_account+key"
+
+ // Previous versions of autocert stored the value under a different key.
+ const legacyKeyName = "acme_account.key"
genKey := func() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
@@ -754,6 +918,9 @@ func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
data, err := m.Cache.Get(ctx, keyName)
if err == ErrCacheMiss {
+ data, err = m.Cache.Get(ctx, legacyKeyName)
+ }
+ if err == ErrCacheMiss {
key, err := genKey()
if err != nil {
return nil, err
@@ -824,6 +991,13 @@ func (m *Manager) renewBefore() time.Duration {
return 720 * time.Hour // 30 days
}
+func (m *Manager) now() time.Time {
+ if m.nowFunc != nil {
+ return m.nowFunc()
+ }
+ return time.Now()
+}
+
// certState is ready when its mutex is unlocked for reading.
type certState struct {
sync.RWMutex
@@ -849,12 +1023,12 @@ func (s *certState) tlscert() (*tls.Certificate, error) {
}, nil
}
-// certRequest creates a certificate request for the given common name cn
-// and optional SANs.
-func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) {
+// certRequest generates a CSR for the given common name cn and optional SANs.
+func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) {
req := &x509.CertificateRequest{
- Subject: pkix.Name{CommonName: cn},
- DNSNames: san,
+ Subject: pkix.Name{CommonName: cn},
+ DNSNames: san,
+ ExtraExtensions: ext,
}
return x509.CreateCertificateRequest(rand.Reader, req, key)
}
@@ -885,12 +1059,12 @@ func parsePrivateKey(der []byte) (crypto.Signer, error) {
return nil, errors.New("acme/autocert: failed to parse private key")
}
-// validCert parses a cert chain provided as der argument and verifies the leaf, der[0],
-// corresponds to the private key, as well as the domain match and expiration dates.
-// It doesn't do any revocation checking.
+// validCert parses a cert chain provided as der argument and verifies the leaf and der[0]
+// correspond to the private key, the domain and key type match, and expiration dates
+// are valid. It doesn't do any revocation checking.
//
// The returned value is the verified leaf cert.
-func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) {
+func validCert(ck certKey, der [][]byte, key crypto.Signer, now time.Time) (leaf *x509.Certificate, err error) {
// parse public part(s)
var n int
for _, b := range der {
@@ -902,22 +1076,21 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
n += copy(pub[n:], b)
}
x509Cert, err := x509.ParseCertificates(pub)
- if len(x509Cert) == 0 {
+ if err != nil || len(x509Cert) == 0 {
return nil, errors.New("acme/autocert: no public key found")
}
// verify the leaf is not expired and matches the domain name
leaf = x509Cert[0]
- now := timeNow()
if now.Before(leaf.NotBefore) {
return nil, errors.New("acme/autocert: certificate is not valid yet")
}
if now.After(leaf.NotAfter) {
return nil, errors.New("acme/autocert: expired certificate")
}
- if err := leaf.VerifyHostname(domain); err != nil {
+ if err := leaf.VerifyHostname(ck.domain); err != nil {
return nil, err
}
- // ensure the leaf corresponds to the private key
+ // ensure the leaf corresponds to the private key and matches the certKey type
switch pub := leaf.PublicKey.(type) {
case *rsa.PublicKey:
prv, ok := key.(*rsa.PrivateKey)
@@ -927,6 +1100,9 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
if pub.N.Cmp(prv.N) != 0 {
return nil, errors.New("acme/autocert: private key does not match public key")
}
+ if !ck.isRSA && !ck.isToken {
+ return nil, errors.New("acme/autocert: key type does not match expected value")
+ }
case *ecdsa.PublicKey:
prv, ok := key.(*ecdsa.PrivateKey)
if !ok {
@@ -935,6 +1111,9 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 {
return nil, errors.New("acme/autocert: private key does not match public key")
}
+ if ck.isRSA && !ck.isToken {
+ return nil, errors.New("acme/autocert: key type does not match expected value")
+ }
default:
return nil, errors.New("acme/autocert: unknown public key algorithm")
}
@@ -955,8 +1134,6 @@ func (r *lockedMathRand) int63n(max int64) int64 {
// For easier testing.
var (
- timeNow = time.Now
-
// Called when a state is removed.
- testDidRemoveState = func(domain string) {}
+ testDidRemoveState = func(certKey) {}
)
diff --git a/vendor/golang.org/x/crypto/acme/autocert/cache.go b/vendor/golang.org/x/crypto/acme/autocert/cache.go
index 61a5fd23..aa9aa845 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/cache.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/cache.go
@@ -16,10 +16,10 @@ import (
var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
// Cache is used by Manager to store and retrieve previously obtained certificates
-// as opaque data.
+// and other account data as opaque blobs.
//
-// The key argument of the methods refers to a domain name but need not be an FQDN.
-// Cache implementations should not rely on the key naming pattern.
+// Cache implementations should not rely on the key naming pattern. Keys can
+// include any printable ASCII characters, except the following: \/:*?"<>|
type Cache interface {
// Get returns a certificate data for the specified key.
// If there's no such key, Get returns ErrCacheMiss.
diff --git a/vendor/golang.org/x/crypto/acme/autocert/listener.go b/vendor/golang.org/x/crypto/acme/autocert/listener.go
index d744df0e..1e069818 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/listener.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/listener.go
@@ -72,11 +72,8 @@ func NewListener(domains ...string) net.Listener {
// the Manager m's Prompt, Cache, HostPolicy, and other desired options.
func (m *Manager) Listener() net.Listener {
ln := &listener{
- m: m,
- conf: &tls.Config{
- GetCertificate: m.GetCertificate, // bonus: panic on nil m
- NextProtos: []string{"h2", "http/1.1"}, // Enable HTTP/2
- },
+ m: m,
+ conf: m.TLSConfig(),
}
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
return ln
diff --git a/vendor/golang.org/x/crypto/acme/autocert/renewal.go b/vendor/golang.org/x/crypto/acme/autocert/renewal.go
index 6c5da2bc..665f870d 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/renewal.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/renewal.go
@@ -17,9 +17,9 @@ const renewJitter = time.Hour
// domainRenewal tracks the state used by the periodic timers
// renewing a single domain's cert.
type domainRenewal struct {
- m *Manager
- domain string
- key crypto.Signer
+ m *Manager
+ ck certKey
+ key crypto.Signer
timerMu sync.Mutex
timer *time.Timer
@@ -71,25 +71,43 @@ func (dr *domainRenewal) renew() {
testDidRenewLoop(next, err)
}
+// updateState locks and replaces the relevant Manager.state item with the given
+// state. It additionally updates dr.key with the given state's key.
+func (dr *domainRenewal) updateState(state *certState) {
+ dr.m.stateMu.Lock()
+ defer dr.m.stateMu.Unlock()
+ dr.key = state.key
+ dr.m.state[dr.ck] = state
+}
+
// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
// Instead, it requests a new certificate independently and, upon success,
// replaces dr.m.state item with a new one and updates cache for the given domain.
//
-// It may return immediately if the expiration date of the currently cached cert
-// is far enough in the future.
+// It may lock and update the Manager.state if the expiration date of the currently
+// cached cert is far enough in the future.
//
// The returned value is a time interval after which the renewal should occur again.
func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
// a race is likely unavoidable in a distributed environment
// but we try nonetheless
- if tlscert, err := dr.m.cacheGet(ctx, dr.domain); err == nil {
+ if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil {
next := dr.next(tlscert.Leaf.NotAfter)
if next > dr.m.renewBefore()+renewJitter {
- return next, nil
+ signer, ok := tlscert.PrivateKey.(crypto.Signer)
+ if ok {
+ state := &certState{
+ key: signer,
+ cert: tlscert.Certificate,
+ leaf: tlscert.Leaf,
+ }
+ dr.updateState(state)
+ return next, nil
+ }
}
}
- der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.domain)
+ der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck)
if err != nil {
return 0, err
}
@@ -102,16 +120,15 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
if err != nil {
return 0, err
}
- dr.m.cachePut(ctx, dr.domain, tlscert)
- dr.m.stateMu.Lock()
- defer dr.m.stateMu.Unlock()
- // m.state is guaranteed to be non-nil at this point
- dr.m.state[dr.domain] = state
+ if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil {
+ return 0, err
+ }
+ dr.updateState(state)
return dr.next(leaf.NotAfter), nil
}
func (dr *domainRenewal) next(expiry time.Time) time.Duration {
- d := expiry.Sub(timeNow()) - dr.m.renewBefore()
+ d := expiry.Sub(dr.m.now()) - dr.m.renewBefore()
// add a bit of randomness to renew deadline
n := pseudoRand.int63n(int64(renewJitter))
d -= time.Duration(n)
diff --git a/vendor/golang.org/x/crypto/acme/http.go b/vendor/golang.org/x/crypto/acme/http.go
new file mode 100644
index 00000000..a43ce6a5
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/http.go
@@ -0,0 +1,281 @@
+// 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.
+
+package acme
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/rand"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "math/big"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// retryTimer encapsulates common logic for retrying unsuccessful requests.
+// It is not safe for concurrent use.
+type retryTimer struct {
+ // backoffFn provides backoff delay sequence for retries.
+ // See Client.RetryBackoff doc comment.
+ backoffFn func(n int, r *http.Request, res *http.Response) time.Duration
+ // n is the current retry attempt.
+ n int
+}
+
+func (t *retryTimer) inc() {
+ t.n++
+}
+
+// backoff pauses the current goroutine as described in Client.RetryBackoff.
+func (t *retryTimer) backoff(ctx context.Context, r *http.Request, res *http.Response) error {
+ d := t.backoffFn(t.n, r, res)
+ if d <= 0 {
+ return fmt.Errorf("acme: no more retries for %s; tried %d time(s)", r.URL, t.n)
+ }
+ wakeup := time.NewTimer(d)
+ defer wakeup.Stop()
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-wakeup.C:
+ return nil
+ }
+}
+
+func (c *Client) retryTimer() *retryTimer {
+ f := c.RetryBackoff
+ if f == nil {
+ f = defaultBackoff
+ }
+ return &retryTimer{backoffFn: f}
+}
+
+// defaultBackoff provides default Client.RetryBackoff implementation
+// using a truncated exponential backoff algorithm,
+// as described in Client.RetryBackoff.
+//
+// The n argument is always bounded between 1 and 30.
+// The returned value is always greater than 0.
+func defaultBackoff(n int, r *http.Request, res *http.Response) time.Duration {
+ const max = 10 * time.Second
+ var jitter time.Duration
+ if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
+ // Set the minimum to 1ms to avoid a case where
+ // an invalid Retry-After value is parsed into 0 below,
+ // resulting in the 0 returned value which would unintentionally
+ // stop the retries.
+ jitter = (1 + time.Duration(x.Int64())) * time.Millisecond
+ }
+ if v, ok := res.Header["Retry-After"]; ok {
+ return retryAfter(v[0]) + jitter
+ }
+
+ if n < 1 {
+ n = 1
+ }
+ if n > 30 {
+ n = 30
+ }
+ d := time.Duration(1<<uint(n-1))*time.Second + jitter
+ if d > max {
+ return max
+ }
+ return d
+}
+
+// retryAfter parses a Retry-After HTTP header value,
+// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
+// It returns zero value if v cannot be parsed.
+func retryAfter(v string) time.Duration {
+ if i, err := strconv.Atoi(v); err == nil {
+ return time.Duration(i) * time.Second
+ }
+ t, err := http.ParseTime(v)
+ if err != nil {
+ return 0
+ }
+ return t.Sub(timeNow())
+}
+
+// resOkay is a function that reports whether the provided response is okay.
+// It is expected to keep the response body unread.
+type resOkay func(*http.Response) bool
+
+// wantStatus returns a function which reports whether the code
+// matches the status code of a response.
+func wantStatus(codes ...int) resOkay {
+ return func(res *http.Response) bool {
+ for _, code := range codes {
+ if code == res.StatusCode {
+ return true
+ }
+ }
+ return false
+ }
+}
+
+// get issues an unsigned GET request to the specified URL.
+// It returns a non-error value only when ok reports true.
+//
+// get retries unsuccessful attempts according to c.RetryBackoff
+// until the context is done or a non-retriable error is received.
+func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Response, error) {
+ retry := c.retryTimer()
+ for {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ res, err := c.doNoRetry(ctx, req)
+ switch {
+ case err != nil:
+ return nil, err
+ case ok(res):
+ return res, nil
+ case isRetriable(res.StatusCode):
+ retry.inc()
+ resErr := responseError(res)
+ res.Body.Close()
+ // Ignore the error value from retry.backoff
+ // and return the one from last retry, as received from the CA.
+ if retry.backoff(ctx, req, res) != nil {
+ return nil, resErr
+ }
+ default:
+ defer res.Body.Close()
+ return nil, responseError(res)
+ }
+ }
+}
+
+// post issues a signed POST request in JWS format using the provided key
+// to the specified URL.
+// It returns a non-error value only when ok reports true.
+//
+// post retries unsuccessful attempts according to c.RetryBackoff
+// until the context is done or a non-retriable error is received.
+// It uses postNoRetry to make individual requests.
+func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body interface{}, ok resOkay) (*http.Response, error) {
+ retry := c.retryTimer()
+ for {
+ res, req, err := c.postNoRetry(ctx, key, url, body)
+ if err != nil {
+ return nil, err
+ }
+ if ok(res) {
+ return res, nil
+ }
+ resErr := responseError(res)
+ res.Body.Close()
+ switch {
+ // Check for bad nonce before isRetriable because it may have been returned
+ // with an unretriable response code such as 400 Bad Request.
+ case isBadNonce(resErr):
+ // Consider any previously stored nonce values to be invalid.
+ c.clearNonces()
+ case !isRetriable(res.StatusCode):
+ return nil, resErr
+ }
+ retry.inc()
+ // Ignore the error value from retry.backoff
+ // and return the one from last retry, as received from the CA.
+ if err := retry.backoff(ctx, req, res); err != nil {
+ return nil, resErr
+ }
+ }
+}
+
+// postNoRetry signs the body with the given key and POSTs it to the provided url.
+// The body argument must be JSON-serializable.
+// It is used by c.post to retry unsuccessful attempts.
+func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) {
+ nonce, err := c.popNonce(ctx, url)
+ if err != nil {
+ return nil, nil, err
+ }
+ b, err := jwsEncodeJSON(body, key, nonce)
+ if err != nil {
+ return nil, nil, err
+ }
+ req, err := http.NewRequest("POST", url, bytes.NewReader(b))
+ if err != nil {
+ return nil, nil, err
+ }
+ req.Header.Set("Content-Type", "application/jose+json")
+ res, err := c.doNoRetry(ctx, req)
+ if err != nil {
+ return nil, nil, err
+ }
+ c.addNonce(res.Header)
+ return res, req, nil
+}
+
+// doNoRetry issues a request req, replacing its context (if any) with ctx.
+func (c *Client) doNoRetry(ctx context.Context, req *http.Request) (*http.Response, error) {
+ res, err := c.httpClient().Do(req.WithContext(ctx))
+ if err != nil {
+ select {
+ case <-ctx.Done():
+ // Prefer the unadorned context error.
+ // (The acme package had tests assuming this, previously from ctxhttp's
+ // behavior, predating net/http supporting contexts natively)
+ // TODO(bradfitz): reconsider this in the future. But for now this
+ // requires no test updates.
+ return nil, ctx.Err()
+ default:
+ return nil, err
+ }
+ }
+ return res, nil
+}
+
+func (c *Client) httpClient() *http.Client {
+ if c.HTTPClient != nil {
+ return c.HTTPClient
+ }
+ return http.DefaultClient
+}
+
+// isBadNonce reports whether err is an ACME "badnonce" error.
+func isBadNonce(err error) bool {
+ // According to the spec badNonce is urn:ietf:params:acme:error:badNonce.
+ // However, ACME servers in the wild return their versions of the error.
+ // See https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4
+ // and https://github.com/letsencrypt/boulder/blob/0e07eacb/docs/acme-divergences.md#section-66.
+ ae, ok := err.(*Error)
+ return ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce")
+}
+
+// isRetriable reports whether a request can be retried
+// based on the response status code.
+//
+// Note that a "bad nonce" error is returned with a non-retriable 400 Bad Request code.
+// Callers should parse the response and check with isBadNonce.
+func isRetriable(code int) bool {
+ return code <= 399 || code >= 500 || code == http.StatusTooManyRequests
+}
+
+// responseError creates an error of Error type from resp.
+func responseError(resp *http.Response) error {
+ // don't care if ReadAll returns an error:
+ // json.Unmarshal will fail in that case anyway
+ b, _ := ioutil.ReadAll(resp.Body)
+ e := &wireError{Status: resp.StatusCode}
+ if err := json.Unmarshal(b, e); err != nil {
+ // this is not a regular error response:
+ // populate detail with anything we received,
+ // e.Status will already contain HTTP response code value
+ e.Detail = string(b)
+ if e.Detail == "" {
+ e.Detail = resp.Status
+ }
+ }
+ return e.error(resp.Header)
+}
diff --git a/vendor/golang.org/x/crypto/acme/types.go b/vendor/golang.org/x/crypto/acme/types.go
index 3e199749..54792c06 100644
--- a/vendor/golang.org/x/crypto/acme/types.go
+++ b/vendor/golang.org/x/crypto/acme/types.go
@@ -104,7 +104,7 @@ func RateLimit(err error) (time.Duration, bool) {
if e.Header == nil {
return 0, true
}
- return retryAfter(e.Header.Get("Retry-After"), 0), true
+ return retryAfter(e.Header.Get("Retry-After")), true
}
// Account is a user account. It is associated with a private key.
@@ -296,8 +296,8 @@ func (e *wireError) error(h http.Header) *Error {
}
}
-// CertOption is an optional argument type for the TLSSNIxChallengeCert methods for
-// customizing a temporary certificate for TLS-SNI challenges.
+// CertOption is an optional argument type for the TLS ChallengeCert methods for
+// customizing a temporary certificate for TLS-based challenges.
type CertOption interface {
privateCertOpt()
}
@@ -317,7 +317,7 @@ func (*certOptKey) privateCertOpt() {}
// WithTemplate creates an option for specifying a certificate template.
// See x509.CreateCertificate for template usage details.
//
-// In TLSSNIxChallengeCert methods, the template is also used as parent,
+// In TLS ChallengeCert methods, the template is also used as parent,
// resulting in a self-signed certificate.
// The DNSNames field of t is always overwritten for tls-sni challenge certs.
func WithTemplate(t *x509.Certificate) CertOption {
diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519.go b/vendor/golang.org/x/crypto/ed25519/ed25519.go
index 4f26b49b..d6f683ba 100644
--- a/vendor/golang.org/x/crypto/ed25519/ed25519.go
+++ b/vendor/golang.org/x/crypto/ed25519/ed25519.go
@@ -6,7 +6,10 @@
// https://ed25519.cr.yp.to/.
//
// These functions are also compatible with the “Ed25519” function defined in
-// RFC 8032.
+// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
+// representation includes a public key suffix to make multiple signing
+// operations with the same key more efficient. This package refers to the RFC
+// 8032 private key as the “seed”.
package ed25519
// This code is a port of the public domain, “ref10” implementation of ed25519
@@ -31,6 +34,8 @@ const (
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
SignatureSize = 64
+ // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
+ SeedSize = 32
)
// PublicKey is the type of Ed25519 public keys.
@@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.PublicKey {
return PublicKey(publicKey)
}
+// Seed returns the private key seed corresponding to priv. It is provided for
+// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
+// in this package.
+func (priv PrivateKey) Seed() []byte {
+ seed := make([]byte, SeedSize)
+ copy(seed, priv[:32])
+ return seed
+}
+
// Sign signs the given message with priv.
// Ed25519 performs two passes over messages to be signed and therefore cannot
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
@@ -61,19 +75,33 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
-func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
+func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
if rand == nil {
rand = cryptorand.Reader
}
- privateKey = make([]byte, PrivateKeySize)
- publicKey = make([]byte, PublicKeySize)
- _, err = io.ReadFull(rand, privateKey[:32])
- if err != nil {
+ seed := make([]byte, SeedSize)
+ if _, err := io.ReadFull(rand, seed); err != nil {
return nil, nil, err
}
- digest := sha512.Sum512(privateKey[:32])
+ privateKey := NewKeyFromSeed(seed)
+ publicKey := make([]byte, PublicKeySize)
+ copy(publicKey, privateKey[32:])
+
+ return publicKey, privateKey, nil
+}
+
+// NewKeyFromSeed calculates a private key from a seed. It will panic if
+// len(seed) is not SeedSize. This function is provided for interoperability
+// with RFC 8032. RFC 8032's private keys correspond to seeds in this
+// package.
+func NewKeyFromSeed(seed []byte) PrivateKey {
+ if l := len(seed); l != SeedSize {
+ panic("ed25519: bad seed length: " + strconv.Itoa(l))
+ }
+
+ digest := sha512.Sum512(seed)
digest[0] &= 248
digest[31] &= 127
digest[31] |= 64
@@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er
var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes)
+ privateKey := make([]byte, PrivateKeySize)
+ copy(privateKey, seed)
copy(privateKey[32:], publicKeyBytes[:])
- copy(publicKey, publicKeyBytes[:])
- return publicKey, privateKey, nil
+ return privateKey
}
// Sign signs the message with privateKey and returns a signature. It will
@@ -171,9 +200,16 @@ func Verify(publicKey PublicKey, message, sig []byte) bool {
edwards25519.ScReduce(&hReduced, &digest)
var R edwards25519.ProjectiveGroupElement
- var b [32]byte
- copy(b[:], sig[32:])
- edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b)
+ var s [32]byte
+ copy(s[:], sig[32:])
+
+ // https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
+ // the range [0, order) in order to prevent signature malleability.
+ if !edwards25519.ScMinimal(&s) {
+ return false
+ }
+
+ edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s)
var checkR [32]byte
R.ToBytes(&checkR)
diff --git a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
index 5f8b9947..fd03c252 100644
--- a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
+++ b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
@@ -4,6 +4,8 @@
package edwards25519
+import "encoding/binary"
+
// This code is a port of the public domain, “ref10” implementation of ed25519
// from SUPERCOP.
@@ -1769,3 +1771,23 @@ func ScReduce(out *[32]byte, s *[64]byte) {
out[30] = byte(s11 >> 9)
out[31] = byte(s11 >> 17)
}
+
+// order is the order of Curve25519 in little-endian form.
+var order = [4]uint64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0, 0x1000000000000000}
+
+// ScMinimal returns true if the given scalar is less than the order of the
+// curve.
+func ScMinimal(scalar *[32]byte) bool {
+ for i := 3; ; i-- {
+ v := binary.LittleEndian.Uint64(scalar[i*8:])
+ if v > order[i] {
+ return false
+ } else if v < order[i] {
+ break
+ } else if i == 0 {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
index 0f8efdba..6570847f 100644
--- a/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
+++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
@@ -2,197 +2,263 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package ChaCha20 implements the core ChaCha20 function as specified in https://tools.ietf.org/html/rfc7539#section-2.3.
+// Package ChaCha20 implements the core ChaCha20 function as specified
+// in https://tools.ietf.org/html/rfc7539#section-2.3.
package chacha20
-import "encoding/binary"
-
-const rounds = 20
-
-// core applies the ChaCha20 core function to 16-byte input in, 32-byte key k,
-// and 16-byte constant c, and puts the result into 64-byte array out.
-func core(out *[64]byte, in *[16]byte, k *[32]byte) {
- j0 := uint32(0x61707865)
- j1 := uint32(0x3320646e)
- j2 := uint32(0x79622d32)
- j3 := uint32(0x6b206574)
- j4 := binary.LittleEndian.Uint32(k[0:4])
- j5 := binary.LittleEndian.Uint32(k[4:8])
- j6 := binary.LittleEndian.Uint32(k[8:12])
- j7 := binary.LittleEndian.Uint32(k[12:16])
- j8 := binary.LittleEndian.Uint32(k[16:20])
- j9 := binary.LittleEndian.Uint32(k[20:24])
- j10 := binary.LittleEndian.Uint32(k[24:28])
- j11 := binary.LittleEndian.Uint32(k[28:32])
- j12 := binary.LittleEndian.Uint32(in[0:4])
- j13 := binary.LittleEndian.Uint32(in[4:8])
- j14 := binary.LittleEndian.Uint32(in[8:12])
- j15 := binary.LittleEndian.Uint32(in[12:16])
-
- x0, x1, x2, x3, x4, x5, x6, x7 := j0, j1, j2, j3, j4, j5, j6, j7
- x8, x9, x10, x11, x12, x13, x14, x15 := j8, j9, j10, j11, j12, j13, j14, j15
-
- for i := 0; i < rounds; i += 2 {
- x0 += x4
- x12 ^= x0
- x12 = (x12 << 16) | (x12 >> (16))
- x8 += x12
- x4 ^= x8
- x4 = (x4 << 12) | (x4 >> (20))
- x0 += x4
- x12 ^= x0
- x12 = (x12 << 8) | (x12 >> (24))
- x8 += x12
- x4 ^= x8
- x4 = (x4 << 7) | (x4 >> (25))
- x1 += x5
- x13 ^= x1
- x13 = (x13 << 16) | (x13 >> 16)
- x9 += x13
- x5 ^= x9
- x5 = (x5 << 12) | (x5 >> 20)
- x1 += x5
- x13 ^= x1
- x13 = (x13 << 8) | (x13 >> 24)
- x9 += x13
- x5 ^= x9
- x5 = (x5 << 7) | (x5 >> 25)
- x2 += x6
- x14 ^= x2
- x14 = (x14 << 16) | (x14 >> 16)
- x10 += x14
- x6 ^= x10
- x6 = (x6 << 12) | (x6 >> 20)
- x2 += x6
- x14 ^= x2
- x14 = (x14 << 8) | (x14 >> 24)
- x10 += x14
- x6 ^= x10
- x6 = (x6 << 7) | (x6 >> 25)
- x3 += x7
- x15 ^= x3
- x15 = (x15 << 16) | (x15 >> 16)
- x11 += x15
- x7 ^= x11
- x7 = (x7 << 12) | (x7 >> 20)
- x3 += x7
- x15 ^= x3
- x15 = (x15 << 8) | (x15 >> 24)
- x11 += x15
- x7 ^= x11
- x7 = (x7 << 7) | (x7 >> 25)
- x0 += x5
- x15 ^= x0
- x15 = (x15 << 16) | (x15 >> 16)
- x10 += x15
- x5 ^= x10
- x5 = (x5 << 12) | (x5 >> 20)
- x0 += x5
- x15 ^= x0
- x15 = (x15 << 8) | (x15 >> 24)
- x10 += x15
- x5 ^= x10
- x5 = (x5 << 7) | (x5 >> 25)
- x1 += x6
- x12 ^= x1
- x12 = (x12 << 16) | (x12 >> 16)
- x11 += x12
- x6 ^= x11
- x6 = (x6 << 12) | (x6 >> 20)
- x1 += x6
- x12 ^= x1
- x12 = (x12 << 8) | (x12 >> 24)
- x11 += x12
- x6 ^= x11
- x6 = (x6 << 7) | (x6 >> 25)
- x2 += x7
- x13 ^= x2
- x13 = (x13 << 16) | (x13 >> 16)
- x8 += x13
- x7 ^= x8
- x7 = (x7 << 12) | (x7 >> 20)
- x2 += x7
- x13 ^= x2
- x13 = (x13 << 8) | (x13 >> 24)
- x8 += x13
- x7 ^= x8
- x7 = (x7 << 7) | (x7 >> 25)
- x3 += x4
- x14 ^= x3
- x14 = (x14 << 16) | (x14 >> 16)
- x9 += x14
- x4 ^= x9
- x4 = (x4 << 12) | (x4 >> 20)
- x3 += x4
- x14 ^= x3
- x14 = (x14 << 8) | (x14 >> 24)
- x9 += x14
- x4 ^= x9
- x4 = (x4 << 7) | (x4 >> 25)
+import (
+ "crypto/cipher"
+ "encoding/binary"
+
+ "golang.org/x/crypto/internal/subtle"
+)
+
+// assert that *Cipher implements cipher.Stream
+var _ cipher.Stream = (*Cipher)(nil)
+
+// Cipher is a stateful instance of ChaCha20 using a particular key
+// and nonce. A *Cipher implements the cipher.Stream interface.
+type Cipher struct {
+ key [8]uint32
+ counter uint32 // incremented after each block
+ nonce [3]uint32
+ buf [bufSize]byte // buffer for unused keystream bytes
+ len int // number of unused keystream bytes at end of buf
+}
+
+// New creates a new ChaCha20 stream cipher with the given key and nonce.
+// The initial counter value is set to 0.
+func New(key [8]uint32, nonce [3]uint32) *Cipher {
+ return &Cipher{key: key, nonce: nonce}
+}
+
+// ChaCha20 constants spelling "expand 32-byte k"
+const (
+ j0 uint32 = 0x61707865
+ j1 uint32 = 0x3320646e
+ j2 uint32 = 0x79622d32
+ j3 uint32 = 0x6b206574
+)
+
+func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
+ a += b
+ d ^= a
+ d = (d << 16) | (d >> 16)
+ c += d
+ b ^= c
+ b = (b << 12) | (b >> 20)
+ a += b
+ d ^= a
+ d = (d << 8) | (d >> 24)
+ c += d
+ b ^= c
+ b = (b << 7) | (b >> 25)
+ return a, b, c, d
+}
+
+// XORKeyStream XORs each byte in the given slice with a byte from the
+// cipher's key stream. Dst and src must overlap entirely or not at all.
+//
+// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
+// to pass a dst bigger than src, and in that case, XORKeyStream will
+// only update dst[:len(src)] and will not touch the rest of dst.
+//
+// Multiple calls to XORKeyStream behave as if the concatenation of
+// the src buffers was passed in a single run. That is, Cipher
+// maintains state and does not reset at each XORKeyStream call.
+func (s *Cipher) XORKeyStream(dst, src []byte) {
+ if len(dst) < len(src) {
+ panic("chacha20: output smaller than input")
+ }
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("chacha20: invalid buffer overlap")
+ }
+
+ // xor src with buffered keystream first
+ if s.len != 0 {
+ buf := s.buf[len(s.buf)-s.len:]
+ if len(src) < len(buf) {
+ buf = buf[:len(src)]
+ }
+ td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
+ for i, b := range buf {
+ td[i] = ts[i] ^ b
+ }
+ s.len -= len(buf)
+ if s.len != 0 {
+ return
+ }
+ s.buf = [len(s.buf)]byte{} // zero the empty buffer
+ src = src[len(buf):]
+ dst = dst[len(buf):]
+ }
+
+ if len(src) == 0 {
+ return
}
+ if haveAsm {
+ if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
+ panic("chacha20: counter overflow")
+ }
+ s.xorKeyStreamAsm(dst, src)
+ return
+ }
+
+ // set up a 64-byte buffer to pad out the final block if needed
+ // (hoisted out of the main loop to avoid spills)
+ rem := len(src) % 64 // length of final block
+ fin := len(src) - rem // index of final block
+ if rem > 0 {
+ copy(s.buf[len(s.buf)-64:], src[fin:])
+ }
+
+ // pre-calculate most of the first round
+ s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0])
+ s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1])
+ s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2])
+
+ n := len(src)
+ src, dst = src[:n:n], dst[:n:n] // BCE hint
+ for i := 0; i < n; i += 64 {
+ // calculate the remainder of the first round
+ s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter)
- x0 += j0
- x1 += j1
- x2 += j2
- x3 += j3
- x4 += j4
- x5 += j5
- x6 += j6
- x7 += j7
- x8 += j8
- x9 += j9
- x10 += j10
- x11 += j11
- x12 += j12
- x13 += j13
- x14 += j14
- x15 += j15
-
- binary.LittleEndian.PutUint32(out[0:4], x0)
- binary.LittleEndian.PutUint32(out[4:8], x1)
- binary.LittleEndian.PutUint32(out[8:12], x2)
- binary.LittleEndian.PutUint32(out[12:16], x3)
- binary.LittleEndian.PutUint32(out[16:20], x4)
- binary.LittleEndian.PutUint32(out[20:24], x5)
- binary.LittleEndian.PutUint32(out[24:28], x6)
- binary.LittleEndian.PutUint32(out[28:32], x7)
- binary.LittleEndian.PutUint32(out[32:36], x8)
- binary.LittleEndian.PutUint32(out[36:40], x9)
- binary.LittleEndian.PutUint32(out[40:44], x10)
- binary.LittleEndian.PutUint32(out[44:48], x11)
- binary.LittleEndian.PutUint32(out[48:52], x12)
- binary.LittleEndian.PutUint32(out[52:56], x13)
- binary.LittleEndian.PutUint32(out[56:60], x14)
- binary.LittleEndian.PutUint32(out[60:64], x15)
+ // execute the second round
+ x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15)
+ x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12)
+ x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13)
+ x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14)
+
+ // execute the remaining 18 rounds
+ for i := 0; i < 9; i++ {
+ x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
+ x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
+ x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
+ x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
+
+ x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
+ x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
+ x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
+ x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
+ }
+
+ x0 += j0
+ x1 += j1
+ x2 += j2
+ x3 += j3
+
+ x4 += s.key[0]
+ x5 += s.key[1]
+ x6 += s.key[2]
+ x7 += s.key[3]
+ x8 += s.key[4]
+ x9 += s.key[5]
+ x10 += s.key[6]
+ x11 += s.key[7]
+
+ x12 += s.counter
+ x13 += s.nonce[0]
+ x14 += s.nonce[1]
+ x15 += s.nonce[2]
+
+ // increment the counter
+ s.counter += 1
+ if s.counter == 0 {
+ panic("chacha20: counter overflow")
+ }
+
+ // pad to 64 bytes if needed
+ in, out := src[i:], dst[i:]
+ if i == fin {
+ // src[fin:] has already been copied into s.buf before
+ // the main loop
+ in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
+ }
+ in, out = in[:64], out[:64] // BCE 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)
+ }
+ // copy any trailing bytes out of the buffer and into dst
+ if rem != 0 {
+ s.len = 64 - rem
+ copy(dst[fin:], s.buf[len(s.buf)-64:])
+ }
+}
+
+// Advance discards bytes in the key stream until the next 64 byte block
+// boundary is reached and updates the counter accordingly. If the key
+// stream is already at a block boundary no bytes will be discarded and
+// the counter will be unchanged.
+func (s *Cipher) Advance() {
+ s.len -= s.len % 64
+ if s.len == 0 {
+ s.buf = [len(s.buf)]byte{}
+ }
}
// XORKeyStream crypts bytes from in to out using the given key and counters.
// In and out must overlap entirely or not at all. Counter contains the raw
// ChaCha20 counter bytes (i.e. block counter followed by nonce).
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
- var block [64]byte
- var counterCopy [16]byte
- copy(counterCopy[:], counter[:])
-
- for len(in) >= 64 {
- core(&block, &counterCopy, key)
- for i, x := range block {
- out[i] = in[i] ^ x
- }
- u := uint32(1)
- for i := 0; i < 4; i++ {
- u += uint32(counterCopy[i])
- counterCopy[i] = byte(u)
- u >>= 8
- }
- in = in[64:]
- out = out[64:]
+ s := Cipher{
+ key: [8]uint32{
+ binary.LittleEndian.Uint32(key[0:4]),
+ binary.LittleEndian.Uint32(key[4:8]),
+ binary.LittleEndian.Uint32(key[8:12]),
+ binary.LittleEndian.Uint32(key[12:16]),
+ binary.LittleEndian.Uint32(key[16:20]),
+ binary.LittleEndian.Uint32(key[20:24]),
+ binary.LittleEndian.Uint32(key[24:28]),
+ binary.LittleEndian.Uint32(key[28:32]),
+ },
+ nonce: [3]uint32{
+ binary.LittleEndian.Uint32(counter[4:8]),
+ binary.LittleEndian.Uint32(counter[8:12]),
+ binary.LittleEndian.Uint32(counter[12:16]),
+ },
+ counter: binary.LittleEndian.Uint32(counter[0:4]),
}
+ s.XORKeyStream(out, in)
+}
- if len(in) > 0 {
- core(&block, &counterCopy, key)
- for i, v := range in {
- out[i] = v ^ block[i]
- }
+// HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
+// nonce. It should only be used as part of the XChaCha20 construction.
+func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 {
+ x0, x1, x2, x3 := j0, j1, j2, j3
+ x4, x5, x6, x7 := key[0], key[1], key[2], key[3]
+ x8, x9, x10, x11 := key[4], key[5], key[6], key[7]
+ x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3]
+
+ for i := 0; i < 10; i++ {
+ x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
+ x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
+ x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
+ x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
+
+ x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
+ x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
+ x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
+ x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
}
+
+ var out [8]uint32
+ out[0], out[1], out[2], out[3] = x0, x1, x2, x3
+ out[4], out[5], out[6], out[7] = x12, x13, x14, x15
+ return out
}
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
new file mode 100644
index 00000000..91520d1d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
@@ -0,0 +1,16 @@
+// 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 gccgo appengine
+
+package chacha20
+
+const (
+ bufSize = 64
+ haveAsm = false
+)
+
+func (*Cipher) xorKeyStreamAsm(dst, src []byte) {
+ panic("not implemented")
+}
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
new file mode 100644
index 00000000..0c1c671c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
@@ -0,0 +1,30 @@
+// 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,!gccgo,!appengine
+
+package chacha20
+
+var haveAsm = hasVectorFacility()
+
+const bufSize = 256
+
+// hasVectorFacility reports whether the machine supports the vector
+// facility (vx).
+// Implementation in asm_s390x.s.
+func hasVectorFacility() bool
+
+// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
+// be called when the vector facility is available.
+// Implementation in asm_s390x.s.
+//go:noescape
+func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int)
+
+func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
+ xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter, &c.buf, &c.len)
+}
+
+// EXRL targets, DO NOT CALL!
+func mvcSrcToBuf()
+func mvcBufToDst()
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
new file mode 100644
index 00000000..98427c5e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
@@ -0,0 +1,283 @@
+// 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,!gccgo,!appengine
+
+#include "go_asm.h"
+#include "textflag.h"
+
+// This is an implementation of the ChaCha20 encryption algorithm as
+// specified in RFC 7539. It uses vector instructions to compute
+// 4 keystream blocks in parallel (256 bytes) which are then XORed
+// with the bytes in the input slice.
+
+GLOBL ·constants<>(SB), RODATA|NOPTR, $32
+// BSWAP: swap bytes in each 4-byte element
+DATA ·constants<>+0x00(SB)/4, $0x03020100
+DATA ·constants<>+0x04(SB)/4, $0x07060504
+DATA ·constants<>+0x08(SB)/4, $0x0b0a0908
+DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c
+// J0: [j0, j1, j2, j3]
+DATA ·constants<>+0x10(SB)/4, $0x61707865
+DATA ·constants<>+0x14(SB)/4, $0x3320646e
+DATA ·constants<>+0x18(SB)/4, $0x79622d32
+DATA ·constants<>+0x1c(SB)/4, $0x6b206574
+
+// EXRL targets:
+TEXT ·mvcSrcToBuf(SB), NOFRAME|NOSPLIT, $0
+ MVC $1, (R1), (R8)
+ RET
+
+TEXT ·mvcBufToDst(SB), NOFRAME|NOSPLIT, $0
+ MVC $1, (R8), (R9)
+ RET
+
+#define BSWAP V5
+#define J0 V6
+#define KEY0 V7
+#define KEY1 V8
+#define NONCE V9
+#define CTR V10
+#define M0 V11
+#define M1 V12
+#define M2 V13
+#define M3 V14
+#define INC V15
+#define X0 V16
+#define X1 V17
+#define X2 V18
+#define X3 V19
+#define X4 V20
+#define X5 V21
+#define X6 V22
+#define X7 V23
+#define X8 V24
+#define X9 V25
+#define X10 V26
+#define X11 V27
+#define X12 V28
+#define X13 V29
+#define X14 V30
+#define X15 V31
+
+#define NUM_ROUNDS 20
+
+#define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \
+ VAF a1, a0, a0 \
+ VAF b1, b0, b0 \
+ VAF c1, c0, c0 \
+ VAF d1, d0, d0 \
+ VX a0, a2, a2 \
+ VX b0, b2, b2 \
+ VX c0, c2, c2 \
+ VX d0, d2, d2 \
+ VERLLF $16, a2, a2 \
+ VERLLF $16, b2, b2 \
+ VERLLF $16, c2, c2 \
+ VERLLF $16, d2, d2 \
+ VAF a2, a3, a3 \
+ VAF b2, b3, b3 \
+ VAF c2, c3, c3 \
+ VAF d2, d3, d3 \
+ VX a3, a1, a1 \
+ VX b3, b1, b1 \
+ VX c3, c1, c1 \
+ VX d3, d1, d1 \
+ VERLLF $12, a1, a1 \
+ VERLLF $12, b1, b1 \
+ VERLLF $12, c1, c1 \
+ VERLLF $12, d1, d1 \
+ VAF a1, a0, a0 \
+ VAF b1, b0, b0 \
+ VAF c1, c0, c0 \
+ VAF d1, d0, d0 \
+ VX a0, a2, a2 \
+ VX b0, b2, b2 \
+ VX c0, c2, c2 \
+ VX d0, d2, d2 \
+ VERLLF $8, a2, a2 \
+ VERLLF $8, b2, b2 \
+ VERLLF $8, c2, c2 \
+ VERLLF $8, d2, d2 \
+ VAF a2, a3, a3 \
+ VAF b2, b3, b3 \
+ VAF c2, c3, c3 \
+ VAF d2, d3, d3 \
+ VX a3, a1, a1 \
+ VX b3, b1, b1 \
+ VX c3, c1, c1 \
+ VX d3, d1, d1 \
+ VERLLF $7, a1, a1 \
+ VERLLF $7, b1, b1 \
+ VERLLF $7, c1, c1 \
+ VERLLF $7, d1, d1
+
+#define PERMUTE(mask, v0, v1, v2, v3) \
+ VPERM v0, v0, mask, v0 \
+ VPERM v1, v1, mask, v1 \
+ VPERM v2, v2, mask, v2 \
+ VPERM v3, v3, mask, v3
+
+#define ADDV(x, v0, v1, v2, v3) \
+ VAF x, v0, v0 \
+ VAF x, v1, v1 \
+ VAF x, v2, v2 \
+ VAF x, v3, v3
+
+#define XORV(off, dst, src, v0, v1, v2, v3) \
+ VLM off(src), M0, M3 \
+ PERMUTE(BSWAP, v0, v1, v2, v3) \
+ VX v0, M0, M0 \
+ VX v1, M1, M1 \
+ VX v2, M2, M2 \
+ VX v3, M3, M3 \
+ VSTM M0, M3, off(dst)
+
+#define SHUFFLE(a, b, c, d, t, u, v, w) \
+ VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]}
+ VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]}
+ VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]}
+ VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]}
+ VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]}
+ VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]}
+ VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]}
+ VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]}
+
+// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int)
+TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
+ MOVD $·constants<>(SB), R1
+ MOVD dst+0(FP), R2 // R2=&dst[0]
+ LMG src+24(FP), R3, R4 // R3=&src[0] R4=len(src)
+ MOVD key+48(FP), R5 // R5=key
+ MOVD nonce+56(FP), R6 // R6=nonce
+ MOVD counter+64(FP), R7 // R7=counter
+ MOVD buf+72(FP), R8 // R8=buf
+ MOVD len+80(FP), R9 // R9=len
+
+ // load BSWAP and J0
+ VLM (R1), BSWAP, J0
+
+ // set up tail buffer
+ ADD $-1, R4, R12
+ MOVBZ R12, R12
+ CMPUBEQ R12, $255, aligned
+ MOVD R4, R1
+ AND $~255, R1
+ MOVD $(R3)(R1*1), R1
+ EXRL $·mvcSrcToBuf(SB), R12
+ MOVD $255, R0
+ SUB R12, R0
+ MOVD R0, (R9) // update len
+
+aligned:
+ // setup
+ MOVD $95, R0
+ VLM (R5), KEY0, KEY1
+ VLL R0, (R6), NONCE
+ VZERO M0
+ VLEIB $7, $32, M0
+ VSRLB M0, NONCE, NONCE
+
+ // initialize counter values
+ VLREPF (R7), CTR
+ VZERO INC
+ VLEIF $1, $1, INC
+ VLEIF $2, $2, INC
+ VLEIF $3, $3, INC
+ VAF INC, CTR, CTR
+ VREPIF $4, INC
+
+chacha:
+ VREPF $0, J0, X0
+ VREPF $1, J0, X1
+ VREPF $2, J0, X2
+ VREPF $3, J0, X3
+ VREPF $0, KEY0, X4
+ VREPF $1, KEY0, X5
+ VREPF $2, KEY0, X6
+ VREPF $3, KEY0, X7
+ VREPF $0, KEY1, X8
+ VREPF $1, KEY1, X9
+ VREPF $2, KEY1, X10
+ VREPF $3, KEY1, X11
+ VLR CTR, X12
+ VREPF $1, NONCE, X13
+ VREPF $2, NONCE, X14
+ VREPF $3, NONCE, X15
+
+ MOVD $(NUM_ROUNDS/2), R1
+
+loop:
+ ROUND4(X0, X4, X12, X8, X1, X5, X13, X9, X2, X6, X14, X10, X3, X7, X15, X11)
+ ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8, X3, X4, X14, X9)
+
+ ADD $-1, R1
+ BNE loop
+
+ // decrement length
+ ADD $-256, R4
+ BLT tail
+
+continue:
+ // rearrange vectors
+ SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3)
+ ADDV(J0, X0, X1, X2, X3)
+ SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3)
+ ADDV(KEY0, X4, X5, X6, X7)
+ SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3)
+ ADDV(KEY1, X8, X9, X10, X11)
+ VAF CTR, X12, X12
+ SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3)
+ ADDV(NONCE, X12, X13, X14, X15)
+
+ // increment counters
+ VAF INC, CTR, CTR
+
+ // xor keystream with plaintext
+ XORV(0*64, R2, R3, X0, X4, X8, X12)
+ XORV(1*64, R2, R3, X1, X5, X9, X13)
+ XORV(2*64, R2, R3, X2, X6, X10, X14)
+ XORV(3*64, R2, R3, X3, X7, X11, X15)
+
+ // increment pointers
+ MOVD $256(R2), R2
+ MOVD $256(R3), R3
+
+ CMPBNE R4, $0, chacha
+ CMPUBEQ R12, $255, return
+ EXRL $·mvcBufToDst(SB), R12 // len was updated during setup
+
+return:
+ VSTEF $0, CTR, (R7)
+ RET
+
+tail:
+ MOVD R2, R9
+ MOVD R8, R2
+ MOVD R8, R3
+ MOVD $0, R4
+ JMP continue
+
+// func hasVectorFacility() bool
+TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1
+ MOVD $x-24(SP), R1
+ XC $24, 0(R1), 0(R1) // clear the storage
+ MOVD $2, R0 // R0 is the number of double words stored -1
+ WORD $0xB2B01000 // STFLE 0(R1)
+ XOR R0, R0 // reset the value of R0
+ MOVBZ z-8(SP), R1
+ AND $0x40, R1
+ BEQ novector
+
+vectorinstalled:
+ // check if the vector instruction has been enabled
+ VLEIB $0, $0xF, V16
+ VLGVB $0, V16, R1
+ CMPBNE R1, $0xF, novector
+ MOVB $1, ret+0(FP) // have vx
+ RET
+
+novector:
+ MOVB $0, ret+0(FP) // no vx
+ RET
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/xor.go b/vendor/golang.org/x/crypto/internal/chacha20/xor.go
new file mode 100644
index 00000000..9c5ba0b3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/chacha20/xor.go
@@ -0,0 +1,43 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found src the LICENSE file.
+
+package chacha20
+
+import (
+ "runtime"
+)
+
+// Platforms that have fast unaligned 32-bit little endian accesses.
+const unaligned = runtime.GOARCH == "386" ||
+ runtime.GOARCH == "amd64" ||
+ runtime.GOARCH == "arm64" ||
+ runtime.GOARCH == "ppc64le" ||
+ runtime.GOARCH == "s390x"
+
+// xor reads a little endian uint32 from src, XORs it with u and
+// places the result in little endian byte order in dst.
+func xor(dst, src []byte, u uint32) {
+ _, _ = src[3], dst[3] // eliminate bounds checks
+ if unaligned {
+ // The compiler should optimize this code into
+ // 32-bit unaligned little endian loads and stores.
+ // TODO: delete once the compiler does a reliably
+ // good job with the generic code below.
+ // See issue #25111 for more details.
+ v := uint32(src[0])
+ v |= uint32(src[1]) << 8
+ v |= uint32(src[2]) << 16
+ v |= uint32(src[3]) << 24
+ v ^= u
+ dst[0] = byte(v)
+ dst[1] = byte(v >> 8)
+ dst[2] = byte(v >> 16)
+ dst[3] = byte(v >> 24)
+ } else {
+ dst[0] = src[0] ^ byte(u)
+ dst[1] = src[1] ^ byte(u>>8)
+ dst[2] = src[2] ^ byte(u>>16)
+ dst[3] = src[3] ^ byte(u>>24)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go
new file mode 100644
index 00000000..f38797bf
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go
@@ -0,0 +1,32 @@
+// 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 !appengine
+
+// Package subtle implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+package subtle // import "golang.org/x/crypto/internal/subtle"
+
+import "unsafe"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+ uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+ if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+ return false
+ }
+ return AnyOverlap(x, y)
+}
diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go
new file mode 100644
index 00000000..0cc4a8a6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go
@@ -0,0 +1,35 @@
+// 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 appengine
+
+// Package subtle implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+package subtle // import "golang.org/x/crypto/internal/subtle"
+
+// This is the Google App Engine standard variant based on reflect
+// because the unsafe package and cgo are disallowed.
+
+import "reflect"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() &&
+ reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer()
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+ if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+ return false
+ }
+ return AnyOverlap(x, y)
+}
diff --git a/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go
index 53ee83cf..a98d1bd4 100644
--- a/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go
+++ b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go
@@ -35,6 +35,7 @@ This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
package secretbox // import "golang.org/x/crypto/nacl/secretbox"
import (
+ "golang.org/x/crypto/internal/subtle"
"golang.org/x/crypto/poly1305"
"golang.org/x/crypto/salsa20/salsa"
)
@@ -87,6 +88,9 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
copy(poly1305Key[:], firstBlock[:])
ret, out := sliceForAppend(out, len(message)+poly1305.TagSize)
+ if subtle.AnyOverlap(out, message) {
+ panic("nacl: invalid buffer overlap")
+ }
// We XOR up to 32 bytes of message with the keystream generated from
// the first block.
@@ -118,7 +122,7 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
// Open authenticates and decrypts a box produced by Seal and appends the
// message to out, which must not overlap box. The output will be Overhead
// bytes smaller than box.
-func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
+func Open(out, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
if len(box) < Overhead {
return nil, false
}
@@ -143,6 +147,9 @@ func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool)
}
ret, out := sliceForAppend(out, len(box)-Overhead)
+ if subtle.AnyOverlap(out, box) {
+ panic("nacl: invalid buffer overlap")
+ }
// We XOR up to 32 bytes of box with the keystream generated from
// the first block.
diff --git a/vendor/golang.org/x/crypto/poly1305/sum_noasm.go b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go
new file mode 100644
index 00000000..751eec52
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go
@@ -0,0 +1,14 @@
+// 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 !arm,!amd64,!s390x gccgo appengine nacl
+
+package poly1305
+
+// Sum generates an authenticator for msg using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) {
+ sumGeneric(out, msg, key)
+}
diff --git a/vendor/golang.org/x/crypto/poly1305/sum_ref.go b/vendor/golang.org/x/crypto/poly1305/sum_ref.go
index b2805a5c..c4d59bd0 100644
--- a/vendor/golang.org/x/crypto/poly1305/sum_ref.go
+++ b/vendor/golang.org/x/crypto/poly1305/sum_ref.go
@@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!arm gccgo appengine nacl
-
package poly1305
import "encoding/binary"
-// Sum generates an authenticator for msg using a one-time key and puts the
-// 16-byte result into out. Authenticating two different messages with the same
-// key allows an attacker to forge messages at will.
-func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) {
+// sumGeneric generates an authenticator for msg using a one-time key and
+// puts the 16-byte result into out. This is the generic implementation of
+// Sum and should be called if no assembly implementation is available.
+func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
var (
h0, h1, h2, h3, h4 uint32 // the hash accumulators
r0, r1, r2, r3, r4 uint64 // the r part of the key
diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.go b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go
new file mode 100644
index 00000000..7a266cec
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go
@@ -0,0 +1,49 @@
+// 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,!gccgo,!appengine
+
+package poly1305
+
+// hasVectorFacility reports whether the machine supports
+// the vector facility (vx).
+func hasVectorFacility() bool
+
+// hasVMSLFacility reports whether the machine supports
+// Vector Multiply Sum Logical (VMSL).
+func hasVMSLFacility() bool
+
+var hasVX = hasVectorFacility()
+var hasVMSL = hasVMSLFacility()
+
+// poly1305vx is an assembly implementation of Poly1305 that uses vector
+// instructions. It must only be called if the vector facility (vx) is
+// available.
+//go:noescape
+func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
+
+// poly1305vmsl is an assembly implementation of Poly1305 that uses vector
+// instructions, including VMSL. It must only be called if the vector facility (vx) is
+// available and if VMSL is supported.
+//go:noescape
+func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ if hasVX {
+ var mPtr *byte
+ if len(m) > 0 {
+ mPtr = &m[0]
+ }
+ if hasVMSL && len(m) > 256 {
+ poly1305vmsl(out, mPtr, uint64(len(m)), key)
+ } else {
+ poly1305vx(out, mPtr, uint64(len(m)), key)
+ }
+ } else {
+ sumGeneric(out, m, key)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.s b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s
new file mode 100644
index 00000000..356c07a6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s
@@ -0,0 +1,400 @@
+// 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,!gccgo,!appengine
+
+#include "textflag.h"
+
+// Implementation of Poly1305 using the vector facility (vx).
+
+// constants
+#define MOD26 V0
+#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
+
+// key (r)
+#define R_0 V9
+#define R_1 V10
+#define R_2 V11
+#define R_3 V12
+#define R_4 V13
+#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
+#define F_0 V18
+#define F_1 V19
+#define F_2 V20
+#define F_3 V21
+#define F_4 V22
+
+// accumulator
+#define H_0 V23
+#define H_1 V24
+#define H_2 V25
+#define H_3 V26
+#define H_4 V27
+
+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, $64
+// MOD26
+DATA ·constants<>+0(SB)/8, $0x3ffffff
+DATA ·constants<>+8(SB)/8, $0x3ffffff
+// EX0
+DATA ·constants<>+16(SB)/8, $0x0006050403020100
+DATA ·constants<>+24(SB)/8, $0x1016151413121110
+// EX1
+DATA ·constants<>+32(SB)/8, $0x060c0b0a09080706
+DATA ·constants<>+40(SB)/8, $0x161c1b1a19181716
+// EX2
+DATA ·constants<>+48(SB)/8, $0x0d0d0d0d0d0f0e0d
+DATA ·constants<>+56(SB)/8, $0x1d1d1d1d1d1f1e1d
+
+// h = (f*g) % (2**130-5) [partial reduction]
+#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, g1, h1 \
+ VMLOF f0, g2, h2 \
+ VMLOF f0, g3, h3 \
+ VMLOF f0, g4, h4 \
+ VMLOF f1, g54, T_0 \
+ VMLOF f1, g0, T_1 \
+ VMLOF f1, g1, T_2 \
+ VMLOF f1, g2, T_3 \
+ VMLOF f1, g3, T_4 \
+ VMALOF f2, g53, h0, h0 \
+ VMALOF f2, g54, h1, h1 \
+ VMALOF f2, g0, h2, h2 \
+ VMALOF f2, g1, h3, h3 \
+ VMALOF f2, g2, h4, h4 \
+ 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, g1, T_4, T_4 \
+ VMALOF f4, g51, h0, h0 \
+ VMALOF f4, g52, h1, h1 \
+ VMALOF f4, g53, h2, h2 \
+ VMALOF f4, g54, h3, h3 \
+ VMALOF f4, g0, h4, h4 \
+ VAG T_0, h0, h0 \
+ VAG T_1, h1, h1 \
+ VAG T_2, h2, h2 \
+ VAG T_3, h3, h3 \
+ VAG T_4, h4, h4
+
+// carry h0->h1 h3->h4, h1->h2 h4->h0, h0->h1 h2->h3, h3->h4
+#define REDUCE(h0, h1, h2, h3, h4) \
+ VESRLG $26, h0, T_0 \
+ VESRLG $26, h3, T_1 \
+ VN MOD26, h0, h0 \
+ VN MOD26, h3, h3 \
+ VAG T_0, h1, h1 \
+ VAG T_1, h4, h4 \
+ VESRLG $26, h1, T_2 \
+ VESRLG $26, h4, T_3 \
+ VN MOD26, h1, h1 \
+ VN MOD26, h4, h4 \
+ VESLG $2, T_3, T_4 \
+ VAG T_3, T_4, T_4 \
+ VAG T_2, h2, h2 \
+ VAG T_4, h0, h0 \
+ VESRLG $26, h2, T_0 \
+ VESRLG $26, h0, T_1 \
+ VN MOD26, h2, h2 \
+ VN MOD26, h0, h0 \
+ VAG T_0, h3, h3 \
+ VAG T_1, h1, h1 \
+ VESRLG $26, h3, T_2 \
+ VN MOD26, h3, h3 \
+ VAG T_2, h4, h4
+
+// expand in0 into d[0] and in1 into d[1]
+#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, EX1, d2 \
+ VN d1, d4, d4 \
+ VESRLG $26, d0, d1 \
+ VESRLG $30, d2, d3 \
+ VESRLG $4, d2, d2 \
+ VN MOD26, d0, d0 \
+ VN MOD26, d1, d1 \
+ VN MOD26, d2, d2 \
+ VN MOD26, d3, d3
+
+// pack h4:h0 into h1:h0 (no carry)
+#define PACK(h0, h1, h2, h3, h4) \
+ VESLG $26, h1, h1 \
+ VESLG $26, h3, h3 \
+ 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
+#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
+ VLM (R5), MOD26, EX2
+
+ // setup r
+ VL (R4), T_0
+ MOVD $·keyMask<>(SB), R6
+ 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
+ VLEIG $0, $5, T_0
+ VLEIG $1, $5, T_0
+
+ // store r (for final block)
+ VMLOF T_0, R_1, R5SAVE_1
+ VMLOF T_0, R_2, R5SAVE_2
+ VMLOF T_0, R_3, R5SAVE_3
+ VMLOF T_0, R_4, R5SAVE_4
+ VLGVG $0, R_0, RSAVE_0
+ VLGVG $0, R_1, RSAVE_1
+ VLGVG $0, R_2, RSAVE_2
+ VLGVG $0, R_3, RSAVE_3
+ VLGVG $0, R_4, RSAVE_4
+
+ // skip r**2 calculation
+ CMPBLE R3, $16, skip
+
+ // calculate r**2
+ 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)
+ REDUCE(H_0, H_1, H_2, H_3, H_4)
+ VLEIG $0, $5, T_0
+ VLEIG $1, $5, T_0
+ VMLOF T_0, H_1, R5_1
+ VMLOF T_0, H_2, R5_2
+ VMLOF T_0, H_3, R5_3
+ VMLOF T_0, H_4, R5_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
+ VZERO H_0
+ VZERO H_1
+ VZERO H_2
+ VZERO H_3
+ VZERO H_4
+
+loop:
+ CMPBLE R3, $32, b2
+ VLM (R2), T_0, T_1
+ SUB $32, R3
+ MOVD $32(R2), R2
+ EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
+ VLEIB $4, $1, F_4
+ VLEIB $12, $1, F_4
+
+multiply:
+ VAG H_0, F_0, F_0
+ VAG H_1, F_1, F_1
+ VAG H_2, F_2, F_2
+ VAG H_3, F_3, F_3
+ VAG H_4, F_4, F_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)
+ REDUCE(H_0, H_1, H_2, H_3, H_4)
+ CMPBNE R3, $0, loop
+
+finish:
+ // sum vectors
+ VZERO T_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_4, T_0, H_4
+
+ // h may be >= 2*(2**130-5) so we need to reduce it again
+ REDUCE(H_0, H_1, H_2, H_3, H_4)
+
+ // carry h1->h4
+ VESRLG $26, H_1, T_1
+ VN MOD26, H_1, H_1
+ VAQ T_1, H_2, H_2
+ VESRLG $26, H_2, T_2
+ VN MOD26, H_2, H_2
+ VAQ T_2, H_3, H_3
+ VESRLG $26, H_3, T_3
+ VN MOD26, H_3, H_3
+ VAQ T_3, H_4, H_4
+
+ // h is now < 2*(2**130-5)
+ // pack h into h1 (hi) and h0 (lo)
+ PACK(H_0, H_1, H_2, H_3, H_4)
+
+ // if h > 2**130-5 then h -= 2**130-5
+ MOD(H_0, H_1, 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, H_0, H_0
+ VPERM H_0, H_0, T_1, H_0 // reverse bytes (to little)
+ VST H_0, (R1)
+
+ RET
+
+b2:
+ CMPBLE R3, $16, b1
+
+ // 2 blocks remaining
+ SUB $17, R3
+ VL (R2), T_0
+ VLL R3, 16(R2), T_1
+ 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]
+ VLVGG $1, RSAVE_0, R_0
+ VLVGG $1, RSAVE_1, R_1
+ VLVGG $1, RSAVE_2, R_2
+ VLVGG $1, RSAVE_3, R_3
+ VLVGG $1, RSAVE_4, R_4
+ VPDI $0, R5_1, R5SAVE_1, R5_1
+ VPDI $0, R5_2, R5SAVE_2, R5_2
+ VPDI $0, R5_3, R5SAVE_3, R5_3
+ VPDI $0, R5_4, R5SAVE_4, R5_4
+
+ MOVD $0, R3
+ BR multiply
+
+skip:
+ VZERO H_0
+ VZERO H_1
+ VZERO H_2
+ VZERO H_3
+ VZERO H_4
+
+ CMPBEQ R3, $0, finish
+
+b1:
+ // 1 block remaining
+ SUB $1, R3
+ VLL R3, (R2), T_0
+ ADD $1, R3
+ MOVBZ $1, R0
+ CMPBEQ R3, $16, 2(PC)
+ 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]
+ VLVGG $0, RSAVE_0, R_0
+ VLVGG $0, RSAVE_1, R_1
+ VLVGG $0, RSAVE_2, R_2
+ VLVGG $0, RSAVE_3, R_3
+ VLVGG $0, RSAVE_4, R_4
+ VPDI $0, R5SAVE_1, R5_1, R5_1
+ VPDI $0, R5SAVE_2, R5_2, R5_2
+ VPDI $0, R5SAVE_3, R5_3, R5_3
+ VPDI $0, R5SAVE_4, R5_4, R5_4
+
+ MOVD $0, R3
+ BR multiply
+
+TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1
+ MOVD $x-24(SP), R1
+ XC $24, 0(R1), 0(R1) // clear the storage
+ MOVD $2, R0 // R0 is the number of double words stored -1
+ WORD $0xB2B01000 // STFLE 0(R1)
+ XOR R0, R0 // reset the value of R0
+ MOVBZ z-8(SP), R1
+ AND $0x40, R1
+ BEQ novector
+
+vectorinstalled:
+ // check if the vector instruction has been enabled
+ VLEIB $0, $0xF, V16
+ VLGVB $0, V16, R1
+ CMPBNE R1, $0xF, novector
+ MOVB $1, ret+0(FP) // have vx
+ RET
+
+novector:
+ MOVB $0, ret+0(FP) // no vx
+ RET
diff --git a/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s b/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s
new file mode 100644
index 00000000..e548020b
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s
@@ -0,0 +1,931 @@
+// 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,!gccgo,!appengine
+
+#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
+
+TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1
+ MOVD $x-24(SP), R1
+ XC $24, 0(R1), 0(R1) // clear the storage
+ MOVD $2, R0 // R0 is the number of double words stored -1
+ WORD $0xB2B01000 // STFLE 0(R1)
+ XOR R0, R0 // reset the value of R0
+ MOVBZ z-8(SP), R1
+ AND $0x01, R1
+ BEQ novmsl
+
+vectorinstalled:
+ // check if the vector instruction has been enabled
+ VLEIB $0, $0xF, V16
+ VLGVB $0, V16, R1
+ CMPBNE R1, $0xF, novmsl
+ MOVB $1, ret+0(FP) // have vx
+ RET
+
+novmsl:
+ MOVB $0, ret+0(FP) // no vx
+ RET
diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go
index 42106f3f..00ed9923 100644
--- a/vendor/golang.org/x/crypto/ssh/certs.go
+++ b/vendor/golang.org/x/crypto/ssh/certs.go
@@ -222,6 +222,11 @@ type openSSHCertSigner struct {
signer Signer
}
+type algorithmOpenSSHCertSigner struct {
+ *openSSHCertSigner
+ algorithmSigner AlgorithmSigner
+}
+
// NewCertSigner returns a Signer that signs with the given Certificate, whose
// private key is held by signer. It returns an error if the public key in cert
// doesn't match the key used by signer.
@@ -230,7 +235,12 @@ func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
return nil, errors.New("ssh: signer and cert have different public key")
}
- return &openSSHCertSigner{cert, signer}, nil
+ if algorithmSigner, ok := signer.(AlgorithmSigner); ok {
+ return &algorithmOpenSSHCertSigner{
+ &openSSHCertSigner{cert, signer}, algorithmSigner}, nil
+ } else {
+ return &openSSHCertSigner{cert, signer}, nil
+ }
}
func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
@@ -241,6 +251,10 @@ func (s *openSSHCertSigner) PublicKey() PublicKey {
return s.pub
}
+func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
+ return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm)
+}
+
const sourceAddressCriticalOption = "source-address"
// CertChecker does the work of verifying a certificate. Its methods
diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go
index 30a49fdf..67b01261 100644
--- a/vendor/golang.org/x/crypto/ssh/cipher.go
+++ b/vendor/golang.org/x/crypto/ssh/cipher.go
@@ -16,6 +16,7 @@ import (
"hash"
"io"
"io/ioutil"
+ "math/bits"
"golang.org/x/crypto/internal/chacha20"
"golang.org/x/crypto/poly1305"
@@ -641,8 +642,8 @@ const chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
// the methods here also implement padding, which RFC4253 Section 6
// also requires of stream ciphers.
type chacha20Poly1305Cipher struct {
- lengthKey [32]byte
- contentKey [32]byte
+ lengthKey [8]uint32
+ contentKey [8]uint32
buf []byte
}
@@ -655,20 +656,21 @@ func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionA
buf: make([]byte, 256),
}
- copy(c.contentKey[:], key[:32])
- copy(c.lengthKey[:], key[32:])
+ for i := range c.contentKey {
+ c.contentKey[i] = binary.LittleEndian.Uint32(key[i*4 : (i+1)*4])
+ }
+ for i := range c.lengthKey {
+ c.lengthKey[i] = binary.LittleEndian.Uint32(key[(i+8)*4 : (i+9)*4])
+ }
return c, nil
}
-// The Poly1305 key is obtained by encrypting 32 0-bytes.
-var chacha20PolyKeyInput [32]byte
-
func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
- var counter [16]byte
- binary.BigEndian.PutUint64(counter[8:], uint64(seqNum))
-
+ nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
+ s := chacha20.New(c.contentKey, nonce)
var polyKey [32]byte
- chacha20.XORKeyStream(polyKey[:], chacha20PolyKeyInput[:], &counter, &c.contentKey)
+ s.XORKeyStream(polyKey[:], polyKey[:])
+ s.Advance() // skip next 32 bytes
encryptedLength := c.buf[:4]
if _, err := io.ReadFull(r, encryptedLength); err != nil {
@@ -676,7 +678,7 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte,
}
var lenBytes [4]byte
- chacha20.XORKeyStream(lenBytes[:], encryptedLength, &counter, &c.lengthKey)
+ chacha20.New(c.lengthKey, nonce).XORKeyStream(lenBytes[:], encryptedLength)
length := binary.BigEndian.Uint32(lenBytes[:])
if length > maxPacket {
@@ -702,10 +704,8 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte,
return nil, errors.New("ssh: MAC failure")
}
- counter[0] = 1
-
plain := c.buf[4:contentEnd]
- chacha20.XORKeyStream(plain, plain, &counter, &c.contentKey)
+ s.XORKeyStream(plain, plain)
padding := plain[0]
if padding < 4 {
@@ -724,11 +724,11 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte,
}
func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
- var counter [16]byte
- binary.BigEndian.PutUint64(counter[8:], uint64(seqNum))
-
+ nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
+ s := chacha20.New(c.contentKey, nonce)
var polyKey [32]byte
- chacha20.XORKeyStream(polyKey[:], chacha20PolyKeyInput[:], &counter, &c.contentKey)
+ s.XORKeyStream(polyKey[:], polyKey[:])
+ s.Advance() // skip next 32 bytes
// There is no blocksize, so fall back to multiple of 8 byte
// padding, as described in RFC 4253, Sec 6.
@@ -748,7 +748,7 @@ func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io
}
binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding))
- chacha20.XORKeyStream(c.buf, c.buf[:4], &counter, &c.lengthKey)
+ chacha20.New(c.lengthKey, nonce).XORKeyStream(c.buf, c.buf[:4])
c.buf[4] = byte(padding)
copy(c.buf[5:], payload)
packetEnd := 5 + len(payload) + padding
@@ -756,8 +756,7 @@ func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io
return err
}
- counter[0] = 1
- chacha20.XORKeyStream(c.buf[4:], c.buf[4:packetEnd], &counter, &c.contentKey)
+ s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd])
var mac [poly1305.TagSize]byte
poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey)
diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go
index 6fd19945..7b00bff1 100644
--- a/vendor/golang.org/x/crypto/ssh/client.go
+++ b/vendor/golang.org/x/crypto/ssh/client.go
@@ -19,6 +19,8 @@ import (
type Client struct {
Conn
+ handleForwardsOnce sync.Once // guards calling (*Client).handleForwards
+
forwards forwardList // forwarded tcpip connections from the remote side
mu sync.Mutex
channelHandlers map[string]chan NewChannel
@@ -60,8 +62,6 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
conn.Wait()
conn.forwards.closeAll()
}()
- go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip"))
- go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
return conn
}
@@ -185,7 +185,7 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) {
// keys. A HostKeyCallback must return nil if the host key is OK, or
// an error to reject it. It receives the hostname as passed to Dial
// or NewClientConn. The remote address is the RemoteAddr of the
-// net.Conn underlying the the SSH connection.
+// net.Conn underlying the SSH connection.
type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
// BannerCallback is the function type used for treat the banner sent by
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
index 73697ded..96980479 100644
--- a/vendor/golang.org/x/crypto/ssh/keys.go
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -38,6 +38,16 @@ const (
KeyAlgoED25519 = "ssh-ed25519"
)
+// These constants represent non-default signature algorithms that are supported
+// as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See
+// [PROTOCOL.agent] section 4.5.1 and
+// https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10
+const (
+ SigAlgoRSA = "ssh-rsa"
+ SigAlgoRSASHA2256 = "rsa-sha2-256"
+ SigAlgoRSASHA2512 = "rsa-sha2-512"
+)
+
// parsePubKey parses a public key of the given algorithm.
// Use ParsePublicKey for keys with prepended algorithm.
func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) {
@@ -301,6 +311,19 @@ type Signer interface {
Sign(rand io.Reader, data []byte) (*Signature, error)
}
+// A AlgorithmSigner is a Signer that also supports specifying a specific
+// algorithm to use for signing.
+type AlgorithmSigner interface {
+ Signer
+
+ // SignWithAlgorithm is like Signer.Sign, but allows specification of a
+ // non-default signing algorithm. See the SigAlgo* constants in this
+ // package for signature algorithms supported by this package. Callers may
+ // pass an empty string for the algorithm in which case the AlgorithmSigner
+ // will use its default algorithm.
+ SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
+}
+
type rsaPublicKey rsa.PublicKey
func (r *rsaPublicKey) Type() string {
@@ -349,13 +372,21 @@ func (r *rsaPublicKey) Marshal() []byte {
}
func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
- if sig.Format != r.Type() {
+ var hash crypto.Hash
+ switch sig.Format {
+ case SigAlgoRSA:
+ hash = crypto.SHA1
+ case SigAlgoRSASHA2256:
+ hash = crypto.SHA256
+ case SigAlgoRSASHA2512:
+ hash = crypto.SHA512
+ default:
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
}
- h := crypto.SHA1.New()
+ h := hash.New()
h.Write(data)
digest := h.Sum(nil)
- return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob)
+ return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob)
}
func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
@@ -459,6 +490,14 @@ func (k *dsaPrivateKey) PublicKey() PublicKey {
}
func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
+ return k.SignWithAlgorithm(rand, data, "")
+}
+
+func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
+ if algorithm != "" && algorithm != k.PublicKey().Type() {
+ return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
+ }
+
h := crypto.SHA1.New()
h.Write(data)
digest := h.Sum(nil)
@@ -691,16 +730,42 @@ func (s *wrappedSigner) PublicKey() PublicKey {
}
func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
+ return s.SignWithAlgorithm(rand, data, "")
+}
+
+func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
var hashFunc crypto.Hash
- switch key := s.pubKey.(type) {
- case *rsaPublicKey, *dsaPublicKey:
- hashFunc = crypto.SHA1
- case *ecdsaPublicKey:
- hashFunc = ecHash(key.Curve)
- case ed25519PublicKey:
- default:
- return nil, fmt.Errorf("ssh: unsupported key type %T", key)
+ if _, ok := s.pubKey.(*rsaPublicKey); ok {
+ // RSA keys support a few hash functions determined by the requested signature algorithm
+ switch algorithm {
+ case "", SigAlgoRSA:
+ algorithm = SigAlgoRSA
+ hashFunc = crypto.SHA1
+ case SigAlgoRSASHA2256:
+ hashFunc = crypto.SHA256
+ case SigAlgoRSASHA2512:
+ hashFunc = crypto.SHA512
+ default:
+ return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
+ }
+ } else {
+ // The only supported algorithm for all other key types is the same as the type of the key
+ if algorithm == "" {
+ algorithm = s.pubKey.Type()
+ } else if algorithm != s.pubKey.Type() {
+ return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
+ }
+
+ switch key := s.pubKey.(type) {
+ case *dsaPublicKey:
+ hashFunc = crypto.SHA1
+ case *ecdsaPublicKey:
+ hashFunc = ecHash(key.Curve)
+ case ed25519PublicKey:
+ default:
+ return nil, fmt.Errorf("ssh: unsupported key type %T", key)
+ }
}
var digest []byte
@@ -745,7 +810,7 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
}
return &Signature{
- Format: s.pubKey.Type(),
+ Format: algorithm,
Blob: signature,
}, nil
}
@@ -803,7 +868,7 @@ func encryptedBlock(block *pem.Block) bool {
}
// ParseRawPrivateKey returns a private key from a PEM encoded private key. It
-// supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys.
+// supports RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys.
func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
@@ -817,6 +882,9 @@ func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
switch block.Type {
case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey(block.Bytes)
+ // RFC5208 - https://tools.ietf.org/html/rfc5208
+ case "PRIVATE KEY":
+ return x509.ParsePKCS8PrivateKey(block.Bytes)
case "EC PRIVATE KEY":
return x509.ParseECPrivateKey(block.Bytes)
case "DSA PRIVATE KEY":
@@ -900,8 +968,8 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
// Implemented based on the documentation at
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
func parseOpenSSHPrivateKey(key []byte) (crypto.PrivateKey, error) {
- magic := append([]byte("openssh-key-v1"), 0)
- if !bytes.Equal(magic, key[0:len(magic)]) {
+ const magic = "openssh-key-v1\x00"
+ if len(key) < len(magic) || string(key[:len(magic)]) != magic {
return nil, errors.New("ssh: invalid openssh private key format")
}
remaining := key[len(magic):]
diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go
index d0f48253..122c03e7 100644
--- a/vendor/golang.org/x/crypto/ssh/server.go
+++ b/vendor/golang.org/x/crypto/ssh/server.go
@@ -404,7 +404,7 @@ userAuthLoop:
perms, authErr = config.PasswordCallback(s, password)
case "keyboard-interactive":
if config.KeyboardInteractiveCallback == nil {
- authErr = errors.New("ssh: keyboard-interactive auth not configubred")
+ authErr = errors.New("ssh: keyboard-interactive auth not configured")
break
}
diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go
index a2dccc64..b171b330 100644
--- a/vendor/golang.org/x/crypto/ssh/streamlocal.go
+++ b/vendor/golang.org/x/crypto/ssh/streamlocal.go
@@ -32,6 +32,7 @@ type streamLocalChannelForwardMsg struct {
// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
+ c.handleForwardsOnce.Do(c.handleForwards)
m := streamLocalChannelForwardMsg{
socketPath,
}
diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go
index acf17175..80d35f5e 100644
--- a/vendor/golang.org/x/crypto/ssh/tcpip.go
+++ b/vendor/golang.org/x/crypto/ssh/tcpip.go
@@ -90,10 +90,19 @@ type channelForwardMsg struct {
rport uint32
}
+// handleForwards starts goroutines handling forwarded connections.
+// It's called on first use by (*Client).ListenTCP to not launch
+// goroutines until needed.
+func (c *Client) handleForwards() {
+ go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip"))
+ go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
+}
+
// ListenTCP requests the remote peer open a listening socket
// on laddr. Incoming connections will be available by calling
// Accept on the returned net.Listener.
func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
+ c.handleForwardsOnce.Do(c.handleForwards)
if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
return c.autoPortListenWorkaround(laddr)
}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go
index 02dad484..731c89a2 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/util.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util.go
@@ -108,9 +108,7 @@ func ReadPassword(fd int) ([]byte, error) {
return nil, err
}
- defer func() {
- unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
- }()
+ defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
return readPasswordLine(passwordReader(fd))
}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
index a2e1b57d..9e41b9f4 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
@@ -14,7 +14,7 @@ import (
// State contains the state of a terminal.
type State struct {
- state *unix.Termios
+ termios unix.Termios
}
// IsTerminal returns true if the given file descriptor is a terminal.
@@ -75,47 +75,43 @@ func ReadPassword(fd int) ([]byte, error) {
// restored.
// see http://cr.illumos.org/~webrev/andy_js/1060/
func MakeRaw(fd int) (*State, error) {
- oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+ termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
if err != nil {
return nil, err
}
- oldTermios := *oldTermiosPtr
-
- newTermios := oldTermios
- newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
- newTermios.Oflag &^= syscall.OPOST
- newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
- newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB
- newTermios.Cflag |= syscall.CS8
- newTermios.Cc[unix.VMIN] = 1
- newTermios.Cc[unix.VTIME] = 0
-
- if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
+
+ oldState := State{termios: *termios}
+
+ termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
+ termios.Oflag &^= unix.OPOST
+ termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
+ termios.Cflag &^= unix.CSIZE | unix.PARENB
+ termios.Cflag |= unix.CS8
+ termios.Cc[unix.VMIN] = 1
+ termios.Cc[unix.VTIME] = 0
+
+ if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
return nil, err
}
- return &State{
- state: oldTermiosPtr,
- }, nil
+ return &oldState, nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, oldState *State) error {
- return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state)
+ return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
- oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+ termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
if err != nil {
return nil, err
}
- return &State{
- state: oldTermiosPtr,
- }, nil
+ return &State{termios: *termios}, nil
}
// GetSize returns the dimensions of the given terminal.
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
index 4933ac36..8618955d 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
@@ -89,9 +89,7 @@ func ReadPassword(fd int) ([]byte, error) {
return nil, err
}
- defer func() {
- windows.SetConsoleMode(windows.Handle(fd), old)
- }()
+ defer windows.SetConsoleMode(windows.Handle(fd), old)
var h windows.Handle
p, _ := windows.GetCurrentProcess()
diff --git a/vendor/modules.txt b/vendor/modules.txt
index d622bd7b..efdababa 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -15,6 +15,8 @@ github.com/Philipp15b/go-steam/rwu
github.com/Philipp15b/go-steam/socialcache
# github.com/alecthomas/log4go v0.0.0-20160307011253-e5dc62318d9b
github.com/alecthomas/log4go
+# github.com/bwmarrin/discordgo v0.19.0
+github.com/bwmarrin/discordgo
# github.com/davecgh/go-spew v1.1.0
github.com/davecgh/go-spew/spew
# github.com/dfordsoft/golib v0.0.0-20180313113957-2ea3495aee1d
@@ -34,7 +36,7 @@ github.com/google/gops/internal
github.com/google/gops/signal
# github.com/gorilla/schema v0.0.0-20170317173100-f3c80893412c
github.com/gorilla/schema
-# github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777
+# github.com/gorilla/websocket v1.4.0
github.com/gorilla/websocket
# github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad
github.com/hashicorp/golang-lru
@@ -66,8 +68,6 @@ github.com/labstack/gommon/random
github.com/lrstanley/girc
# github.com/magiconair/properties v0.0.0-20180217134545-2c9e95027885
github.com/magiconair/properties
-# github.com/matterbridge/discordgo v0.0.0-20180806170629-ef40ff5ba64f
-github.com/matterbridge/discordgo
# github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91
github.com/matterbridge/go-xmpp
# github.com/matterbridge/gomatrix v0.0.0-20171224233421-78ac6a1a0f5f
@@ -146,19 +146,20 @@ github.com/valyala/bytebufferpool
github.com/valyala/fasttemplate
# github.com/zfjagann/golang-ring v0.0.0-20141111230621-17637388c9f6
github.com/zfjagann/golang-ring
-# golang.org/x/crypto v0.0.0-20180228161326-91a49db82a88
+# golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16
golang.org/x/crypto/ssh/terminal
golang.org/x/crypto/acme/autocert
golang.org/x/crypto/nacl/secretbox
-golang.org/x/crypto/ssh
golang.org/x/crypto/bcrypt
+golang.org/x/crypto/ssh
golang.org/x/crypto/acme
+golang.org/x/crypto/internal/subtle
golang.org/x/crypto/poly1305
golang.org/x/crypto/salsa20/salsa
+golang.org/x/crypto/blowfish
golang.org/x/crypto/curve25519
golang.org/x/crypto/ed25519
golang.org/x/crypto/internal/chacha20
-golang.org/x/crypto/blowfish
golang.org/x/crypto/ed25519/internal/edwards25519
# golang.org/x/sys v0.0.0-20171130163741-8b4580aae2a0
golang.org/x/sys/unix