Updates regarding moving to source.pztrn.name and dependencies bundling with golang/dep.
This commit is contained in:
		
							
								
								
									
										48
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. | ||||
|  | ||||
|  | ||||
| [[projects]] | ||||
|   name = "github.com/sirupsen/logrus" | ||||
|   packages = ["."] | ||||
|   revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba" | ||||
|   version = "v1.0.4" | ||||
|  | ||||
| [[projects]] | ||||
|   branch = "master" | ||||
|   name = "golang.org/x/crypto" | ||||
|   packages = ["ssh/terminal"] | ||||
|   revision = "1875d0a70c90e57f11972aefd42276df65e895b9" | ||||
|  | ||||
| [[projects]] | ||||
|   branch = "master" | ||||
|   name = "golang.org/x/sys" | ||||
|   packages = [ | ||||
|     "unix", | ||||
|     "windows" | ||||
|   ] | ||||
|   revision = "8f27ce8a604014414f8dfffc25cbcde83a3f2216" | ||||
|  | ||||
| [[projects]] | ||||
|   branch = "v2" | ||||
|   name = "gopkg.in/yaml.v2" | ||||
|   packages = ["."] | ||||
|   revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4" | ||||
|  | ||||
| [[projects]] | ||||
|   branch = "master" | ||||
|   name = "source.pztrn.name/golibs/flagger" | ||||
|   packages = ["."] | ||||
|   revision = "c9b4726e1787adb01126cdf9a7932e2bccbb51a7" | ||||
|  | ||||
| [[projects]] | ||||
|   branch = "master" | ||||
|   name = "source.pztrn.name/golibs/mogrus" | ||||
|   packages = ["."] | ||||
|   revision = "2e3a9d38c8e4b0036f714f88ef0fe9fc14b4c6b8" | ||||
|  | ||||
| [solve-meta] | ||||
|   analyzer-name = "dep" | ||||
|   analyzer-version = 1 | ||||
|   inputs-digest = "2b99cf1ed594e6ce9e2bc8bf1be8cbe0018db897ef6dc6c3e59ae5030099ef48" | ||||
|   solver-name = "gps-cdcl" | ||||
|   solver-version = 1 | ||||
							
								
								
									
										33
									
								
								Gopkg.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Gopkg.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| # Gopkg.toml example | ||||
| # | ||||
| # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md | ||||
| # for detailed Gopkg.toml documentation. | ||||
| # | ||||
| # required = ["github.com/user/thing/cmd/thing"] | ||||
| # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] | ||||
| # | ||||
| # [[constraint]] | ||||
| #   name = "github.com/user/project" | ||||
| #   version = "1.0.0" | ||||
| # | ||||
| # [[constraint]] | ||||
| #   name = "github.com/user/project2" | ||||
| #   branch = "dev" | ||||
| #   source = "github.com/myfork/project2" | ||||
| # | ||||
| # [[override]] | ||||
| #  name = "github.com/x/y" | ||||
| #  version = "2.4.0" | ||||
|  | ||||
|  | ||||
| [[constraint]] | ||||
|   branch = "v2" | ||||
|   name = "gopkg.in/yaml.v2" | ||||
|  | ||||
| [[constraint]] | ||||
|   branch = "master" | ||||
|   name = "source.pztrn.name/golibs/flagger" | ||||
|  | ||||
| [[constraint]] | ||||
|   branch = "master" | ||||
|   name = "source.pztrn.name/golibs/mogrus" | ||||
							
								
								
									
										126
									
								
								config/config.go
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								config/config.go
									
									
									
									
									
								
							| @@ -18,110 +18,110 @@ | ||||
| package config | ||||
|  | ||||
| import ( | ||||
|     // stdlib | ||||
|     "errors" | ||||
|     "fmt" | ||||
|     "io/ioutil" | ||||
|     "os/user" | ||||
|     "strings" | ||||
| 	// stdlib | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os/user" | ||||
| 	"strings" | ||||
|  | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/config/struct" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/config/struct" | ||||
|  | ||||
|     // other | ||||
|     "gopkg.in/yaml.v2" | ||||
|     "lab.pztrn.name/golibs/flagger" | ||||
| 	// other | ||||
| 	"gopkg.in/yaml.v2" | ||||
| 	"source.pztrn.name/golibs/flagger" | ||||
| ) | ||||
|  | ||||
| type Configuration struct {} | ||||
| type Configuration struct{} | ||||
|  | ||||
| // Returns configuration to caller. | ||||
| func (conf Configuration) GetConfig() *configstruct.ConfigStruct { | ||||
|     return config | ||||
| 	return config | ||||
| } | ||||
|  | ||||
| // Gets value from temporary configuration storage. | ||||
| // If value isn't found - returns empty string with error. | ||||
| func (conf Configuration) GetTempValue(key string) (string, error) { | ||||
|     value, found := tempconfig[key] | ||||
|     if !found { | ||||
|         return "", errors.New("No such key in temporary configuration storage: " + key) | ||||
|     } | ||||
| 	value, found := tempconfig[key] | ||||
| 	if !found { | ||||
| 		return "", errors.New("No such key in temporary configuration storage: " + key) | ||||
| 	} | ||||
|  | ||||
|     // If we have path with tilde in front (home directory) - replace | ||||
|     // tilde with actual home directory. | ||||
|     if value[0] == '~' { | ||||
|         usr, err := user.Current() | ||||
|         if err != nil { | ||||
|             c.Log.Fatalln("Failed to get current user data: " + err.Error()) | ||||
|         } | ||||
|         value = strings.Replace(value, "~", usr.HomeDir, 1) | ||||
|     } | ||||
| 	// If we have path with tilde in front (home directory) - replace | ||||
| 	// tilde with actual home directory. | ||||
| 	if value[0] == '~' { | ||||
| 		usr, err := user.Current() | ||||
| 		if err != nil { | ||||
| 			c.Log.Fatalln("Failed to get current user data: " + err.Error()) | ||||
| 		} | ||||
| 		value = strings.Replace(value, "~", usr.HomeDir, 1) | ||||
| 	} | ||||
|  | ||||
|     return value, nil | ||||
| 	return value, nil | ||||
| } | ||||
|  | ||||
| func (conf Configuration) Initialize() { | ||||
|     c.Log.Infoln("Initializing configuration storage...") | ||||
| 	c.Log.Infoln("Initializing configuration storage...") | ||||
|  | ||||
|     tempconfig = make(map[string]string) | ||||
| 	tempconfig = make(map[string]string) | ||||
|  | ||||
|     flag_configpath := flagger.Flag{ | ||||
|         Name: "config", | ||||
|         Description: "Path to configuration file.", | ||||
|         Type: "string", | ||||
|         DefaultValue: "~/.config/OpenSAPS/config.yaml", | ||||
|     } | ||||
| 	flag_configpath := flagger.Flag{ | ||||
| 		Name:         "config", | ||||
| 		Description:  "Path to configuration file.", | ||||
| 		Type:         "string", | ||||
| 		DefaultValue: "~/.config/OpenSAPS/config.yaml", | ||||
| 	} | ||||
|  | ||||
|     c.Flagger.AddFlag(&flag_configpath) | ||||
| 	c.Flagger.AddFlag(&flag_configpath) | ||||
| } | ||||
|  | ||||
| // Initializes configuration root path for later usage. | ||||
| func (conf Configuration) initializeConfigurationFilePath() { | ||||
|     c.Log.Debugln("Asking flagger about configuration root path supplied by user...") | ||||
| 	c.Log.Debugln("Asking flagger about configuration root path supplied by user...") | ||||
|  | ||||
|     configpath, err := c.Flagger.GetStringValue("config") | ||||
|     if err != nil { | ||||
|         c.Log.Fatalln("Something went wrong - Flagger doesn't know about \"-config\" parameter!") | ||||
|     } | ||||
| 	configpath, err := c.Flagger.GetStringValue("config") | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalln("Something went wrong - Flagger doesn't know about \"-config\" parameter!") | ||||
| 	} | ||||
|  | ||||
|     c.Log.Infoln("Will use configuration file: '" + configpath + "'") | ||||
|     conf.SetTempValue("CONFIGURATION_FILE", configpath) | ||||
| 	c.Log.Infoln("Will use configuration file: '" + configpath + "'") | ||||
| 	conf.SetTempValue("CONFIGURATION_FILE", configpath) | ||||
| } | ||||
|  | ||||
| // Asking Flagger about flags, initialize internal variables. | ||||
| // Should be called **after** Flagger.Parse(). | ||||
| func (conf Configuration) InitializeLater() { | ||||
|     c.Log.Infoln("Completing configuration initialization...") | ||||
| 	c.Log.Infoln("Completing configuration initialization...") | ||||
|  | ||||
|     conf.initializeConfigurationFilePath() | ||||
| 	conf.initializeConfigurationFilePath() | ||||
| } | ||||
|  | ||||
| // Loads configuration from file. | ||||
| func (conf Configuration) LoadConfigurationFromFile() { | ||||
|     configpath, err := conf.GetTempValue("CONFIGURATION_FILE") | ||||
|     if err != nil { | ||||
|         c.Log.Fatalln("Failed to get configuration file path from internal temporary configuration storage! OpenSAPS is BROKEN!") | ||||
|     } | ||||
|     c.Log.Infof("Loading configuration from '%s'...", configpath) | ||||
| 	configpath, err := conf.GetTempValue("CONFIGURATION_FILE") | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalln("Failed to get configuration file path from internal temporary configuration storage! OpenSAPS is BROKEN!") | ||||
| 	} | ||||
| 	c.Log.Infof("Loading configuration from '%s'...", configpath) | ||||
|  | ||||
|     // Read file into memory. | ||||
|     config_bytes, err1 := ioutil.ReadFile(configpath) | ||||
|     if err1 != nil { | ||||
|         c.Log.Fatalf("Error occured while reading configuration file: %s", err1.Error()) | ||||
|     } | ||||
| 	// Read file into memory. | ||||
| 	config_bytes, err1 := ioutil.ReadFile(configpath) | ||||
| 	if err1 != nil { | ||||
| 		c.Log.Fatalf("Error occured while reading configuration file: %s", err1.Error()) | ||||
| 	} | ||||
|  | ||||
|     config = &configstruct.ConfigStruct{} | ||||
|     // Parse YAML. | ||||
|     err2 := yaml.Unmarshal(config_bytes, config) | ||||
|     if err2 != nil { | ||||
|         c.Log.Fatalf("Failed to parse configuration file: %s", err2.Error()) | ||||
|     } | ||||
|     c.Log.Debugln("Loaded configuration:", fmt.Sprintf("%+v", config)) | ||||
| 	config = &configstruct.ConfigStruct{} | ||||
| 	// Parse YAML. | ||||
| 	err2 := yaml.Unmarshal(config_bytes, config) | ||||
| 	if err2 != nil { | ||||
| 		c.Log.Fatalf("Failed to parse configuration file: %s", err2.Error()) | ||||
| 	} | ||||
| 	c.Log.Debugln("Loaded configuration:", fmt.Sprintf("%+v", config)) | ||||
| } | ||||
|  | ||||
| // Sets value to key in temporary configuration storage. | ||||
| // If key already present in map - value will be replaced. | ||||
| func (conf Configuration) SetTempValue(key, value string) { | ||||
|     tempconfig[key] = value | ||||
| 	tempconfig[key] = value | ||||
| } | ||||
|   | ||||
| @@ -18,22 +18,22 @@ | ||||
| package config | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/config/interface" | ||||
|     "lab.pztrn.name/pztrn/opensaps/config/struct" | ||||
|     "lab.pztrn.name/pztrn/opensaps/context" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/config/interface" | ||||
| 	"source.pztrn.name/misc/opensaps/config/struct" | ||||
| 	"source.pztrn.name/misc/opensaps/context" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|     c *context.Context | ||||
|     // Temporary configuration. | ||||
|     tempconfig map[string]string | ||||
|     // Configuration from YAML file. | ||||
|     config *configstruct.ConfigStruct | ||||
| 	c *context.Context | ||||
| 	// Temporary configuration. | ||||
| 	tempconfig map[string]string | ||||
| 	// Configuration from YAML file. | ||||
| 	config *configstruct.ConfigStruct | ||||
| ) | ||||
|  | ||||
| func New(cc *context.Context) { | ||||
|     c = cc | ||||
|     conf := Configuration{} | ||||
|     c.RegisterConfigurationInterface(configurationinterface.ConfigurationInterface(conf)) | ||||
| 	c = cc | ||||
| 	conf := Configuration{} | ||||
| 	c.RegisterConfigurationInterface(configurationinterface.ConfigurationInterface(conf)) | ||||
| } | ||||
|   | ||||
| @@ -18,15 +18,15 @@ | ||||
| package configurationinterface | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/config/struct" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/config/struct" | ||||
| ) | ||||
|  | ||||
| type ConfigurationInterface interface { | ||||
|     GetConfig() *configstruct.ConfigStruct | ||||
|     GetTempValue(key string) (string, error) | ||||
|     Initialize() | ||||
|     InitializeLater() | ||||
|     LoadConfigurationFromFile() | ||||
|     SetTempValue(key, value string) | ||||
| 	GetConfig() *configstruct.ConfigStruct | ||||
| 	GetTempValue(key string) (string, error) | ||||
| 	Initialize() | ||||
| 	InitializeLater() | ||||
| 	LoadConfigurationFromFile() | ||||
| 	SetTempValue(key, value string) | ||||
| } | ||||
|   | ||||
| @@ -23,15 +23,15 @@ import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	// local | ||||
| 	"lab.pztrn.name/pztrn/opensaps/config/interface" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/parsers/interface" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/pushers/interface" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/slack/apiserverinterface" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	"source.pztrn.name/misc/opensaps/config/interface" | ||||
| 	"source.pztrn.name/misc/opensaps/parsers/interface" | ||||
| 	"source.pztrn.name/misc/opensaps/pushers/interface" | ||||
| 	"source.pztrn.name/misc/opensaps/slack/apiserverinterface" | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
|  | ||||
| 	// other | ||||
| 	"lab.pztrn.name/golibs/flagger" | ||||
| 	"lab.pztrn.name/golibs/mogrus" | ||||
| 	"source.pztrn.name/golibs/flagger" | ||||
| 	"source.pztrn.name/golibs/mogrus" | ||||
| ) | ||||
|  | ||||
| type Context struct { | ||||
|   | ||||
							
								
								
									
										16
									
								
								opensaps.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								opensaps.go
									
									
									
									
									
								
							| @@ -24,14 +24,14 @@ import ( | ||||
| 	"syscall" | ||||
|  | ||||
| 	// local | ||||
| 	"lab.pztrn.name/pztrn/opensaps/config" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/context" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/parsers/default" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/parsers/gitea" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/parsers/gitlab" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/pushers/matrix" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/pushers/telegram" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/slack" | ||||
| 	"source.pztrn.name/misc/opensaps/config" | ||||
| 	"source.pztrn.name/misc/opensaps/context" | ||||
| 	"source.pztrn.name/misc/opensaps/parsers/default" | ||||
| 	"source.pztrn.name/misc/opensaps/parsers/gitea" | ||||
| 	"source.pztrn.name/misc/opensaps/parsers/gitlab" | ||||
| 	"source.pztrn.name/misc/opensaps/pushers/matrix" | ||||
| 	"source.pztrn.name/misc/opensaps/pushers/telegram" | ||||
| 	"source.pztrn.name/misc/opensaps/slack" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
|   | ||||
| @@ -18,20 +18,20 @@ | ||||
| package defaultparser | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type DefaultParser struct {} | ||||
| type DefaultParser struct{} | ||||
|  | ||||
| func (dp DefaultParser) Initialize() { | ||||
|     c.Log.Infoln("Initializing default parser...") | ||||
| 	c.Log.Infoln("Initializing default parser...") | ||||
| } | ||||
|  | ||||
| func (dp DefaultParser) ParseMessage(message slackmessage.SlackMessage) map[string]string { | ||||
|     c.Log.Debugln("Parsing default message...") | ||||
| 	c.Log.Debugln("Parsing default message...") | ||||
|  | ||||
|     data := make(map[string]string) | ||||
|     data["message"] = message.Text | ||||
|     return data | ||||
| 	data := make(map[string]string) | ||||
| 	data["message"] = message.Text | ||||
| 	return data | ||||
| } | ||||
|   | ||||
| @@ -18,17 +18,17 @@ | ||||
| package defaultparser | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/context" | ||||
|     "lab.pztrn.name/pztrn/opensaps/parsers/interface" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/context" | ||||
| 	"source.pztrn.name/misc/opensaps/parsers/interface" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|     c *context.Context | ||||
| 	c *context.Context | ||||
| ) | ||||
|  | ||||
| func New(cc *context.Context) { | ||||
|     c = cc | ||||
|     dp := DefaultParser{} | ||||
|     c.RegisterParserInterface("default", parserinterface.ParserInterface(dp)) | ||||
| 	c = cc | ||||
| 	dp := DefaultParser{} | ||||
| 	c.RegisterParserInterface("default", parserinterface.ParserInterface(dp)) | ||||
| } | ||||
|   | ||||
| @@ -18,17 +18,17 @@ | ||||
| package giteaparser | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/context" | ||||
|     "lab.pztrn.name/pztrn/opensaps/parsers/interface" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/context" | ||||
| 	"source.pztrn.name/misc/opensaps/parsers/interface" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|     c *context.Context | ||||
| 	c *context.Context | ||||
| ) | ||||
|  | ||||
| func New(cc *context.Context) { | ||||
|     c = cc | ||||
|     gp := GiteaParser{} | ||||
|     c.RegisterParserInterface("gitea", parserinterface.ParserInterface(gp)) | ||||
| 	c = cc | ||||
| 	gp := GiteaParser{} | ||||
| 	c.RegisterParserInterface("gitea", parserinterface.ParserInterface(gp)) | ||||
| } | ||||
|   | ||||
| @@ -25,7 +25,7 @@ import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	// local | ||||
| 	"lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type GiteaParser struct{} | ||||
|   | ||||
| @@ -18,17 +18,17 @@ | ||||
| package gitlabparser | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/context" | ||||
|     "lab.pztrn.name/pztrn/opensaps/parsers/interface" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/context" | ||||
| 	"source.pztrn.name/misc/opensaps/parsers/interface" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|     c *context.Context | ||||
| 	c *context.Context | ||||
| ) | ||||
|  | ||||
| func New(cc *context.Context) { | ||||
|     c = cc | ||||
|     gp := GitlabParser{} | ||||
|     c.RegisterParserInterface("gitlab", parserinterface.ParserInterface(gp)) | ||||
| 	c = cc | ||||
| 	gp := GitlabParser{} | ||||
| 	c.RegisterParserInterface("gitlab", parserinterface.ParserInterface(gp)) | ||||
| } | ||||
|   | ||||
| @@ -25,7 +25,7 @@ import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	// local | ||||
| 	"lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type GitlabParser struct{} | ||||
|   | ||||
| @@ -18,11 +18,11 @@ | ||||
| package parserinterface | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type ParserInterface interface { | ||||
|     Initialize() | ||||
|     ParseMessage(message slackmessage.SlackMessage) map[string]string | ||||
| 	Initialize() | ||||
| 	ParseMessage(message slackmessage.SlackMessage) map[string]string | ||||
| } | ||||
|   | ||||
| @@ -18,12 +18,12 @@ | ||||
| package pusherinterface | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type PusherInterface interface { | ||||
|     Initialize() | ||||
|     Push(connection string, data slackmessage.SlackMessage) | ||||
|     Shutdown() | ||||
| 	Initialize() | ||||
| 	Push(connection string, data slackmessage.SlackMessage) | ||||
| 	Shutdown() | ||||
| } | ||||
|   | ||||
| @@ -18,20 +18,20 @@ | ||||
| package matrixpusher | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/context" | ||||
|     "lab.pztrn.name/pztrn/opensaps/pushers/interface" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/context" | ||||
| 	"source.pztrn.name/misc/opensaps/pushers/interface" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|     c *context.Context | ||||
|     connections map[string]*MatrixConnection | ||||
| 	c           *context.Context | ||||
| 	connections map[string]*MatrixConnection | ||||
| ) | ||||
|  | ||||
| func New(cc *context.Context) { | ||||
|     c = cc | ||||
|     connections = make(map[string]*MatrixConnection) | ||||
| 	c = cc | ||||
| 	connections = make(map[string]*MatrixConnection) | ||||
|  | ||||
|     mp := MatrixPusher{} | ||||
|     c.RegisterPusherInterface("matrix", pusherinterface.PusherInterface(mp)) | ||||
| 	mp := MatrixPusher{} | ||||
| 	c.RegisterPusherInterface("matrix", pusherinterface.PusherInterface(mp)) | ||||
| } | ||||
|   | ||||
| @@ -18,313 +18,313 @@ | ||||
| package matrixpusher | ||||
|  | ||||
| import ( | ||||
|     // stdlib | ||||
|     "bytes" | ||||
|     crand "crypto/rand" | ||||
|     "encoding/json" | ||||
|     "errors" | ||||
|     "fmt" | ||||
|     "io/ioutil" | ||||
|     "net/http" | ||||
|     "strconv" | ||||
|     "strings" | ||||
| 	// stdlib | ||||
| 	"bytes" | ||||
| 	crand "crypto/rand" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| // Constants for random transaction ID. | ||||
| const ( | ||||
|     letterBytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // 36 possibilities | ||||
|     letterIdxBits = 6                    // 6 bits to represent 64 possibilities / indexes | ||||
|     letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits | ||||
| 	letterBytes   = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // 36 possibilities | ||||
| 	letterIdxBits = 6                                      // 6 bits to represent 64 possibilities / indexes | ||||
| 	letterIdxMask = 1<<letterIdxBits - 1                   // All 1-bits, as many as letterIdxBits | ||||
| ) | ||||
|  | ||||
| type MatrixMessage struct { | ||||
|     MsgType             string      `json:"msgtype"` | ||||
|     Body                string      `json:"body"` | ||||
|     Format              string      `json:"format"` | ||||
|     FormattedBody       string      `json:"formatted_body"` | ||||
| 	MsgType       string `json:"msgtype"` | ||||
| 	Body          string `json:"body"` | ||||
| 	Format        string `json:"format"` | ||||
| 	FormattedBody string `json:"formatted_body"` | ||||
| } | ||||
|  | ||||
| type MatrixConnection struct { | ||||
|     // API root for connection. | ||||
|     api_root string | ||||
|     // Connection name. | ||||
|     conn_name string | ||||
|     // Our device ID. | ||||
|     device_id string | ||||
|     // Password for user. | ||||
|     password string | ||||
|     // Room ID. | ||||
|     room_id string | ||||
|     // Token we obtained after logging in. | ||||
|     token string | ||||
|     // Our username for logging in to server. | ||||
|     username string | ||||
| 	// API root for connection. | ||||
| 	api_root string | ||||
| 	// Connection name. | ||||
| 	conn_name string | ||||
| 	// Our device ID. | ||||
| 	device_id string | ||||
| 	// Password for user. | ||||
| 	password string | ||||
| 	// Room ID. | ||||
| 	room_id string | ||||
| 	// Token we obtained after logging in. | ||||
| 	token string | ||||
| 	// Our username for logging in to server. | ||||
| 	username string | ||||
| } | ||||
|  | ||||
| func (mxc *MatrixConnection) doPostRequest(endpoint string, data string) ([]byte, error) { | ||||
|     c.Log.Debugln("Data to send:", data) | ||||
| 	c.Log.Debugln("Data to send:", data) | ||||
|  | ||||
|     api_root := mxc.api_root + endpoint | ||||
|     if mxc.token != "" { | ||||
|         api_root += fmt.Sprintf("?access_token=%s", mxc.token) | ||||
|     } | ||||
|     c.Log.Debugln("Request URL:", api_root) | ||||
|     req, _ := http.NewRequest("POST", api_root, bytes.NewBuffer([]byte(data))) | ||||
|     req.Header.Set("Content-Type", "application/json") | ||||
| 	api_root := mxc.api_root + endpoint | ||||
| 	if mxc.token != "" { | ||||
| 		api_root += fmt.Sprintf("?access_token=%s", mxc.token) | ||||
| 	} | ||||
| 	c.Log.Debugln("Request URL:", api_root) | ||||
| 	req, _ := http.NewRequest("POST", api_root, bytes.NewBuffer([]byte(data))) | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
|  | ||||
|     client := &http.Client{} | ||||
|     resp, err := client.Do(req) | ||||
|     if err != nil { | ||||
|         return nil, errors.New("Failed to perform POST request to Matrix as '" + mxc.username + "' (conn " + mxc.conn_name + "): " + err.Error()) | ||||
|     } | ||||
|     defer resp.Body.Close() | ||||
|     body, _ := ioutil.ReadAll(resp.Body) | ||||
| 	client := &http.Client{} | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.New("Failed to perform POST request to Matrix as '" + mxc.username + "' (conn " + mxc.conn_name + "): " + err.Error()) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	body, _ := ioutil.ReadAll(resp.Body) | ||||
|  | ||||
|     if resp.Status == "200 OK" { | ||||
|         // Return body. | ||||
|         return body, nil | ||||
|     } else { | ||||
|         return nil, errors.New("Status: " + resp.Status + ", body: " + string(body)) | ||||
|     } | ||||
| 	if resp.Status == "200 OK" { | ||||
| 		// Return body. | ||||
| 		return body, nil | ||||
| 	} else { | ||||
| 		return nil, errors.New("Status: " + resp.Status + ", body: " + string(body)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (mxc *MatrixConnection) doPutRequest(endpoint string, data string) ([]byte, error) { | ||||
|     c.Log.Debugln("Data to send:", data) | ||||
| api_root := mxc.api_root + endpoint | ||||
|     if mxc.token != "" { | ||||
|         api_root += fmt.Sprintf("?access_token=%s", mxc.token) | ||||
|     } | ||||
|     c.Log.Debugln("Request URL:", api_root) | ||||
|     req, _ := http.NewRequest("PUT", api_root, bytes.NewBuffer([]byte(data))) | ||||
|     req.Header.Set("Content-Type", "application/json") | ||||
| 	c.Log.Debugln("Data to send:", data) | ||||
| 	api_root := mxc.api_root + endpoint | ||||
| 	if mxc.token != "" { | ||||
| 		api_root += fmt.Sprintf("?access_token=%s", mxc.token) | ||||
| 	} | ||||
| 	c.Log.Debugln("Request URL:", api_root) | ||||
| 	req, _ := http.NewRequest("PUT", api_root, bytes.NewBuffer([]byte(data))) | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
|  | ||||
|     client := &http.Client{} | ||||
|     resp, err := client.Do(req) | ||||
|     if err != nil { | ||||
|         return nil, errors.New("Failed to perform PUT request to Matrix as '" + mxc.username + "' (conn " + mxc.conn_name + "): " + err.Error()) | ||||
|     } | ||||
|     defer resp.Body.Close() | ||||
|     body, _ := ioutil.ReadAll(resp.Body) | ||||
| 	client := &http.Client{} | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.New("Failed to perform PUT request to Matrix as '" + mxc.username + "' (conn " + mxc.conn_name + "): " + err.Error()) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	body, _ := ioutil.ReadAll(resp.Body) | ||||
|  | ||||
|     if resp.Status == "200 OK" { | ||||
|         // Return body. | ||||
|         return body, nil | ||||
|     } else { | ||||
|         return nil, errors.New("Status: " + resp.Status + ", body: " + string(body)) | ||||
|     } | ||||
| 	if resp.Status == "200 OK" { | ||||
| 		// Return body. | ||||
| 		return body, nil | ||||
| 	} else { | ||||
| 		return nil, errors.New("Status: " + resp.Status + ", body: " + string(body)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (mxc *MatrixConnection) generateTnxId() string { | ||||
|     // Random tnxid - 16 chars. | ||||
|     length := 16 | ||||
| 	// Random tnxid - 16 chars. | ||||
| 	length := 16 | ||||
|  | ||||
|     result := make([]byte, length) | ||||
|     bufferSize := int(float64(length)*1.3) | ||||
| 	result := make([]byte, length) | ||||
| 	bufferSize := int(float64(length) * 1.3) | ||||
|  | ||||
|     // Making sure that we have only letters and numbers and resulted | ||||
|     // string will be exactly requested length. | ||||
|     for i, j, randomBytes := 0, 0, []byte{}; i < length; j++ { | ||||
|         if j%bufferSize == 0 { | ||||
|             randomBytes = mxc.generateTnxIdSecureBytes(bufferSize) | ||||
|         } | ||||
|         if idx := int(randomBytes[j%length] & letterIdxMask); idx < len(letterBytes) { | ||||
|             result[i] = letterBytes[idx] | ||||
|             i++ | ||||
|         } | ||||
|     } | ||||
|     return string(result) | ||||
| 	// Making sure that we have only letters and numbers and resulted | ||||
| 	// string will be exactly requested length. | ||||
| 	for i, j, randomBytes := 0, 0, []byte{}; i < length; j++ { | ||||
| 		if j%bufferSize == 0 { | ||||
| 			randomBytes = mxc.generateTnxIdSecureBytes(bufferSize) | ||||
| 		} | ||||
| 		if idx := int(randomBytes[j%length] & letterIdxMask); idx < len(letterBytes) { | ||||
| 			result[i] = letterBytes[idx] | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
| 	return string(result) | ||||
| } | ||||
|  | ||||
| func (mxc *MatrixConnection) generateTnxIdSecureBytes(length int) []byte { | ||||
|     // Get random bytes. | ||||
|     var randomBytes = make([]byte, length) | ||||
|     _, err := crand.Read(randomBytes) | ||||
|     if err != nil { | ||||
|         c.Log.Fatalln("Unable to generate random bytes for transaction ID!") | ||||
|     } | ||||
| 	// Get random bytes. | ||||
| 	var randomBytes = make([]byte, length) | ||||
| 	_, err := crand.Read(randomBytes) | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalln("Unable to generate random bytes for transaction ID!") | ||||
| 	} | ||||
|  | ||||
|     return randomBytes | ||||
| 	return randomBytes | ||||
| } | ||||
|  | ||||
| func (mxc *MatrixConnection) Initialize(conn_name string, api_root string, user string, password string, room_id string) { | ||||
|     mxc.conn_name = conn_name | ||||
|     mxc.api_root = api_root | ||||
|     mxc.username = user | ||||
|     mxc.password = password | ||||
|     mxc.room_id = room_id | ||||
|     mxc.token = "" | ||||
| 	mxc.conn_name = conn_name | ||||
| 	mxc.api_root = api_root | ||||
| 	mxc.username = user | ||||
| 	mxc.password = password | ||||
| 	mxc.room_id = room_id | ||||
| 	mxc.token = "" | ||||
|  | ||||
|     c.Log.Debugln("Trying to connect to", mxc.conn_name, "(" + api_root + ")") | ||||
| 	c.Log.Debugln("Trying to connect to", mxc.conn_name, "("+api_root+")") | ||||
|  | ||||
|     loginStr := fmt.Sprintf(`{"type": "m.login.password", "user": "%s", "password": "%s"}`, mxc.username, mxc.password) | ||||
|     c.Log.Debugln("Login string:", loginStr) | ||||
|     reply, err := mxc.doPostRequest("/login", loginStr) | ||||
|     if err != nil { | ||||
|         c.Log.Fatalf("Failed to login to Matrix with user '%s' (conn %s): '%s'", mxc.username, mxc.conn_name, err.Error()) | ||||
|     } | ||||
|     // Parse received JSON and get access token. | ||||
|     data := make(map[string]string) | ||||
|     err1 := json.Unmarshal(reply, &data) | ||||
|     if err1 != nil { | ||||
|         c.Log.Fatalf("Failed to parse received JSON from Matrix for user '%s' (conn %s): %s", mxc.username, mxc.conn_name, err1.Error()) | ||||
|     } | ||||
|     mxc.token = data["access_token"] | ||||
|     mxc.device_id = data["device_id"] | ||||
| 	loginStr := fmt.Sprintf(`{"type": "m.login.password", "user": "%s", "password": "%s"}`, mxc.username, mxc.password) | ||||
| 	c.Log.Debugln("Login string:", loginStr) | ||||
| 	reply, err := mxc.doPostRequest("/login", loginStr) | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalf("Failed to login to Matrix with user '%s' (conn %s): '%s'", mxc.username, mxc.conn_name, err.Error()) | ||||
| 	} | ||||
| 	// Parse received JSON and get access token. | ||||
| 	data := make(map[string]string) | ||||
| 	err1 := json.Unmarshal(reply, &data) | ||||
| 	if err1 != nil { | ||||
| 		c.Log.Fatalf("Failed to parse received JSON from Matrix for user '%s' (conn %s): %s", mxc.username, mxc.conn_name, err1.Error()) | ||||
| 	} | ||||
| 	mxc.token = data["access_token"] | ||||
| 	mxc.device_id = data["device_id"] | ||||
|  | ||||
|     c.Log.Debugf("Login successful for conn '%s', access token is '%s', our device_id is '%s'", mxc.conn_name, mxc.token, mxc.device_id) | ||||
| 	c.Log.Debugf("Login successful for conn '%s', access token is '%s', our device_id is '%s'", mxc.conn_name, mxc.token, mxc.device_id) | ||||
|  | ||||
|     // We should check if we're already in room and, if not, join it. | ||||
|     // We will do this by simply trying to join. We don't care about reply | ||||
|     // here. | ||||
|     _, err2 := mxc.doPostRequest("/rooms/" + mxc.room_id + "/join", "{}") | ||||
|     if err2 != nil { | ||||
|         c.Log.Fatalf("Failed to join room: %s", err2.Error()) | ||||
|     } | ||||
| 	// We should check if we're already in room and, if not, join it. | ||||
| 	// We will do this by simply trying to join. We don't care about reply | ||||
| 	// here. | ||||
| 	_, err2 := mxc.doPostRequest("/rooms/"+mxc.room_id+"/join", "{}") | ||||
| 	if err2 != nil { | ||||
| 		c.Log.Fatalf("Failed to join room: %s", err2.Error()) | ||||
| 	} | ||||
|  | ||||
|     // If we're here - everything is okay and we already in room. Send | ||||
|     // greeting message. | ||||
|     mxc.SendMessage("OpenSAPS is back in business for connection '" + mxc.conn_name + "'!") | ||||
| 	// If we're here - everything is okay and we already in room. Send | ||||
| 	// greeting message. | ||||
| 	mxc.SendMessage("OpenSAPS is back in business for connection '" + mxc.conn_name + "'!") | ||||
| } | ||||
|  | ||||
| // This function launches when new data was received thru Slack API. | ||||
| // It will prepare a message which will be passed to mxc.SendMessage(). | ||||
| func (mxc *MatrixConnection) ProcessMessage(message slackmessage.SlackMessage) { | ||||
|     // Prepare message body. | ||||
|     message_data := c.SendToParser(message.Username, message) | ||||
| 	// Prepare message body. | ||||
| 	message_data := c.SendToParser(message.Username, message) | ||||
|  | ||||
|     // Get message template. | ||||
|     msg_tpl := message_data["message"] | ||||
|     delete(message_data, "message") | ||||
| 	// Get message template. | ||||
| 	msg_tpl := message_data["message"] | ||||
| 	delete(message_data, "message") | ||||
|  | ||||
|     // Repeatables. | ||||
|     var repeatables []string | ||||
|     repeatables_raw, repeatables_found := message_data["repeatables"] | ||||
|     if repeatables_found { | ||||
|         repeatables = strings.Split(repeatables_raw, ",") | ||||
|         c.Log.Debugln("Repeatable keys:", repeatables, ", length:", len(repeatables)) | ||||
|     } | ||||
| 	// Repeatables. | ||||
| 	var repeatables []string | ||||
| 	repeatables_raw, repeatables_found := message_data["repeatables"] | ||||
| 	if repeatables_found { | ||||
| 		repeatables = strings.Split(repeatables_raw, ",") | ||||
| 		c.Log.Debugln("Repeatable keys:", repeatables, ", length:", len(repeatables)) | ||||
| 	} | ||||
|  | ||||
|     // Process keys. | ||||
|     for key, value := range message_data { | ||||
|         // Do nothing for keys with "_url" appendix. | ||||
|         if strings.Contains(key, "_url") { | ||||
|             c.Log.Debugln("_url key found in pre-stage, skipping:", key) | ||||
|             continue | ||||
|         } | ||||
|         // Do nothing (yet) on repeatables. | ||||
|         if strings.Contains(key, "repeatable") { | ||||
|             c.Log.Debugln("Key containing 'repeatable' in pre-stage, skipping:", key) | ||||
|             continue | ||||
|         } | ||||
| 	// Process keys. | ||||
| 	for key, value := range message_data { | ||||
| 		// Do nothing for keys with "_url" appendix. | ||||
| 		if strings.Contains(key, "_url") { | ||||
| 			c.Log.Debugln("_url key found in pre-stage, skipping:", key) | ||||
| 			continue | ||||
| 		} | ||||
| 		// Do nothing (yet) on repeatables. | ||||
| 		if strings.Contains(key, "repeatable") { | ||||
| 			c.Log.Debugln("Key containing 'repeatable' in pre-stage, skipping:", key) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
|         if len(repeatables) > 0 { | ||||
|             if strings.Contains(key, "repeatable_item_") { | ||||
|                 c.Log.Debugln("Repeatable key in pre-stage, skipping:", key) | ||||
|                 continue | ||||
|             } | ||||
|         } | ||||
|         c.Log.Debugln("Processing message data key:", key) | ||||
| 		if len(repeatables) > 0 { | ||||
| 			if strings.Contains(key, "repeatable_item_") { | ||||
| 				c.Log.Debugln("Repeatable key in pre-stage, skipping:", key) | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 		c.Log.Debugln("Processing message data key:", key) | ||||
|  | ||||
|         // Check if we have an item with "_url" appendix. This means | ||||
|         // that we should generate a link. | ||||
|         val_url, found := message_data[key + "_url"] | ||||
|         // Generate a link and put into message if key with "_url" | ||||
|         // was found. | ||||
|         var s string = "" | ||||
|         if found { | ||||
|             c.Log.Debugln("Found _url key, will create HTML link") | ||||
|             s = fmt.Sprintf("<a href='%s'>%s</a>", val_url, value) | ||||
|         } else { | ||||
|             c.Log.Debugln("Found no _url key, will use as-is") | ||||
|             s = value | ||||
|         } | ||||
|         msg_tpl = strings.Replace(msg_tpl, "{" + key + "}", s, -1) | ||||
|     } | ||||
| 		// Check if we have an item with "_url" appendix. This means | ||||
| 		// that we should generate a link. | ||||
| 		val_url, found := message_data[key+"_url"] | ||||
| 		// Generate a link and put into message if key with "_url" | ||||
| 		// was found. | ||||
| 		var s string = "" | ||||
| 		if found { | ||||
| 			c.Log.Debugln("Found _url key, will create HTML link") | ||||
| 			s = fmt.Sprintf("<a href='%s'>%s</a>", val_url, value) | ||||
| 		} else { | ||||
| 			c.Log.Debugln("Found no _url key, will use as-is") | ||||
| 			s = value | ||||
| 		} | ||||
| 		msg_tpl = strings.Replace(msg_tpl, "{"+key+"}", s, -1) | ||||
| 	} | ||||
|  | ||||
|     // Process repeatables. | ||||
|     repeatable_tpl, repeatable_found := message_data["repeatable_message"] | ||||
|     if repeatable_found { | ||||
|         var repeatables_string string = "" | ||||
|         repeatables_count, _ := strconv.Atoi(message_data["repeatables_count"]) | ||||
|         idx := 0 | ||||
|         for { | ||||
|             if (idx == repeatables_count) { | ||||
|                 c.Log.Debug("IDX goes above repeatables_count, breaking loop") | ||||
|                 break | ||||
|             } | ||||
| 	// Process repeatables. | ||||
| 	repeatable_tpl, repeatable_found := message_data["repeatable_message"] | ||||
| 	if repeatable_found { | ||||
| 		var repeatables_string string = "" | ||||
| 		repeatables_count, _ := strconv.Atoi(message_data["repeatables_count"]) | ||||
| 		idx := 0 | ||||
| 		for { | ||||
| 			if idx == repeatables_count { | ||||
| 				c.Log.Debug("IDX goes above repeatables_count, breaking loop") | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
|             var repstring string = repeatable_tpl | ||||
|             for i := range repeatables { | ||||
|                 c.Log.Debugln("Processing repeatable variable:", repeatables[i] + strconv.Itoa(idx)) | ||||
|                 var data string = "" | ||||
|                 rdata := message_data["repeatable_item_" + repeatables[i] + strconv.Itoa(idx)] | ||||
|                 rurl, rurl_found := message_data["repeatable_item_" + repeatables[i] + strconv.Itoa(idx) + "_url"] | ||||
|                 if rurl_found { | ||||
|                     c.Log.Debugln("Found _url key, will create HTML link") | ||||
|                     data = fmt.Sprintf("<a href='%s'>%s</a>", rurl, rdata) | ||||
|                 } else { | ||||
|                     c.Log.Debugln("Found no _url key, will use as-is") | ||||
|                     data = rdata | ||||
|                 } | ||||
|                 repstring = strings.Replace(repstring, "{" + repeatables[i] + "}", data, -1) | ||||
|             } | ||||
| 			var repstring string = repeatable_tpl | ||||
| 			for i := range repeatables { | ||||
| 				c.Log.Debugln("Processing repeatable variable:", repeatables[i]+strconv.Itoa(idx)) | ||||
| 				var data string = "" | ||||
| 				rdata := message_data["repeatable_item_"+repeatables[i]+strconv.Itoa(idx)] | ||||
| 				rurl, rurl_found := message_data["repeatable_item_"+repeatables[i]+strconv.Itoa(idx)+"_url"] | ||||
| 				if rurl_found { | ||||
| 					c.Log.Debugln("Found _url key, will create HTML link") | ||||
| 					data = fmt.Sprintf("<a href='%s'>%s</a>", rurl, rdata) | ||||
| 				} else { | ||||
| 					c.Log.Debugln("Found no _url key, will use as-is") | ||||
| 					data = rdata | ||||
| 				} | ||||
| 				repstring = strings.Replace(repstring, "{"+repeatables[i]+"}", data, -1) | ||||
| 			} | ||||
|  | ||||
|             repeatables_string += repstring | ||||
|             c.Log.Debugln("Repeatable string:", repstring) | ||||
|             idx += 1 | ||||
|         } | ||||
| 			repeatables_string += repstring | ||||
| 			c.Log.Debugln("Repeatable string:", repstring) | ||||
| 			idx += 1 | ||||
| 		} | ||||
|  | ||||
|         msg_tpl = strings.Replace(msg_tpl, "{repeatables}", repeatables_string, -1) | ||||
|     } | ||||
| 		msg_tpl = strings.Replace(msg_tpl, "{repeatables}", repeatables_string, -1) | ||||
| 	} | ||||
|  | ||||
|     msg_tpl = strings.Replace(msg_tpl, "{newline}", "<br />", -1) | ||||
| 	msg_tpl = strings.Replace(msg_tpl, "{newline}", "<br />", -1) | ||||
|  | ||||
|     // Replace all "\n" with "<br />". | ||||
|     msg_tpl = strings.Replace(msg_tpl, "\n", "<br />", -1) | ||||
| 	// Replace all "\n" with "<br />". | ||||
| 	msg_tpl = strings.Replace(msg_tpl, "\n", "<br />", -1) | ||||
|  | ||||
|     c.Log.Debugln("Crafted message:", msg_tpl) | ||||
| 	c.Log.Debugln("Crafted message:", msg_tpl) | ||||
|  | ||||
|     // Send message. | ||||
|     mxc.SendMessage(msg_tpl) | ||||
| 	// Send message. | ||||
| 	mxc.SendMessage(msg_tpl) | ||||
| } | ||||
|  | ||||
| // This function sends already prepared message to room. | ||||
| func (mxc *MatrixConnection) SendMessage(message string) { | ||||
|     c.Log.Debugf("Sending message to connection '%s': '%s'", mxc.conn_name, message) | ||||
| 	c.Log.Debugf("Sending message to connection '%s': '%s'", mxc.conn_name, message) | ||||
|  | ||||
|     // We should send notices as it is preferred behaviour for bots and | ||||
|     // appservices. | ||||
|     //msgStr := fmt.Sprintf(`{"msgtype": "m.text", "body": "%s", "format": "org.matrix.custom.html", "formatted_body": "%s"}`, message, message) | ||||
|     msg := MatrixMessage{} | ||||
|     msg.MsgType = "m.notice" | ||||
|     msg.Body = message | ||||
|     msg.Format = "org.matrix.custom.html" | ||||
|     msg.FormattedBody = message | ||||
| 	// We should send notices as it is preferred behaviour for bots and | ||||
| 	// appservices. | ||||
| 	//msgStr := fmt.Sprintf(`{"msgtype": "m.text", "body": "%s", "format": "org.matrix.custom.html", "formatted_body": "%s"}`, message, message) | ||||
| 	msg := MatrixMessage{} | ||||
| 	msg.MsgType = "m.notice" | ||||
| 	msg.Body = message | ||||
| 	msg.Format = "org.matrix.custom.html" | ||||
| 	msg.FormattedBody = message | ||||
|  | ||||
|     msgBytes, err := json.Marshal(&msg) | ||||
|     if err != nil { | ||||
|         c.Log.Errorln("Failed to marshal message into JSON:", err.Error()) | ||||
|         return | ||||
|     } | ||||
|     msgStr := string(msgBytes) | ||||
| 	msgBytes, err := json.Marshal(&msg) | ||||
| 	if err != nil { | ||||
| 		c.Log.Errorln("Failed to marshal message into JSON:", err.Error()) | ||||
| 		return | ||||
| 	} | ||||
| 	msgStr := string(msgBytes) | ||||
|  | ||||
|     reply, err := mxc.doPutRequest("/rooms/" + mxc.room_id + "/send/m.room.message/" + mxc.generateTnxId(), msgStr) | ||||
|     if err != nil { | ||||
|         c.Log.Fatalf("Failed to send message to room '%s' (conn: '%s'): %s", mxc.room_id, mxc.conn_name, err.Error()) | ||||
|     } | ||||
|     c.Log.Debugf("Message sent, reply: %s", string(reply)) | ||||
| 	reply, err := mxc.doPutRequest("/rooms/"+mxc.room_id+"/send/m.room.message/"+mxc.generateTnxId(), msgStr) | ||||
| 	if err != nil { | ||||
| 		c.Log.Fatalf("Failed to send message to room '%s' (conn: '%s'): %s", mxc.room_id, mxc.conn_name, err.Error()) | ||||
| 	} | ||||
| 	c.Log.Debugf("Message sent, reply: %s", string(reply)) | ||||
| } | ||||
|  | ||||
| func (mxc *MatrixConnection) Shutdown() { | ||||
|     c.Log.Infof("Shutting down connection '%s'...", mxc.conn_name) | ||||
| 	c.Log.Infof("Shutting down connection '%s'...", mxc.conn_name) | ||||
|  | ||||
|     _, err := mxc.doPostRequest("/logout", "{}") | ||||
|     if err != nil { | ||||
|         c.Log.Errorf("Error occured while trying to log out from Matrix (conn %s): %s", mxc.conn_name, err.Error()) | ||||
|     } | ||||
|     mxc.token = "" | ||||
|     c.Log.Infof("Connection '%s' successfully shutted down", mxc.conn_name) | ||||
| 	_, err := mxc.doPostRequest("/logout", "{}") | ||||
| 	if err != nil { | ||||
| 		c.Log.Errorf("Error occured while trying to log out from Matrix (conn %s): %s", mxc.conn_name, err.Error()) | ||||
| 	} | ||||
| 	mxc.token = "" | ||||
| 	c.Log.Infof("Connection '%s' successfully shutted down", mxc.conn_name) | ||||
| } | ||||
|   | ||||
| @@ -18,39 +18,39 @@ | ||||
| package matrixpusher | ||||
|  | ||||
| import ( | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type MatrixPusher struct {} | ||||
| type MatrixPusher struct{} | ||||
|  | ||||
| func (mp MatrixPusher) Initialize() { | ||||
|     c.Log.Infoln("Initializing Matrix protocol pusher...") | ||||
| 	c.Log.Infoln("Initializing Matrix protocol pusher...") | ||||
|  | ||||
|     // Get configuration for pushers and initialize every connection. | ||||
|     cfg := c.Config.GetConfig() | ||||
|     for name, config := range cfg.Matrix { | ||||
|         c.Log.Infof("Initializing connection: '%s'", name) | ||||
|         conn := MatrixConnection{} | ||||
|         connections[name] = &conn | ||||
|         go conn.Initialize(name, config.ApiRoot, config.User, config.Password, config.Room) | ||||
|     } | ||||
| 	// Get configuration for pushers and initialize every connection. | ||||
| 	cfg := c.Config.GetConfig() | ||||
| 	for name, config := range cfg.Matrix { | ||||
| 		c.Log.Infof("Initializing connection: '%s'", name) | ||||
| 		conn := MatrixConnection{} | ||||
| 		connections[name] = &conn | ||||
| 		go conn.Initialize(name, config.ApiRoot, config.User, config.Password, config.Room) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (mp MatrixPusher) Push(connection string, data slackmessage.SlackMessage) { | ||||
|     conn, found := connections[connection] | ||||
|     if !found { | ||||
|         c.Log.Errorf("Connection not found: '%s'!", connection) | ||||
|         return | ||||
|     } | ||||
|     c.Log.Debugf("Pushing data to '%s'", connection) | ||||
|     conn.ProcessMessage(data) | ||||
| 	conn, found := connections[connection] | ||||
| 	if !found { | ||||
| 		c.Log.Errorf("Connection not found: '%s'!", connection) | ||||
| 		return | ||||
| 	} | ||||
| 	c.Log.Debugf("Pushing data to '%s'", connection) | ||||
| 	conn.ProcessMessage(data) | ||||
| } | ||||
|  | ||||
| func (mp MatrixPusher) Shutdown() { | ||||
|     c.Log.Infoln("Shutting down Matrix pusher...") | ||||
| 	c.Log.Infoln("Shutting down Matrix pusher...") | ||||
|  | ||||
|     for _, conn := range connections { | ||||
|         conn.Shutdown() | ||||
|     } | ||||
| 	for _, conn := range connections { | ||||
| 		conn.Shutdown() | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -19,8 +19,8 @@ package telegrampusher | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	"lab.pztrn.name/pztrn/opensaps/context" | ||||
| 	"lab.pztrn.name/pztrn/opensaps/pushers/interface" | ||||
| 	"source.pztrn.name/misc/opensaps/context" | ||||
| 	"source.pztrn.name/misc/opensaps/pushers/interface" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -26,7 +26,7 @@ import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	// local | ||||
| 	"lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type TelegramConnection struct { | ||||
|   | ||||
| @@ -19,7 +19,7 @@ package telegrampusher | ||||
|  | ||||
| import ( | ||||
| 	// local | ||||
| 	"lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type TelegramPusher struct{} | ||||
|   | ||||
| @@ -18,22 +18,22 @@ | ||||
| package slack | ||||
|  | ||||
| import ( | ||||
|     // stdlib | ||||
|     "net/http" | ||||
| 	// stdlib | ||||
| 	"net/http" | ||||
|  | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/context" | ||||
|     "lab.pztrn.name/pztrn/opensaps/slack/apiserverinterface" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/context" | ||||
| 	"source.pztrn.name/misc/opensaps/slack/apiserverinterface" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|     c *context.Context | ||||
|     // HTTP server. | ||||
|     httpsrv *http.Server | ||||
| 	c *context.Context | ||||
| 	// HTTP server. | ||||
| 	httpsrv *http.Server | ||||
| ) | ||||
|  | ||||
| func New(cc *context.Context) { | ||||
|     c = cc | ||||
|     sh := SlackAPIServer{} | ||||
|     c.RegisterSlackAPIServerInterface(slackapiserverinterface.SlackAPIServerInterface(sh)) | ||||
| 	c = cc | ||||
| 	sh := SlackAPIServer{} | ||||
| 	c.RegisterSlackAPIServerInterface(slackapiserverinterface.SlackAPIServerInterface(sh)) | ||||
| } | ||||
|   | ||||
| @@ -18,78 +18,78 @@ | ||||
| package slack | ||||
|  | ||||
| import ( | ||||
|     // stdlib | ||||
|     "encoding/json" | ||||
|     "fmt" | ||||
|     "io/ioutil" | ||||
|     "net/http" | ||||
|     "net/url" | ||||
|     "strings" | ||||
| 	// stdlib | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
|  | ||||
|     // local | ||||
|     "lab.pztrn.name/pztrn/opensaps/slack/message" | ||||
| 	// local | ||||
| 	"source.pztrn.name/misc/opensaps/slack/message" | ||||
| ) | ||||
|  | ||||
| type SlackHandler struct {} | ||||
| type SlackHandler struct{} | ||||
|  | ||||
| func (sh SlackHandler) ServeHTTP(respwriter http.ResponseWriter, req *http.Request) { | ||||
|     c.Log.Debugf("Received '%s' (empty = GET) request from %s, URL: '%s'", req.Method, req.Host, req.URL.Path) | ||||
| 	c.Log.Debugf("Received '%s' (empty = GET) request from %s, URL: '%s'", req.Method, req.Host, req.URL.Path) | ||||
|  | ||||
|     // We should catch only POST requests. Otherwise return HTTP 404. | ||||
|     if req.Method != "POST" { | ||||
|         c.Log.Debugln("Not a POST request, returning HTTP 404") | ||||
|         respwriter.WriteHeader(404) | ||||
|         fmt.Fprintf(respwriter, "NOT FOUND") | ||||
|         return | ||||
|     } | ||||
| 	// We should catch only POST requests. Otherwise return HTTP 404. | ||||
| 	if req.Method != "POST" { | ||||
| 		c.Log.Debugln("Not a POST request, returning HTTP 404") | ||||
| 		respwriter.WriteHeader(404) | ||||
| 		fmt.Fprintf(respwriter, "NOT FOUND") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
|     body, _ := ioutil.ReadAll(req.Body) | ||||
|     req.Body.Close() | ||||
| 	body, _ := ioutil.ReadAll(req.Body) | ||||
| 	req.Body.Close() | ||||
|  | ||||
|     c.Log.Debugf("Received body: %s", string(body)) | ||||
| 	c.Log.Debugf("Received body: %s", string(body)) | ||||
|  | ||||
|     // Try to figure out where we should push received data. | ||||
|     url_splitted := strings.Split(req.URL.Path, "/") | ||||
|     fmt.Println(url_splitted) | ||||
|     cfg := c.Config.GetConfig() | ||||
| 	// Try to figure out where we should push received data. | ||||
| 	url_splitted := strings.Split(req.URL.Path, "/") | ||||
| 	fmt.Println(url_splitted) | ||||
| 	cfg := c.Config.GetConfig() | ||||
|  | ||||
|     var sent_to_pusher bool = false | ||||
|     for name, config := range cfg.Webhooks { | ||||
|         if strings.Contains(url_splitted[2], config.Slack.Random1) && strings.Contains(url_splitted[3], config.Slack.Random2) && strings.Contains(url_splitted[4], config.Slack.LongRandom) { | ||||
|             c.Log.Debugf("Passed data belongs to '%s' and should go to '%s' pusher, protocol '%s'", name, config.Remote.PushTo, config.Remote.Pusher) | ||||
|             // Parse message into SlackMessage structure. | ||||
|             if strings.Contains(string(body)[0:7], "payload") { | ||||
|                 // We have HTTP form payload. It still should be a | ||||
|                 // parseable JSON string, we just need to do some | ||||
|                 // preparations. | ||||
|                 // First - remove "payload=" from the beginning. | ||||
|                 temp_body := string(body) | ||||
|                 temp_body = strings.Replace(temp_body, "payload=", "", 1) | ||||
|                 // Second - unescape data. | ||||
|                 temp_body, err := url.QueryUnescape(temp_body) | ||||
|                 if err != nil { | ||||
|                     c.Log.Errorln("Failed to decode body into parseable string!") | ||||
|                     return | ||||
|                 } | ||||
| 	var sent_to_pusher bool = false | ||||
| 	for name, config := range cfg.Webhooks { | ||||
| 		if strings.Contains(url_splitted[2], config.Slack.Random1) && strings.Contains(url_splitted[3], config.Slack.Random2) && strings.Contains(url_splitted[4], config.Slack.LongRandom) { | ||||
| 			c.Log.Debugf("Passed data belongs to '%s' and should go to '%s' pusher, protocol '%s'", name, config.Remote.PushTo, config.Remote.Pusher) | ||||
| 			// Parse message into SlackMessage structure. | ||||
| 			if strings.Contains(string(body)[0:7], "payload") { | ||||
| 				// We have HTTP form payload. It still should be a | ||||
| 				// parseable JSON string, we just need to do some | ||||
| 				// preparations. | ||||
| 				// First - remove "payload=" from the beginning. | ||||
| 				temp_body := string(body) | ||||
| 				temp_body = strings.Replace(temp_body, "payload=", "", 1) | ||||
| 				// Second - unescape data. | ||||
| 				temp_body, err := url.QueryUnescape(temp_body) | ||||
| 				if err != nil { | ||||
| 					c.Log.Errorln("Failed to decode body into parseable string!") | ||||
| 					return | ||||
| 				} | ||||
|  | ||||
|                 // And finally - convert body back to bytes. | ||||
|                 body = []byte(temp_body) | ||||
|             } | ||||
|             slackmsg := slackmessage.SlackMessage{} | ||||
|             err := json.Unmarshal(body, &slackmsg) | ||||
|             if err != nil { | ||||
|                 c.Log.Error("Failed to decode JSON into SlackMessage struct: '%s'", err.Error()) | ||||
|                 return | ||||
|             } | ||||
|             c.Log.Debug("Received message:", fmt.Sprintf("%+v", slackmsg)) | ||||
|             c.SendToPusher(config.Remote.Pusher, config.Remote.PushTo, slackmsg) | ||||
|             sent_to_pusher = true | ||||
|         } | ||||
|     } | ||||
| 				// And finally - convert body back to bytes. | ||||
| 				body = []byte(temp_body) | ||||
| 			} | ||||
| 			slackmsg := slackmessage.SlackMessage{} | ||||
| 			err := json.Unmarshal(body, &slackmsg) | ||||
| 			if err != nil { | ||||
| 				c.Log.Error("Failed to decode JSON into SlackMessage struct: '%s'", err.Error()) | ||||
| 				return | ||||
| 			} | ||||
| 			c.Log.Debug("Received message:", fmt.Sprintf("%+v", slackmsg)) | ||||
| 			c.SendToPusher(config.Remote.Pusher, config.Remote.PushTo, slackmsg) | ||||
| 			sent_to_pusher = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     if !sent_to_pusher { | ||||
|         c.Log.Debug("Don't know where to push data. Ignoring with HTTP 404") | ||||
|         respwriter.WriteHeader(404) | ||||
|         fmt.Fprintf(respwriter, "NOT FOUND") | ||||
|     } | ||||
| 	if !sent_to_pusher { | ||||
| 		c.Log.Debug("Don't know where to push data. Ignoring with HTTP 404") | ||||
| 		respwriter.WriteHeader(404) | ||||
| 		fmt.Fprintf(respwriter, "NOT FOUND") | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										1
									
								
								vendor/github.com/sirupsen/logrus/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/sirupsen/logrus/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| logrus | ||||
							
								
								
									
										15
									
								
								vendor/github.com/sirupsen/logrus/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/sirupsen/logrus/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| language: go | ||||
| go: | ||||
|   - 1.6.x | ||||
|   - 1.7.x | ||||
|   - 1.8.x | ||||
|   - tip | ||||
| env: | ||||
|   - GOMAXPROCS=4 GORACE=halt_on_error=1 | ||||
| install: | ||||
|   - go get github.com/stretchr/testify/assert | ||||
|   - go get gopkg.in/gemnasium/logrus-airbrake-hook.v2 | ||||
|   - go get golang.org/x/sys/unix | ||||
|   - go get golang.org/x/sys/windows | ||||
| script: | ||||
|   - go test -race -v ./... | ||||
							
								
								
									
										118
									
								
								vendor/github.com/sirupsen/logrus/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								vendor/github.com/sirupsen/logrus/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| # 1.0.4 | ||||
|  | ||||
| * Fix race when adding hooks (#612) | ||||
| * Fix terminal check in AppEngine (#635) | ||||
|  | ||||
| # 1.0.3 | ||||
|  | ||||
| * Replace example files with testable examples | ||||
|  | ||||
| # 1.0.2 | ||||
|  | ||||
| * bug: quote non-string values in text formatter (#583) | ||||
| * Make (*Logger) SetLevel a public method | ||||
|  | ||||
| # 1.0.1 | ||||
|  | ||||
| * bug: fix escaping in text formatter (#575) | ||||
|  | ||||
| # 1.0.0 | ||||
|  | ||||
| * Officially changed name to lower-case | ||||
| * bug: colors on Windows 10 (#541) | ||||
| * bug: fix race in accessing level (#512) | ||||
|  | ||||
| # 0.11.5 | ||||
|  | ||||
| * feature: add writer and writerlevel to entry (#372) | ||||
|  | ||||
| # 0.11.4 | ||||
|  | ||||
| * bug: fix undefined variable on solaris (#493) | ||||
|  | ||||
| # 0.11.3 | ||||
|  | ||||
| * formatter: configure quoting of empty values (#484) | ||||
| * formatter: configure quoting character (default is `"`) (#484) | ||||
| * bug: fix not importing io correctly in non-linux environments (#481) | ||||
|  | ||||
| # 0.11.2 | ||||
|  | ||||
| * bug: fix windows terminal detection (#476) | ||||
|  | ||||
| # 0.11.1 | ||||
|  | ||||
| * bug: fix tty detection with custom out (#471) | ||||
|  | ||||
| # 0.11.0 | ||||
|  | ||||
| * performance: Use bufferpool to allocate (#370) | ||||
| * terminal: terminal detection for app-engine (#343) | ||||
| * feature: exit handler (#375) | ||||
|  | ||||
| # 0.10.0 | ||||
|  | ||||
| * feature: Add a test hook (#180) | ||||
| * feature: `ParseLevel` is now case-insensitive (#326) | ||||
| * feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) | ||||
| * performance: avoid re-allocations on `WithFields` (#335) | ||||
|  | ||||
| # 0.9.0 | ||||
|  | ||||
| * logrus/text_formatter: don't emit empty msg | ||||
| * logrus/hooks/airbrake: move out of main repository | ||||
| * logrus/hooks/sentry: move out of main repository | ||||
| * logrus/hooks/papertrail: move out of main repository | ||||
| * logrus/hooks/bugsnag: move out of main repository | ||||
| * logrus/core: run tests with `-race` | ||||
| * logrus/core: detect TTY based on `stderr` | ||||
| * logrus/core: support `WithError` on logger | ||||
| * logrus/core: Solaris support | ||||
|  | ||||
| # 0.8.7 | ||||
|  | ||||
| * logrus/core: fix possible race (#216) | ||||
| * logrus/doc: small typo fixes and doc improvements | ||||
|  | ||||
|  | ||||
| # 0.8.6 | ||||
|  | ||||
| * hooks/raven: allow passing an initialized client | ||||
|  | ||||
| # 0.8.5 | ||||
|  | ||||
| * logrus/core: revert #208 | ||||
|  | ||||
| # 0.8.4 | ||||
|  | ||||
| * formatter/text: fix data race (#218) | ||||
|  | ||||
| # 0.8.3 | ||||
|  | ||||
| * logrus/core: fix entry log level (#208) | ||||
| * logrus/core: improve performance of text formatter by 40% | ||||
| * logrus/core: expose `LevelHooks` type | ||||
| * logrus/core: add support for DragonflyBSD and NetBSD | ||||
| * formatter/text: print structs more verbosely | ||||
|  | ||||
| # 0.8.2 | ||||
|  | ||||
| * logrus: fix more Fatal family functions | ||||
|  | ||||
| # 0.8.1 | ||||
|  | ||||
| * logrus: fix not exiting on `Fatalf` and `Fatalln` | ||||
|  | ||||
| # 0.8.0 | ||||
|  | ||||
| * logrus: defaults to stderr instead of stdout | ||||
| * hooks/sentry: add special field for `*http.Request` | ||||
| * formatter/text: ignore Windows for colors | ||||
|  | ||||
| # 0.7.3 | ||||
|  | ||||
| * formatter/\*: allow configuration of timestamp layout | ||||
|  | ||||
| # 0.7.2 | ||||
|  | ||||
| * formatter/text: Add configuration option for time format (#158) | ||||
							
								
								
									
										21
									
								
								vendor/github.com/sirupsen/logrus/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/sirupsen/logrus/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| The MIT License (MIT) | ||||
|  | ||||
| Copyright (c) 2014 Simon Eskildsen | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in | ||||
| all copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
| THE SOFTWARE. | ||||
							
								
								
									
										509
									
								
								vendor/github.com/sirupsen/logrus/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										509
									
								
								vendor/github.com/sirupsen/logrus/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,509 @@ | ||||
| # Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://travis-ci.org/sirupsen/logrus) [](https://godoc.org/github.com/sirupsen/logrus) | ||||
|  | ||||
| Logrus is a structured logger for Go (golang), completely API compatible with | ||||
| the standard library logger. | ||||
|  | ||||
| **Seeing weird case-sensitive problems?** It's in the past been possible to | ||||
| import Logrus as both upper- and lower-case. Due to the Go package environment, | ||||
| this caused issues in the community and we needed a standard. Some environments | ||||
| experienced problems with the upper-case variant, so the lower-case was decided. | ||||
| Everything using `logrus` will need to use the lower-case: | ||||
| `github.com/sirupsen/logrus`. Any package that isn't, should be changed. | ||||
|  | ||||
| To fix Glide, see [these | ||||
| comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437). | ||||
| For an in-depth explanation of the casing issue, see [this | ||||
| comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276). | ||||
|  | ||||
| **Are you interested in assisting in maintaining Logrus?** Currently I have a | ||||
| lot of obligations, and I am unable to provide Logrus with the maintainership it | ||||
| needs. If you'd like to help, please reach out to me at `simon at author's | ||||
| username dot com`. | ||||
|  | ||||
| Nicely color-coded in development (when a TTY is attached, otherwise just | ||||
| plain text): | ||||
|  | ||||
|  | ||||
|  | ||||
| With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash | ||||
| or Splunk: | ||||
|  | ||||
| ```json | ||||
| {"animal":"walrus","level":"info","msg":"A group of walrus emerges from the | ||||
| ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} | ||||
|  | ||||
| {"level":"warning","msg":"The group's number increased tremendously!", | ||||
| "number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} | ||||
|  | ||||
| {"animal":"walrus","level":"info","msg":"A giant walrus appears!", | ||||
| "size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} | ||||
|  | ||||
| {"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", | ||||
| "size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} | ||||
|  | ||||
| {"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, | ||||
| "time":"2014-03-10 19:57:38.562543128 -0400 EDT"} | ||||
| ``` | ||||
|  | ||||
| With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not | ||||
| attached, the output is compatible with the | ||||
| [logfmt](http://godoc.org/github.com/kr/logfmt) format: | ||||
|  | ||||
| ```text | ||||
| time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 | ||||
| time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 | ||||
| time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true | ||||
| time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 | ||||
| time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 | ||||
| time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true | ||||
| exit status 1 | ||||
| ``` | ||||
|  | ||||
| #### Case-sensitivity | ||||
|  | ||||
| The organization's name was changed to lower-case--and this will not be changed | ||||
| back. If you are getting import conflicts due to case sensitivity, please use | ||||
| the lower-case import: `github.com/sirupsen/logrus`. | ||||
|  | ||||
| #### Example | ||||
|  | ||||
| The simplest way to use Logrus is simply the package-level exported logger: | ||||
|  | ||||
| ```go | ||||
| package main | ||||
|  | ||||
| import ( | ||||
|   log "github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
|   log.WithFields(log.Fields{ | ||||
|     "animal": "walrus", | ||||
|   }).Info("A walrus appears") | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Note that it's completely api-compatible with the stdlib logger, so you can | ||||
| replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"` | ||||
| and you'll now have the flexibility of Logrus. You can customize it all you | ||||
| want: | ||||
|  | ||||
| ```go | ||||
| package main | ||||
|  | ||||
| import ( | ||||
|   "os" | ||||
|   log "github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
|   // Log as JSON instead of the default ASCII formatter. | ||||
|   log.SetFormatter(&log.JSONFormatter{}) | ||||
|  | ||||
|   // Output to stdout instead of the default stderr | ||||
|   // Can be any io.Writer, see below for File example | ||||
|   log.SetOutput(os.Stdout) | ||||
|  | ||||
|   // Only log the warning severity or above. | ||||
|   log.SetLevel(log.WarnLevel) | ||||
| } | ||||
|  | ||||
| func main() { | ||||
|   log.WithFields(log.Fields{ | ||||
|     "animal": "walrus", | ||||
|     "size":   10, | ||||
|   }).Info("A group of walrus emerges from the ocean") | ||||
|  | ||||
|   log.WithFields(log.Fields{ | ||||
|     "omg":    true, | ||||
|     "number": 122, | ||||
|   }).Warn("The group's number increased tremendously!") | ||||
|  | ||||
|   log.WithFields(log.Fields{ | ||||
|     "omg":    true, | ||||
|     "number": 100, | ||||
|   }).Fatal("The ice breaks!") | ||||
|  | ||||
|   // A common pattern is to re-use fields between logging statements by re-using | ||||
|   // the logrus.Entry returned from WithFields() | ||||
|   contextLogger := log.WithFields(log.Fields{ | ||||
|     "common": "this is a common field", | ||||
|     "other": "I also should be logged always", | ||||
|   }) | ||||
|  | ||||
|   contextLogger.Info("I'll be logged with common and other field") | ||||
|   contextLogger.Info("Me too") | ||||
| } | ||||
| ``` | ||||
|  | ||||
| For more advanced usage such as logging to multiple locations from the same | ||||
| application, you can also create an instance of the `logrus` Logger: | ||||
|  | ||||
| ```go | ||||
| package main | ||||
|  | ||||
| import ( | ||||
|   "os" | ||||
|   "github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| // Create a new instance of the logger. You can have any number of instances. | ||||
| var log = logrus.New() | ||||
|  | ||||
| func main() { | ||||
|   // The API for setting attributes is a little different than the package level | ||||
|   // exported logger. See Godoc. | ||||
|   log.Out = os.Stdout | ||||
|  | ||||
|   // You could set this to any `io.Writer` such as a file | ||||
|   // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) | ||||
|   // if err == nil { | ||||
|   //  log.Out = file | ||||
|   // } else { | ||||
|   //  log.Info("Failed to log to file, using default stderr") | ||||
|   // } | ||||
|  | ||||
|   log.WithFields(logrus.Fields{ | ||||
|     "animal": "walrus", | ||||
|     "size":   10, | ||||
|   }).Info("A group of walrus emerges from the ocean") | ||||
| } | ||||
| ``` | ||||
|  | ||||
| #### Fields | ||||
|  | ||||
| Logrus encourages careful, structured logging through logging fields instead of | ||||
| long, unparseable error messages. For example, instead of: `log.Fatalf("Failed | ||||
| to send event %s to topic %s with key %d")`, you should log the much more | ||||
| discoverable: | ||||
|  | ||||
| ```go | ||||
| log.WithFields(log.Fields{ | ||||
|   "event": event, | ||||
|   "topic": topic, | ||||
|   "key": key, | ||||
| }).Fatal("Failed to send event") | ||||
| ``` | ||||
|  | ||||
| We've found this API forces you to think about logging in a way that produces | ||||
| much more useful logging messages. We've been in countless situations where just | ||||
| a single added field to a log statement that was already there would've saved us | ||||
| hours. The `WithFields` call is optional. | ||||
|  | ||||
| In general, with Logrus using any of the `printf`-family functions should be | ||||
| seen as a hint you should add a field, however, you can still use the | ||||
| `printf`-family functions with Logrus. | ||||
|  | ||||
| #### Default Fields | ||||
|  | ||||
| Often it's helpful to have fields _always_ attached to log statements in an | ||||
| application or parts of one. For example, you may want to always log the | ||||
| `request_id` and `user_ip` in the context of a request. Instead of writing | ||||
| `log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on | ||||
| every line, you can create a `logrus.Entry` to pass around instead: | ||||
|  | ||||
| ```go | ||||
| requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) | ||||
| requestLogger.Info("something happened on that request") # will log request_id and user_ip | ||||
| requestLogger.Warn("something not great happened") | ||||
| ``` | ||||
|  | ||||
| #### Hooks | ||||
|  | ||||
| You can add hooks for logging levels. For example to send errors to an exception | ||||
| tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to | ||||
| multiple places simultaneously, e.g. syslog. | ||||
|  | ||||
| Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in | ||||
| `init`: | ||||
|  | ||||
| ```go | ||||
| import ( | ||||
|   log "github.com/sirupsen/logrus" | ||||
|   "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake" | ||||
|   logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" | ||||
|   "log/syslog" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
|  | ||||
|   // Use the Airbrake hook to report errors that have Error severity or above to | ||||
|   // an exception tracker. You can create custom hooks, see the Hooks section. | ||||
|   log.AddHook(airbrake.NewHook(123, "xyz", "production")) | ||||
|  | ||||
|   hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") | ||||
|   if err != nil { | ||||
|     log.Error("Unable to connect to local syslog daemon") | ||||
|   } else { | ||||
|     log.AddHook(hook) | ||||
|   } | ||||
| } | ||||
| ``` | ||||
| Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). | ||||
|  | ||||
| | Hook  | Description | | ||||
| | ----- | ----------- | | ||||
| | [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. | | ||||
| | [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. | | ||||
| | [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) | | ||||
| | [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) | | ||||
| | [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage| | ||||
| | [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | | ||||
| | [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic | | ||||
| | [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) | | ||||
| | [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| | ||||
| | [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/) | ||||
| | [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd | | ||||
| | [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) | | ||||
| | [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) | | ||||
| | [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. | | ||||
| | [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger | | ||||
| | [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb | | ||||
| | [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) | | ||||
| | [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` | | ||||
| | [KafkaLogrus](https://github.com/tracer0tong/kafkalogrus) | Hook for logging to Kafka | | ||||
| | [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem | | ||||
| | [Logbeat](https://github.com/macandmia/logbeat) | Hook for logging to [Opbeat](https://opbeat.com/) | | ||||
| | [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) | | ||||
| | [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) | | ||||
| | [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) | | ||||
| | [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) | | ||||
| | [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) | | ||||
| | [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | | ||||
| | [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) | | ||||
| | [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | | ||||
| | [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) | | ||||
| | [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit | | ||||
| | [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | | ||||
| | [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) | | ||||
| | [Promrus](https://github.com/weaveworks/promrus) | Expose number of log messages as [Prometheus](https://prometheus.io/) metrics | | ||||
| | [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) | | ||||
| | [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) | | ||||
| | [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) | | ||||
| | [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar | | ||||
| | [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)| | ||||
| | [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. | | ||||
| | [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. | | ||||
| | [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) | | ||||
| | [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)| | ||||
| | [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | | ||||
| | [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. | | ||||
| | [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) | | ||||
| | [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) | | ||||
| | [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | | ||||
| | [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash | | ||||
| | [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) | | ||||
|  | ||||
| #### Level logging | ||||
|  | ||||
| Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic. | ||||
|  | ||||
| ```go | ||||
| log.Debug("Useful debugging information.") | ||||
| log.Info("Something noteworthy happened!") | ||||
| log.Warn("You should probably take a look at this.") | ||||
| log.Error("Something failed but I'm not quitting.") | ||||
| // Calls os.Exit(1) after logging | ||||
| log.Fatal("Bye.") | ||||
| // Calls panic() after logging | ||||
| log.Panic("I'm bailing.") | ||||
| ``` | ||||
|  | ||||
| You can set the logging level on a `Logger`, then it will only log entries with | ||||
| that severity or anything above it: | ||||
|  | ||||
| ```go | ||||
| // Will log anything that is info or above (warn, error, fatal, panic). Default. | ||||
| log.SetLevel(log.InfoLevel) | ||||
| ``` | ||||
|  | ||||
| It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose | ||||
| environment if your application has that. | ||||
|  | ||||
| #### Entries | ||||
|  | ||||
| Besides the fields added with `WithField` or `WithFields` some fields are | ||||
| automatically added to all logging events: | ||||
|  | ||||
| 1. `time`. The timestamp when the entry was created. | ||||
| 2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after | ||||
|    the `AddFields` call. E.g. `Failed to send event.` | ||||
| 3. `level`. The logging level. E.g. `info`. | ||||
|  | ||||
| #### Environments | ||||
|  | ||||
| Logrus has no notion of environment. | ||||
|  | ||||
| If you wish for hooks and formatters to only be used in specific environments, | ||||
| you should handle that yourself. For example, if your application has a global | ||||
| variable `Environment`, which is a string representation of the environment you | ||||
| could do: | ||||
|  | ||||
| ```go | ||||
| import ( | ||||
|   log "github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| init() { | ||||
|   // do something here to set environment depending on an environment variable | ||||
|   // or command-line flag | ||||
|   if Environment == "production" { | ||||
|     log.SetFormatter(&log.JSONFormatter{}) | ||||
|   } else { | ||||
|     // The TextFormatter is default, you don't actually have to do this. | ||||
|     log.SetFormatter(&log.TextFormatter{}) | ||||
|   } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| This configuration is how `logrus` was intended to be used, but JSON in | ||||
| production is mostly only useful if you do log aggregation with tools like | ||||
| Splunk or Logstash. | ||||
|  | ||||
| #### Formatters | ||||
|  | ||||
| The built-in logging formatters are: | ||||
|  | ||||
| * `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise | ||||
|   without colors. | ||||
|   * *Note:* to force colored output when there is no TTY, set the `ForceColors` | ||||
|     field to `true`.  To force no colored output even if there is a TTY  set the | ||||
|     `DisableColors` field to `true`. For Windows, see | ||||
|     [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). | ||||
|   * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). | ||||
| * `logrus.JSONFormatter`. Logs fields as JSON. | ||||
|   * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). | ||||
|  | ||||
| Third party logging formatters: | ||||
|  | ||||
| * [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. | ||||
| * [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. | ||||
| * [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. | ||||
| * [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. | ||||
|  | ||||
| You can define your formatter by implementing the `Formatter` interface, | ||||
| requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a | ||||
| `Fields` type (`map[string]interface{}`) with all your fields as well as the | ||||
| default ones (see Entries section above): | ||||
|  | ||||
| ```go | ||||
| type MyJSONFormatter struct { | ||||
| } | ||||
|  | ||||
| log.SetFormatter(new(MyJSONFormatter)) | ||||
|  | ||||
| func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { | ||||
|   // Note this doesn't include Time, Level and Message which are available on | ||||
|   // the Entry. Consult `godoc` on information about those fields or read the | ||||
|   // source of the official loggers. | ||||
|   serialized, err := json.Marshal(entry.Data) | ||||
|     if err != nil { | ||||
|       return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) | ||||
|     } | ||||
|   return append(serialized, '\n'), nil | ||||
| } | ||||
| ``` | ||||
|  | ||||
| #### Logger as an `io.Writer` | ||||
|  | ||||
| Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. | ||||
|  | ||||
| ```go | ||||
| w := logger.Writer() | ||||
| defer w.Close() | ||||
|  | ||||
| srv := http.Server{ | ||||
|     // create a stdlib log.Logger that writes to | ||||
|     // logrus.Logger. | ||||
|     ErrorLog: log.New(w, "", 0), | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Each line written to that writer will be printed the usual way, using formatters | ||||
| and hooks. The level for those entries is `info`. | ||||
|  | ||||
| This means that we can override the standard library logger easily: | ||||
|  | ||||
| ```go | ||||
| logger := logrus.New() | ||||
| logger.Formatter = &logrus.JSONFormatter{} | ||||
|  | ||||
| // Use logrus for standard log output | ||||
| // Note that `log` here references stdlib's log | ||||
| // Not logrus imported under the name `log`. | ||||
| log.SetOutput(logger.Writer()) | ||||
| ``` | ||||
|  | ||||
| #### Rotation | ||||
|  | ||||
| Log rotation is not provided with Logrus. Log rotation should be done by an | ||||
| external program (like `logrotate(8)`) that can compress and delete old log | ||||
| entries. It should not be a feature of the application-level logger. | ||||
|  | ||||
| #### Tools | ||||
|  | ||||
| | Tool | Description | | ||||
| | ---- | ----------- | | ||||
| |[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| | ||||
| |[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | | ||||
|  | ||||
| #### Testing | ||||
|  | ||||
| Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: | ||||
|  | ||||
| * decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook | ||||
| * a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): | ||||
|  | ||||
| ```go | ||||
| import( | ||||
|   "github.com/sirupsen/logrus" | ||||
|   "github.com/sirupsen/logrus/hooks/test" | ||||
|   "github.com/stretchr/testify/assert" | ||||
|   "testing" | ||||
| ) | ||||
|  | ||||
| func TestSomething(t*testing.T){ | ||||
|   logger, hook := test.NewNullLogger() | ||||
|   logger.Error("Helloerror") | ||||
|  | ||||
|   assert.Equal(t, 1, len(hook.Entries)) | ||||
|   assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level) | ||||
|   assert.Equal(t, "Helloerror", hook.LastEntry().Message) | ||||
|  | ||||
|   hook.Reset() | ||||
|   assert.Nil(t, hook.LastEntry()) | ||||
| } | ||||
| ``` | ||||
|  | ||||
| #### Fatal handlers | ||||
|  | ||||
| Logrus can register one or more functions that will be called when any `fatal` | ||||
| level message is logged. The registered handlers will be executed before | ||||
| logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need | ||||
| to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. | ||||
|  | ||||
| ``` | ||||
| ... | ||||
| handler := func() { | ||||
|   // gracefully shutdown something... | ||||
| } | ||||
| logrus.RegisterExitHandler(handler) | ||||
| ... | ||||
| ``` | ||||
|  | ||||
| #### Thread safety | ||||
|  | ||||
| By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs. | ||||
| If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. | ||||
|  | ||||
| Situation when locking is not needed includes: | ||||
|  | ||||
| * You have no hooks registered, or hooks calling is already thread-safe. | ||||
|  | ||||
| * Writing to logger.Out is already thread-safe, for example: | ||||
|  | ||||
|   1) logger.Out is protected by locks. | ||||
|  | ||||
|   2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing) | ||||
|  | ||||
|      (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/) | ||||
							
								
								
									
										64
									
								
								vendor/github.com/sirupsen/logrus/alt_exit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								vendor/github.com/sirupsen/logrus/alt_exit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| package logrus | ||||
|  | ||||
| // The following code was sourced and modified from the | ||||
| // https://github.com/tebeka/atexit package governed by the following license: | ||||
| // | ||||
| // Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>. | ||||
| // | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| // this software and associated documentation files (the "Software"), to deal in | ||||
| // the Software without restriction, including without limitation the rights to | ||||
| // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| // the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| // subject to the following conditions: | ||||
| // | ||||
| // The above copyright notice and this permission notice shall be included in all | ||||
| // copies or substantial portions of the Software. | ||||
| // | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| var handlers = []func(){} | ||||
|  | ||||
| func runHandler(handler func()) { | ||||
| 	defer func() { | ||||
| 		if err := recover(); err != nil { | ||||
| 			fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err) | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	handler() | ||||
| } | ||||
|  | ||||
| func runHandlers() { | ||||
| 	for _, handler := range handlers { | ||||
| 		runHandler(handler) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) | ||||
| func Exit(code int) { | ||||
| 	runHandlers() | ||||
| 	os.Exit(code) | ||||
| } | ||||
|  | ||||
| // RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke | ||||
| // all handlers. The handlers will also be invoked when any Fatal log entry is | ||||
| // made. | ||||
| // | ||||
| // This method is useful when a caller wishes to use logrus to log a fatal | ||||
| // message but also needs to gracefully shutdown. An example usecase could be | ||||
| // closing database connections, or sending a alert that the application is | ||||
| // closing. | ||||
| func RegisterExitHandler(handler func()) { | ||||
| 	handlers = append(handlers, handler) | ||||
| } | ||||
							
								
								
									
										83
									
								
								vendor/github.com/sirupsen/logrus/alt_exit_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								vendor/github.com/sirupsen/logrus/alt_exit_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestRegister(t *testing.T) { | ||||
| 	current := len(handlers) | ||||
| 	RegisterExitHandler(func() {}) | ||||
| 	if len(handlers) != current+1 { | ||||
| 		t.Fatalf("expected %d handlers, got %d", current+1, len(handlers)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestHandler(t *testing.T) { | ||||
| 	tempDir, err := ioutil.TempDir("", "test_handler") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("can't create temp dir. %q", err) | ||||
| 	} | ||||
| 	defer os.RemoveAll(tempDir) | ||||
|  | ||||
| 	gofile := filepath.Join(tempDir, "gofile.go") | ||||
| 	if err := ioutil.WriteFile(gofile, testprog, 0666); err != nil { | ||||
| 		t.Fatalf("can't create go file. %q", err) | ||||
| 	} | ||||
|  | ||||
| 	outfile := filepath.Join(tempDir, "outfile.out") | ||||
| 	arg := time.Now().UTC().String() | ||||
| 	err = exec.Command("go", "run", gofile, outfile, arg).Run() | ||||
| 	if err == nil { | ||||
| 		t.Fatalf("completed normally, should have failed") | ||||
| 	} | ||||
|  | ||||
| 	data, err := ioutil.ReadFile(outfile) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("can't read output file %s. %q", outfile, err) | ||||
| 	} | ||||
|  | ||||
| 	if string(data) != arg { | ||||
| 		t.Fatalf("bad data. Expected %q, got %q", data, arg) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var testprog = []byte(` | ||||
| // Test program for atexit, gets output file and data as arguments and writes | ||||
| // data to output file in atexit handler. | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| ) | ||||
|  | ||||
| var outfile = "" | ||||
| var data = "" | ||||
|  | ||||
| func handler() { | ||||
| 	ioutil.WriteFile(outfile, []byte(data), 0666) | ||||
| } | ||||
|  | ||||
| func badHandler() { | ||||
| 	n := 0 | ||||
| 	fmt.Println(1/n) | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	flag.Parse() | ||||
| 	outfile = flag.Arg(0) | ||||
| 	data = flag.Arg(1) | ||||
|  | ||||
| 	logrus.RegisterExitHandler(handler) | ||||
| 	logrus.RegisterExitHandler(badHandler) | ||||
| 	logrus.Fatal("Bye bye") | ||||
| } | ||||
| `) | ||||
							
								
								
									
										14
									
								
								vendor/github.com/sirupsen/logrus/appveyor.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/sirupsen/logrus/appveyor.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| version: "{build}" | ||||
| platform: x64 | ||||
| clone_folder: c:\gopath\src\github.com\sirupsen\logrus | ||||
| environment:   | ||||
|   GOPATH: c:\gopath | ||||
| branches:   | ||||
|   only: | ||||
|     - master | ||||
| install:   | ||||
|   - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% | ||||
|   - go version | ||||
| build_script:   | ||||
|   - go get -t | ||||
|   - go test | ||||
							
								
								
									
										26
									
								
								vendor/github.com/sirupsen/logrus/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/sirupsen/logrus/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| /* | ||||
| Package logrus is a structured logger for Go, completely API compatible with the standard library logger. | ||||
|  | ||||
|  | ||||
| The simplest way to use Logrus is simply the package-level exported logger: | ||||
|  | ||||
|   package main | ||||
|  | ||||
|   import ( | ||||
|     log "github.com/sirupsen/logrus" | ||||
|   ) | ||||
|  | ||||
|   func main() { | ||||
|     log.WithFields(log.Fields{ | ||||
|       "animal": "walrus", | ||||
|       "number": 1, | ||||
|       "size":   10, | ||||
|     }).Info("A walrus appears") | ||||
|   } | ||||
|  | ||||
| Output: | ||||
|   time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 | ||||
|  | ||||
| For a full guide visit https://github.com/sirupsen/logrus | ||||
| */ | ||||
| package logrus | ||||
							
								
								
									
										279
									
								
								vendor/github.com/sirupsen/logrus/entry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								vendor/github.com/sirupsen/logrus/entry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,279 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| var bufferPool *sync.Pool | ||||
|  | ||||
| func init() { | ||||
| 	bufferPool = &sync.Pool{ | ||||
| 		New: func() interface{} { | ||||
| 			return new(bytes.Buffer) | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Defines the key when adding errors using WithError. | ||||
| var ErrorKey = "error" | ||||
|  | ||||
| // An entry is the final or intermediate Logrus logging entry. It contains all | ||||
| // the fields passed with WithField{,s}. It's finally logged when Debug, Info, | ||||
| // Warn, Error, Fatal or Panic is called on it. These objects can be reused and | ||||
| // passed around as much as you wish to avoid field duplication. | ||||
| type Entry struct { | ||||
| 	Logger *Logger | ||||
|  | ||||
| 	// Contains all the fields set by the user. | ||||
| 	Data Fields | ||||
|  | ||||
| 	// Time at which the log entry was created | ||||
| 	Time time.Time | ||||
|  | ||||
| 	// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic | ||||
| 	// This field will be set on entry firing and the value will be equal to the one in Logger struct field. | ||||
| 	Level Level | ||||
|  | ||||
| 	// Message passed to Debug, Info, Warn, Error, Fatal or Panic | ||||
| 	Message string | ||||
|  | ||||
| 	// When formatter is called in entry.log(), an Buffer may be set to entry | ||||
| 	Buffer *bytes.Buffer | ||||
| } | ||||
|  | ||||
| func NewEntry(logger *Logger) *Entry { | ||||
| 	return &Entry{ | ||||
| 		Logger: logger, | ||||
| 		// Default is three fields, give a little extra room | ||||
| 		Data: make(Fields, 5), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Returns the string representation from the reader and ultimately the | ||||
| // formatter. | ||||
| func (entry *Entry) String() (string, error) { | ||||
| 	serialized, err := entry.Logger.Formatter.Format(entry) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	str := string(serialized) | ||||
| 	return str, nil | ||||
| } | ||||
|  | ||||
| // Add an error as single field (using the key defined in ErrorKey) to the Entry. | ||||
| func (entry *Entry) WithError(err error) *Entry { | ||||
| 	return entry.WithField(ErrorKey, err) | ||||
| } | ||||
|  | ||||
| // Add a single field to the Entry. | ||||
| func (entry *Entry) WithField(key string, value interface{}) *Entry { | ||||
| 	return entry.WithFields(Fields{key: value}) | ||||
| } | ||||
|  | ||||
| // Add a map of fields to the Entry. | ||||
| func (entry *Entry) WithFields(fields Fields) *Entry { | ||||
| 	data := make(Fields, len(entry.Data)+len(fields)) | ||||
| 	for k, v := range entry.Data { | ||||
| 		data[k] = v | ||||
| 	} | ||||
| 	for k, v := range fields { | ||||
| 		data[k] = v | ||||
| 	} | ||||
| 	return &Entry{Logger: entry.Logger, Data: data} | ||||
| } | ||||
|  | ||||
| // This function is not declared with a pointer value because otherwise | ||||
| // race conditions will occur when using multiple goroutines | ||||
| func (entry Entry) log(level Level, msg string) { | ||||
| 	var buffer *bytes.Buffer | ||||
| 	entry.Time = time.Now() | ||||
| 	entry.Level = level | ||||
| 	entry.Message = msg | ||||
|  | ||||
| 	entry.Logger.mu.Lock() | ||||
| 	err := entry.Logger.Hooks.Fire(level, &entry) | ||||
| 	entry.Logger.mu.Unlock() | ||||
| 	if err != nil { | ||||
| 		entry.Logger.mu.Lock() | ||||
| 		fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) | ||||
| 		entry.Logger.mu.Unlock() | ||||
| 	} | ||||
| 	buffer = bufferPool.Get().(*bytes.Buffer) | ||||
| 	buffer.Reset() | ||||
| 	defer bufferPool.Put(buffer) | ||||
| 	entry.Buffer = buffer | ||||
| 	serialized, err := entry.Logger.Formatter.Format(&entry) | ||||
| 	entry.Buffer = nil | ||||
| 	if err != nil { | ||||
| 		entry.Logger.mu.Lock() | ||||
| 		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) | ||||
| 		entry.Logger.mu.Unlock() | ||||
| 	} else { | ||||
| 		entry.Logger.mu.Lock() | ||||
| 		_, err = entry.Logger.Out.Write(serialized) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) | ||||
| 		} | ||||
| 		entry.Logger.mu.Unlock() | ||||
| 	} | ||||
|  | ||||
| 	// To avoid Entry#log() returning a value that only would make sense for | ||||
| 	// panic() to use in Entry#Panic(), we avoid the allocation by checking | ||||
| 	// directly here. | ||||
| 	if level <= PanicLevel { | ||||
| 		panic(&entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Debug(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= DebugLevel { | ||||
| 		entry.log(DebugLevel, fmt.Sprint(args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Print(args ...interface{}) { | ||||
| 	entry.Info(args...) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Info(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= InfoLevel { | ||||
| 		entry.log(InfoLevel, fmt.Sprint(args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Warn(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= WarnLevel { | ||||
| 		entry.log(WarnLevel, fmt.Sprint(args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Warning(args ...interface{}) { | ||||
| 	entry.Warn(args...) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Error(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= ErrorLevel { | ||||
| 		entry.log(ErrorLevel, fmt.Sprint(args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Fatal(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= FatalLevel { | ||||
| 		entry.log(FatalLevel, fmt.Sprint(args...)) | ||||
| 	} | ||||
| 	Exit(1) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Panic(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= PanicLevel { | ||||
| 		entry.log(PanicLevel, fmt.Sprint(args...)) | ||||
| 	} | ||||
| 	panic(fmt.Sprint(args...)) | ||||
| } | ||||
|  | ||||
| // Entry Printf family functions | ||||
|  | ||||
| func (entry *Entry) Debugf(format string, args ...interface{}) { | ||||
| 	if entry.Logger.level() >= DebugLevel { | ||||
| 		entry.Debug(fmt.Sprintf(format, args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Infof(format string, args ...interface{}) { | ||||
| 	if entry.Logger.level() >= InfoLevel { | ||||
| 		entry.Info(fmt.Sprintf(format, args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Printf(format string, args ...interface{}) { | ||||
| 	entry.Infof(format, args...) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Warnf(format string, args ...interface{}) { | ||||
| 	if entry.Logger.level() >= WarnLevel { | ||||
| 		entry.Warn(fmt.Sprintf(format, args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Warningf(format string, args ...interface{}) { | ||||
| 	entry.Warnf(format, args...) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Errorf(format string, args ...interface{}) { | ||||
| 	if entry.Logger.level() >= ErrorLevel { | ||||
| 		entry.Error(fmt.Sprintf(format, args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Fatalf(format string, args ...interface{}) { | ||||
| 	if entry.Logger.level() >= FatalLevel { | ||||
| 		entry.Fatal(fmt.Sprintf(format, args...)) | ||||
| 	} | ||||
| 	Exit(1) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Panicf(format string, args ...interface{}) { | ||||
| 	if entry.Logger.level() >= PanicLevel { | ||||
| 		entry.Panic(fmt.Sprintf(format, args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Entry Println family functions | ||||
|  | ||||
| func (entry *Entry) Debugln(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= DebugLevel { | ||||
| 		entry.Debug(entry.sprintlnn(args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Infoln(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= InfoLevel { | ||||
| 		entry.Info(entry.sprintlnn(args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Println(args ...interface{}) { | ||||
| 	entry.Infoln(args...) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Warnln(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= WarnLevel { | ||||
| 		entry.Warn(entry.sprintlnn(args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Warningln(args ...interface{}) { | ||||
| 	entry.Warnln(args...) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Errorln(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= ErrorLevel { | ||||
| 		entry.Error(entry.sprintlnn(args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Fatalln(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= FatalLevel { | ||||
| 		entry.Fatal(entry.sprintlnn(args...)) | ||||
| 	} | ||||
| 	Exit(1) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Panicln(args ...interface{}) { | ||||
| 	if entry.Logger.level() >= PanicLevel { | ||||
| 		entry.Panic(entry.sprintlnn(args...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Sprintlnn => Sprint no newline. This is to get the behavior of how | ||||
| // fmt.Sprintln where spaces are always added between operands, regardless of | ||||
| // their type. Instead of vendoring the Sprintln implementation to spare a | ||||
| // string allocation, we do the simplest thing. | ||||
| func (entry *Entry) sprintlnn(args ...interface{}) string { | ||||
| 	msg := fmt.Sprintln(args...) | ||||
| 	return msg[:len(msg)-1] | ||||
| } | ||||
							
								
								
									
										77
									
								
								vendor/github.com/sirupsen/logrus/entry_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								vendor/github.com/sirupsen/logrus/entry_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestEntryWithError(t *testing.T) { | ||||
|  | ||||
| 	assert := assert.New(t) | ||||
|  | ||||
| 	defer func() { | ||||
| 		ErrorKey = "error" | ||||
| 	}() | ||||
|  | ||||
| 	err := fmt.Errorf("kaboom at layer %d", 4711) | ||||
|  | ||||
| 	assert.Equal(err, WithError(err).Data["error"]) | ||||
|  | ||||
| 	logger := New() | ||||
| 	logger.Out = &bytes.Buffer{} | ||||
| 	entry := NewEntry(logger) | ||||
|  | ||||
| 	assert.Equal(err, entry.WithError(err).Data["error"]) | ||||
|  | ||||
| 	ErrorKey = "err" | ||||
|  | ||||
| 	assert.Equal(err, entry.WithError(err).Data["err"]) | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestEntryPanicln(t *testing.T) { | ||||
| 	errBoom := fmt.Errorf("boom time") | ||||
|  | ||||
| 	defer func() { | ||||
| 		p := recover() | ||||
| 		assert.NotNil(t, p) | ||||
|  | ||||
| 		switch pVal := p.(type) { | ||||
| 		case *Entry: | ||||
| 			assert.Equal(t, "kaboom", pVal.Message) | ||||
| 			assert.Equal(t, errBoom, pVal.Data["err"]) | ||||
| 		default: | ||||
| 			t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	logger := New() | ||||
| 	logger.Out = &bytes.Buffer{} | ||||
| 	entry := NewEntry(logger) | ||||
| 	entry.WithField("err", errBoom).Panicln("kaboom") | ||||
| } | ||||
|  | ||||
| func TestEntryPanicf(t *testing.T) { | ||||
| 	errBoom := fmt.Errorf("boom again") | ||||
|  | ||||
| 	defer func() { | ||||
| 		p := recover() | ||||
| 		assert.NotNil(t, p) | ||||
|  | ||||
| 		switch pVal := p.(type) { | ||||
| 		case *Entry: | ||||
| 			assert.Equal(t, "kaboom true", pVal.Message) | ||||
| 			assert.Equal(t, errBoom, pVal.Data["err"]) | ||||
| 		default: | ||||
| 			t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	logger := New() | ||||
| 	logger.Out = &bytes.Buffer{} | ||||
| 	entry := NewEntry(logger) | ||||
| 	entry.WithField("err", errBoom).Panicf("kaboom %v", true) | ||||
| } | ||||
							
								
								
									
										69
									
								
								vendor/github.com/sirupsen/logrus/example_basic_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								vendor/github.com/sirupsen/logrus/example_basic_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| package logrus_test | ||||
|  | ||||
| import ( | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| func Example_basic() { | ||||
| 	var log = logrus.New() | ||||
| 	log.Formatter = new(logrus.JSONFormatter) | ||||
| 	log.Formatter = new(logrus.TextFormatter)                     //default | ||||
| 	log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output | ||||
| 	log.Level = logrus.DebugLevel | ||||
| 	log.Out = os.Stdout | ||||
|  | ||||
| 	// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) | ||||
| 	// if err == nil { | ||||
| 	// 	log.Out = file | ||||
| 	// } else { | ||||
| 	// 	log.Info("Failed to log to file, using default stderr") | ||||
| 	// } | ||||
|  | ||||
| 	defer func() { | ||||
| 		err := recover() | ||||
| 		if err != nil { | ||||
| 			entry := err.(*logrus.Entry) | ||||
| 			log.WithFields(logrus.Fields{ | ||||
| 				"omg":         true, | ||||
| 				"err_animal":  entry.Data["animal"], | ||||
| 				"err_size":    entry.Data["size"], | ||||
| 				"err_level":   entry.Level, | ||||
| 				"err_message": entry.Message, | ||||
| 				"number":      100, | ||||
| 			}).Error("The ice breaks!") // or use Fatal() to force the process to exit with a nonzero code | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	log.WithFields(logrus.Fields{ | ||||
| 		"animal": "walrus", | ||||
| 		"number": 8, | ||||
| 	}).Debug("Started observing beach") | ||||
|  | ||||
| 	log.WithFields(logrus.Fields{ | ||||
| 		"animal": "walrus", | ||||
| 		"size":   10, | ||||
| 	}).Info("A group of walrus emerges from the ocean") | ||||
|  | ||||
| 	log.WithFields(logrus.Fields{ | ||||
| 		"omg":    true, | ||||
| 		"number": 122, | ||||
| 	}).Warn("The group's number increased tremendously!") | ||||
|  | ||||
| 	log.WithFields(logrus.Fields{ | ||||
| 		"temperature": -4, | ||||
| 	}).Debug("Temperature changes") | ||||
|  | ||||
| 	log.WithFields(logrus.Fields{ | ||||
| 		"animal": "orca", | ||||
| 		"size":   9009, | ||||
| 	}).Panic("It's over 9000!") | ||||
|  | ||||
| 	// Output: | ||||
| 	// level=debug msg="Started observing beach" animal=walrus number=8 | ||||
| 	// level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 | ||||
| 	// level=warning msg="The group's number increased tremendously!" number=122 omg=true | ||||
| 	// level=debug msg="Temperature changes" temperature=-4 | ||||
| 	// level=panic msg="It's over 9000!" animal=orca size=9009 | ||||
| 	// level=error msg="The ice breaks!" err_animal=orca err_level=panic err_message="It's over 9000!" err_size=9009 number=100 omg=true | ||||
| } | ||||
							
								
								
									
										35
									
								
								vendor/github.com/sirupsen/logrus/example_hook_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/sirupsen/logrus/example_hook_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| package logrus_test | ||||
|  | ||||
| import ( | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"gopkg.in/gemnasium/logrus-airbrake-hook.v2" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| func Example_hook() { | ||||
| 	var log = logrus.New() | ||||
| 	log.Formatter = new(logrus.TextFormatter)                     // default | ||||
| 	log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output | ||||
| 	log.Hooks.Add(airbrake.NewHook(123, "xyz", "development")) | ||||
| 	log.Out = os.Stdout | ||||
|  | ||||
| 	log.WithFields(logrus.Fields{ | ||||
| 		"animal": "walrus", | ||||
| 		"size":   10, | ||||
| 	}).Info("A group of walrus emerges from the ocean") | ||||
|  | ||||
| 	log.WithFields(logrus.Fields{ | ||||
| 		"omg":    true, | ||||
| 		"number": 122, | ||||
| 	}).Warn("The group's number increased tremendously!") | ||||
|  | ||||
| 	log.WithFields(logrus.Fields{ | ||||
| 		"omg":    true, | ||||
| 		"number": 100, | ||||
| 	}).Error("The ice breaks!") | ||||
|  | ||||
| 	// Output: | ||||
| 	// level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 | ||||
| 	// level=warning msg="The group's number increased tremendously!" number=122 omg=true | ||||
| 	// level=error msg="The ice breaks!" number=100 omg=true | ||||
| } | ||||
							
								
								
									
										193
									
								
								vendor/github.com/sirupsen/logrus/exported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								vendor/github.com/sirupsen/logrus/exported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// std is the name of the standard logger in stdlib `log` | ||||
| 	std = New() | ||||
| ) | ||||
|  | ||||
| func StandardLogger() *Logger { | ||||
| 	return std | ||||
| } | ||||
|  | ||||
| // SetOutput sets the standard logger output. | ||||
| func SetOutput(out io.Writer) { | ||||
| 	std.mu.Lock() | ||||
| 	defer std.mu.Unlock() | ||||
| 	std.Out = out | ||||
| } | ||||
|  | ||||
| // SetFormatter sets the standard logger formatter. | ||||
| func SetFormatter(formatter Formatter) { | ||||
| 	std.mu.Lock() | ||||
| 	defer std.mu.Unlock() | ||||
| 	std.Formatter = formatter | ||||
| } | ||||
|  | ||||
| // SetLevel sets the standard logger level. | ||||
| func SetLevel(level Level) { | ||||
| 	std.mu.Lock() | ||||
| 	defer std.mu.Unlock() | ||||
| 	std.SetLevel(level) | ||||
| } | ||||
|  | ||||
| // GetLevel returns the standard logger level. | ||||
| func GetLevel() Level { | ||||
| 	std.mu.Lock() | ||||
| 	defer std.mu.Unlock() | ||||
| 	return std.level() | ||||
| } | ||||
|  | ||||
| // AddHook adds a hook to the standard logger hooks. | ||||
| func AddHook(hook Hook) { | ||||
| 	std.mu.Lock() | ||||
| 	defer std.mu.Unlock() | ||||
| 	std.Hooks.Add(hook) | ||||
| } | ||||
|  | ||||
| // WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. | ||||
| func WithError(err error) *Entry { | ||||
| 	return std.WithField(ErrorKey, err) | ||||
| } | ||||
|  | ||||
| // WithField creates an entry from the standard logger and adds a field to | ||||
| // it. If you want multiple fields, use `WithFields`. | ||||
| // | ||||
| // Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal | ||||
| // or Panic on the Entry it returns. | ||||
| func WithField(key string, value interface{}) *Entry { | ||||
| 	return std.WithField(key, value) | ||||
| } | ||||
|  | ||||
| // WithFields creates an entry from the standard logger and adds multiple | ||||
| // fields to it. This is simply a helper for `WithField`, invoking it | ||||
| // once for each field. | ||||
| // | ||||
| // Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal | ||||
| // or Panic on the Entry it returns. | ||||
| func WithFields(fields Fields) *Entry { | ||||
| 	return std.WithFields(fields) | ||||
| } | ||||
|  | ||||
| // Debug logs a message at level Debug on the standard logger. | ||||
| func Debug(args ...interface{}) { | ||||
| 	std.Debug(args...) | ||||
| } | ||||
|  | ||||
| // Print logs a message at level Info on the standard logger. | ||||
| func Print(args ...interface{}) { | ||||
| 	std.Print(args...) | ||||
| } | ||||
|  | ||||
| // Info logs a message at level Info on the standard logger. | ||||
| func Info(args ...interface{}) { | ||||
| 	std.Info(args...) | ||||
| } | ||||
|  | ||||
| // Warn logs a message at level Warn on the standard logger. | ||||
| func Warn(args ...interface{}) { | ||||
| 	std.Warn(args...) | ||||
| } | ||||
|  | ||||
| // Warning logs a message at level Warn on the standard logger. | ||||
| func Warning(args ...interface{}) { | ||||
| 	std.Warning(args...) | ||||
| } | ||||
|  | ||||
| // Error logs a message at level Error on the standard logger. | ||||
| func Error(args ...interface{}) { | ||||
| 	std.Error(args...) | ||||
| } | ||||
|  | ||||
| // Panic logs a message at level Panic on the standard logger. | ||||
| func Panic(args ...interface{}) { | ||||
| 	std.Panic(args...) | ||||
| } | ||||
|  | ||||
| // Fatal logs a message at level Fatal on the standard logger. | ||||
| func Fatal(args ...interface{}) { | ||||
| 	std.Fatal(args...) | ||||
| } | ||||
|  | ||||
| // Debugf logs a message at level Debug on the standard logger. | ||||
| func Debugf(format string, args ...interface{}) { | ||||
| 	std.Debugf(format, args...) | ||||
| } | ||||
|  | ||||
| // Printf logs a message at level Info on the standard logger. | ||||
| func Printf(format string, args ...interface{}) { | ||||
| 	std.Printf(format, args...) | ||||
| } | ||||
|  | ||||
| // Infof logs a message at level Info on the standard logger. | ||||
| func Infof(format string, args ...interface{}) { | ||||
| 	std.Infof(format, args...) | ||||
| } | ||||
|  | ||||
| // Warnf logs a message at level Warn on the standard logger. | ||||
| func Warnf(format string, args ...interface{}) { | ||||
| 	std.Warnf(format, args...) | ||||
| } | ||||
|  | ||||
| // Warningf logs a message at level Warn on the standard logger. | ||||
| func Warningf(format string, args ...interface{}) { | ||||
| 	std.Warningf(format, args...) | ||||
| } | ||||
|  | ||||
| // Errorf logs a message at level Error on the standard logger. | ||||
| func Errorf(format string, args ...interface{}) { | ||||
| 	std.Errorf(format, args...) | ||||
| } | ||||
|  | ||||
| // Panicf logs a message at level Panic on the standard logger. | ||||
| func Panicf(format string, args ...interface{}) { | ||||
| 	std.Panicf(format, args...) | ||||
| } | ||||
|  | ||||
| // Fatalf logs a message at level Fatal on the standard logger. | ||||
| func Fatalf(format string, args ...interface{}) { | ||||
| 	std.Fatalf(format, args...) | ||||
| } | ||||
|  | ||||
| // Debugln logs a message at level Debug on the standard logger. | ||||
| func Debugln(args ...interface{}) { | ||||
| 	std.Debugln(args...) | ||||
| } | ||||
|  | ||||
| // Println logs a message at level Info on the standard logger. | ||||
| func Println(args ...interface{}) { | ||||
| 	std.Println(args...) | ||||
| } | ||||
|  | ||||
| // Infoln logs a message at level Info on the standard logger. | ||||
| func Infoln(args ...interface{}) { | ||||
| 	std.Infoln(args...) | ||||
| } | ||||
|  | ||||
| // Warnln logs a message at level Warn on the standard logger. | ||||
| func Warnln(args ...interface{}) { | ||||
| 	std.Warnln(args...) | ||||
| } | ||||
|  | ||||
| // Warningln logs a message at level Warn on the standard logger. | ||||
| func Warningln(args ...interface{}) { | ||||
| 	std.Warningln(args...) | ||||
| } | ||||
|  | ||||
| // Errorln logs a message at level Error on the standard logger. | ||||
| func Errorln(args ...interface{}) { | ||||
| 	std.Errorln(args...) | ||||
| } | ||||
|  | ||||
| // Panicln logs a message at level Panic on the standard logger. | ||||
| func Panicln(args ...interface{}) { | ||||
| 	std.Panicln(args...) | ||||
| } | ||||
|  | ||||
| // Fatalln logs a message at level Fatal on the standard logger. | ||||
| func Fatalln(args ...interface{}) { | ||||
| 	std.Fatalln(args...) | ||||
| } | ||||
							
								
								
									
										45
									
								
								vendor/github.com/sirupsen/logrus/formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/sirupsen/logrus/formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| package logrus | ||||
|  | ||||
| import "time" | ||||
|  | ||||
| const defaultTimestampFormat = time.RFC3339 | ||||
|  | ||||
| // The Formatter interface is used to implement a custom Formatter. It takes an | ||||
| // `Entry`. It exposes all the fields, including the default ones: | ||||
| // | ||||
| // * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. | ||||
| // * `entry.Data["time"]`. The timestamp. | ||||
| // * `entry.Data["level"]. The level the entry was logged at. | ||||
| // | ||||
| // Any additional fields added with `WithField` or `WithFields` are also in | ||||
| // `entry.Data`. Format is expected to return an array of bytes which are then | ||||
| // logged to `logger.Out`. | ||||
| type Formatter interface { | ||||
| 	Format(*Entry) ([]byte, error) | ||||
| } | ||||
|  | ||||
| // This is to not silently overwrite `time`, `msg` and `level` fields when | ||||
| // dumping it. If this code wasn't there doing: | ||||
| // | ||||
| //  logrus.WithField("level", 1).Info("hello") | ||||
| // | ||||
| // Would just silently drop the user provided level. Instead with this code | ||||
| // it'll logged as: | ||||
| // | ||||
| //  {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} | ||||
| // | ||||
| // It's not exported because it's still using Data in an opinionated way. It's to | ||||
| // avoid code duplication between the two default formatters. | ||||
| func prefixFieldClashes(data Fields) { | ||||
| 	if t, ok := data["time"]; ok { | ||||
| 		data["fields.time"] = t | ||||
| 	} | ||||
|  | ||||
| 	if m, ok := data["msg"]; ok { | ||||
| 		data["fields.msg"] = m | ||||
| 	} | ||||
|  | ||||
| 	if l, ok := data["level"]; ok { | ||||
| 		data["fields.level"] = l | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										101
									
								
								vendor/github.com/sirupsen/logrus/formatter_bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								vendor/github.com/sirupsen/logrus/formatter_bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // smallFields is a small size data set for benchmarking | ||||
| var smallFields = Fields{ | ||||
| 	"foo":   "bar", | ||||
| 	"baz":   "qux", | ||||
| 	"one":   "two", | ||||
| 	"three": "four", | ||||
| } | ||||
|  | ||||
| // largeFields is a large size data set for benchmarking | ||||
| var largeFields = Fields{ | ||||
| 	"foo":       "bar", | ||||
| 	"baz":       "qux", | ||||
| 	"one":       "two", | ||||
| 	"three":     "four", | ||||
| 	"five":      "six", | ||||
| 	"seven":     "eight", | ||||
| 	"nine":      "ten", | ||||
| 	"eleven":    "twelve", | ||||
| 	"thirteen":  "fourteen", | ||||
| 	"fifteen":   "sixteen", | ||||
| 	"seventeen": "eighteen", | ||||
| 	"nineteen":  "twenty", | ||||
| 	"a":         "b", | ||||
| 	"c":         "d", | ||||
| 	"e":         "f", | ||||
| 	"g":         "h", | ||||
| 	"i":         "j", | ||||
| 	"k":         "l", | ||||
| 	"m":         "n", | ||||
| 	"o":         "p", | ||||
| 	"q":         "r", | ||||
| 	"s":         "t", | ||||
| 	"u":         "v", | ||||
| 	"w":         "x", | ||||
| 	"y":         "z", | ||||
| 	"this":      "will", | ||||
| 	"make":      "thirty", | ||||
| 	"entries":   "yeah", | ||||
| } | ||||
|  | ||||
| var errorFields = Fields{ | ||||
| 	"foo": fmt.Errorf("bar"), | ||||
| 	"baz": fmt.Errorf("qux"), | ||||
| } | ||||
|  | ||||
| func BenchmarkErrorTextFormatter(b *testing.B) { | ||||
| 	doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields) | ||||
| } | ||||
|  | ||||
| func BenchmarkSmallTextFormatter(b *testing.B) { | ||||
| 	doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields) | ||||
| } | ||||
|  | ||||
| func BenchmarkLargeTextFormatter(b *testing.B) { | ||||
| 	doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields) | ||||
| } | ||||
|  | ||||
| func BenchmarkSmallColoredTextFormatter(b *testing.B) { | ||||
| 	doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields) | ||||
| } | ||||
|  | ||||
| func BenchmarkLargeColoredTextFormatter(b *testing.B) { | ||||
| 	doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields) | ||||
| } | ||||
|  | ||||
| func BenchmarkSmallJSONFormatter(b *testing.B) { | ||||
| 	doBenchmark(b, &JSONFormatter{}, smallFields) | ||||
| } | ||||
|  | ||||
| func BenchmarkLargeJSONFormatter(b *testing.B) { | ||||
| 	doBenchmark(b, &JSONFormatter{}, largeFields) | ||||
| } | ||||
|  | ||||
| func doBenchmark(b *testing.B, formatter Formatter, fields Fields) { | ||||
| 	logger := New() | ||||
|  | ||||
| 	entry := &Entry{ | ||||
| 		Time:    time.Time{}, | ||||
| 		Level:   InfoLevel, | ||||
| 		Message: "message", | ||||
| 		Data:    fields, | ||||
| 		Logger:  logger, | ||||
| 	} | ||||
| 	var d []byte | ||||
| 	var err error | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		d, err = formatter.Format(entry) | ||||
| 		if err != nil { | ||||
| 			b.Fatal(err) | ||||
| 		} | ||||
| 		b.SetBytes(int64(len(d))) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										144
									
								
								vendor/github.com/sirupsen/logrus/hook_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/sirupsen/logrus/hook_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"sync" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| type TestHook struct { | ||||
| 	Fired bool | ||||
| } | ||||
|  | ||||
| func (hook *TestHook) Fire(entry *Entry) error { | ||||
| 	hook.Fired = true | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (hook *TestHook) Levels() []Level { | ||||
| 	return []Level{ | ||||
| 		DebugLevel, | ||||
| 		InfoLevel, | ||||
| 		WarnLevel, | ||||
| 		ErrorLevel, | ||||
| 		FatalLevel, | ||||
| 		PanicLevel, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestHookFires(t *testing.T) { | ||||
| 	hook := new(TestHook) | ||||
|  | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Hooks.Add(hook) | ||||
| 		assert.Equal(t, hook.Fired, false) | ||||
|  | ||||
| 		log.Print("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, hook.Fired, true) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| type ModifyHook struct { | ||||
| } | ||||
|  | ||||
| func (hook *ModifyHook) Fire(entry *Entry) error { | ||||
| 	entry.Data["wow"] = "whale" | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (hook *ModifyHook) Levels() []Level { | ||||
| 	return []Level{ | ||||
| 		DebugLevel, | ||||
| 		InfoLevel, | ||||
| 		WarnLevel, | ||||
| 		ErrorLevel, | ||||
| 		FatalLevel, | ||||
| 		PanicLevel, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestHookCanModifyEntry(t *testing.T) { | ||||
| 	hook := new(ModifyHook) | ||||
|  | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Hooks.Add(hook) | ||||
| 		log.WithField("wow", "elephant").Print("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["wow"], "whale") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestCanFireMultipleHooks(t *testing.T) { | ||||
| 	hook1 := new(ModifyHook) | ||||
| 	hook2 := new(TestHook) | ||||
|  | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Hooks.Add(hook1) | ||||
| 		log.Hooks.Add(hook2) | ||||
|  | ||||
| 		log.WithField("wow", "elephant").Print("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["wow"], "whale") | ||||
| 		assert.Equal(t, hook2.Fired, true) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| type ErrorHook struct { | ||||
| 	Fired bool | ||||
| } | ||||
|  | ||||
| func (hook *ErrorHook) Fire(entry *Entry) error { | ||||
| 	hook.Fired = true | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (hook *ErrorHook) Levels() []Level { | ||||
| 	return []Level{ | ||||
| 		ErrorLevel, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestErrorHookShouldntFireOnInfo(t *testing.T) { | ||||
| 	hook := new(ErrorHook) | ||||
|  | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Hooks.Add(hook) | ||||
| 		log.Info("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, hook.Fired, false) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestErrorHookShouldFireOnError(t *testing.T) { | ||||
| 	hook := new(ErrorHook) | ||||
|  | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Hooks.Add(hook) | ||||
| 		log.Error("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, hook.Fired, true) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestAddHookRace(t *testing.T) { | ||||
| 	var wg sync.WaitGroup | ||||
| 	wg.Add(2) | ||||
| 	hook := new(ErrorHook) | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		go func() { | ||||
| 			defer wg.Done() | ||||
| 			log.AddHook(hook) | ||||
| 		}() | ||||
| 		go func() { | ||||
| 			defer wg.Done() | ||||
| 			log.Error("test") | ||||
| 		}() | ||||
| 		wg.Wait() | ||||
| 	}, func(fields Fields) { | ||||
| 		// the line may have been logged | ||||
| 		// before the hook was added, so we can't | ||||
| 		// actually assert on the hook | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										34
									
								
								vendor/github.com/sirupsen/logrus/hooks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/sirupsen/logrus/hooks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| package logrus | ||||
|  | ||||
| // A hook to be fired when logging on the logging levels returned from | ||||
| // `Levels()` on your implementation of the interface. Note that this is not | ||||
| // fired in a goroutine or a channel with workers, you should handle such | ||||
| // functionality yourself if your call is non-blocking and you don't wish for | ||||
| // the logging calls for levels returned from `Levels()` to block. | ||||
| type Hook interface { | ||||
| 	Levels() []Level | ||||
| 	Fire(*Entry) error | ||||
| } | ||||
|  | ||||
| // Internal type for storing the hooks on a logger instance. | ||||
| type LevelHooks map[Level][]Hook | ||||
|  | ||||
| // Add a hook to an instance of logger. This is called with | ||||
| // `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. | ||||
| func (hooks LevelHooks) Add(hook Hook) { | ||||
| 	for _, level := range hook.Levels() { | ||||
| 		hooks[level] = append(hooks[level], hook) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Fire all the hooks for the passed level. Used by `entry.log` to fire | ||||
| // appropriate hooks for a log entry. | ||||
| func (hooks LevelHooks) Fire(level Level, entry *Entry) error { | ||||
| 	for _, hook := range hooks[level] { | ||||
| 		if err := hook.Fire(entry); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										39
									
								
								vendor/github.com/sirupsen/logrus/hooks/syslog/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/sirupsen/logrus/hooks/syslog/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| # Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| ```go | ||||
| import ( | ||||
|   "log/syslog" | ||||
|   "github.com/sirupsen/logrus" | ||||
|   lSyslog "github.com/sirupsen/logrus/hooks/syslog" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
|   log       := logrus.New() | ||||
|   hook, err := lSyslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") | ||||
|  | ||||
|   if err == nil { | ||||
|     log.Hooks.Add(hook) | ||||
|   } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following. | ||||
|  | ||||
| ```go | ||||
| import ( | ||||
|   "log/syslog" | ||||
|   "github.com/sirupsen/logrus" | ||||
|   lSyslog "github.com/sirupsen/logrus/hooks/syslog" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
|   log       := logrus.New() | ||||
|   hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO, "") | ||||
|  | ||||
|   if err == nil { | ||||
|     log.Hooks.Add(hook) | ||||
|   } | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										55
									
								
								vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // +build !windows,!nacl,!plan9 | ||||
|  | ||||
| package syslog | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log/syslog" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| // SyslogHook to send logs via syslog. | ||||
| type SyslogHook struct { | ||||
| 	Writer        *syslog.Writer | ||||
| 	SyslogNetwork string | ||||
| 	SyslogRaddr   string | ||||
| } | ||||
|  | ||||
| // Creates a hook to be added to an instance of logger. This is called with | ||||
| // `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")` | ||||
| // `if err == nil { log.Hooks.Add(hook) }` | ||||
| func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) { | ||||
| 	w, err := syslog.Dial(network, raddr, priority, tag) | ||||
| 	return &SyslogHook{w, network, raddr}, err | ||||
| } | ||||
|  | ||||
| func (hook *SyslogHook) Fire(entry *logrus.Entry) error { | ||||
| 	line, err := entry.String() | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	switch entry.Level { | ||||
| 	case logrus.PanicLevel: | ||||
| 		return hook.Writer.Crit(line) | ||||
| 	case logrus.FatalLevel: | ||||
| 		return hook.Writer.Crit(line) | ||||
| 	case logrus.ErrorLevel: | ||||
| 		return hook.Writer.Err(line) | ||||
| 	case logrus.WarnLevel: | ||||
| 		return hook.Writer.Warning(line) | ||||
| 	case logrus.InfoLevel: | ||||
| 		return hook.Writer.Info(line) | ||||
| 	case logrus.DebugLevel: | ||||
| 		return hook.Writer.Debug(line) | ||||
| 	default: | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (hook *SyslogHook) Levels() []logrus.Level { | ||||
| 	return logrus.AllLevels | ||||
| } | ||||
							
								
								
									
										27
									
								
								vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| package syslog | ||||
|  | ||||
| import ( | ||||
| 	"log/syslog" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| func TestLocalhostAddAndPrint(t *testing.T) { | ||||
| 	log := logrus.New() | ||||
| 	hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") | ||||
|  | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Unable to connect to local syslog.") | ||||
| 	} | ||||
|  | ||||
| 	log.Hooks.Add(hook) | ||||
|  | ||||
| 	for _, level := range hook.Levels() { | ||||
| 		if len(log.Hooks[level]) != 1 { | ||||
| 			t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level])) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	log.Info("Congratulations!") | ||||
| } | ||||
							
								
								
									
										95
									
								
								vendor/github.com/sirupsen/logrus/hooks/test/test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								vendor/github.com/sirupsen/logrus/hooks/test/test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| // The Test package is used for testing logrus. It is here for backwards | ||||
| // compatibility from when logrus' organization was upper-case. Please use | ||||
| // lower-case logrus and the `null` package instead of this one. | ||||
| package test | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| // Hook is a hook designed for dealing with logs in test scenarios. | ||||
| type Hook struct { | ||||
| 	// Entries is an array of all entries that have been received by this hook. | ||||
| 	// For safe access, use the AllEntries() method, rather than reading this | ||||
| 	// value directly. | ||||
| 	Entries []*logrus.Entry | ||||
| 	mu      sync.RWMutex | ||||
| } | ||||
|  | ||||
| // NewGlobal installs a test hook for the global logger. | ||||
| func NewGlobal() *Hook { | ||||
|  | ||||
| 	hook := new(Hook) | ||||
| 	logrus.AddHook(hook) | ||||
|  | ||||
| 	return hook | ||||
|  | ||||
| } | ||||
|  | ||||
| // NewLocal installs a test hook for a given local logger. | ||||
| func NewLocal(logger *logrus.Logger) *Hook { | ||||
|  | ||||
| 	hook := new(Hook) | ||||
| 	logger.Hooks.Add(hook) | ||||
|  | ||||
| 	return hook | ||||
|  | ||||
| } | ||||
|  | ||||
| // NewNullLogger creates a discarding logger and installs the test hook. | ||||
| func NewNullLogger() (*logrus.Logger, *Hook) { | ||||
|  | ||||
| 	logger := logrus.New() | ||||
| 	logger.Out = ioutil.Discard | ||||
|  | ||||
| 	return logger, NewLocal(logger) | ||||
|  | ||||
| } | ||||
|  | ||||
| func (t *Hook) Fire(e *logrus.Entry) error { | ||||
| 	t.mu.Lock() | ||||
| 	defer t.mu.Unlock() | ||||
| 	t.Entries = append(t.Entries, e) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (t *Hook) Levels() []logrus.Level { | ||||
| 	return logrus.AllLevels | ||||
| } | ||||
|  | ||||
| // LastEntry returns the last entry that was logged or nil. | ||||
| func (t *Hook) LastEntry() *logrus.Entry { | ||||
| 	t.mu.RLock() | ||||
| 	defer t.mu.RUnlock() | ||||
| 	i := len(t.Entries) - 1 | ||||
| 	if i < 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	// Make a copy, for safety | ||||
| 	e := *t.Entries[i] | ||||
| 	return &e | ||||
| } | ||||
|  | ||||
| // AllEntries returns all entries that were logged. | ||||
| func (t *Hook) AllEntries() []*logrus.Entry { | ||||
| 	t.mu.RLock() | ||||
| 	defer t.mu.RUnlock() | ||||
| 	// Make a copy so the returned value won't race with future log requests | ||||
| 	entries := make([]*logrus.Entry, len(t.Entries)) | ||||
| 	for i, entry := range t.Entries { | ||||
| 		// Make a copy, for safety | ||||
| 		e := *entry | ||||
| 		entries[i] = &e | ||||
| 	} | ||||
| 	return entries | ||||
| } | ||||
|  | ||||
| // Reset removes all Entries from this test hook. | ||||
| func (t *Hook) Reset() { | ||||
| 	t.mu.Lock() | ||||
| 	defer t.mu.Unlock() | ||||
| 	t.Entries = make([]*logrus.Entry, 0) | ||||
| } | ||||
							
								
								
									
										39
									
								
								vendor/github.com/sirupsen/logrus/hooks/test/test_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/sirupsen/logrus/hooks/test/test_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| package test | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestAllHooks(t *testing.T) { | ||||
|  | ||||
| 	assert := assert.New(t) | ||||
|  | ||||
| 	logger, hook := NewNullLogger() | ||||
| 	assert.Nil(hook.LastEntry()) | ||||
| 	assert.Equal(0, len(hook.Entries)) | ||||
|  | ||||
| 	logger.Error("Hello error") | ||||
| 	assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) | ||||
| 	assert.Equal("Hello error", hook.LastEntry().Message) | ||||
| 	assert.Equal(1, len(hook.Entries)) | ||||
|  | ||||
| 	logger.Warn("Hello warning") | ||||
| 	assert.Equal(logrus.WarnLevel, hook.LastEntry().Level) | ||||
| 	assert.Equal("Hello warning", hook.LastEntry().Message) | ||||
| 	assert.Equal(2, len(hook.Entries)) | ||||
|  | ||||
| 	hook.Reset() | ||||
| 	assert.Nil(hook.LastEntry()) | ||||
| 	assert.Equal(0, len(hook.Entries)) | ||||
|  | ||||
| 	hook = NewGlobal() | ||||
|  | ||||
| 	logrus.Error("Hello error") | ||||
| 	assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) | ||||
| 	assert.Equal("Hello error", hook.LastEntry().Message) | ||||
| 	assert.Equal(1, len(hook.Entries)) | ||||
|  | ||||
| } | ||||
							
								
								
									
										79
									
								
								vendor/github.com/sirupsen/logrus/json_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/sirupsen/logrus/json_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| ) | ||||
|  | ||||
| type fieldKey string | ||||
|  | ||||
| // FieldMap allows customization of the key names for default fields. | ||||
| type FieldMap map[fieldKey]string | ||||
|  | ||||
| // Default key names for the default fields | ||||
| const ( | ||||
| 	FieldKeyMsg   = "msg" | ||||
| 	FieldKeyLevel = "level" | ||||
| 	FieldKeyTime  = "time" | ||||
| ) | ||||
|  | ||||
| func (f FieldMap) resolve(key fieldKey) string { | ||||
| 	if k, ok := f[key]; ok { | ||||
| 		return k | ||||
| 	} | ||||
|  | ||||
| 	return string(key) | ||||
| } | ||||
|  | ||||
| // JSONFormatter formats logs into parsable json | ||||
| type JSONFormatter struct { | ||||
| 	// TimestampFormat sets the format used for marshaling timestamps. | ||||
| 	TimestampFormat string | ||||
|  | ||||
| 	// DisableTimestamp allows disabling automatic timestamps in output | ||||
| 	DisableTimestamp bool | ||||
|  | ||||
| 	// FieldMap allows users to customize the names of keys for default fields. | ||||
| 	// As an example: | ||||
| 	// formatter := &JSONFormatter{ | ||||
| 	//   	FieldMap: FieldMap{ | ||||
| 	// 		 FieldKeyTime: "@timestamp", | ||||
| 	// 		 FieldKeyLevel: "@level", | ||||
| 	// 		 FieldKeyMsg: "@message", | ||||
| 	//    }, | ||||
| 	// } | ||||
| 	FieldMap FieldMap | ||||
| } | ||||
|  | ||||
| // Format renders a single log entry | ||||
| func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { | ||||
| 	data := make(Fields, len(entry.Data)+3) | ||||
| 	for k, v := range entry.Data { | ||||
| 		switch v := v.(type) { | ||||
| 		case error: | ||||
| 			// Otherwise errors are ignored by `encoding/json` | ||||
| 			// https://github.com/sirupsen/logrus/issues/137 | ||||
| 			data[k] = v.Error() | ||||
| 		default: | ||||
| 			data[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	prefixFieldClashes(data) | ||||
|  | ||||
| 	timestampFormat := f.TimestampFormat | ||||
| 	if timestampFormat == "" { | ||||
| 		timestampFormat = defaultTimestampFormat | ||||
| 	} | ||||
|  | ||||
| 	if !f.DisableTimestamp { | ||||
| 		data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) | ||||
| 	} | ||||
| 	data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message | ||||
| 	data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() | ||||
|  | ||||
| 	serialized, err := json.Marshal(data) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) | ||||
| 	} | ||||
| 	return append(serialized, '\n'), nil | ||||
| } | ||||
							
								
								
									
										199
									
								
								vendor/github.com/sirupsen/logrus/json_formatter_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								vendor/github.com/sirupsen/logrus/json_formatter_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestErrorNotLost(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("error", errors.New("wild walrus"))) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	entry := make(map[string]interface{}) | ||||
| 	err = json.Unmarshal(b, &entry) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to unmarshal formatted entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	if entry["error"] != "wild walrus" { | ||||
| 		t.Fatal("Error field not set") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestErrorNotLostOnFieldNotNamedError(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("omg", errors.New("wild walrus"))) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	entry := make(map[string]interface{}) | ||||
| 	err = json.Unmarshal(b, &entry) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to unmarshal formatted entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	if entry["omg"] != "wild walrus" { | ||||
| 		t.Fatal("Error field not set") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestFieldClashWithTime(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("time", "right now!")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	entry := make(map[string]interface{}) | ||||
| 	err = json.Unmarshal(b, &entry) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to unmarshal formatted entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	if entry["fields.time"] != "right now!" { | ||||
| 		t.Fatal("fields.time not set to original time field") | ||||
| 	} | ||||
|  | ||||
| 	if entry["time"] != "0001-01-01T00:00:00Z" { | ||||
| 		t.Fatal("time field not set to current time, was: ", entry["time"]) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestFieldClashWithMsg(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("msg", "something")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	entry := make(map[string]interface{}) | ||||
| 	err = json.Unmarshal(b, &entry) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to unmarshal formatted entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	if entry["fields.msg"] != "something" { | ||||
| 		t.Fatal("fields.msg not set to original msg field") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestFieldClashWithLevel(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("level", "something")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	entry := make(map[string]interface{}) | ||||
| 	err = json.Unmarshal(b, &entry) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to unmarshal formatted entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	if entry["fields.level"] != "something" { | ||||
| 		t.Fatal("fields.level not set to original level field") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJSONEntryEndsWithNewline(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("level", "something")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
|  | ||||
| 	if b[len(b)-1] != '\n' { | ||||
| 		t.Fatal("Expected JSON log entry to end with a newline") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJSONMessageKey(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{ | ||||
| 		FieldMap: FieldMap{ | ||||
| 			FieldKeyMsg: "message", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	b, err := formatter.Format(&Entry{Message: "oh hai"}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
| 	s := string(b) | ||||
| 	if !(strings.Contains(s, "message") && strings.Contains(s, "oh hai")) { | ||||
| 		t.Fatal("Expected JSON to format message key") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJSONLevelKey(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{ | ||||
| 		FieldMap: FieldMap{ | ||||
| 			FieldKeyLevel: "somelevel", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("level", "something")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
| 	s := string(b) | ||||
| 	if !strings.Contains(s, "somelevel") { | ||||
| 		t.Fatal("Expected JSON to format level key") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJSONTimeKey(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{ | ||||
| 		FieldMap: FieldMap{ | ||||
| 			FieldKeyTime: "timeywimey", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("level", "something")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
| 	s := string(b) | ||||
| 	if !strings.Contains(s, "timeywimey") { | ||||
| 		t.Fatal("Expected JSON to format time key") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJSONDisableTimestamp(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{ | ||||
| 		DisableTimestamp: true, | ||||
| 	} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("level", "something")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
| 	s := string(b) | ||||
| 	if strings.Contains(s, FieldKeyTime) { | ||||
| 		t.Error("Did not prevent timestamp", s) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJSONEnableTimestamp(t *testing.T) { | ||||
| 	formatter := &JSONFormatter{} | ||||
|  | ||||
| 	b, err := formatter.Format(WithField("level", "something")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Unable to format entry: ", err) | ||||
| 	} | ||||
| 	s := string(b) | ||||
| 	if !strings.Contains(s, FieldKeyTime) { | ||||
| 		t.Error("Timestamp not present", s) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										323
									
								
								vendor/github.com/sirupsen/logrus/logger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								vendor/github.com/sirupsen/logrus/logger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,323 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| ) | ||||
|  | ||||
| type Logger struct { | ||||
| 	// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a | ||||
| 	// file, or leave it default which is `os.Stderr`. You can also set this to | ||||
| 	// something more adventorous, such as logging to Kafka. | ||||
| 	Out io.Writer | ||||
| 	// Hooks for the logger instance. These allow firing events based on logging | ||||
| 	// levels and log entries. For example, to send errors to an error tracking | ||||
| 	// service, log to StatsD or dump the core on fatal errors. | ||||
| 	Hooks LevelHooks | ||||
| 	// All log entries pass through the formatter before logged to Out. The | ||||
| 	// included formatters are `TextFormatter` and `JSONFormatter` for which | ||||
| 	// TextFormatter is the default. In development (when a TTY is attached) it | ||||
| 	// logs with colors, but to a file it wouldn't. You can easily implement your | ||||
| 	// own that implements the `Formatter` interface, see the `README` or included | ||||
| 	// formatters for examples. | ||||
| 	Formatter Formatter | ||||
| 	// The logging level the logger should log at. This is typically (and defaults | ||||
| 	// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be | ||||
| 	// logged. | ||||
| 	Level Level | ||||
| 	// Used to sync writing to the log. Locking is enabled by Default | ||||
| 	mu MutexWrap | ||||
| 	// Reusable empty entry | ||||
| 	entryPool sync.Pool | ||||
| } | ||||
|  | ||||
| type MutexWrap struct { | ||||
| 	lock     sync.Mutex | ||||
| 	disabled bool | ||||
| } | ||||
|  | ||||
| func (mw *MutexWrap) Lock() { | ||||
| 	if !mw.disabled { | ||||
| 		mw.lock.Lock() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (mw *MutexWrap) Unlock() { | ||||
| 	if !mw.disabled { | ||||
| 		mw.lock.Unlock() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (mw *MutexWrap) Disable() { | ||||
| 	mw.disabled = true | ||||
| } | ||||
|  | ||||
| // Creates a new logger. Configuration should be set by changing `Formatter`, | ||||
| // `Out` and `Hooks` directly on the default logger instance. You can also just | ||||
| // instantiate your own: | ||||
| // | ||||
| //    var log = &Logger{ | ||||
| //      Out: os.Stderr, | ||||
| //      Formatter: new(JSONFormatter), | ||||
| //      Hooks: make(LevelHooks), | ||||
| //      Level: logrus.DebugLevel, | ||||
| //    } | ||||
| // | ||||
| // It's recommended to make this a global instance called `log`. | ||||
| func New() *Logger { | ||||
| 	return &Logger{ | ||||
| 		Out:       os.Stderr, | ||||
| 		Formatter: new(TextFormatter), | ||||
| 		Hooks:     make(LevelHooks), | ||||
| 		Level:     InfoLevel, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) newEntry() *Entry { | ||||
| 	entry, ok := logger.entryPool.Get().(*Entry) | ||||
| 	if ok { | ||||
| 		return entry | ||||
| 	} | ||||
| 	return NewEntry(logger) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) releaseEntry(entry *Entry) { | ||||
| 	logger.entryPool.Put(entry) | ||||
| } | ||||
|  | ||||
| // Adds a field to the log entry, note that it doesn't log until you call | ||||
| // Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. | ||||
| // If you want multiple fields, use `WithFields`. | ||||
| func (logger *Logger) WithField(key string, value interface{}) *Entry { | ||||
| 	entry := logger.newEntry() | ||||
| 	defer logger.releaseEntry(entry) | ||||
| 	return entry.WithField(key, value) | ||||
| } | ||||
|  | ||||
| // Adds a struct of fields to the log entry. All it does is call `WithField` for | ||||
| // each `Field`. | ||||
| func (logger *Logger) WithFields(fields Fields) *Entry { | ||||
| 	entry := logger.newEntry() | ||||
| 	defer logger.releaseEntry(entry) | ||||
| 	return entry.WithFields(fields) | ||||
| } | ||||
|  | ||||
| // Add an error as single field to the log entry.  All it does is call | ||||
| // `WithError` for the given `error`. | ||||
| func (logger *Logger) WithError(err error) *Entry { | ||||
| 	entry := logger.newEntry() | ||||
| 	defer logger.releaseEntry(entry) | ||||
| 	return entry.WithError(err) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Debugf(format string, args ...interface{}) { | ||||
| 	if logger.level() >= DebugLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Debugf(format, args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Infof(format string, args ...interface{}) { | ||||
| 	if logger.level() >= InfoLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Infof(format, args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Printf(format string, args ...interface{}) { | ||||
| 	entry := logger.newEntry() | ||||
| 	entry.Printf(format, args...) | ||||
| 	logger.releaseEntry(entry) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Warnf(format string, args ...interface{}) { | ||||
| 	if logger.level() >= WarnLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Warnf(format, args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Warningf(format string, args ...interface{}) { | ||||
| 	if logger.level() >= WarnLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Warnf(format, args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Errorf(format string, args ...interface{}) { | ||||
| 	if logger.level() >= ErrorLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Errorf(format, args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Fatalf(format string, args ...interface{}) { | ||||
| 	if logger.level() >= FatalLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Fatalf(format, args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| 	Exit(1) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Panicf(format string, args ...interface{}) { | ||||
| 	if logger.level() >= PanicLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Panicf(format, args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Debug(args ...interface{}) { | ||||
| 	if logger.level() >= DebugLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Debug(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Info(args ...interface{}) { | ||||
| 	if logger.level() >= InfoLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Info(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Print(args ...interface{}) { | ||||
| 	entry := logger.newEntry() | ||||
| 	entry.Info(args...) | ||||
| 	logger.releaseEntry(entry) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Warn(args ...interface{}) { | ||||
| 	if logger.level() >= WarnLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Warn(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Warning(args ...interface{}) { | ||||
| 	if logger.level() >= WarnLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Warn(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Error(args ...interface{}) { | ||||
| 	if logger.level() >= ErrorLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Error(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Fatal(args ...interface{}) { | ||||
| 	if logger.level() >= FatalLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Fatal(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| 	Exit(1) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Panic(args ...interface{}) { | ||||
| 	if logger.level() >= PanicLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Panic(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Debugln(args ...interface{}) { | ||||
| 	if logger.level() >= DebugLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Debugln(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Infoln(args ...interface{}) { | ||||
| 	if logger.level() >= InfoLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Infoln(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Println(args ...interface{}) { | ||||
| 	entry := logger.newEntry() | ||||
| 	entry.Println(args...) | ||||
| 	logger.releaseEntry(entry) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Warnln(args ...interface{}) { | ||||
| 	if logger.level() >= WarnLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Warnln(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Warningln(args ...interface{}) { | ||||
| 	if logger.level() >= WarnLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Warnln(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Errorln(args ...interface{}) { | ||||
| 	if logger.level() >= ErrorLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Errorln(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Fatalln(args ...interface{}) { | ||||
| 	if logger.level() >= FatalLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Fatalln(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| 	Exit(1) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) Panicln(args ...interface{}) { | ||||
| 	if logger.level() >= PanicLevel { | ||||
| 		entry := logger.newEntry() | ||||
| 		entry.Panicln(args...) | ||||
| 		logger.releaseEntry(entry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| //When file is opened with appending mode, it's safe to | ||||
| //write concurrently to a file (within 4k message on Linux). | ||||
| //In these cases user can choose to disable the lock. | ||||
| func (logger *Logger) SetNoLock() { | ||||
| 	logger.mu.Disable() | ||||
| } | ||||
|  | ||||
| func (logger *Logger) level() Level { | ||||
| 	return Level(atomic.LoadUint32((*uint32)(&logger.Level))) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) SetLevel(level Level) { | ||||
| 	atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) AddHook(hook Hook) { | ||||
| 	logger.mu.Lock() | ||||
| 	defer logger.mu.Unlock() | ||||
| 	logger.Hooks.Add(hook) | ||||
| } | ||||
							
								
								
									
										61
									
								
								vendor/github.com/sirupsen/logrus/logger_bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								vendor/github.com/sirupsen/logrus/logger_bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| // smallFields is a small size data set for benchmarking | ||||
| var loggerFields = Fields{ | ||||
| 	"foo":   "bar", | ||||
| 	"baz":   "qux", | ||||
| 	"one":   "two", | ||||
| 	"three": "four", | ||||
| } | ||||
|  | ||||
| func BenchmarkDummyLogger(b *testing.B) { | ||||
| 	nullf, err := os.OpenFile("/dev/null", os.O_WRONLY, 0666) | ||||
| 	if err != nil { | ||||
| 		b.Fatalf("%v", err) | ||||
| 	} | ||||
| 	defer nullf.Close() | ||||
| 	doLoggerBenchmark(b, nullf, &TextFormatter{DisableColors: true}, smallFields) | ||||
| } | ||||
|  | ||||
| func BenchmarkDummyLoggerNoLock(b *testing.B) { | ||||
| 	nullf, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND, 0666) | ||||
| 	if err != nil { | ||||
| 		b.Fatalf("%v", err) | ||||
| 	} | ||||
| 	defer nullf.Close() | ||||
| 	doLoggerBenchmarkNoLock(b, nullf, &TextFormatter{DisableColors: true}, smallFields) | ||||
| } | ||||
|  | ||||
| func doLoggerBenchmark(b *testing.B, out *os.File, formatter Formatter, fields Fields) { | ||||
| 	logger := Logger{ | ||||
| 		Out:       out, | ||||
| 		Level:     InfoLevel, | ||||
| 		Formatter: formatter, | ||||
| 	} | ||||
| 	entry := logger.WithFields(fields) | ||||
| 	b.RunParallel(func(pb *testing.PB) { | ||||
| 		for pb.Next() { | ||||
| 			entry.Info("aaa") | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fields Fields) { | ||||
| 	logger := Logger{ | ||||
| 		Out:       out, | ||||
| 		Level:     InfoLevel, | ||||
| 		Formatter: formatter, | ||||
| 	} | ||||
| 	logger.SetNoLock() | ||||
| 	entry := logger.WithFields(fields) | ||||
| 	b.RunParallel(func(pb *testing.PB) { | ||||
| 		for pb.Next() { | ||||
| 			entry.Info("aaa") | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										143
									
								
								vendor/github.com/sirupsen/logrus/logrus.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/github.com/sirupsen/logrus/logrus.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // Fields type, used to pass to `WithFields`. | ||||
| type Fields map[string]interface{} | ||||
|  | ||||
| // Level type | ||||
| type Level uint32 | ||||
|  | ||||
| // Convert the Level to a string. E.g. PanicLevel becomes "panic". | ||||
| func (level Level) String() string { | ||||
| 	switch level { | ||||
| 	case DebugLevel: | ||||
| 		return "debug" | ||||
| 	case InfoLevel: | ||||
| 		return "info" | ||||
| 	case WarnLevel: | ||||
| 		return "warning" | ||||
| 	case ErrorLevel: | ||||
| 		return "error" | ||||
| 	case FatalLevel: | ||||
| 		return "fatal" | ||||
| 	case PanicLevel: | ||||
| 		return "panic" | ||||
| 	} | ||||
|  | ||||
| 	return "unknown" | ||||
| } | ||||
|  | ||||
| // ParseLevel takes a string level and returns the Logrus log level constant. | ||||
| func ParseLevel(lvl string) (Level, error) { | ||||
| 	switch strings.ToLower(lvl) { | ||||
| 	case "panic": | ||||
| 		return PanicLevel, nil | ||||
| 	case "fatal": | ||||
| 		return FatalLevel, nil | ||||
| 	case "error": | ||||
| 		return ErrorLevel, nil | ||||
| 	case "warn", "warning": | ||||
| 		return WarnLevel, nil | ||||
| 	case "info": | ||||
| 		return InfoLevel, nil | ||||
| 	case "debug": | ||||
| 		return DebugLevel, nil | ||||
| 	} | ||||
|  | ||||
| 	var l Level | ||||
| 	return l, fmt.Errorf("not a valid logrus Level: %q", lvl) | ||||
| } | ||||
|  | ||||
| // A constant exposing all logging levels | ||||
| var AllLevels = []Level{ | ||||
| 	PanicLevel, | ||||
| 	FatalLevel, | ||||
| 	ErrorLevel, | ||||
| 	WarnLevel, | ||||
| 	InfoLevel, | ||||
| 	DebugLevel, | ||||
| } | ||||
|  | ||||
| // These are the different logging levels. You can set the logging level to log | ||||
| // on your instance of logger, obtained with `logrus.New()`. | ||||
| const ( | ||||
| 	// PanicLevel level, highest level of severity. Logs and then calls panic with the | ||||
| 	// message passed to Debug, Info, ... | ||||
| 	PanicLevel Level = iota | ||||
| 	// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the | ||||
| 	// logging level is set to Panic. | ||||
| 	FatalLevel | ||||
| 	// ErrorLevel level. Logs. Used for errors that should definitely be noted. | ||||
| 	// Commonly used for hooks to send errors to an error tracking service. | ||||
| 	ErrorLevel | ||||
| 	// WarnLevel level. Non-critical entries that deserve eyes. | ||||
| 	WarnLevel | ||||
| 	// InfoLevel level. General operational entries about what's going on inside the | ||||
| 	// application. | ||||
| 	InfoLevel | ||||
| 	// DebugLevel level. Usually only enabled when debugging. Very verbose logging. | ||||
| 	DebugLevel | ||||
| ) | ||||
|  | ||||
| // Won't compile if StdLogger can't be realized by a log.Logger | ||||
| var ( | ||||
| 	_ StdLogger = &log.Logger{} | ||||
| 	_ StdLogger = &Entry{} | ||||
| 	_ StdLogger = &Logger{} | ||||
| ) | ||||
|  | ||||
| // StdLogger is what your logrus-enabled library should take, that way | ||||
| // it'll accept a stdlib logger and a logrus logger. There's no standard | ||||
| // interface, this is the closest we get, unfortunately. | ||||
| type StdLogger interface { | ||||
| 	Print(...interface{}) | ||||
| 	Printf(string, ...interface{}) | ||||
| 	Println(...interface{}) | ||||
|  | ||||
| 	Fatal(...interface{}) | ||||
| 	Fatalf(string, ...interface{}) | ||||
| 	Fatalln(...interface{}) | ||||
|  | ||||
| 	Panic(...interface{}) | ||||
| 	Panicf(string, ...interface{}) | ||||
| 	Panicln(...interface{}) | ||||
| } | ||||
|  | ||||
| // The FieldLogger interface generalizes the Entry and Logger types | ||||
| type FieldLogger interface { | ||||
| 	WithField(key string, value interface{}) *Entry | ||||
| 	WithFields(fields Fields) *Entry | ||||
| 	WithError(err error) *Entry | ||||
|  | ||||
| 	Debugf(format string, args ...interface{}) | ||||
| 	Infof(format string, args ...interface{}) | ||||
| 	Printf(format string, args ...interface{}) | ||||
| 	Warnf(format string, args ...interface{}) | ||||
| 	Warningf(format string, args ...interface{}) | ||||
| 	Errorf(format string, args ...interface{}) | ||||
| 	Fatalf(format string, args ...interface{}) | ||||
| 	Panicf(format string, args ...interface{}) | ||||
|  | ||||
| 	Debug(args ...interface{}) | ||||
| 	Info(args ...interface{}) | ||||
| 	Print(args ...interface{}) | ||||
| 	Warn(args ...interface{}) | ||||
| 	Warning(args ...interface{}) | ||||
| 	Error(args ...interface{}) | ||||
| 	Fatal(args ...interface{}) | ||||
| 	Panic(args ...interface{}) | ||||
|  | ||||
| 	Debugln(args ...interface{}) | ||||
| 	Infoln(args ...interface{}) | ||||
| 	Println(args ...interface{}) | ||||
| 	Warnln(args ...interface{}) | ||||
| 	Warningln(args ...interface{}) | ||||
| 	Errorln(args ...interface{}) | ||||
| 	Fatalln(args ...interface{}) | ||||
| 	Panicln(args ...interface{}) | ||||
| } | ||||
							
								
								
									
										386
									
								
								vendor/github.com/sirupsen/logrus/logrus_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										386
									
								
								vendor/github.com/sirupsen/logrus/logrus_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,386 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) { | ||||
| 	var buffer bytes.Buffer | ||||
| 	var fields Fields | ||||
|  | ||||
| 	logger := New() | ||||
| 	logger.Out = &buffer | ||||
| 	logger.Formatter = new(JSONFormatter) | ||||
|  | ||||
| 	log(logger) | ||||
|  | ||||
| 	err := json.Unmarshal(buffer.Bytes(), &fields) | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	assertions(fields) | ||||
| } | ||||
|  | ||||
| func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) { | ||||
| 	var buffer bytes.Buffer | ||||
|  | ||||
| 	logger := New() | ||||
| 	logger.Out = &buffer | ||||
| 	logger.Formatter = &TextFormatter{ | ||||
| 		DisableColors: true, | ||||
| 	} | ||||
|  | ||||
| 	log(logger) | ||||
|  | ||||
| 	fields := make(map[string]string) | ||||
| 	for _, kv := range strings.Split(buffer.String(), " ") { | ||||
| 		if !strings.Contains(kv, "=") { | ||||
| 			continue | ||||
| 		} | ||||
| 		kvArr := strings.Split(kv, "=") | ||||
| 		key := strings.TrimSpace(kvArr[0]) | ||||
| 		val := kvArr[1] | ||||
| 		if kvArr[1][0] == '"' { | ||||
| 			var err error | ||||
| 			val, err = strconv.Unquote(val) | ||||
| 			assert.NoError(t, err) | ||||
| 		} | ||||
| 		fields[key] = val | ||||
| 	} | ||||
| 	assertions(fields) | ||||
| } | ||||
|  | ||||
| func TestPrint(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Print("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "test") | ||||
| 		assert.Equal(t, fields["level"], "info") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestInfo(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Info("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "test") | ||||
| 		assert.Equal(t, fields["level"], "info") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestWarn(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Warn("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "test") | ||||
| 		assert.Equal(t, fields["level"], "warning") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Infoln("test", "test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "test test") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Infoln("test", 10) | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "test 10") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Infoln(10, 10) | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "10 10") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Infoln(10, 10) | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "10 10") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Info("test", 10) | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "test10") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.Info("test", "test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "testtest") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestWithFieldsShouldAllowAssignments(t *testing.T) { | ||||
| 	var buffer bytes.Buffer | ||||
| 	var fields Fields | ||||
|  | ||||
| 	logger := New() | ||||
| 	logger.Out = &buffer | ||||
| 	logger.Formatter = new(JSONFormatter) | ||||
|  | ||||
| 	localLog := logger.WithFields(Fields{ | ||||
| 		"key1": "value1", | ||||
| 	}) | ||||
|  | ||||
| 	localLog.WithField("key2", "value2").Info("test") | ||||
| 	err := json.Unmarshal(buffer.Bytes(), &fields) | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	assert.Equal(t, "value2", fields["key2"]) | ||||
| 	assert.Equal(t, "value1", fields["key1"]) | ||||
|  | ||||
| 	buffer = bytes.Buffer{} | ||||
| 	fields = Fields{} | ||||
| 	localLog.Info("test") | ||||
| 	err = json.Unmarshal(buffer.Bytes(), &fields) | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	_, ok := fields["key2"] | ||||
| 	assert.Equal(t, false, ok) | ||||
| 	assert.Equal(t, "value1", fields["key1"]) | ||||
| } | ||||
|  | ||||
| func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.WithField("msg", "hello").Info("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "test") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.WithField("msg", "hello").Info("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["msg"], "test") | ||||
| 		assert.Equal(t, fields["fields.msg"], "hello") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.WithField("time", "hello").Info("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["fields.time"], "hello") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) { | ||||
| 	LogAndAssertJSON(t, func(log *Logger) { | ||||
| 		log.WithField("level", 1).Info("test") | ||||
| 	}, func(fields Fields) { | ||||
| 		assert.Equal(t, fields["level"], "info") | ||||
| 		assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestDefaultFieldsAreNotPrefixed(t *testing.T) { | ||||
| 	LogAndAssertText(t, func(log *Logger) { | ||||
| 		ll := log.WithField("herp", "derp") | ||||
| 		ll.Info("hello") | ||||
| 		ll.Info("bye") | ||||
| 	}, func(fields map[string]string) { | ||||
| 		for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} { | ||||
| 			if _, ok := fields[fieldName]; ok { | ||||
| 				t.Fatalf("should not have prefixed %q: %v", fieldName, fields) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) { | ||||
|  | ||||
| 	var buffer bytes.Buffer | ||||
| 	var fields Fields | ||||
|  | ||||
| 	logger := New() | ||||
| 	logger.Out = &buffer | ||||
| 	logger.Formatter = new(JSONFormatter) | ||||
|  | ||||
| 	llog := logger.WithField("context", "eating raw fish") | ||||
|  | ||||
| 	llog.Info("looks delicious") | ||||
|  | ||||
| 	err := json.Unmarshal(buffer.Bytes(), &fields) | ||||
| 	assert.NoError(t, err, "should have decoded first message") | ||||
| 	assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") | ||||
| 	assert.Equal(t, fields["msg"], "looks delicious") | ||||
| 	assert.Equal(t, fields["context"], "eating raw fish") | ||||
|  | ||||
| 	buffer.Reset() | ||||
|  | ||||
| 	llog.Warn("omg it is!") | ||||
|  | ||||
| 	err = json.Unmarshal(buffer.Bytes(), &fields) | ||||
| 	assert.NoError(t, err, "should have decoded second message") | ||||
| 	assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") | ||||
| 	assert.Equal(t, fields["msg"], "omg it is!") | ||||
| 	assert.Equal(t, fields["context"], "eating raw fish") | ||||
| 	assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry") | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestConvertLevelToString(t *testing.T) { | ||||
| 	assert.Equal(t, "debug", DebugLevel.String()) | ||||
| 	assert.Equal(t, "info", InfoLevel.String()) | ||||
| 	assert.Equal(t, "warning", WarnLevel.String()) | ||||
| 	assert.Equal(t, "error", ErrorLevel.String()) | ||||
| 	assert.Equal(t, "fatal", FatalLevel.String()) | ||||
| 	assert.Equal(t, "panic", PanicLevel.String()) | ||||
| } | ||||
|  | ||||
| func TestParseLevel(t *testing.T) { | ||||
| 	l, err := ParseLevel("panic") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, PanicLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("PANIC") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, PanicLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("fatal") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, FatalLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("FATAL") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, FatalLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("error") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, ErrorLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("ERROR") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, ErrorLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("warn") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, WarnLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("WARN") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, WarnLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("warning") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, WarnLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("WARNING") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, WarnLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("info") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, InfoLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("INFO") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, InfoLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("debug") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, DebugLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("DEBUG") | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, DebugLevel, l) | ||||
|  | ||||
| 	l, err = ParseLevel("invalid") | ||||
| 	assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error()) | ||||
| } | ||||
|  | ||||
| func TestGetSetLevelRace(t *testing.T) { | ||||
| 	wg := sync.WaitGroup{} | ||||
| 	for i := 0; i < 100; i++ { | ||||
| 		wg.Add(1) | ||||
| 		go func(i int) { | ||||
| 			defer wg.Done() | ||||
| 			if i%2 == 0 { | ||||
| 				SetLevel(InfoLevel) | ||||
| 			} else { | ||||
| 				GetLevel() | ||||
| 			} | ||||
| 		}(i) | ||||
|  | ||||
| 	} | ||||
| 	wg.Wait() | ||||
| } | ||||
|  | ||||
| func TestLoggingRace(t *testing.T) { | ||||
| 	logger := New() | ||||
|  | ||||
| 	var wg sync.WaitGroup | ||||
| 	wg.Add(100) | ||||
|  | ||||
| 	for i := 0; i < 100; i++ { | ||||
| 		go func() { | ||||
| 			logger.Info("info") | ||||
| 			wg.Done() | ||||
| 		}() | ||||
| 	} | ||||
| 	wg.Wait() | ||||
| } | ||||
|  | ||||
| // Compile test | ||||
| func TestLogrusInterface(t *testing.T) { | ||||
| 	var buffer bytes.Buffer | ||||
| 	fn := func(l FieldLogger) { | ||||
| 		b := l.WithField("key", "value") | ||||
| 		b.Debug("Test") | ||||
| 	} | ||||
| 	// test logger | ||||
| 	logger := New() | ||||
| 	logger.Out = &buffer | ||||
| 	fn(logger) | ||||
|  | ||||
| 	// test Entry | ||||
| 	e := logger.WithField("another", "value") | ||||
| 	fn(e) | ||||
| } | ||||
|  | ||||
| // Implements io.Writer using channels for synchronization, so we can wait on | ||||
| // the Entry.Writer goroutine to write in a non-racey way. This does assume that | ||||
| // there is a single call to Logger.Out for each message. | ||||
| type channelWriter chan []byte | ||||
|  | ||||
| func (cw channelWriter) Write(p []byte) (int, error) { | ||||
| 	cw <- p | ||||
| 	return len(p), nil | ||||
| } | ||||
|  | ||||
| func TestEntryWriter(t *testing.T) { | ||||
| 	cw := channelWriter(make(chan []byte, 1)) | ||||
| 	log := New() | ||||
| 	log.Out = cw | ||||
| 	log.Formatter = new(JSONFormatter) | ||||
| 	log.WithField("foo", "bar").WriterLevel(WarnLevel).Write([]byte("hello\n")) | ||||
|  | ||||
| 	bs := <-cw | ||||
| 	var fields Fields | ||||
| 	err := json.Unmarshal(bs, &fields) | ||||
| 	assert.Nil(t, err) | ||||
| 	assert.Equal(t, fields["foo"], "bar") | ||||
| 	assert.Equal(t, fields["level"], "warning") | ||||
| } | ||||
							
								
								
									
										10
									
								
								vendor/github.com/sirupsen/logrus/terminal_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/sirupsen/logrus/terminal_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| // +build darwin freebsd openbsd netbsd dragonfly | ||||
| // +build !appengine | ||||
|  | ||||
| package logrus | ||||
|  | ||||
| import "golang.org/x/sys/unix" | ||||
|  | ||||
| const ioctlReadTermios = unix.TIOCGETA | ||||
|  | ||||
| type Termios unix.Termios | ||||
							
								
								
									
										11
									
								
								vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| // +build appengine | ||||
|  | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| func checkIfTerminal(w io.Writer) bool { | ||||
| 	return true | ||||
| } | ||||
							
								
								
									
										19
									
								
								vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| // +build !appengine | ||||
|  | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"os" | ||||
|  | ||||
| 	"golang.org/x/crypto/ssh/terminal" | ||||
| ) | ||||
|  | ||||
| func checkIfTerminal(w io.Writer) bool { | ||||
| 	switch v := w.(type) { | ||||
| 	case *os.File: | ||||
| 		return terminal.IsTerminal(int(v.Fd())) | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										14
									
								
								vendor/github.com/sirupsen/logrus/terminal_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/sirupsen/logrus/terminal_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| // Based on ssh/terminal: | ||||
| // Copyright 2013 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 logrus | ||||
|  | ||||
| import "golang.org/x/sys/unix" | ||||
|  | ||||
| const ioctlReadTermios = unix.TCGETS | ||||
|  | ||||
| type Termios unix.Termios | ||||
							
								
								
									
										178
									
								
								vendor/github.com/sirupsen/logrus/text_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								vendor/github.com/sirupsen/logrus/text_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,178 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	nocolor = 0 | ||||
| 	red     = 31 | ||||
| 	green   = 32 | ||||
| 	yellow  = 33 | ||||
| 	blue    = 36 | ||||
| 	gray    = 37 | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	baseTimestamp time.Time | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	baseTimestamp = time.Now() | ||||
| } | ||||
|  | ||||
| // TextFormatter formats logs into text | ||||
| type TextFormatter struct { | ||||
| 	// Set to true to bypass checking for a TTY before outputting colors. | ||||
| 	ForceColors bool | ||||
|  | ||||
| 	// Force disabling colors. | ||||
| 	DisableColors bool | ||||
|  | ||||
| 	// Disable timestamp logging. useful when output is redirected to logging | ||||
| 	// system that already adds timestamps. | ||||
| 	DisableTimestamp bool | ||||
|  | ||||
| 	// Enable logging the full timestamp when a TTY is attached instead of just | ||||
| 	// the time passed since beginning of execution. | ||||
| 	FullTimestamp bool | ||||
|  | ||||
| 	// TimestampFormat to use for display when a full timestamp is printed | ||||
| 	TimestampFormat string | ||||
|  | ||||
| 	// The fields are sorted by default for a consistent output. For applications | ||||
| 	// that log extremely frequently and don't use the JSON formatter this may not | ||||
| 	// be desired. | ||||
| 	DisableSorting bool | ||||
|  | ||||
| 	// QuoteEmptyFields will wrap empty fields in quotes if true | ||||
| 	QuoteEmptyFields bool | ||||
|  | ||||
| 	// Whether the logger's out is to a terminal | ||||
| 	isTerminal bool | ||||
|  | ||||
| 	sync.Once | ||||
| } | ||||
|  | ||||
| func (f *TextFormatter) init(entry *Entry) { | ||||
| 	if entry.Logger != nil { | ||||
| 		f.isTerminal = checkIfTerminal(entry.Logger.Out) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Format renders a single log entry | ||||
| func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { | ||||
| 	var b *bytes.Buffer | ||||
| 	keys := make([]string, 0, len(entry.Data)) | ||||
| 	for k := range entry.Data { | ||||
| 		keys = append(keys, k) | ||||
| 	} | ||||
|  | ||||
| 	if !f.DisableSorting { | ||||
| 		sort.Strings(keys) | ||||
| 	} | ||||
| 	if entry.Buffer != nil { | ||||
| 		b = entry.Buffer | ||||
| 	} else { | ||||
| 		b = &bytes.Buffer{} | ||||
| 	} | ||||
|  | ||||
| 	prefixFieldClashes(entry.Data) | ||||
|  | ||||
| 	f.Do(func() { f.init(entry) }) | ||||
|  | ||||
| 	isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors | ||||
|  | ||||
| 	timestampFormat := f.TimestampFormat | ||||
| 	if timestampFormat == "" { | ||||
| 		timestampFormat = defaultTimestampFormat | ||||
| 	} | ||||
| 	if isColored { | ||||
| 		f.printColored(b, entry, keys, timestampFormat) | ||||
| 	} else { | ||||
| 		if !f.DisableTimestamp { | ||||
| 			f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat)) | ||||
| 		} | ||||
| 		f.appendKeyValue(b, "level", entry.Level.String()) | ||||
| 		if entry.Message != "" { | ||||
| 			f.appendKeyValue(b, "msg", entry.Message) | ||||
| 		} | ||||
| 		for _, key := range keys { | ||||
| 			f.appendKeyValue(b, key, entry.Data[key]) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	b.WriteByte('\n') | ||||
| 	return b.Bytes(), nil | ||||
| } | ||||
|  | ||||
| func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) { | ||||
| 	var levelColor int | ||||
| 	switch entry.Level { | ||||
| 	case DebugLevel: | ||||
| 		levelColor = gray | ||||
| 	case WarnLevel: | ||||
| 		levelColor = yellow | ||||
| 	case ErrorLevel, FatalLevel, PanicLevel: | ||||
| 		levelColor = red | ||||
| 	default: | ||||
| 		levelColor = blue | ||||
| 	} | ||||
|  | ||||
| 	levelText := strings.ToUpper(entry.Level.String())[0:4] | ||||
|  | ||||
| 	if f.DisableTimestamp { | ||||
| 		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message) | ||||
| 	} else if !f.FullTimestamp { | ||||
| 		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message) | ||||
| 	} else { | ||||
| 		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message) | ||||
| 	} | ||||
| 	for _, k := range keys { | ||||
| 		v := entry.Data[k] | ||||
| 		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) | ||||
| 		f.appendValue(b, v) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (f *TextFormatter) needsQuoting(text string) bool { | ||||
| 	if f.QuoteEmptyFields && len(text) == 0 { | ||||
| 		return true | ||||
| 	} | ||||
| 	for _, ch := range text { | ||||
| 		if !((ch >= 'a' && ch <= 'z') || | ||||
| 			(ch >= 'A' && ch <= 'Z') || | ||||
| 			(ch >= '0' && ch <= '9') || | ||||
| 			ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { | ||||
| 	if b.Len() > 0 { | ||||
| 		b.WriteByte(' ') | ||||
| 	} | ||||
| 	b.WriteString(key) | ||||
| 	b.WriteByte('=') | ||||
| 	f.appendValue(b, value) | ||||
| } | ||||
|  | ||||
| func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { | ||||
| 	stringVal, ok := value.(string) | ||||
| 	if !ok { | ||||
| 		stringVal = fmt.Sprint(value) | ||||
| 	} | ||||
|  | ||||
| 	if !f.needsQuoting(stringVal) { | ||||
| 		b.WriteString(stringVal) | ||||
| 	} else { | ||||
| 		b.WriteString(fmt.Sprintf("%q", stringVal)) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										141
									
								
								vendor/github.com/sirupsen/logrus/text_formatter_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								vendor/github.com/sirupsen/logrus/text_formatter_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestFormatting(t *testing.T) { | ||||
| 	tf := &TextFormatter{DisableColors: true} | ||||
|  | ||||
| 	testCases := []struct { | ||||
| 		value    string | ||||
| 		expected string | ||||
| 	}{ | ||||
| 		{`foo`, "time=\"0001-01-01T00:00:00Z\" level=panic test=foo\n"}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		b, _ := tf.Format(WithField("test", tc.value)) | ||||
|  | ||||
| 		if string(b) != tc.expected { | ||||
| 			t.Errorf("formatting expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestQuoting(t *testing.T) { | ||||
| 	tf := &TextFormatter{DisableColors: true} | ||||
|  | ||||
| 	checkQuoting := func(q bool, value interface{}) { | ||||
| 		b, _ := tf.Format(WithField("test", value)) | ||||
| 		idx := bytes.Index(b, ([]byte)("test=")) | ||||
| 		cont := bytes.Contains(b[idx+5:], []byte("\"")) | ||||
| 		if cont != q { | ||||
| 			if q { | ||||
| 				t.Errorf("quoting expected for: %#v", value) | ||||
| 			} else { | ||||
| 				t.Errorf("quoting not expected for: %#v", value) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	checkQuoting(false, "") | ||||
| 	checkQuoting(false, "abcd") | ||||
| 	checkQuoting(false, "v1.0") | ||||
| 	checkQuoting(false, "1234567890") | ||||
| 	checkQuoting(false, "/foobar") | ||||
| 	checkQuoting(false, "foo_bar") | ||||
| 	checkQuoting(false, "foo@bar") | ||||
| 	checkQuoting(false, "foobar^") | ||||
| 	checkQuoting(false, "+/-_^@f.oobar") | ||||
| 	checkQuoting(true, "foobar$") | ||||
| 	checkQuoting(true, "&foobar") | ||||
| 	checkQuoting(true, "x y") | ||||
| 	checkQuoting(true, "x,y") | ||||
| 	checkQuoting(false, errors.New("invalid")) | ||||
| 	checkQuoting(true, errors.New("invalid argument")) | ||||
|  | ||||
| 	// Test for quoting empty fields. | ||||
| 	tf.QuoteEmptyFields = true | ||||
| 	checkQuoting(true, "") | ||||
| 	checkQuoting(false, "abcd") | ||||
| 	checkQuoting(true, errors.New("invalid argument")) | ||||
| } | ||||
|  | ||||
| func TestEscaping(t *testing.T) { | ||||
| 	tf := &TextFormatter{DisableColors: true} | ||||
|  | ||||
| 	testCases := []struct { | ||||
| 		value    string | ||||
| 		expected string | ||||
| 	}{ | ||||
| 		{`ba"r`, `ba\"r`}, | ||||
| 		{`ba'r`, `ba'r`}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		b, _ := tf.Format(WithField("test", tc.value)) | ||||
| 		if !bytes.Contains(b, []byte(tc.expected)) { | ||||
| 			t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestEscaping_Interface(t *testing.T) { | ||||
| 	tf := &TextFormatter{DisableColors: true} | ||||
|  | ||||
| 	ts := time.Now() | ||||
|  | ||||
| 	testCases := []struct { | ||||
| 		value    interface{} | ||||
| 		expected string | ||||
| 	}{ | ||||
| 		{ts, fmt.Sprintf("\"%s\"", ts.String())}, | ||||
| 		{errors.New("error: something went wrong"), "\"error: something went wrong\""}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		b, _ := tf.Format(WithField("test", tc.value)) | ||||
| 		if !bytes.Contains(b, []byte(tc.expected)) { | ||||
| 			t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestTimestampFormat(t *testing.T) { | ||||
| 	checkTimeStr := func(format string) { | ||||
| 		customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format} | ||||
| 		customStr, _ := customFormatter.Format(WithField("test", "test")) | ||||
| 		timeStart := bytes.Index(customStr, ([]byte)("time=")) | ||||
| 		timeEnd := bytes.Index(customStr, ([]byte)("level=")) | ||||
| 		timeStr := customStr[timeStart+5+len("\"") : timeEnd-1-len("\"")] | ||||
| 		if format == "" { | ||||
| 			format = time.RFC3339 | ||||
| 		} | ||||
| 		_, e := time.Parse(format, (string)(timeStr)) | ||||
| 		if e != nil { | ||||
| 			t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	checkTimeStr("2006-01-02T15:04:05.000000000Z07:00") | ||||
| 	checkTimeStr("Mon Jan _2 15:04:05 2006") | ||||
| 	checkTimeStr("") | ||||
| } | ||||
|  | ||||
| func TestDisableTimestampWithColoredOutput(t *testing.T) { | ||||
| 	tf := &TextFormatter{DisableTimestamp: true, ForceColors: true} | ||||
|  | ||||
| 	b, _ := tf.Format(WithField("test", "test")) | ||||
| 	if strings.Contains(string(b), "[0000]") { | ||||
| 		t.Error("timestamp not expected when DisableTimestamp is true") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // TODO add tests for sorting etc., this requires a parser for the text | ||||
| // formatter output. | ||||
							
								
								
									
										62
									
								
								vendor/github.com/sirupsen/logrus/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								vendor/github.com/sirupsen/logrus/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| package logrus | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"io" | ||||
| 	"runtime" | ||||
| ) | ||||
|  | ||||
| func (logger *Logger) Writer() *io.PipeWriter { | ||||
| 	return logger.WriterLevel(InfoLevel) | ||||
| } | ||||
|  | ||||
| func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { | ||||
| 	return NewEntry(logger).WriterLevel(level) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Writer() *io.PipeWriter { | ||||
| 	return entry.WriterLevel(InfoLevel) | ||||
| } | ||||
|  | ||||
| func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { | ||||
| 	reader, writer := io.Pipe() | ||||
|  | ||||
| 	var printFunc func(args ...interface{}) | ||||
|  | ||||
| 	switch level { | ||||
| 	case DebugLevel: | ||||
| 		printFunc = entry.Debug | ||||
| 	case InfoLevel: | ||||
| 		printFunc = entry.Info | ||||
| 	case WarnLevel: | ||||
| 		printFunc = entry.Warn | ||||
| 	case ErrorLevel: | ||||
| 		printFunc = entry.Error | ||||
| 	case FatalLevel: | ||||
| 		printFunc = entry.Fatal | ||||
| 	case PanicLevel: | ||||
| 		printFunc = entry.Panic | ||||
| 	default: | ||||
| 		printFunc = entry.Print | ||||
| 	} | ||||
|  | ||||
| 	go entry.writerScanner(reader, printFunc) | ||||
| 	runtime.SetFinalizer(writer, writerFinalizer) | ||||
|  | ||||
| 	return writer | ||||
| } | ||||
|  | ||||
| func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { | ||||
| 	scanner := bufio.NewScanner(reader) | ||||
| 	for scanner.Scan() { | ||||
| 		printFunc(scanner.Text()) | ||||
| 	} | ||||
| 	if err := scanner.Err(); err != nil { | ||||
| 		entry.Errorf("Error while reading from Writer: %s", err) | ||||
| 	} | ||||
| 	reader.Close() | ||||
| } | ||||
|  | ||||
| func writerFinalizer(writer *io.PipeWriter) { | ||||
| 	writer.Close() | ||||
| } | ||||
							
								
								
									
										10
									
								
								vendor/golang.org/x/crypto/.gitattributes
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/golang.org/x/crypto/.gitattributes
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| # Treat all files in this repo as binary, with no git magic updating | ||||
| # line endings. Windows users contributing to Go will need to use a | ||||
| # modern version of git and editors capable of LF line endings. | ||||
| # | ||||
| # We'll prevent accidental CRLF line endings from entering the repo | ||||
| # via the git-review gofmt checks. | ||||
| # | ||||
| # See golang.org/issue/9281 | ||||
|  | ||||
| * -text | ||||
							
								
								
									
										2
									
								
								vendor/golang.org/x/crypto/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/golang.org/x/crypto/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| # Add no patterns to .hgignore except for files generated by the build. | ||||
| last-change | ||||
							
								
								
									
										3
									
								
								vendor/golang.org/x/crypto/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/golang.org/x/crypto/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| # This source code refers to The Go Authors for copyright purposes. | ||||
| # The master list of authors is in the main Go distribution, | ||||
| # visible at https://tip.golang.org/AUTHORS. | ||||
							
								
								
									
										31
									
								
								vendor/golang.org/x/crypto/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/golang.org/x/crypto/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| # Contributing to Go | ||||
|  | ||||
| Go is an open source project. | ||||
|  | ||||
| It is the work of hundreds of contributors. We appreciate your help! | ||||
|  | ||||
|  | ||||
| ## Filing issues | ||||
|  | ||||
| When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: | ||||
|  | ||||
| 1. What version of Go are you using (`go version`)? | ||||
| 2. What operating system and processor architecture are you using? | ||||
| 3. What did you do? | ||||
| 4. What did you expect to see? | ||||
| 5. What did you see instead? | ||||
|  | ||||
| General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. | ||||
| The gophers there will answer or ask you to file an issue if you've tripped over a bug. | ||||
|  | ||||
| ## Contributing code | ||||
|  | ||||
| Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) | ||||
| before sending patches. | ||||
|  | ||||
| **We do not accept GitHub pull requests** | ||||
| (we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review). | ||||
|  | ||||
| Unless otherwise noted, the Go source files are distributed under | ||||
| the BSD-style license found in the LICENSE file. | ||||
|  | ||||
							
								
								
									
										3
									
								
								vendor/golang.org/x/crypto/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/golang.org/x/crypto/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| # This source code was written by the Go contributors. | ||||
| # The master list of contributors is in the main Go distribution, | ||||
| # visible at https://tip.golang.org/CONTRIBUTORS. | ||||
							
								
								
									
										27
									
								
								vendor/golang.org/x/crypto/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/crypto/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Copyright (c) 2009 The Go Authors. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
|    * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
|    * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
|    * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										22
									
								
								vendor/golang.org/x/crypto/PATENTS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/golang.org/x/crypto/PATENTS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| Additional IP Rights Grant (Patents) | ||||
|  | ||||
| "This implementation" means the copyrightable works distributed by | ||||
| Google as part of the Go project. | ||||
|  | ||||
| Google hereby grants to You a perpetual, worldwide, non-exclusive, | ||||
| no-charge, royalty-free, irrevocable (except as stated in this section) | ||||
| patent license to make, have made, use, offer to sell, sell, import, | ||||
| transfer and otherwise run, modify and propagate the contents of this | ||||
| implementation of Go, where such license applies only to those patent | ||||
| claims, both currently owned or controlled by Google and acquired in | ||||
| the future, licensable by Google that are necessarily infringed by this | ||||
| implementation of Go.  This grant does not include claims that would be | ||||
| infringed only as a consequence of further modification of this | ||||
| implementation.  If you or your agent or exclusive licensee institute or | ||||
| order or agree to the institution of patent litigation against any | ||||
| entity (including a cross-claim or counterclaim in a lawsuit) alleging | ||||
| that this implementation of Go or any code incorporated within this | ||||
| implementation of Go constitutes direct or contributory patent | ||||
| infringement, or inducement of patent infringement, then any patent | ||||
| rights granted to you under this License for this implementation of Go | ||||
| shall terminate as of the date such litigation is filed. | ||||
							
								
								
									
										21
									
								
								vendor/golang.org/x/crypto/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/golang.org/x/crypto/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| # Go Cryptography | ||||
|  | ||||
| This repository holds supplementary Go cryptography libraries. | ||||
|  | ||||
| ## Download/Install | ||||
|  | ||||
| The easiest way to install is to run `go get -u golang.org/x/crypto/...`. You | ||||
| can also manually git clone the repository to `$GOPATH/src/golang.org/x/crypto`. | ||||
|  | ||||
| ## Report Issues / Send Patches | ||||
|  | ||||
| This repository uses Gerrit for code changes. To learn how to submit changes to | ||||
| this repository, see https://golang.org/doc/contribute.html. | ||||
|  | ||||
| The main issue tracker for the crypto repository is located at | ||||
| https://github.com/golang/go/issues. Prefix your issue with "x/crypto:" in the | ||||
| subject line, so it is easy to find. | ||||
|  | ||||
| Note that contributions to the cryptography package receive additional scrutiny | ||||
| due to their sensitive nature. Patches may take longer than normal to receive | ||||
| feedback. | ||||
							
								
								
									
										1058
									
								
								vendor/golang.org/x/crypto/acme/acme.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1058
									
								
								vendor/golang.org/x/crypto/acme/acme.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1352
									
								
								vendor/golang.org/x/crypto/acme/acme_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1352
									
								
								vendor/golang.org/x/crypto/acme/acme_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										973
									
								
								vendor/golang.org/x/crypto/acme/autocert/autocert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										973
									
								
								vendor/golang.org/x/crypto/acme/autocert/autocert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,973 @@ | ||||
| // Copyright 2016 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 autocert provides automatic access to certificates from Let's Encrypt | ||||
| // and any other ACME-based CA. | ||||
| // | ||||
| // This package is a work in progress and makes no API stability promises. | ||||
| package autocert | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"crypto" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/tls" | ||||
| 	"crypto/x509" | ||||
| 	"crypto/x509/pkix" | ||||
| 	"encoding/pem" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	mathrand "math/rand" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"path" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"golang.org/x/crypto/acme" | ||||
| ) | ||||
|  | ||||
| // createCertRetryAfter is how much time to wait before removing a failed state | ||||
| // entry due to an unsuccessful createCert call. | ||||
| // This is a variable instead of a const for testing. | ||||
| // TODO: Consider making it configurable or an exp backoff? | ||||
| var createCertRetryAfter = time.Minute | ||||
|  | ||||
| // pseudoRand is safe for concurrent use. | ||||
| var pseudoRand *lockedMathRand | ||||
|  | ||||
| func init() { | ||||
| 	src := mathrand.NewSource(timeNow().UnixNano()) | ||||
| 	pseudoRand = &lockedMathRand{rnd: mathrand.New(src)} | ||||
| } | ||||
|  | ||||
| // AcceptTOS is a Manager.Prompt function that always returns true to | ||||
| // indicate acceptance of the CA's Terms of Service during account | ||||
| // registration. | ||||
| func AcceptTOS(tosURL string) bool { return true } | ||||
|  | ||||
| // HostPolicy specifies which host names the Manager is allowed to respond to. | ||||
| // It returns a non-nil error if the host should be rejected. | ||||
| // The returned error is accessible via tls.Conn.Handshake and its callers. | ||||
| // See Manager's HostPolicy field and GetCertificate method docs for more details. | ||||
| type HostPolicy func(ctx context.Context, host string) error | ||||
|  | ||||
| // HostWhitelist returns a policy where only the specified host names are allowed. | ||||
| // Only exact matches are currently supported. Subdomains, regexp or wildcard | ||||
| // will not match. | ||||
| func HostWhitelist(hosts ...string) HostPolicy { | ||||
| 	whitelist := make(map[string]bool, len(hosts)) | ||||
| 	for _, h := range hosts { | ||||
| 		whitelist[h] = true | ||||
| 	} | ||||
| 	return func(_ context.Context, host string) error { | ||||
| 		if !whitelist[host] { | ||||
| 			return errors.New("acme/autocert: host not configured") | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // defaultHostPolicy is used when Manager.HostPolicy is not set. | ||||
| func defaultHostPolicy(context.Context, string) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| // | ||||
| // You must specify a cache implementation, such as DirCache, | ||||
| // to reuse obtained certificates across program restarts. | ||||
| // Otherwise your server is very likely to exceed the certificate | ||||
| // issuer's request rate limits. | ||||
| type Manager struct { | ||||
| 	// Prompt specifies a callback function to conditionally accept a CA's Terms of Service (TOS). | ||||
| 	// The registration may require the caller to agree to the CA's TOS. | ||||
| 	// If so, Manager calls Prompt with a TOS URL provided by the CA. Prompt should report | ||||
| 	// whether the caller agrees to the terms. | ||||
| 	// | ||||
| 	// 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. | ||||
| 	// | ||||
| 	// Manager passes the Cache certificates data encoded in PEM, with private/public | ||||
| 	// parts combined in a single Cache.Put call, private key first. | ||||
| 	Cache Cache | ||||
|  | ||||
| 	// HostPolicy controls which domains the Manager will attempt | ||||
| 	// to retrieve new certificates for. It does not affect cached certs. | ||||
| 	// | ||||
| 	// If non-nil, HostPolicy is called before requesting a new cert. | ||||
| 	// If nil, all hosts are currently allowed. This is not recommended, | ||||
| 	// as it opens a potential attack where clients connect to a server | ||||
| 	// by IP address and pretend to be asking for an incorrect host name. | ||||
| 	// Manager will attempt to obtain a certificate for that host, incorrectly, | ||||
| 	// eventually reaching the CA's rate limit for certificate requests | ||||
| 	// and making it impossible to obtain actual certificates. | ||||
| 	// | ||||
| 	// See GetCertificate for more details. | ||||
| 	HostPolicy HostPolicy | ||||
|  | ||||
| 	// RenewBefore optionally specifies how early certificates should | ||||
| 	// be renewed before they expire. | ||||
| 	// | ||||
| 	// If zero, they're renewed 30 days before expiration. | ||||
| 	RenewBefore time.Duration | ||||
|  | ||||
| 	// 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. | ||||
| 	// | ||||
| 	// Mutating the field after the first call of GetCertificate method will have no effect. | ||||
| 	Client *acme.Client | ||||
|  | ||||
| 	// Email optionally specifies a contact email address. | ||||
| 	// This is used by CAs, such as Let's Encrypt, to notify about problems | ||||
| 	// with issued certificates. | ||||
| 	// | ||||
| 	// 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. | ||||
| 	// | ||||
| 	// If false, a default is used. Currently the default | ||||
| 	// is EC-based keys using the P-256 curve. | ||||
| 	ForceRSA bool | ||||
|  | ||||
| 	clientMu sync.Mutex | ||||
| 	client   *acme.Client // initialized by acmeClient method | ||||
|  | ||||
| 	stateMu sync.Mutex | ||||
| 	state   map[string]*certState // keyed by domain name | ||||
|  | ||||
| 	// renewal tracks the set of domains currently running renewal timers. | ||||
| 	// It is keyed by domain name. | ||||
| 	renewalMu sync.Mutex | ||||
| 	renewal   map[string]*domainRenewal | ||||
|  | ||||
| 	// tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens. | ||||
| 	tokensMu sync.RWMutex | ||||
| 	// tryHTTP01 indicates whether the Manager should try "http-01" challenge type | ||||
| 	// during the authorization flow. | ||||
| 	tryHTTP01 bool | ||||
| 	// httpTokens contains response body values for http-01 challenges | ||||
| 	// and is keyed by the URL path at which a challenge response is expected | ||||
| 	// 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 | ||||
| 	// and is keyed by token domain name, which matches server name of ClientHello. | ||||
| 	// Keys always have ".acme.invalid" suffix. | ||||
| 	// The entries are stored for the duration of the authorization flow. | ||||
| 	certTokens map[string]*tls.Certificate | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| // | ||||
| // 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. | ||||
| func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { | ||||
| 	if m.Prompt == nil { | ||||
| 		return nil, errors.New("acme/autocert: Manager.Prompt not set") | ||||
| 	} | ||||
|  | ||||
| 	name := hello.ServerName | ||||
| 	if name == "" { | ||||
| 		return nil, errors.New("acme/autocert: missing server name") | ||||
| 	} | ||||
| 	if !strings.Contains(strings.Trim(name, "."), ".") { | ||||
| 		return nil, errors.New("acme/autocert: server name component count invalid") | ||||
| 	} | ||||
| 	if strings.ContainsAny(name, `/\`) { | ||||
| 		return nil, errors.New("acme/autocert: server name contains invalid character") | ||||
| 	} | ||||
|  | ||||
| 	// In the worst-case scenario, the timeout needs to account for caching, host policy, | ||||
| 	// domain ownership verification and certificate issuance. | ||||
| 	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") { | ||||
| 		m.tokensMu.RLock() | ||||
| 		defer m.tokensMu.RUnlock() | ||||
| 		if cert := m.certTokens[name]; cert != nil { | ||||
| 			return cert, nil | ||||
| 		} | ||||
| 		if cert, err := m.cacheGet(ctx, name); err == nil { | ||||
| 			return cert, nil | ||||
| 		} | ||||
| 		// TODO: cache error results? | ||||
| 		return nil, fmt.Errorf("acme/autocert: no token cert for %q", name) | ||||
| 	} | ||||
|  | ||||
| 	// regular domain | ||||
| 	name = strings.TrimSuffix(name, ".") // golang.org/issue/18114 | ||||
| 	cert, err := m.cert(ctx, name) | ||||
| 	if err == nil { | ||||
| 		return cert, nil | ||||
| 	} | ||||
| 	if err != ErrCacheMiss { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// first-time | ||||
| 	if err := m.hostPolicy()(ctx, name); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cert, err = m.createCert(ctx, name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	m.cachePut(ctx, name, cert) | ||||
| 	return cert, nil | ||||
| } | ||||
|  | ||||
| // 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, | ||||
| // it delegates the request to the optional fallback handler. | ||||
| // | ||||
| // If fallback is nil, the returned handler redirects all GET and HEAD requests | ||||
| // to the default TLS port 443 with 302 Found status code, preserving the original | ||||
| // request path and query. It responds with 400 Bad Request to all other HTTP methods. | ||||
| // The fallback is not protected by the optional HostPolicy. | ||||
| // | ||||
| // 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. | ||||
| func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler { | ||||
| 	m.tokensMu.Lock() | ||||
| 	defer m.tokensMu.Unlock() | ||||
| 	m.tryHTTP01 = true | ||||
|  | ||||
| 	if fallback == nil { | ||||
| 		fallback = http.HandlerFunc(handleHTTPRedirect) | ||||
| 	} | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		if !strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge/") { | ||||
| 			fallback.ServeHTTP(w, r) | ||||
| 			return | ||||
| 		} | ||||
| 		// A reasonable context timeout for cache and host policy only, | ||||
| 		// because we don't wait for a new certificate issuance here. | ||||
| 		ctx, cancel := context.WithTimeout(r.Context(), time.Minute) | ||||
| 		defer cancel() | ||||
| 		if err := m.hostPolicy()(ctx, r.Host); err != nil { | ||||
| 			http.Error(w, err.Error(), http.StatusForbidden) | ||||
| 			return | ||||
| 		} | ||||
| 		data, err := m.httpToken(ctx, r.URL.Path) | ||||
| 		if err != nil { | ||||
| 			http.Error(w, err.Error(), http.StatusNotFound) | ||||
| 			return | ||||
| 		} | ||||
| 		w.Write(data) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func handleHTTPRedirect(w http.ResponseWriter, r *http.Request) { | ||||
| 	if r.Method != "GET" && r.Method != "HEAD" { | ||||
| 		http.Error(w, "Use HTTPS", http.StatusBadRequest) | ||||
| 		return | ||||
| 	} | ||||
| 	target := "https://" + stripPort(r.Host) + r.URL.RequestURI() | ||||
| 	http.Redirect(w, r, target, http.StatusFound) | ||||
| } | ||||
|  | ||||
| func stripPort(hostport string) string { | ||||
| 	host, _, err := net.SplitHostPort(hostport) | ||||
| 	if err != nil { | ||||
| 		return hostport | ||||
| 	} | ||||
| 	return net.JoinHostPort(host, "443") | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	m.stateMu.Lock() | ||||
| 	if s, ok := m.state[name]; ok { | ||||
| 		m.stateMu.Unlock() | ||||
| 		s.RLock() | ||||
| 		defer s.RUnlock() | ||||
| 		return s.tlscert() | ||||
| 	} | ||||
| 	defer m.stateMu.Unlock() | ||||
| 	cert, err := m.cacheGet(ctx, name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	signer, ok := cert.PrivateKey.(crypto.Signer) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("acme/autocert: private key cannot sign") | ||||
| 	} | ||||
| 	if m.state == nil { | ||||
| 		m.state = make(map[string]*certState) | ||||
| 	} | ||||
| 	s := &certState{ | ||||
| 		key:  signer, | ||||
| 		cert: cert.Certificate, | ||||
| 		leaf: cert.Leaf, | ||||
| 	} | ||||
| 	m.state[name] = s | ||||
| 	go m.renew(name, 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 m.Cache == nil { | ||||
| 		return nil, ErrCacheMiss | ||||
| 	} | ||||
| 	data, err := m.Cache.Get(ctx, domain) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// private | ||||
| 	priv, pub := pem.Decode(data) | ||||
| 	if priv == nil || !strings.Contains(priv.Type, "PRIVATE") { | ||||
| 		return nil, ErrCacheMiss | ||||
| 	} | ||||
| 	privKey, err := parsePrivateKey(priv.Bytes) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// public | ||||
| 	var pubDER [][]byte | ||||
| 	for len(pub) > 0 { | ||||
| 		var b *pem.Block | ||||
| 		b, pub = pem.Decode(pub) | ||||
| 		if b == nil { | ||||
| 			break | ||||
| 		} | ||||
| 		pubDER = append(pubDER, b.Bytes) | ||||
| 	} | ||||
| 	if len(pub) > 0 { | ||||
| 		// Leftover content not consumed by pem.Decode. Corrupt. Ignore. | ||||
| 		return nil, ErrCacheMiss | ||||
| 	} | ||||
|  | ||||
| 	// verify and create TLS cert | ||||
| 	leaf, err := validCert(domain, pubDER, privKey) | ||||
| 	if err != nil { | ||||
| 		return nil, ErrCacheMiss | ||||
| 	} | ||||
| 	tlscert := &tls.Certificate{ | ||||
| 		Certificate: pubDER, | ||||
| 		PrivateKey:  privKey, | ||||
| 		Leaf:        leaf, | ||||
| 	} | ||||
| 	return tlscert, nil | ||||
| } | ||||
|  | ||||
| func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Certificate) error { | ||||
| 	if m.Cache == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// contains PEM-encoded data | ||||
| 	var buf bytes.Buffer | ||||
|  | ||||
| 	// private | ||||
| 	switch key := tlscert.PrivateKey.(type) { | ||||
| 	case *ecdsa.PrivateKey: | ||||
| 		if err := encodeECDSAKey(&buf, key); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	case *rsa.PrivateKey: | ||||
| 		b := x509.MarshalPKCS1PrivateKey(key) | ||||
| 		pb := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: b} | ||||
| 		if err := pem.Encode(&buf, pb); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	default: | ||||
| 		return errors.New("acme/autocert: unknown private key type") | ||||
| 	} | ||||
|  | ||||
| 	// public | ||||
| 	for _, b := range tlscert.Certificate { | ||||
| 		pb := &pem.Block{Type: "CERTIFICATE", Bytes: b} | ||||
| 		if err := pem.Encode(&buf, pb); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return m.Cache.Put(ctx, domain, buf.Bytes()) | ||||
| } | ||||
|  | ||||
| func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error { | ||||
| 	b, err := x509.MarshalECPrivateKey(key) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pb := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} | ||||
| 	return pem.Encode(w, pb) | ||||
| } | ||||
|  | ||||
| // createCert starts the domain ownership verification and returns a certificate | ||||
| // for that domain upon success. | ||||
| // | ||||
| // 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) { | ||||
| 	// TODO: maybe rewrite this whole piece using sync.Once | ||||
| 	state, err := m.certState(domain) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// state may exist if another goroutine is already working on it | ||||
| 	// in which case just wait for it to finish | ||||
| 	if !state.locked { | ||||
| 		state.RLock() | ||||
| 		defer state.RUnlock() | ||||
| 		return state.tlscert() | ||||
| 	} | ||||
|  | ||||
| 	// We are the first; state is locked. | ||||
| 	// Unblock the readers when domain ownership is verified | ||||
| 	// and we got the cert or the process failed. | ||||
| 	defer state.Unlock() | ||||
| 	state.locked = false | ||||
|  | ||||
| 	der, leaf, err := m.authorizedCert(ctx, state.key, domain) | ||||
| 	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) | ||||
| 			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] | ||||
| 			if !ok { | ||||
| 				return | ||||
| 			} | ||||
| 			if _, err := validCert(domain, s.cert, s.key); err == nil { | ||||
| 				return | ||||
| 			} | ||||
| 			delete(m.state, domain) | ||||
| 		}) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	state.cert = der | ||||
| 	state.leaf = leaf | ||||
| 	go m.renew(domain, 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) { | ||||
| 	m.stateMu.Lock() | ||||
| 	defer m.stateMu.Unlock() | ||||
| 	if m.state == nil { | ||||
| 		m.state = make(map[string]*certState) | ||||
| 	} | ||||
| 	// existing state | ||||
| 	if state, ok := m.state[domain]; ok { | ||||
| 		return state, nil | ||||
| 	} | ||||
|  | ||||
| 	// new locked state | ||||
| 	var ( | ||||
| 		err error | ||||
| 		key crypto.Signer | ||||
| 	) | ||||
| 	if m.ForceRSA { | ||||
| 		key, err = rsa.GenerateKey(rand.Reader, 2048) | ||||
| 	} else { | ||||
| 		key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	state := &certState{ | ||||
| 		key:    key, | ||||
| 		locked: true, | ||||
| 	} | ||||
| 	state.Lock() // will be unlocked by m.certState caller | ||||
| 	m.state[domain] = 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) { | ||||
| 	client, err := m.acmeClient(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	if err := m.verify(ctx, client, domain); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	csr, err := certRequest(key, domain) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	der, _, err = client.CreateCert(ctx, csr, 0, true) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	leaf, err = validCert(domain, der, key) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	return der, leaf, nil | ||||
| } | ||||
|  | ||||
| // 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"} | ||||
| 	m.tokensMu.RLock() | ||||
| 	if m.tryHTTP01 { | ||||
| 		challengeTypes = append(challengeTypes, "http-01") | ||||
| 	} | ||||
| 	m.tokensMu.RUnlock() | ||||
|  | ||||
| 	var nextTyp int // challengeType index of the next challenge type to try | ||||
| 	for { | ||||
| 		// Start domain authorization and get the challenge. | ||||
| 		authz, err := client.Authorize(ctx, domain) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		// No point in accepting challenges if the authorization status | ||||
| 		// is in a final state. | ||||
| 		switch authz.Status { | ||||
| 		case acme.StatusValid: | ||||
| 			return nil // already authorized | ||||
| 		case acme.StatusInvalid: | ||||
| 			return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI) | ||||
| 		} | ||||
|  | ||||
| 		// Pick the next preferred challenge. | ||||
| 		var chal *acme.Challenge | ||||
| 		for chal == nil && nextTyp < len(challengeTypes) { | ||||
| 			chal = pickChallenge(challengeTypes[nextTyp], authz.Challenges) | ||||
| 			nextTyp++ | ||||
| 		} | ||||
| 		if chal == nil { | ||||
| 			return fmt.Errorf("acme/autocert: unable to authorize %q; tried %q", domain, challengeTypes) | ||||
| 		} | ||||
| 		cleanup, err := m.fulfill(ctx, client, chal) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		defer cleanup() | ||||
| 		if _, err := client.Accept(ctx, chal); err != nil { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// A challenge is fulfilled and accepted: wait for the CA to validate. | ||||
| 		if _, err := client.WaitAuthorization(ctx, authz.URI); err == nil { | ||||
| 			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) { | ||||
| 	switch chal.Type { | ||||
| 	case "tls-sni-01": | ||||
| 		cert, name, err := client.TLSSNI01ChallengeCert(chal.Token) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		m.putCertToken(ctx, name, &cert) | ||||
| 		return func() { go m.deleteCertToken(name) }, nil | ||||
| 	case "tls-sni-02": | ||||
| 		cert, name, err := client.TLSSNI02ChallengeCert(chal.Token) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		m.putCertToken(ctx, name, &cert) | ||||
| 		return func() { go m.deleteCertToken(name) }, nil | ||||
| 	case "http-01": | ||||
| 		resp, err := client.HTTP01ChallengeResponse(chal.Token) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		p := client.HTTP01ChallengePath(chal.Token) | ||||
| 		m.putHTTPToken(ctx, p, resp) | ||||
| 		return func() { go m.deleteHTTPToken(p) }, nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type) | ||||
| } | ||||
|  | ||||
| func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge { | ||||
| 	for _, c := range chal { | ||||
| 		if c.Type == typ { | ||||
| 			return c | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // putCertToken stores the cert under the named key 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() | ||||
| 	if m.certTokens == nil { | ||||
| 		m.certTokens = make(map[string]*tls.Certificate) | ||||
| 	} | ||||
| 	m.certTokens[name] = cert | ||||
| 	m.cachePut(ctx, name, cert) | ||||
| } | ||||
|  | ||||
| // deleteCertToken removes the token certificate for the specified domain 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) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // httpToken retrieves an existing http-01 token value from an in-memory map | ||||
| // or the optional cache. | ||||
| func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) { | ||||
| 	m.tokensMu.RLock() | ||||
| 	defer m.tokensMu.RUnlock() | ||||
| 	if v, ok := m.httpTokens[tokenPath]; ok { | ||||
| 		return v, nil | ||||
| 	} | ||||
| 	if m.Cache == nil { | ||||
| 		return nil, fmt.Errorf("acme/autocert: no token at %q", tokenPath) | ||||
| 	} | ||||
| 	return m.Cache.Get(ctx, httpTokenCacheKey(tokenPath)) | ||||
| } | ||||
|  | ||||
| // putHTTPToken stores an http-01 token value using tokenPath as key | ||||
| // in both in-memory map and the optional Cache. | ||||
| // | ||||
| // It ignores any error returned from Cache.Put. | ||||
| func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) { | ||||
| 	m.tokensMu.Lock() | ||||
| 	defer m.tokensMu.Unlock() | ||||
| 	if m.httpTokens == nil { | ||||
| 		m.httpTokens = make(map[string][]byte) | ||||
| 	} | ||||
| 	b := []byte(val) | ||||
| 	m.httpTokens[tokenPath] = b | ||||
| 	if m.Cache != nil { | ||||
| 		m.Cache.Put(ctx, httpTokenCacheKey(tokenPath), b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // deleteHTTPToken removes an http-01 token value from both in-memory map | ||||
| // and the optional Cache, ignoring any error returned from the latter. | ||||
| // | ||||
| // If m.Cache is non-nil, it blocks until Cache.Delete returns without a timeout. | ||||
| func (m *Manager) deleteHTTPToken(tokenPath string) { | ||||
| 	m.tokensMu.Lock() | ||||
| 	defer m.tokensMu.Unlock() | ||||
| 	delete(m.httpTokens, tokenPath) | ||||
| 	if m.Cache != nil { | ||||
| 		m.Cache.Delete(context.Background(), httpTokenCacheKey(tokenPath)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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) | ||||
| } | ||||
|  | ||||
| // renew starts a cert renewal timer loop, one per domain. | ||||
| // | ||||
| // The loop is scheduled in two cases: | ||||
| // - a cert was fetched from cache for the first time (wasn't in m.state) | ||||
| // - a new cert was created by m.createCert | ||||
| // | ||||
| // 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) { | ||||
| 	m.renewalMu.Lock() | ||||
| 	defer m.renewalMu.Unlock() | ||||
| 	if m.renewal[domain] != nil { | ||||
| 		// another goroutine is already on it | ||||
| 		return | ||||
| 	} | ||||
| 	if m.renewal == nil { | ||||
| 		m.renewal = make(map[string]*domainRenewal) | ||||
| 	} | ||||
| 	dr := &domainRenewal{m: m, domain: domain, key: key} | ||||
| 	m.renewal[domain] = dr | ||||
| 	dr.start(exp) | ||||
| } | ||||
|  | ||||
| // stopRenew stops all currently running cert renewal timers. | ||||
| // The timers are not restarted during the lifetime of the Manager. | ||||
| func (m *Manager) stopRenew() { | ||||
| 	m.renewalMu.Lock() | ||||
| 	defer m.renewalMu.Unlock() | ||||
| 	for name, dr := range m.renewal { | ||||
| 		delete(m.renewal, name) | ||||
| 		dr.stop() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) { | ||||
| 	const keyName = "acme_account.key" | ||||
|  | ||||
| 	genKey := func() (*ecdsa.PrivateKey, error) { | ||||
| 		return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	} | ||||
|  | ||||
| 	if m.Cache == nil { | ||||
| 		return genKey() | ||||
| 	} | ||||
|  | ||||
| 	data, err := m.Cache.Get(ctx, keyName) | ||||
| 	if err == ErrCacheMiss { | ||||
| 		key, err := genKey() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		var buf bytes.Buffer | ||||
| 		if err := encodeECDSAKey(&buf, key); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if err := m.Cache.Put(ctx, keyName, buf.Bytes()); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return key, nil | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	priv, _ := pem.Decode(data) | ||||
| 	if priv == nil || !strings.Contains(priv.Type, "PRIVATE") { | ||||
| 		return nil, errors.New("acme/autocert: invalid account key found in cache") | ||||
| 	} | ||||
| 	return parsePrivateKey(priv.Bytes) | ||||
| } | ||||
|  | ||||
| func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) { | ||||
| 	m.clientMu.Lock() | ||||
| 	defer m.clientMu.Unlock() | ||||
| 	if m.client != nil { | ||||
| 		return m.client, nil | ||||
| 	} | ||||
|  | ||||
| 	client := m.Client | ||||
| 	if client == nil { | ||||
| 		client = &acme.Client{DirectoryURL: acme.LetsEncryptURL} | ||||
| 	} | ||||
| 	if client.Key == nil { | ||||
| 		var err error | ||||
| 		client.Key, err = m.accountKey(ctx) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	var contact []string | ||||
| 	if m.Email != "" { | ||||
| 		contact = []string{"mailto:" + m.Email} | ||||
| 	} | ||||
| 	a := &acme.Account{Contact: contact} | ||||
| 	_, err := client.Register(ctx, a, m.Prompt) | ||||
| 	if ae, ok := err.(*acme.Error); err == nil || ok && ae.StatusCode == http.StatusConflict { | ||||
| 		// conflict indicates the key is already registered | ||||
| 		m.client = client | ||||
| 		err = nil | ||||
| 	} | ||||
| 	return m.client, err | ||||
| } | ||||
|  | ||||
| func (m *Manager) hostPolicy() HostPolicy { | ||||
| 	if m.HostPolicy != nil { | ||||
| 		return m.HostPolicy | ||||
| 	} | ||||
| 	return defaultHostPolicy | ||||
| } | ||||
|  | ||||
| func (m *Manager) renewBefore() time.Duration { | ||||
| 	if m.RenewBefore > renewJitter { | ||||
| 		return m.RenewBefore | ||||
| 	} | ||||
| 	return 720 * time.Hour // 30 days | ||||
| } | ||||
|  | ||||
| // certState is ready when its mutex is unlocked for reading. | ||||
| type certState struct { | ||||
| 	sync.RWMutex | ||||
| 	locked bool              // locked for read/write | ||||
| 	key    crypto.Signer     // private key for cert | ||||
| 	cert   [][]byte          // DER encoding | ||||
| 	leaf   *x509.Certificate // parsed cert[0]; always non-nil if cert != nil | ||||
| } | ||||
|  | ||||
| // tlscert creates a tls.Certificate from s.key and s.cert. | ||||
| // Callers should wrap it in s.RLock() and s.RUnlock(). | ||||
| func (s *certState) tlscert() (*tls.Certificate, error) { | ||||
| 	if s.key == nil { | ||||
| 		return nil, errors.New("acme/autocert: missing signer") | ||||
| 	} | ||||
| 	if len(s.cert) == 0 { | ||||
| 		return nil, errors.New("acme/autocert: missing certificate") | ||||
| 	} | ||||
| 	return &tls.Certificate{ | ||||
| 		PrivateKey:  s.key, | ||||
| 		Certificate: s.cert, | ||||
| 		Leaf:        s.leaf, | ||||
| 	}, 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) { | ||||
| 	req := &x509.CertificateRequest{ | ||||
| 		Subject:  pkix.Name{CommonName: cn}, | ||||
| 		DNSNames: san, | ||||
| 	} | ||||
| 	return x509.CreateCertificateRequest(rand.Reader, req, key) | ||||
| } | ||||
|  | ||||
| // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates | ||||
| // PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. | ||||
| // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. | ||||
| // | ||||
| // Inspired by parsePrivateKey in crypto/tls/tls.go. | ||||
| func parsePrivateKey(der []byte) (crypto.Signer, error) { | ||||
| 	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { | ||||
| 		return key, nil | ||||
| 	} | ||||
| 	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { | ||||
| 		switch key := key.(type) { | ||||
| 		case *rsa.PrivateKey: | ||||
| 			return key, nil | ||||
| 		case *ecdsa.PrivateKey: | ||||
| 			return key, nil | ||||
| 		default: | ||||
| 			return nil, errors.New("acme/autocert: unknown private key type in PKCS#8 wrapping") | ||||
| 		} | ||||
| 	} | ||||
| 	if key, err := x509.ParseECPrivateKey(der); err == nil { | ||||
| 		return key, nil | ||||
| 	} | ||||
|  | ||||
| 	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. | ||||
| // | ||||
| // The returned value is the verified leaf cert. | ||||
| func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) { | ||||
| 	// parse public part(s) | ||||
| 	var n int | ||||
| 	for _, b := range der { | ||||
| 		n += len(b) | ||||
| 	} | ||||
| 	pub := make([]byte, n) | ||||
| 	n = 0 | ||||
| 	for _, b := range der { | ||||
| 		n += copy(pub[n:], b) | ||||
| 	} | ||||
| 	x509Cert, err := x509.ParseCertificates(pub) | ||||
| 	if 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 { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// ensure the leaf corresponds to the private key | ||||
| 	switch pub := leaf.PublicKey.(type) { | ||||
| 	case *rsa.PublicKey: | ||||
| 		prv, ok := key.(*rsa.PrivateKey) | ||||
| 		if !ok { | ||||
| 			return nil, errors.New("acme/autocert: private key type does not match public key type") | ||||
| 		} | ||||
| 		if pub.N.Cmp(prv.N) != 0 { | ||||
| 			return nil, errors.New("acme/autocert: private key does not match public key") | ||||
| 		} | ||||
| 	case *ecdsa.PublicKey: | ||||
| 		prv, ok := key.(*ecdsa.PrivateKey) | ||||
| 		if !ok { | ||||
| 			return nil, errors.New("acme/autocert: private key type does not match public key type") | ||||
| 		} | ||||
| 		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") | ||||
| 		} | ||||
| 	default: | ||||
| 		return nil, errors.New("acme/autocert: unknown public key algorithm") | ||||
| 	} | ||||
| 	return leaf, nil | ||||
| } | ||||
|  | ||||
| func retryAfter(v string) time.Duration { | ||||
| 	if i, err := strconv.Atoi(v); err == nil { | ||||
| 		return time.Duration(i) * time.Second | ||||
| 	} | ||||
| 	if t, err := http.ParseTime(v); err == nil { | ||||
| 		return t.Sub(timeNow()) | ||||
| 	} | ||||
| 	return time.Second | ||||
| } | ||||
|  | ||||
| type lockedMathRand struct { | ||||
| 	sync.Mutex | ||||
| 	rnd *mathrand.Rand | ||||
| } | ||||
|  | ||||
| func (r *lockedMathRand) int63n(max int64) int64 { | ||||
| 	r.Lock() | ||||
| 	n := r.rnd.Int63n(max) | ||||
| 	r.Unlock() | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| // For easier testing. | ||||
| var ( | ||||
| 	timeNow = time.Now | ||||
|  | ||||
| 	// Called when a state is removed. | ||||
| 	testDidRemoveState = func(domain string) {} | ||||
| ) | ||||
							
								
								
									
										757
									
								
								vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										757
									
								
								vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,757 @@ | ||||
| // Copyright 2016 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 autocert | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/tls" | ||||
| 	"crypto/x509" | ||||
| 	"crypto/x509/pkix" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"html/template" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"net/http" | ||||
| 	"net/http/httptest" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"golang.org/x/crypto/acme" | ||||
| ) | ||||
|  | ||||
| var discoTmpl = template.Must(template.New("disco").Parse(`{ | ||||
| 	"new-reg": "{{.}}/new-reg", | ||||
| 	"new-authz": "{{.}}/new-authz", | ||||
| 	"new-cert": "{{.}}/new-cert" | ||||
| }`)) | ||||
|  | ||||
| var authzTmpl = template.Must(template.New("authz").Parse(`{ | ||||
| 	"status": "pending", | ||||
| 	"challenges": [ | ||||
| 		{ | ||||
| 			"uri": "{{.}}/challenge/1", | ||||
| 			"type": "tls-sni-01", | ||||
| 			"token": "token-01" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"uri": "{{.}}/challenge/2", | ||||
| 			"type": "tls-sni-02", | ||||
| 			"token": "token-02" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"uri": "{{.}}/challenge/dns-01", | ||||
| 			"type": "dns-01", | ||||
| 			"token": "token-dns-01" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"uri": "{{.}}/challenge/http-01", | ||||
| 			"type": "http-01", | ||||
| 			"token": "token-http-01" | ||||
| 		} | ||||
| 	] | ||||
| }`)) | ||||
|  | ||||
| type memCache struct { | ||||
| 	mu      sync.Mutex | ||||
| 	keyData map[string][]byte | ||||
| } | ||||
|  | ||||
| func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) { | ||||
| 	m.mu.Lock() | ||||
| 	defer m.mu.Unlock() | ||||
|  | ||||
| 	v, ok := m.keyData[key] | ||||
| 	if !ok { | ||||
| 		return nil, ErrCacheMiss | ||||
| 	} | ||||
| 	return v, nil | ||||
| } | ||||
|  | ||||
| func (m *memCache) Put(ctx context.Context, key string, data []byte) error { | ||||
| 	m.mu.Lock() | ||||
| 	defer m.mu.Unlock() | ||||
|  | ||||
| 	m.keyData[key] = data | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *memCache) Delete(ctx context.Context, key string) error { | ||||
| 	m.mu.Lock() | ||||
| 	defer m.mu.Unlock() | ||||
|  | ||||
| 	delete(m.keyData, key) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func newMemCache() *memCache { | ||||
| 	return &memCache{ | ||||
| 		keyData: make(map[string][]byte), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func dummyCert(pub interface{}, san ...string) ([]byte, error) { | ||||
| 	return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...) | ||||
| } | ||||
|  | ||||
| func dateDummyCert(pub interface{}, start, end time.Time, san ...string) ([]byte, error) { | ||||
| 	// use EC key to run faster on 386 | ||||
| 	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	t := &x509.Certificate{ | ||||
| 		SerialNumber:          big.NewInt(1), | ||||
| 		NotBefore:             start, | ||||
| 		NotAfter:              end, | ||||
| 		BasicConstraintsValid: true, | ||||
| 		KeyUsage:              x509.KeyUsageKeyEncipherment, | ||||
| 		DNSNames:              san, | ||||
| 	} | ||||
| 	if pub == nil { | ||||
| 		pub = &key.PublicKey | ||||
| 	} | ||||
| 	return x509.CreateCertificate(rand.Reader, t, t, pub, key) | ||||
| } | ||||
|  | ||||
| func decodePayload(v interface{}, r io.Reader) error { | ||||
| 	var req struct{ Payload string } | ||||
| 	if err := json.NewDecoder(r).Decode(&req); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	payload, err := base64.RawURLEncoding.DecodeString(req.Payload) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return json.Unmarshal(payload, v) | ||||
| } | ||||
|  | ||||
| func TestGetCertificate(t *testing.T) { | ||||
| 	man := &Manager{Prompt: AcceptTOS} | ||||
| 	defer man.stopRenew() | ||||
| 	hello := &tls.ClientHelloInfo{ServerName: "example.org"} | ||||
| 	testGetCertificate(t, man, "example.org", hello) | ||||
| } | ||||
|  | ||||
| func TestGetCertificate_trailingDot(t *testing.T) { | ||||
| 	man := &Manager{Prompt: AcceptTOS} | ||||
| 	defer man.stopRenew() | ||||
| 	hello := &tls.ClientHelloInfo{ServerName: "example.org."} | ||||
| 	testGetCertificate(t, man, "example.org", hello) | ||||
| } | ||||
|  | ||||
| func TestGetCertificate_ForceRSA(t *testing.T) { | ||||
| 	man := &Manager{ | ||||
| 		Prompt:   AcceptTOS, | ||||
| 		Cache:    newMemCache(), | ||||
| 		ForceRSA: true, | ||||
| 	} | ||||
| 	defer man.stopRenew() | ||||
| 	hello := &tls.ClientHelloInfo{ServerName: "example.org"} | ||||
| 	testGetCertificate(t, man, "example.org", hello) | ||||
|  | ||||
| 	cert, err := man.cacheGet(context.Background(), "example.org") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("man.cacheGet: %v", err) | ||||
| 	} | ||||
| 	if _, ok := cert.PrivateKey.(*rsa.PrivateKey); !ok { | ||||
| 		t.Errorf("cert.PrivateKey is %T; want *rsa.PrivateKey", cert.PrivateKey) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGetCertificate_nilPrompt(t *testing.T) { | ||||
| 	man := &Manager{} | ||||
| 	defer man.stopRenew() | ||||
| 	url, finish := startACMEServerStub(t, man, "example.org") | ||||
| 	defer finish() | ||||
| 	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	man.Client = &acme.Client{ | ||||
| 		Key:          key, | ||||
| 		DirectoryURL: url, | ||||
| 	} | ||||
| 	hello := &tls.ClientHelloInfo{ServerName: "example.org"} | ||||
| 	if _, err := man.GetCertificate(hello); err == nil { | ||||
| 		t.Error("got certificate for example.org; wanted error") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGetCertificate_expiredCache(t *testing.T) { | ||||
| 	// Make an expired cert and cache it. | ||||
| 	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	tmpl := &x509.Certificate{ | ||||
| 		SerialNumber: big.NewInt(1), | ||||
| 		Subject:      pkix.Name{CommonName: "example.org"}, | ||||
| 		NotAfter:     time.Now(), | ||||
| 	} | ||||
| 	pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	tlscert := &tls.Certificate{ | ||||
| 		Certificate: [][]byte{pub}, | ||||
| 		PrivateKey:  pk, | ||||
| 	} | ||||
|  | ||||
| 	man := &Manager{Prompt: AcceptTOS, Cache: newMemCache()} | ||||
| 	defer man.stopRenew() | ||||
| 	if err := man.cachePut(context.Background(), "example.org", tlscert); err != nil { | ||||
| 		t.Fatalf("man.cachePut: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// The expired cached cert should trigger a new cert issuance | ||||
| 	// and return without an error. | ||||
| 	hello := &tls.ClientHelloInfo{ServerName: "example.org"} | ||||
| 	testGetCertificate(t, man, "example.org", hello) | ||||
| } | ||||
|  | ||||
| func TestGetCertificate_failedAttempt(t *testing.T) { | ||||
| 	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		w.WriteHeader(http.StatusBadRequest) | ||||
| 	})) | ||||
| 	defer ts.Close() | ||||
|  | ||||
| 	const example = "example.org" | ||||
| 	d := createCertRetryAfter | ||||
| 	f := testDidRemoveState | ||||
| 	defer func() { | ||||
| 		createCertRetryAfter = d | ||||
| 		testDidRemoveState = f | ||||
| 	}() | ||||
| 	createCertRetryAfter = 0 | ||||
| 	done := make(chan struct{}) | ||||
| 	testDidRemoveState = func(domain string) { | ||||
| 		if domain != example { | ||||
| 			t.Errorf("testDidRemoveState: domain = %q; want %q", domain, example) | ||||
| 		} | ||||
| 		close(done) | ||||
| 	} | ||||
|  | ||||
| 	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	man := &Manager{ | ||||
| 		Prompt: AcceptTOS, | ||||
| 		Client: &acme.Client{ | ||||
| 			Key:          key, | ||||
| 			DirectoryURL: ts.URL, | ||||
| 		}, | ||||
| 	} | ||||
| 	defer man.stopRenew() | ||||
| 	hello := &tls.ClientHelloInfo{ServerName: example} | ||||
| 	if _, err := man.GetCertificate(hello); err == nil { | ||||
| 		t.Error("GetCertificate: err is nil") | ||||
| 	} | ||||
| 	select { | ||||
| 	case <-time.After(5 * time.Second): | ||||
| 		t.Errorf("took too long to remove the %q state", example) | ||||
| 	case <-done: | ||||
| 		man.stateMu.Lock() | ||||
| 		defer man.stateMu.Unlock() | ||||
| 		if v, exist := man.state[example]; exist { | ||||
| 			t.Errorf("state exists for %q: %+v", example, v) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // startACMEServerStub runs an ACME server | ||||
| // The domain argument is the expected domain name of a certificate request. | ||||
| func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, finish func()) { | ||||
| 	// echo token-02 | shasum -a 256 | ||||
| 	// then divide result in 2 parts separated by dot | ||||
| 	tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid" | ||||
| 	verifyTokenCert := func() { | ||||
| 		hello := &tls.ClientHelloInfo{ServerName: tokenCertName} | ||||
| 		_, err := man.GetCertificate(hello) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// ACME CA server stub | ||||
| 	var ca *httptest.Server | ||||
| 	ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		w.Header().Set("Replay-Nonce", "nonce") | ||||
| 		if r.Method == "HEAD" { | ||||
| 			// a nonce request | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		switch r.URL.Path { | ||||
| 		// discovery | ||||
| 		case "/": | ||||
| 			if err := discoTmpl.Execute(w, ca.URL); err != nil { | ||||
| 				t.Errorf("discoTmpl: %v", err) | ||||
| 			} | ||||
| 		// client key registration | ||||
| 		case "/new-reg": | ||||
| 			w.Write([]byte("{}")) | ||||
| 		// domain authorization | ||||
| 		case "/new-authz": | ||||
| 			w.Header().Set("Location", ca.URL+"/authz/1") | ||||
| 			w.WriteHeader(http.StatusCreated) | ||||
| 			if err := authzTmpl.Execute(w, ca.URL); err != nil { | ||||
| 				t.Errorf("authzTmpl: %v", err) | ||||
| 			} | ||||
| 		// accept tls-sni-02 challenge | ||||
| 		case "/challenge/2": | ||||
| 			verifyTokenCert() | ||||
| 			w.Write([]byte("{}")) | ||||
| 		// authorization status | ||||
| 		case "/authz/1": | ||||
| 			w.Write([]byte(`{"status": "valid"}`)) | ||||
| 		// cert request | ||||
| 		case "/new-cert": | ||||
| 			var req struct { | ||||
| 				CSR string `json:"csr"` | ||||
| 			} | ||||
| 			decodePayload(&req, r.Body) | ||||
| 			b, _ := base64.RawURLEncoding.DecodeString(req.CSR) | ||||
| 			csr, err := x509.ParseCertificateRequest(b) | ||||
| 			if err != nil { | ||||
| 				t.Errorf("new-cert: CSR: %v", err) | ||||
| 			} | ||||
| 			if csr.Subject.CommonName != domain { | ||||
| 				t.Errorf("CommonName in CSR = %q; want %q", csr.Subject.CommonName, domain) | ||||
| 			} | ||||
| 			der, err := dummyCert(csr.PublicKey, domain) | ||||
| 			if err != nil { | ||||
| 				t.Errorf("new-cert: dummyCert: %v", err) | ||||
| 			} | ||||
| 			chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL) | ||||
| 			w.Header().Set("Link", chainUp) | ||||
| 			w.WriteHeader(http.StatusCreated) | ||||
| 			w.Write(der) | ||||
| 		// CA chain cert | ||||
| 		case "/ca-cert": | ||||
| 			der, err := dummyCert(nil, "ca") | ||||
| 			if err != nil { | ||||
| 				t.Errorf("ca-cert: dummyCert: %v", err) | ||||
| 			} | ||||
| 			w.Write(der) | ||||
| 		default: | ||||
| 			t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path) | ||||
| 		} | ||||
| 	})) | ||||
| 	finish = func() { | ||||
| 		ca.Close() | ||||
|  | ||||
| 		// make sure token cert was removed | ||||
| 		cancel := make(chan struct{}) | ||||
| 		done := make(chan struct{}) | ||||
| 		go func() { | ||||
| 			defer close(done) | ||||
| 			tick := time.NewTicker(100 * time.Millisecond) | ||||
| 			defer tick.Stop() | ||||
| 			for { | ||||
| 				hello := &tls.ClientHelloInfo{ServerName: tokenCertName} | ||||
| 				if _, err := man.GetCertificate(hello); err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				select { | ||||
| 				case <-tick.C: | ||||
| 				case <-cancel: | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		}() | ||||
| 		select { | ||||
| 		case <-done: | ||||
| 		case <-time.After(5 * time.Second): | ||||
| 			close(cancel) | ||||
| 			t.Error("token cert was not removed") | ||||
| 			<-done | ||||
| 		} | ||||
| 	} | ||||
| 	return ca.URL, finish | ||||
| } | ||||
|  | ||||
| // tests man.GetCertificate flow using the provided hello argument. | ||||
| // The domain argument is the expected domain name of a certificate request. | ||||
| func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.ClientHelloInfo) { | ||||
| 	url, finish := startACMEServerStub(t, man, domain) | ||||
| 	defer finish() | ||||
|  | ||||
| 	// use EC key to run faster on 386 | ||||
| 	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	man.Client = &acme.Client{ | ||||
| 		Key:          key, | ||||
| 		DirectoryURL: url, | ||||
| 	} | ||||
|  | ||||
| 	// simulate tls.Config.GetCertificate | ||||
| 	var tlscert *tls.Certificate | ||||
| 	done := make(chan struct{}) | ||||
| 	go func() { | ||||
| 		tlscert, err = man.GetCertificate(hello) | ||||
| 		close(done) | ||||
| 	}() | ||||
| 	select { | ||||
| 	case <-time.After(time.Minute): | ||||
| 		t.Fatal("man.GetCertificate took too long to return") | ||||
| 	case <-done: | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("man.GetCertificate: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// verify the tlscert is the same we responded with from the CA stub | ||||
| 	if len(tlscert.Certificate) == 0 { | ||||
| 		t.Fatal("len(tlscert.Certificate) is 0") | ||||
| 	} | ||||
| 	cert, err := x509.ParseCertificate(tlscert.Certificate[0]) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("x509.ParseCertificate: %v", err) | ||||
| 	} | ||||
| 	if len(cert.DNSNames) == 0 || cert.DNSNames[0] != domain { | ||||
| 		t.Errorf("cert.DNSNames = %v; want %q", cert.DNSNames, domain) | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestVerifyHTTP01(t *testing.T) { | ||||
| 	var ( | ||||
| 		http01 http.Handler | ||||
|  | ||||
| 		authzCount      int // num. of created authorizations | ||||
| 		didAcceptHTTP01 bool | ||||
| 	) | ||||
|  | ||||
| 	verifyHTTPToken := func() { | ||||
| 		r := httptest.NewRequest("GET", "/.well-known/acme-challenge/token-http-01", nil) | ||||
| 		w := httptest.NewRecorder() | ||||
| 		http01.ServeHTTP(w, r) | ||||
| 		if w.Code != http.StatusOK { | ||||
| 			t.Errorf("http token: w.Code = %d; want %d", w.Code, http.StatusOK) | ||||
| 		} | ||||
| 		if v := string(w.Body.Bytes()); !strings.HasPrefix(v, "token-http-01.") { | ||||
| 			t.Errorf("http token value = %q; want 'token-http-01.' prefix", v) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// ACME CA server stub, only the needed bits. | ||||
| 	// TODO: Merge this with startACMEServerStub, making it a configurable CA for testing. | ||||
| 	var ca *httptest.Server | ||||
| 	ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		w.Header().Set("Replay-Nonce", "nonce") | ||||
| 		if r.Method == "HEAD" { | ||||
| 			// a nonce request | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		switch r.URL.Path { | ||||
| 		// Discovery. | ||||
| 		case "/": | ||||
| 			if err := discoTmpl.Execute(w, ca.URL); err != nil { | ||||
| 				t.Errorf("discoTmpl: %v", err) | ||||
| 			} | ||||
| 		// Client key registration. | ||||
| 		case "/new-reg": | ||||
| 			w.Write([]byte("{}")) | ||||
| 		// New domain authorization. | ||||
| 		case "/new-authz": | ||||
| 			authzCount++ | ||||
| 			w.Header().Set("Location", fmt.Sprintf("%s/authz/%d", ca.URL, authzCount)) | ||||
| 			w.WriteHeader(http.StatusCreated) | ||||
| 			if err := authzTmpl.Execute(w, ca.URL); err != nil { | ||||
| 				t.Errorf("authzTmpl: %v", err) | ||||
| 			} | ||||
| 		// Accept tls-sni-02. | ||||
| 		case "/challenge/2": | ||||
| 			w.Write([]byte("{}")) | ||||
| 		// Reject tls-sni-01. | ||||
| 		case "/challenge/1": | ||||
| 			http.Error(w, "won't accept tls-sni-01", http.StatusBadRequest) | ||||
| 		// Should not accept dns-01. | ||||
| 		case "/challenge/dns-01": | ||||
| 			t.Errorf("dns-01 challenge was accepted") | ||||
| 			http.Error(w, "won't accept dns-01", http.StatusBadRequest) | ||||
| 		// Accept http-01. | ||||
| 		case "/challenge/http-01": | ||||
| 			didAcceptHTTP01 = true | ||||
| 			verifyHTTPToken() | ||||
| 			w.Write([]byte("{}")) | ||||
| 		// Authorization statuses. | ||||
| 		// Make tls-sni-xxx invalid. | ||||
| 		case "/authz/1", "/authz/2": | ||||
| 			w.Write([]byte(`{"status": "invalid"}`)) | ||||
| 		case "/authz/3", "/authz/4": | ||||
| 			w.Write([]byte(`{"status": "valid"}`)) | ||||
| 		default: | ||||
| 			http.NotFound(w, r) | ||||
| 			t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path) | ||||
| 		} | ||||
| 	})) | ||||
| 	defer ca.Close() | ||||
|  | ||||
| 	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	m := &Manager{ | ||||
| 		Client: &acme.Client{ | ||||
| 			Key:          key, | ||||
| 			DirectoryURL: ca.URL, | ||||
| 		}, | ||||
| 	} | ||||
| 	http01 = m.HTTPHandler(nil) | ||||
| 	if err := m.verify(context.Background(), m.Client, "example.org"); err != nil { | ||||
| 		t.Errorf("m.verify: %v", err) | ||||
| 	} | ||||
| 	// Only tls-sni-01, tls-sni-02 and http-01 must be accepted | ||||
| 	// The dns-01 challenge is unsupported. | ||||
| 	if authzCount != 3 { | ||||
| 		t.Errorf("authzCount = %d; want 3", authzCount) | ||||
| 	} | ||||
| 	if !didAcceptHTTP01 { | ||||
| 		t.Error("did not accept http-01 challenge") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestHTTPHandlerDefaultFallback(t *testing.T) { | ||||
| 	tt := []struct { | ||||
| 		method, url  string | ||||
| 		wantCode     int | ||||
| 		wantLocation string | ||||
| 	}{ | ||||
| 		{"GET", "http://example.org", 302, "https://example.org/"}, | ||||
| 		{"GET", "http://example.org/foo", 302, "https://example.org/foo"}, | ||||
| 		{"GET", "http://example.org/foo/bar/", 302, "https://example.org/foo/bar/"}, | ||||
| 		{"GET", "http://example.org/?a=b", 302, "https://example.org/?a=b"}, | ||||
| 		{"GET", "http://example.org/foo?a=b", 302, "https://example.org/foo?a=b"}, | ||||
| 		{"GET", "http://example.org:80/foo?a=b", 302, "https://example.org:443/foo?a=b"}, | ||||
| 		{"GET", "http://example.org:80/foo%20bar", 302, "https://example.org:443/foo%20bar"}, | ||||
| 		{"GET", "http://[2602:d1:xxxx::c60a]:1234", 302, "https://[2602:d1:xxxx::c60a]:443/"}, | ||||
| 		{"GET", "http://[2602:d1:xxxx::c60a]", 302, "https://[2602:d1:xxxx::c60a]/"}, | ||||
| 		{"GET", "http://[2602:d1:xxxx::c60a]/foo?a=b", 302, "https://[2602:d1:xxxx::c60a]/foo?a=b"}, | ||||
| 		{"HEAD", "http://example.org", 302, "https://example.org/"}, | ||||
| 		{"HEAD", "http://example.org/foo", 302, "https://example.org/foo"}, | ||||
| 		{"HEAD", "http://example.org/foo/bar/", 302, "https://example.org/foo/bar/"}, | ||||
| 		{"HEAD", "http://example.org/?a=b", 302, "https://example.org/?a=b"}, | ||||
| 		{"HEAD", "http://example.org/foo?a=b", 302, "https://example.org/foo?a=b"}, | ||||
| 		{"POST", "http://example.org", 400, ""}, | ||||
| 		{"PUT", "http://example.org", 400, ""}, | ||||
| 		{"GET", "http://example.org/.well-known/acme-challenge/x", 404, ""}, | ||||
| 	} | ||||
| 	var m Manager | ||||
| 	h := m.HTTPHandler(nil) | ||||
| 	for i, test := range tt { | ||||
| 		r := httptest.NewRequest(test.method, test.url, nil) | ||||
| 		w := httptest.NewRecorder() | ||||
| 		h.ServeHTTP(w, r) | ||||
| 		if w.Code != test.wantCode { | ||||
| 			t.Errorf("%d: w.Code = %d; want %d", i, w.Code, test.wantCode) | ||||
| 			t.Errorf("%d: body: %s", i, w.Body.Bytes()) | ||||
| 		} | ||||
| 		if v := w.Header().Get("Location"); v != test.wantLocation { | ||||
| 			t.Errorf("%d: Location = %q; want %q", i, v, test.wantLocation) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestAccountKeyCache(t *testing.T) { | ||||
| 	m := Manager{Cache: newMemCache()} | ||||
| 	ctx := context.Background() | ||||
| 	k1, err := m.accountKey(ctx) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	k2, err := m.accountKey(ctx) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(k1, k2) { | ||||
| 		t.Errorf("account keys don't match: k1 = %#v; k2 = %#v", k1, k2) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCache(t *testing.T) { | ||||
| 	privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	tmpl := &x509.Certificate{ | ||||
| 		SerialNumber: big.NewInt(1), | ||||
| 		Subject:      pkix.Name{CommonName: "example.org"}, | ||||
| 		NotAfter:     time.Now().Add(time.Hour), | ||||
| 	} | ||||
| 	pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &privKey.PublicKey, privKey) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	tlscert := &tls.Certificate{ | ||||
| 		Certificate: [][]byte{pub}, | ||||
| 		PrivateKey:  privKey, | ||||
| 	} | ||||
|  | ||||
| 	man := &Manager{Cache: newMemCache()} | ||||
| 	defer man.stopRenew() | ||||
| 	ctx := context.Background() | ||||
| 	if err := man.cachePut(ctx, "example.org", tlscert); err != nil { | ||||
| 		t.Fatalf("man.cachePut: %v", err) | ||||
| 	} | ||||
| 	res, err := man.cacheGet(ctx, "example.org") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("man.cacheGet: %v", err) | ||||
| 	} | ||||
| 	if res == nil { | ||||
| 		t.Fatal("res is nil") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestHostWhitelist(t *testing.T) { | ||||
| 	policy := HostWhitelist("example.com", "example.org", "*.example.net") | ||||
| 	tt := []struct { | ||||
| 		host  string | ||||
| 		allow bool | ||||
| 	}{ | ||||
| 		{"example.com", true}, | ||||
| 		{"example.org", true}, | ||||
| 		{"one.example.com", false}, | ||||
| 		{"two.example.org", false}, | ||||
| 		{"three.example.net", false}, | ||||
| 		{"dummy", false}, | ||||
| 	} | ||||
| 	for i, test := range tt { | ||||
| 		err := policy(nil, test.host) | ||||
| 		if err != nil && test.allow { | ||||
| 			t.Errorf("%d: policy(%q): %v; want nil", i, test.host, err) | ||||
| 		} | ||||
| 		if err == nil && !test.allow { | ||||
| 			t.Errorf("%d: policy(%q): nil; want an error", i, test.host) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestValidCert(t *testing.T) { | ||||
| 	key1, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	key2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	key3, err := rsa.GenerateKey(rand.Reader, 512) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	cert1, err := dummyCert(key1.Public(), "example.org") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	cert2, err := dummyCert(key2.Public(), "example.org") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	cert3, err := dummyCert(key3.Public(), "example.org") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	now := time.Now() | ||||
| 	early, err := dateDummyCert(key1.Public(), now.Add(time.Hour), now.Add(2*time.Hour), "example.org") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	expired, err := dateDummyCert(key1.Public(), now.Add(-2*time.Hour), now.Add(-time.Hour), "example.org") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	tt := []struct { | ||||
| 		domain string | ||||
| 		key    crypto.Signer | ||||
| 		cert   [][]byte | ||||
| 		ok     bool | ||||
| 	}{ | ||||
| 		{"example.org", key1, [][]byte{cert1}, true}, | ||||
| 		{"example.org", key3, [][]byte{cert3}, true}, | ||||
| 		{"example.org", key1, [][]byte{cert1, cert2, cert3}, true}, | ||||
| 		{"example.org", key1, [][]byte{cert1, {1}}, false}, | ||||
| 		{"example.org", key1, [][]byte{{1}}, false}, | ||||
| 		{"example.org", key1, [][]byte{cert2}, false}, | ||||
| 		{"example.org", key2, [][]byte{cert1}, false}, | ||||
| 		{"example.org", key1, [][]byte{cert3}, false}, | ||||
| 		{"example.org", key3, [][]byte{cert1}, false}, | ||||
| 		{"example.net", key1, [][]byte{cert1}, false}, | ||||
| 		{"example.org", key1, [][]byte{early}, false}, | ||||
| 		{"example.org", key1, [][]byte{expired}, false}, | ||||
| 	} | ||||
| 	for i, test := range tt { | ||||
| 		leaf, err := validCert(test.domain, test.cert, test.key) | ||||
| 		if err != nil && test.ok { | ||||
| 			t.Errorf("%d: err = %v", i, err) | ||||
| 		} | ||||
| 		if err == nil && !test.ok { | ||||
| 			t.Errorf("%d: err is nil", i) | ||||
| 		} | ||||
| 		if err == nil && test.ok && leaf == nil { | ||||
| 			t.Errorf("%d: leaf is nil", i) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type cacheGetFunc func(ctx context.Context, key string) ([]byte, error) | ||||
|  | ||||
| func (f cacheGetFunc) Get(ctx context.Context, key string) ([]byte, error) { | ||||
| 	return f(ctx, key) | ||||
| } | ||||
|  | ||||
| func (f cacheGetFunc) Put(ctx context.Context, key string, data []byte) error { | ||||
| 	return fmt.Errorf("unsupported Put of %q = %q", key, data) | ||||
| } | ||||
|  | ||||
| func (f cacheGetFunc) Delete(ctx context.Context, key string) error { | ||||
| 	return fmt.Errorf("unsupported Delete of %q", key) | ||||
| } | ||||
|  | ||||
| func TestManagerGetCertificateBogusSNI(t *testing.T) { | ||||
| 	m := Manager{ | ||||
| 		Prompt: AcceptTOS, | ||||
| 		Cache: cacheGetFunc(func(ctx context.Context, key string) ([]byte, error) { | ||||
| 			return nil, fmt.Errorf("cache.Get of %s", key) | ||||
| 		}), | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name    string | ||||
| 		wantErr string | ||||
| 	}{ | ||||
| 		{"foo.com", "cache.Get of foo.com"}, | ||||
| 		{"foo.com.", "cache.Get of foo.com"}, | ||||
| 		{`a\b.com`, "acme/autocert: server name contains invalid character"}, | ||||
| 		{`a/b.com`, "acme/autocert: server name contains invalid character"}, | ||||
| 		{"", "acme/autocert: missing server name"}, | ||||
| 		{"foo", "acme/autocert: server name component count invalid"}, | ||||
| 		{".foo", "acme/autocert: server name component count invalid"}, | ||||
| 		{"foo.", "acme/autocert: server name component count invalid"}, | ||||
| 		{"fo.o", "cache.Get of fo.o"}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		_, err := m.GetCertificate(&tls.ClientHelloInfo{ServerName: tt.name}) | ||||
| 		got := fmt.Sprint(err) | ||||
| 		if got != tt.wantErr { | ||||
| 			t.Errorf("GetCertificate(SNI = %q) = %q; want %q", tt.name, got, tt.wantErr) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										130
									
								
								vendor/golang.org/x/crypto/acme/autocert/cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								vendor/golang.org/x/crypto/acme/autocert/cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| // Copyright 2016 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 autocert | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| ) | ||||
|  | ||||
| // ErrCacheMiss is returned when a certificate is not found in cache. | ||||
| var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss") | ||||
|  | ||||
| // Cache is used by Manager to store and retrieve previously obtained certificates | ||||
| // as opaque data. | ||||
| // | ||||
| // 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. | ||||
| type Cache interface { | ||||
| 	// Get returns a certificate data for the specified key. | ||||
| 	// If there's no such key, Get returns ErrCacheMiss. | ||||
| 	Get(ctx context.Context, key string) ([]byte, error) | ||||
|  | ||||
| 	// Put stores the data in the cache under the specified key. | ||||
| 	// Underlying implementations may use any data storage format, | ||||
| 	// as long as the reverse operation, Get, results in the original data. | ||||
| 	Put(ctx context.Context, key string, data []byte) error | ||||
|  | ||||
| 	// Delete removes a certificate data from the cache under the specified key. | ||||
| 	// If there's no such key in the cache, Delete returns nil. | ||||
| 	Delete(ctx context.Context, key string) error | ||||
| } | ||||
|  | ||||
| // DirCache implements Cache using a directory on the local filesystem. | ||||
| // If the directory does not exist, it will be created with 0700 permissions. | ||||
| type DirCache string | ||||
|  | ||||
| // Get reads a certificate data from the specified file name. | ||||
| func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) { | ||||
| 	name = filepath.Join(string(d), name) | ||||
| 	var ( | ||||
| 		data []byte | ||||
| 		err  error | ||||
| 		done = make(chan struct{}) | ||||
| 	) | ||||
| 	go func() { | ||||
| 		data, err = ioutil.ReadFile(name) | ||||
| 		close(done) | ||||
| 	}() | ||||
| 	select { | ||||
| 	case <-ctx.Done(): | ||||
| 		return nil, ctx.Err() | ||||
| 	case <-done: | ||||
| 	} | ||||
| 	if os.IsNotExist(err) { | ||||
| 		return nil, ErrCacheMiss | ||||
| 	} | ||||
| 	return data, err | ||||
| } | ||||
|  | ||||
| // Put writes the certificate data to the specified file name. | ||||
| // The file will be created with 0600 permissions. | ||||
| func (d DirCache) Put(ctx context.Context, name string, data []byte) error { | ||||
| 	if err := os.MkdirAll(string(d), 0700); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	done := make(chan struct{}) | ||||
| 	var err error | ||||
| 	go func() { | ||||
| 		defer close(done) | ||||
| 		var tmp string | ||||
| 		if tmp, err = d.writeTempFile(name, data); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		select { | ||||
| 		case <-ctx.Done(): | ||||
| 			// Don't overwrite the file if the context was canceled. | ||||
| 		default: | ||||
| 			newName := filepath.Join(string(d), name) | ||||
| 			err = os.Rename(tmp, newName) | ||||
| 		} | ||||
| 	}() | ||||
| 	select { | ||||
| 	case <-ctx.Done(): | ||||
| 		return ctx.Err() | ||||
| 	case <-done: | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Delete removes the specified file name. | ||||
| func (d DirCache) Delete(ctx context.Context, name string) error { | ||||
| 	name = filepath.Join(string(d), name) | ||||
| 	var ( | ||||
| 		err  error | ||||
| 		done = make(chan struct{}) | ||||
| 	) | ||||
| 	go func() { | ||||
| 		err = os.Remove(name) | ||||
| 		close(done) | ||||
| 	}() | ||||
| 	select { | ||||
| 	case <-ctx.Done(): | ||||
| 		return ctx.Err() | ||||
| 	case <-done: | ||||
| 	} | ||||
| 	if err != nil && !os.IsNotExist(err) { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // writeTempFile writes b to a temporary file, closes the file and returns its path. | ||||
| func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) { | ||||
| 	// TempFile uses 0600 permissions | ||||
| 	f, err := ioutil.TempFile(string(d), prefix) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	if _, err := f.Write(b); err != nil { | ||||
| 		f.Close() | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return f.Name(), f.Close() | ||||
| } | ||||
							
								
								
									
										58
									
								
								vendor/golang.org/x/crypto/acme/autocert/cache_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								vendor/golang.org/x/crypto/acme/autocert/cache_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| // Copyright 2016 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 autocert | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| // make sure DirCache satisfies Cache interface | ||||
| var _ Cache = DirCache("/") | ||||
|  | ||||
| func TestDirCache(t *testing.T) { | ||||
| 	dir, err := ioutil.TempDir("", "autocert") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer os.RemoveAll(dir) | ||||
| 	dir = filepath.Join(dir, "certs") // a nonexistent dir | ||||
| 	cache := DirCache(dir) | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	// test cache miss | ||||
| 	if _, err := cache.Get(ctx, "nonexistent"); err != ErrCacheMiss { | ||||
| 		t.Errorf("get: %v; want ErrCacheMiss", err) | ||||
| 	} | ||||
|  | ||||
| 	// test put/get | ||||
| 	b1 := []byte{1} | ||||
| 	if err := cache.Put(ctx, "dummy", b1); err != nil { | ||||
| 		t.Fatalf("put: %v", err) | ||||
| 	} | ||||
| 	b2, err := cache.Get(ctx, "dummy") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("get: %v", err) | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(b1, b2) { | ||||
| 		t.Errorf("b1 = %v; want %v", b1, b2) | ||||
| 	} | ||||
| 	name := filepath.Join(dir, "dummy") | ||||
| 	if _, err := os.Stat(name); err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
|  | ||||
| 	// test delete | ||||
| 	if err := cache.Delete(ctx, "dummy"); err != nil { | ||||
| 		t.Fatalf("delete: %v", err) | ||||
| 	} | ||||
| 	if _, err := cache.Get(ctx, "dummy"); err != ErrCacheMiss { | ||||
| 		t.Errorf("get: %v; want ErrCacheMiss", err) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										36
									
								
								vendor/golang.org/x/crypto/acme/autocert/example_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								vendor/golang.org/x/crypto/acme/autocert/example_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| // Copyright 2017 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 autocert_test | ||||
|  | ||||
| import ( | ||||
| 	"crypto/tls" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"golang.org/x/crypto/acme/autocert" | ||||
| ) | ||||
|  | ||||
| func ExampleNewListener() { | ||||
| 	mux := http.NewServeMux() | ||||
| 	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		fmt.Fprintf(w, "Hello, TLS user! Your config: %+v", r.TLS) | ||||
| 	}) | ||||
| 	log.Fatal(http.Serve(autocert.NewListener("example.com"), mux)) | ||||
| } | ||||
|  | ||||
| func ExampleManager() { | ||||
| 	m := &autocert.Manager{ | ||||
| 		Cache:      autocert.DirCache("secret-dir"), | ||||
| 		Prompt:     autocert.AcceptTOS, | ||||
| 		HostPolicy: autocert.HostWhitelist("example.org"), | ||||
| 	} | ||||
| 	go http.ListenAndServe(":http", m.HTTPHandler(nil)) | ||||
| 	s := &http.Server{ | ||||
| 		Addr:      ":https", | ||||
| 		TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, | ||||
| 	} | ||||
| 	s.ListenAndServeTLS("", "") | ||||
| } | ||||
							
								
								
									
										160
									
								
								vendor/golang.org/x/crypto/acme/autocert/listener.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								vendor/golang.org/x/crypto/acme/autocert/listener.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| // Copyright 2017 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 autocert | ||||
|  | ||||
| import ( | ||||
| 	"crypto/tls" | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // NewListener returns a net.Listener that listens on the standard TLS | ||||
| // port (443) on all interfaces and returns *tls.Conn connections with | ||||
| // LetsEncrypt certificates for the provided domain or domains. | ||||
| // | ||||
| // It enables one-line HTTPS servers: | ||||
| // | ||||
| //     log.Fatal(http.Serve(autocert.NewListener("example.com"), handler)) | ||||
| // | ||||
| // NewListener is a convenience function for a common configuration. | ||||
| // More complex or custom configurations can use the autocert.Manager | ||||
| // type instead. | ||||
| // | ||||
| // Use of this function implies acceptance of the LetsEncrypt Terms of | ||||
| // Service. If domains is not empty, the provided domains are passed | ||||
| // to HostWhitelist. If domains is empty, the listener will do | ||||
| // LetsEncrypt challenges for any requested domain, which is not | ||||
| // recommended. | ||||
| // | ||||
| // Certificates are cached in a "golang-autocert" directory under an | ||||
| // operating system-specific cache or temp directory. This may not | ||||
| // be suitable for servers spanning multiple machines. | ||||
| // | ||||
| // The returned listener uses a *tls.Config that enables HTTP/2, and | ||||
| // should only be used with servers that support HTTP/2. | ||||
| // | ||||
| // The returned Listener also enables TCP keep-alives on the accepted | ||||
| // connections. The returned *tls.Conn are returned before their TLS | ||||
| // handshake has completed. | ||||
| func NewListener(domains ...string) net.Listener { | ||||
| 	m := &Manager{ | ||||
| 		Prompt: AcceptTOS, | ||||
| 	} | ||||
| 	if len(domains) > 0 { | ||||
| 		m.HostPolicy = HostWhitelist(domains...) | ||||
| 	} | ||||
| 	dir := cacheDir() | ||||
| 	if err := os.MkdirAll(dir, 0700); err != nil { | ||||
| 		log.Printf("warning: autocert.NewListener not using a cache: %v", err) | ||||
| 	} else { | ||||
| 		m.Cache = DirCache(dir) | ||||
| 	} | ||||
| 	return m.Listener() | ||||
| } | ||||
|  | ||||
| // Listener listens on the standard TLS port (443) on all interfaces | ||||
| // and returns a net.Listener returning *tls.Conn connections. | ||||
| // | ||||
| // The returned listener uses a *tls.Config that enables HTTP/2, and | ||||
| // should only be used with servers that support HTTP/2. | ||||
| // | ||||
| // The returned Listener also enables TCP keep-alives on the accepted | ||||
| // connections. The returned *tls.Conn are returned before their TLS | ||||
| // handshake has completed. | ||||
| // | ||||
| // Unlike NewListener, it is the caller's responsibility to initialize | ||||
| // 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 | ||||
| 		}, | ||||
| 	} | ||||
| 	ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443") | ||||
| 	return ln | ||||
| } | ||||
|  | ||||
| type listener struct { | ||||
| 	m    *Manager | ||||
| 	conf *tls.Config | ||||
|  | ||||
| 	tcpListener  net.Listener | ||||
| 	tcpListenErr error | ||||
| } | ||||
|  | ||||
| func (ln *listener) Accept() (net.Conn, error) { | ||||
| 	if ln.tcpListenErr != nil { | ||||
| 		return nil, ln.tcpListenErr | ||||
| 	} | ||||
| 	conn, err := ln.tcpListener.Accept() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	tcpConn := conn.(*net.TCPConn) | ||||
|  | ||||
| 	// Because Listener is a convenience function, help out with | ||||
| 	// this too.  This is not possible for the caller to set once | ||||
| 	// we return a *tcp.Conn wrapping an inaccessible net.Conn. | ||||
| 	// If callers don't want this, they can do things the manual | ||||
| 	// way and tweak as needed. But this is what net/http does | ||||
| 	// itself, so copy that. If net/http changes, we can change | ||||
| 	// here too. | ||||
| 	tcpConn.SetKeepAlive(true) | ||||
| 	tcpConn.SetKeepAlivePeriod(3 * time.Minute) | ||||
|  | ||||
| 	return tls.Server(tcpConn, ln.conf), nil | ||||
| } | ||||
|  | ||||
| func (ln *listener) Addr() net.Addr { | ||||
| 	if ln.tcpListener != nil { | ||||
| 		return ln.tcpListener.Addr() | ||||
| 	} | ||||
| 	// net.Listen failed. Return something non-nil in case callers | ||||
| 	// call Addr before Accept: | ||||
| 	return &net.TCPAddr{IP: net.IP{0, 0, 0, 0}, Port: 443} | ||||
| } | ||||
|  | ||||
| func (ln *listener) Close() error { | ||||
| 	if ln.tcpListenErr != nil { | ||||
| 		return ln.tcpListenErr | ||||
| 	} | ||||
| 	return ln.tcpListener.Close() | ||||
| } | ||||
|  | ||||
| func homeDir() string { | ||||
| 	if runtime.GOOS == "windows" { | ||||
| 		return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") | ||||
| 	} | ||||
| 	if h := os.Getenv("HOME"); h != "" { | ||||
| 		return h | ||||
| 	} | ||||
| 	return "/" | ||||
| } | ||||
|  | ||||
| func cacheDir() string { | ||||
| 	const base = "golang-autocert" | ||||
| 	switch runtime.GOOS { | ||||
| 	case "darwin": | ||||
| 		return filepath.Join(homeDir(), "Library", "Caches", base) | ||||
| 	case "windows": | ||||
| 		for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} { | ||||
| 			if v := os.Getenv(ev); v != "" { | ||||
| 				return filepath.Join(v, base) | ||||
| 			} | ||||
| 		} | ||||
| 		// Worst case: | ||||
| 		return filepath.Join(homeDir(), base) | ||||
| 	} | ||||
| 	if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" { | ||||
| 		return filepath.Join(xdg, base) | ||||
| 	} | ||||
| 	return filepath.Join(homeDir(), ".cache", base) | ||||
| } | ||||
							
								
								
									
										124
									
								
								vendor/golang.org/x/crypto/acme/autocert/renewal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								vendor/golang.org/x/crypto/acme/autocert/renewal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| // Copyright 2016 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 autocert | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // renewJitter is the maximum deviation from Manager.RenewBefore. | ||||
| 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 | ||||
|  | ||||
| 	timerMu sync.Mutex | ||||
| 	timer   *time.Timer | ||||
| } | ||||
|  | ||||
| // start starts a cert renewal timer at the time | ||||
| // defined by the certificate expiration time exp. | ||||
| // | ||||
| // If the timer is already started, calling start is a noop. | ||||
| func (dr *domainRenewal) start(exp time.Time) { | ||||
| 	dr.timerMu.Lock() | ||||
| 	defer dr.timerMu.Unlock() | ||||
| 	if dr.timer != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	dr.timer = time.AfterFunc(dr.next(exp), dr.renew) | ||||
| } | ||||
|  | ||||
| // stop stops the cert renewal timer. | ||||
| // If the timer is already stopped, calling stop is a noop. | ||||
| func (dr *domainRenewal) stop() { | ||||
| 	dr.timerMu.Lock() | ||||
| 	defer dr.timerMu.Unlock() | ||||
| 	if dr.timer == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	dr.timer.Stop() | ||||
| 	dr.timer = nil | ||||
| } | ||||
|  | ||||
| // renew is called periodically by a timer. | ||||
| // The first renew call is kicked off by dr.start. | ||||
| func (dr *domainRenewal) renew() { | ||||
| 	dr.timerMu.Lock() | ||||
| 	defer dr.timerMu.Unlock() | ||||
| 	if dr.timer == nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) | ||||
| 	defer cancel() | ||||
| 	// TODO: rotate dr.key at some point? | ||||
| 	next, err := dr.do(ctx) | ||||
| 	if err != nil { | ||||
| 		next = renewJitter / 2 | ||||
| 		next += time.Duration(pseudoRand.int63n(int64(next))) | ||||
| 	} | ||||
| 	dr.timer = time.AfterFunc(next, dr.renew) | ||||
| 	testDidRenewLoop(next, err) | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| // | ||||
| // 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 { | ||||
| 		next := dr.next(tlscert.Leaf.NotAfter) | ||||
| 		if next > dr.m.renewBefore()+renewJitter { | ||||
| 			return next, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.domain) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	state := &certState{ | ||||
| 		key:  dr.key, | ||||
| 		cert: der, | ||||
| 		leaf: leaf, | ||||
| 	} | ||||
| 	tlscert, err := state.tlscert() | ||||
| 	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 | ||||
| 	return dr.next(leaf.NotAfter), nil | ||||
| } | ||||
|  | ||||
| func (dr *domainRenewal) next(expiry time.Time) time.Duration { | ||||
| 	d := expiry.Sub(timeNow()) - dr.m.renewBefore() | ||||
| 	// add a bit of randomness to renew deadline | ||||
| 	n := pseudoRand.int63n(int64(renewJitter)) | ||||
| 	d -= time.Duration(n) | ||||
| 	if d < 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| var testDidRenewLoop = func(next time.Duration, err error) {} | ||||
							
								
								
									
										191
									
								
								vendor/golang.org/x/crypto/acme/autocert/renewal_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								vendor/golang.org/x/crypto/acme/autocert/renewal_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | ||||
| // Copyright 2016 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 autocert | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/tls" | ||||
| 	"crypto/x509" | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/http/httptest" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"golang.org/x/crypto/acme" | ||||
| ) | ||||
|  | ||||
| func TestRenewalNext(t *testing.T) { | ||||
| 	now := time.Now() | ||||
| 	timeNow = func() time.Time { return now } | ||||
| 	defer func() { timeNow = time.Now }() | ||||
|  | ||||
| 	man := &Manager{RenewBefore: 7 * 24 * time.Hour} | ||||
| 	defer man.stopRenew() | ||||
| 	tt := []struct { | ||||
| 		expiry   time.Time | ||||
| 		min, max time.Duration | ||||
| 	}{ | ||||
| 		{now.Add(90 * 24 * time.Hour), 83*24*time.Hour - renewJitter, 83 * 24 * time.Hour}, | ||||
| 		{now.Add(time.Hour), 0, 1}, | ||||
| 		{now, 0, 1}, | ||||
| 		{now.Add(-time.Hour), 0, 1}, | ||||
| 	} | ||||
|  | ||||
| 	dr := &domainRenewal{m: man} | ||||
| 	for i, test := range tt { | ||||
| 		next := dr.next(test.expiry) | ||||
| 		if next < test.min || test.max < next { | ||||
| 			t.Errorf("%d: next = %v; want between %v and %v", i, next, test.min, test.max) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestRenewFromCache(t *testing.T) { | ||||
| 	const domain = "example.org" | ||||
|  | ||||
| 	// ACME CA server stub | ||||
| 	var ca *httptest.Server | ||||
| 	ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		w.Header().Set("Replay-Nonce", "nonce") | ||||
| 		if r.Method == "HEAD" { | ||||
| 			// a nonce request | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		switch r.URL.Path { | ||||
| 		// discovery | ||||
| 		case "/": | ||||
| 			if err := discoTmpl.Execute(w, ca.URL); err != nil { | ||||
| 				t.Fatalf("discoTmpl: %v", err) | ||||
| 			} | ||||
| 		// client key registration | ||||
| 		case "/new-reg": | ||||
| 			w.Write([]byte("{}")) | ||||
| 		// domain authorization | ||||
| 		case "/new-authz": | ||||
| 			w.Header().Set("Location", ca.URL+"/authz/1") | ||||
| 			w.WriteHeader(http.StatusCreated) | ||||
| 			w.Write([]byte(`{"status": "valid"}`)) | ||||
| 		// cert request | ||||
| 		case "/new-cert": | ||||
| 			var req struct { | ||||
| 				CSR string `json:"csr"` | ||||
| 			} | ||||
| 			decodePayload(&req, r.Body) | ||||
| 			b, _ := base64.RawURLEncoding.DecodeString(req.CSR) | ||||
| 			csr, err := x509.ParseCertificateRequest(b) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("new-cert: CSR: %v", err) | ||||
| 			} | ||||
| 			der, err := dummyCert(csr.PublicKey, domain) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("new-cert: dummyCert: %v", err) | ||||
| 			} | ||||
| 			chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL) | ||||
| 			w.Header().Set("Link", chainUp) | ||||
| 			w.WriteHeader(http.StatusCreated) | ||||
| 			w.Write(der) | ||||
| 		// CA chain cert | ||||
| 		case "/ca-cert": | ||||
| 			der, err := dummyCert(nil, "ca") | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("ca-cert: dummyCert: %v", err) | ||||
| 			} | ||||
| 			w.Write(der) | ||||
| 		default: | ||||
| 			t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path) | ||||
| 		} | ||||
| 	})) | ||||
| 	defer ca.Close() | ||||
|  | ||||
| 	// use EC key to run faster on 386 | ||||
| 	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	man := &Manager{ | ||||
| 		Prompt:      AcceptTOS, | ||||
| 		Cache:       newMemCache(), | ||||
| 		RenewBefore: 24 * time.Hour, | ||||
| 		Client: &acme.Client{ | ||||
| 			Key:          key, | ||||
| 			DirectoryURL: ca.URL, | ||||
| 		}, | ||||
| 	} | ||||
| 	defer man.stopRenew() | ||||
|  | ||||
| 	// cache an almost expired cert | ||||
| 	now := time.Now() | ||||
| 	cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}} | ||||
| 	if err := man.cachePut(context.Background(), domain, tlscert); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// veriy the renewal happened | ||||
| 	defer func() { | ||||
| 		testDidRenewLoop = func(next time.Duration, err error) {} | ||||
| 	}() | ||||
| 	done := make(chan struct{}) | ||||
| 	testDidRenewLoop = func(next time.Duration, err error) { | ||||
| 		defer close(done) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("testDidRenewLoop: %v", err) | ||||
| 		} | ||||
| 		// Next should be about 90 days: | ||||
| 		// dummyCert creates 90days expiry + account for man.RenewBefore. | ||||
| 		// Previous expiration was within 1 min. | ||||
| 		future := 88 * 24 * time.Hour | ||||
| 		if next < future { | ||||
| 			t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future) | ||||
| 		} | ||||
|  | ||||
| 		// ensure the new cert is cached | ||||
| 		after := time.Now().Add(future) | ||||
| 		tlscert, err := man.cacheGet(context.Background(), domain) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("man.cacheGet: %v", err) | ||||
| 		} | ||||
| 		if !tlscert.Leaf.NotAfter.After(after) { | ||||
| 			t.Errorf("cache leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after) | ||||
| 		} | ||||
|  | ||||
| 		// verify the old cert is also replaced in memory | ||||
| 		man.stateMu.Lock() | ||||
| 		defer man.stateMu.Unlock() | ||||
| 		s := man.state[domain] | ||||
| 		if s == nil { | ||||
| 			t.Fatalf("m.state[%q] is nil", domain) | ||||
| 		} | ||||
| 		tlscert, err = s.tlscert() | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("s.tlscert: %v", err) | ||||
| 		} | ||||
| 		if !tlscert.Leaf.NotAfter.After(after) { | ||||
| 			t.Errorf("state leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// trigger renew | ||||
| 	hello := &tls.ClientHelloInfo{ServerName: domain} | ||||
| 	if _, err := man.GetCertificate(hello); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// wait for renew loop | ||||
| 	select { | ||||
| 	case <-time.After(10 * time.Second): | ||||
| 		t.Fatal("renew took too long to occur") | ||||
| 	case <-done: | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										153
									
								
								vendor/golang.org/x/crypto/acme/jws.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								vendor/golang.org/x/crypto/acme/jws.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | ||||
| // Copyright 2015 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 ( | ||||
| 	"crypto" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/sha256" | ||||
| 	_ "crypto/sha512" // need for EC keys | ||||
| 	"encoding/base64" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"math/big" | ||||
| ) | ||||
|  | ||||
| // jwsEncodeJSON signs claimset using provided key and a nonce. | ||||
| // The result is serialized in JSON format. | ||||
| // See https://tools.ietf.org/html/rfc7515#section-7. | ||||
| func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) { | ||||
| 	jwk, err := jwkEncode(key.Public()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	alg, sha := jwsHasher(key) | ||||
| 	if alg == "" || !sha.Available() { | ||||
| 		return nil, ErrUnsupportedKey | ||||
| 	} | ||||
| 	phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce) | ||||
| 	phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) | ||||
| 	cs, err := json.Marshal(claimset) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	payload := base64.RawURLEncoding.EncodeToString(cs) | ||||
| 	hash := sha.New() | ||||
| 	hash.Write([]byte(phead + "." + payload)) | ||||
| 	sig, err := jwsSign(key, sha, hash.Sum(nil)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	enc := struct { | ||||
| 		Protected string `json:"protected"` | ||||
| 		Payload   string `json:"payload"` | ||||
| 		Sig       string `json:"signature"` | ||||
| 	}{ | ||||
| 		Protected: phead, | ||||
| 		Payload:   payload, | ||||
| 		Sig:       base64.RawURLEncoding.EncodeToString(sig), | ||||
| 	} | ||||
| 	return json.Marshal(&enc) | ||||
| } | ||||
|  | ||||
| // jwkEncode encodes public part of an RSA or ECDSA key into a JWK. | ||||
| // The result is also suitable for creating a JWK thumbprint. | ||||
| // https://tools.ietf.org/html/rfc7517 | ||||
| func jwkEncode(pub crypto.PublicKey) (string, error) { | ||||
| 	switch pub := pub.(type) { | ||||
| 	case *rsa.PublicKey: | ||||
| 		// https://tools.ietf.org/html/rfc7518#section-6.3.1 | ||||
| 		n := pub.N | ||||
| 		e := big.NewInt(int64(pub.E)) | ||||
| 		// Field order is important. | ||||
| 		// See https://tools.ietf.org/html/rfc7638#section-3.3 for details. | ||||
| 		return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`, | ||||
| 			base64.RawURLEncoding.EncodeToString(e.Bytes()), | ||||
| 			base64.RawURLEncoding.EncodeToString(n.Bytes()), | ||||
| 		), nil | ||||
| 	case *ecdsa.PublicKey: | ||||
| 		// https://tools.ietf.org/html/rfc7518#section-6.2.1 | ||||
| 		p := pub.Curve.Params() | ||||
| 		n := p.BitSize / 8 | ||||
| 		if p.BitSize%8 != 0 { | ||||
| 			n++ | ||||
| 		} | ||||
| 		x := pub.X.Bytes() | ||||
| 		if n > len(x) { | ||||
| 			x = append(make([]byte, n-len(x)), x...) | ||||
| 		} | ||||
| 		y := pub.Y.Bytes() | ||||
| 		if n > len(y) { | ||||
| 			y = append(make([]byte, n-len(y)), y...) | ||||
| 		} | ||||
| 		// Field order is important. | ||||
| 		// See https://tools.ietf.org/html/rfc7638#section-3.3 for details. | ||||
| 		return fmt.Sprintf(`{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`, | ||||
| 			p.Name, | ||||
| 			base64.RawURLEncoding.EncodeToString(x), | ||||
| 			base64.RawURLEncoding.EncodeToString(y), | ||||
| 		), nil | ||||
| 	} | ||||
| 	return "", ErrUnsupportedKey | ||||
| } | ||||
|  | ||||
| // jwsSign signs the digest using the given key. | ||||
| // It returns ErrUnsupportedKey if the key type is unknown. | ||||
| // The hash is used only for RSA keys. | ||||
| func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { | ||||
| 	switch key := key.(type) { | ||||
| 	case *rsa.PrivateKey: | ||||
| 		return key.Sign(rand.Reader, digest, hash) | ||||
| 	case *ecdsa.PrivateKey: | ||||
| 		r, s, err := ecdsa.Sign(rand.Reader, key, digest) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		rb, sb := r.Bytes(), s.Bytes() | ||||
| 		size := key.Params().BitSize / 8 | ||||
| 		if size%8 > 0 { | ||||
| 			size++ | ||||
| 		} | ||||
| 		sig := make([]byte, size*2) | ||||
| 		copy(sig[size-len(rb):], rb) | ||||
| 		copy(sig[size*2-len(sb):], sb) | ||||
| 		return sig, nil | ||||
| 	} | ||||
| 	return nil, ErrUnsupportedKey | ||||
| } | ||||
|  | ||||
| // jwsHasher indicates suitable JWS algorithm name and a hash function | ||||
| // to use for signing a digest with the provided key. | ||||
| // It returns ("", 0) if the key is not supported. | ||||
| func jwsHasher(key crypto.Signer) (string, crypto.Hash) { | ||||
| 	switch key := key.(type) { | ||||
| 	case *rsa.PrivateKey: | ||||
| 		return "RS256", crypto.SHA256 | ||||
| 	case *ecdsa.PrivateKey: | ||||
| 		switch key.Params().Name { | ||||
| 		case "P-256": | ||||
| 			return "ES256", crypto.SHA256 | ||||
| 		case "P-384": | ||||
| 			return "ES384", crypto.SHA384 | ||||
| 		case "P-521": | ||||
| 			return "ES512", crypto.SHA512 | ||||
| 		} | ||||
| 	} | ||||
| 	return "", 0 | ||||
| } | ||||
|  | ||||
| // JWKThumbprint creates a JWK thumbprint out of pub | ||||
| // as specified in https://tools.ietf.org/html/rfc7638. | ||||
| func JWKThumbprint(pub crypto.PublicKey) (string, error) { | ||||
| 	jwk, err := jwkEncode(pub) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	b := sha256.Sum256([]byte(jwk)) | ||||
| 	return base64.RawURLEncoding.EncodeToString(b[:]), nil | ||||
| } | ||||
							
								
								
									
										319
									
								
								vendor/golang.org/x/crypto/acme/jws_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										319
									
								
								vendor/golang.org/x/crypto/acme/jws_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,319 @@ | ||||
| // Copyright 2015 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 ( | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/x509" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/json" | ||||
| 	"encoding/pem" | ||||
| 	"fmt" | ||||
| 	"math/big" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	testKeyPEM = ` | ||||
| -----BEGIN RSA PRIVATE KEY----- | ||||
| MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq | ||||
| WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30 | ||||
| Ab7+zawrfRaFONa1HwEzPY1KHnGVkxJc85gNkwYI9SY2RHXtvln3zs5wITNrdosq | ||||
| EXeaIkVYBEhbhNu54pp3kxo6TuWLi9e6pXeWetEwmlBwtWZlPoib2j3TxLBksKZf | ||||
| oyFyek380mHgJAumQ/I2fjj98/97mk3ihOY4AgVdCDj1z/GCoZkG5Rq7nbCGyosy | ||||
| KWyDX00Zs+nNqVhoLeIvXC4nnWdJMZ6rogxyQQIDAQABAoIBACIEZTOI1Kao9nmV | ||||
| 9IeIsuaR1Y61b9neOF/MLmIVIZu+AAJFCMB4Iw11FV6sFodwpEyeZhx2WkpWVN+H | ||||
| r19eGiLX3zsL0DOdqBJoSIHDWCCMxgnYJ6nvS0nRxX3qVrBp8R2g12Ub+gNPbmFm | ||||
| ecf/eeERIVxfifd9VsyRu34eDEvcmKFuLYbElFcPh62xE3x12UZvV/sN7gXbawpP | ||||
| G+w255vbE5MoaKdnnO83cTFlcHvhn24M/78qP7Te5OAeelr1R89kYxQLpuGe4fbS | ||||
| zc6E3ym5Td6urDetGGrSY1Eu10/8sMusX+KNWkm+RsBRbkyKq72ks/qKpOxOa+c6 | ||||
| 9gm+Y8ECgYEA/iNUyg1ubRdH11p82l8KHtFC1DPE0V1gSZsX29TpM5jS4qv46K+s | ||||
| 8Ym1zmrORM8x+cynfPx1VQZQ34EYeCMIX212ryJ+zDATl4NE0I4muMvSiH9vx6Xc | ||||
| 7FmhNnaYzPsBL5Tm9nmtQuP09YEn8poiOJFiDs/4olnD5ogA5O4THGkCgYEA5MIL | ||||
| qWYBUuqbEWLRtMruUtpASclrBqNNsJEsMGbeqBJmoMxdHeSZckbLOrqm7GlMyNRJ | ||||
| Ne/5uWRGSzaMYuGmwsPpERzqEvYFnSrpjW5YtXZ+JtxFXNVfm9Z1gLLgvGpOUCIU | ||||
| RbpoDckDe1vgUuk3y5+DjZihs+rqIJ45XzXTzBkCgYBWuf3segruJZy5rEKhTv+o | ||||
| JqeUvRn0jNYYKFpLBeyTVBrbie6GkbUGNIWbrK05pC+c3K9nosvzuRUOQQL1tJbd | ||||
| 4gA3oiD9U4bMFNr+BRTHyZ7OQBcIXdz3t1qhuHVKtnngIAN1p25uPlbRFUNpshnt | ||||
| jgeVoHlsBhApcs5DUc+pyQKBgDzeHPg/+g4z+nrPznjKnktRY1W+0El93kgi+J0Q | ||||
| YiJacxBKEGTJ1MKBb8X6sDurcRDm22wMpGfd9I5Cv2v4GsUsF7HD/cx5xdih+G73 | ||||
| c4clNj/k0Ff5Nm1izPUno4C+0IOl7br39IPmfpSuR6wH/h6iHQDqIeybjxyKvT1G | ||||
| N0rRAoGBAKGD+4ZI/E1MoJ5CXB8cDDMHagbE3cq/DtmYzE2v1DFpQYu5I4PCm5c7 | ||||
| EQeIP6dZtv8IMgtGIb91QX9pXvP0aznzQKwYIA8nZgoENCPfiMTPiEDT9e/0lObO | ||||
| 9XWsXpbSTsRPj0sv1rB+UzBJ0PgjK4q2zOF0sNo7b1+6nlM3BWPx | ||||
| -----END RSA PRIVATE KEY----- | ||||
| ` | ||||
|  | ||||
| 	// This thumbprint is for the testKey defined above. | ||||
| 	testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ" | ||||
|  | ||||
| 	// openssl ecparam -name secp256k1 -genkey -noout | ||||
| 	testKeyECPEM = ` | ||||
| -----BEGIN EC PRIVATE KEY----- | ||||
| MHcCAQEEIK07hGLr0RwyUdYJ8wbIiBS55CjnkMD23DWr+ccnypWLoAoGCCqGSM49 | ||||
| AwEHoUQDQgAE5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HThqIrvawF5 | ||||
| QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ== | ||||
| -----END EC PRIVATE KEY----- | ||||
| ` | ||||
| 	// openssl ecparam -name secp384r1 -genkey -noout | ||||
| 	testKeyEC384PEM = ` | ||||
| -----BEGIN EC PRIVATE KEY----- | ||||
| MIGkAgEBBDAQ4lNtXRORWr1bgKR1CGysr9AJ9SyEk4jiVnlUWWUChmSNL+i9SLSD | ||||
| Oe/naPqXJ6CgBwYFK4EEACKhZANiAAQzKtj+Ms0vHoTX5dzv3/L5YMXOWuI5UKRj | ||||
| JigpahYCqXD2BA1j0E/2xt5vlPf+gm0PL+UHSQsCokGnIGuaHCsJAp3ry0gHQEke | ||||
| WYXapUUFdvaK1R2/2hn5O+eiQM8YzCg= | ||||
| -----END EC PRIVATE KEY----- | ||||
| ` | ||||
| 	// openssl ecparam -name secp521r1 -genkey -noout | ||||
| 	testKeyEC512PEM = ` | ||||
| -----BEGIN EC PRIVATE KEY----- | ||||
| MIHcAgEBBEIBSNZKFcWzXzB/aJClAb305ibalKgtDA7+70eEkdPt28/3LZMM935Z | ||||
| KqYHh/COcxuu3Kt8azRAUz3gyr4zZKhlKUSgBwYFK4EEACOhgYkDgYYABAHUNKbx | ||||
| 7JwC7H6pa2sV0tERWhHhB3JmW+OP6SUgMWryvIKajlx73eS24dy4QPGrWO9/ABsD | ||||
| FqcRSkNVTXnIv6+0mAF25knqIBIg5Q8M9BnOu9GGAchcwt3O7RDHmqewnJJDrbjd | ||||
| GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ== | ||||
| -----END EC PRIVATE KEY----- | ||||
| ` | ||||
| 	// 1. openssl ec -in key.pem -noout -text | ||||
| 	// 2. remove first byte, 04 (the header); the rest is X and Y | ||||
| 	// 3. convert each with: echo <val> | xxd -r -p | base64 -w 100 | tr -d '=' | tr '/+' '_-' | ||||
| 	testKeyECPubX    = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ" | ||||
| 	testKeyECPubY    = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk" | ||||
| 	testKeyEC384PubX = "MyrY_jLNLx6E1-Xc79_y-WDFzlriOVCkYyYoKWoWAqlw9gQNY9BP9sbeb5T3_oJt" | ||||
| 	testKeyEC384PubY = "Dy_lB0kLAqJBpyBrmhwrCQKd68tIB0BJHlmF2qVFBXb2itUdv9oZ-TvnokDPGMwo" | ||||
| 	testKeyEC512PubX = "AdQ0pvHsnALsfqlraxXS0RFaEeEHcmZb44_pJSAxavK8gpqOXHvd5Lbh3LhA8atY738AGwMWpxFKQ1VNeci_r7SY" | ||||
| 	testKeyEC512PubY = "AXbmSeogEiDlDwz0Gc670YYByFzC3c7tEMeap7CckkOtuN0Yaebqtv42dZH0MiikzSco2ROhagX-HOinG7gB78ax" | ||||
|  | ||||
| 	// echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \ | ||||
| 	// openssl dgst -binary -sha256 | base64 | tr -d '=' | tr '/+' '_-' | ||||
| 	testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	testKey      *rsa.PrivateKey | ||||
| 	testKeyEC    *ecdsa.PrivateKey | ||||
| 	testKeyEC384 *ecdsa.PrivateKey | ||||
| 	testKeyEC512 *ecdsa.PrivateKey | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	testKey = parseRSA(testKeyPEM, "testKeyPEM") | ||||
| 	testKeyEC = parseEC(testKeyECPEM, "testKeyECPEM") | ||||
| 	testKeyEC384 = parseEC(testKeyEC384PEM, "testKeyEC384PEM") | ||||
| 	testKeyEC512 = parseEC(testKeyEC512PEM, "testKeyEC512PEM") | ||||
| } | ||||
|  | ||||
| func decodePEM(s, name string) []byte { | ||||
| 	d, _ := pem.Decode([]byte(s)) | ||||
| 	if d == nil { | ||||
| 		panic("no block found in " + name) | ||||
| 	} | ||||
| 	return d.Bytes | ||||
| } | ||||
|  | ||||
| func parseRSA(s, name string) *rsa.PrivateKey { | ||||
| 	b := decodePEM(s, name) | ||||
| 	k, err := x509.ParsePKCS1PrivateKey(b) | ||||
| 	if err != nil { | ||||
| 		panic(fmt.Sprintf("%s: %v", name, err)) | ||||
| 	} | ||||
| 	return k | ||||
| } | ||||
|  | ||||
| func parseEC(s, name string) *ecdsa.PrivateKey { | ||||
| 	b := decodePEM(s, name) | ||||
| 	k, err := x509.ParseECPrivateKey(b) | ||||
| 	if err != nil { | ||||
| 		panic(fmt.Sprintf("%s: %v", name, err)) | ||||
| 	} | ||||
| 	return k | ||||
| } | ||||
|  | ||||
| func TestJWSEncodeJSON(t *testing.T) { | ||||
| 	claims := struct{ Msg string }{"Hello JWS"} | ||||
| 	// JWS signed with testKey and "nonce" as the nonce value | ||||
| 	// JSON-serialized JWS fields are split for easier testing | ||||
| 	const ( | ||||
| 		// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"} | ||||
| 		protected = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" + | ||||
| 			"IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" + | ||||
| 			"SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" + | ||||
| 			"QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" + | ||||
| 			"VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" + | ||||
| 			"NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" + | ||||
| 			"QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" + | ||||
| 			"bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" + | ||||
| 			"ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" + | ||||
| 			"b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" + | ||||
| 			"UVEifSwibm9uY2UiOiJub25jZSJ9" | ||||
| 		// {"Msg":"Hello JWS"} | ||||
| 		payload   = "eyJNc2ciOiJIZWxsbyBKV1MifQ" | ||||
| 		signature = "eAGUikStX_UxyiFhxSLMyuyBcIB80GeBkFROCpap2sW3EmkU_ggF" + | ||||
| 			"knaQzxrTfItICSAXsCLIquZ5BbrSWA_4vdEYrwWtdUj7NqFKjHRa" + | ||||
| 			"zpLHcoR7r1rEHvkoP1xj49lS5fc3Wjjq8JUhffkhGbWZ8ZVkgPdC" + | ||||
| 			"4tMBWiQDoth-x8jELP_3LYOB_ScUXi2mETBawLgOT2K8rA0Vbbmx" + | ||||
| 			"hWNlOWuUf-8hL5YX4IOEwsS8JK_TrTq5Zc9My0zHJmaieqDV0UlP" + | ||||
| 			"k0onFjPFkGm7MrPSgd0MqRG-4vSAg2O4hDo7rKv4n8POjjXlNQvM" + | ||||
| 			"9IPLr8qZ7usYBKhEGwX3yq_eicAwBw" | ||||
| 	) | ||||
|  | ||||
| 	b, err := jwsEncodeJSON(claims, testKey, "nonce") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	var jws struct{ Protected, Payload, Signature string } | ||||
| 	if err := json.Unmarshal(b, &jws); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if jws.Protected != protected { | ||||
| 		t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected) | ||||
| 	} | ||||
| 	if jws.Payload != payload { | ||||
| 		t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload) | ||||
| 	} | ||||
| 	if jws.Signature != signature { | ||||
| 		t.Errorf("signature:\n%s\nwant:\n%s", jws.Signature, signature) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJWSEncodeJSONEC(t *testing.T) { | ||||
| 	tt := []struct { | ||||
| 		key      *ecdsa.PrivateKey | ||||
| 		x, y     string | ||||
| 		alg, crv string | ||||
| 	}{ | ||||
| 		{testKeyEC, testKeyECPubX, testKeyECPubY, "ES256", "P-256"}, | ||||
| 		{testKeyEC384, testKeyEC384PubX, testKeyEC384PubY, "ES384", "P-384"}, | ||||
| 		{testKeyEC512, testKeyEC512PubX, testKeyEC512PubY, "ES512", "P-521"}, | ||||
| 	} | ||||
| 	for i, test := range tt { | ||||
| 		claims := struct{ Msg string }{"Hello JWS"} | ||||
| 		b, err := jwsEncodeJSON(claims, test.key, "nonce") | ||||
| 		if err != nil { | ||||
| 			t.Errorf("%d: %v", i, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		var jws struct{ Protected, Payload, Signature string } | ||||
| 		if err := json.Unmarshal(b, &jws); err != nil { | ||||
| 			t.Errorf("%d: %v", i, err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		b, err = base64.RawURLEncoding.DecodeString(jws.Protected) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("%d: jws.Protected: %v", i, err) | ||||
| 		} | ||||
| 		var head struct { | ||||
| 			Alg   string | ||||
| 			Nonce string | ||||
| 			JWK   struct { | ||||
| 				Crv string | ||||
| 				Kty string | ||||
| 				X   string | ||||
| 				Y   string | ||||
| 			} `json:"jwk"` | ||||
| 		} | ||||
| 		if err := json.Unmarshal(b, &head); err != nil { | ||||
| 			t.Errorf("%d: jws.Protected: %v", i, err) | ||||
| 		} | ||||
| 		if head.Alg != test.alg { | ||||
| 			t.Errorf("%d: head.Alg = %q; want %q", i, head.Alg, test.alg) | ||||
| 		} | ||||
| 		if head.Nonce != "nonce" { | ||||
| 			t.Errorf("%d: head.Nonce = %q; want nonce", i, head.Nonce) | ||||
| 		} | ||||
| 		if head.JWK.Crv != test.crv { | ||||
| 			t.Errorf("%d: head.JWK.Crv = %q; want %q", i, head.JWK.Crv, test.crv) | ||||
| 		} | ||||
| 		if head.JWK.Kty != "EC" { | ||||
| 			t.Errorf("%d: head.JWK.Kty = %q; want EC", i, head.JWK.Kty) | ||||
| 		} | ||||
| 		if head.JWK.X != test.x { | ||||
| 			t.Errorf("%d: head.JWK.X = %q; want %q", i, head.JWK.X, test.x) | ||||
| 		} | ||||
| 		if head.JWK.Y != test.y { | ||||
| 			t.Errorf("%d: head.JWK.Y = %q; want %q", i, head.JWK.Y, test.y) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJWKThumbprintRSA(t *testing.T) { | ||||
| 	// Key example from RFC 7638 | ||||
| 	const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" + | ||||
| 		"VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn6" + | ||||
| 		"4tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FD" + | ||||
| 		"W2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9" + | ||||
| 		"1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINH" + | ||||
| 		"aQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw" | ||||
| 	const base64E = "AQAB" | ||||
| 	const expected = "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" | ||||
|  | ||||
| 	b, err := base64.RawURLEncoding.DecodeString(base64N) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Error parsing example key N: %v", err) | ||||
| 	} | ||||
| 	n := new(big.Int).SetBytes(b) | ||||
|  | ||||
| 	b, err = base64.RawURLEncoding.DecodeString(base64E) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Error parsing example key E: %v", err) | ||||
| 	} | ||||
| 	e := new(big.Int).SetBytes(b) | ||||
|  | ||||
| 	pub := &rsa.PublicKey{N: n, E: int(e.Uint64())} | ||||
| 	th, err := JWKThumbprint(pub) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 	if th != expected { | ||||
| 		t.Errorf("thumbprint = %q; want %q", th, expected) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJWKThumbprintEC(t *testing.T) { | ||||
| 	// Key example from RFC 7520 | ||||
| 	// expected was computed with | ||||
| 	// echo -n '{"crv":"P-521","kty":"EC","x":"<base64X>","y":"<base64Y>"}' | \ | ||||
| 	// openssl dgst -binary -sha256 | \ | ||||
| 	// base64 | \ | ||||
| 	// tr -d '=' | tr '/+' '_-' | ||||
| 	const ( | ||||
| 		base64X = "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkT" + | ||||
| 			"KqjqvjyekWF-7ytDyRXYgCF5cj0Kt" | ||||
| 		base64Y = "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUda" + | ||||
| 			"QkAgDPrwQrJmbnX9cwlGfP-HqHZR1" | ||||
| 		expected = "dHri3SADZkrush5HU_50AoRhcKFryN-PI6jPBtPL55M" | ||||
| 	) | ||||
|  | ||||
| 	b, err := base64.RawURLEncoding.DecodeString(base64X) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Error parsing example key X: %v", err) | ||||
| 	} | ||||
| 	x := new(big.Int).SetBytes(b) | ||||
|  | ||||
| 	b, err = base64.RawURLEncoding.DecodeString(base64Y) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Error parsing example key Y: %v", err) | ||||
| 	} | ||||
| 	y := new(big.Int).SetBytes(b) | ||||
|  | ||||
| 	pub := &ecdsa.PublicKey{Curve: elliptic.P521(), X: x, Y: y} | ||||
| 	th, err := JWKThumbprint(pub) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 	if th != expected { | ||||
| 		t.Errorf("thumbprint = %q; want %q", th, expected) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestJWKThumbprintErrUnsupportedKey(t *testing.T) { | ||||
| 	_, err := JWKThumbprint(struct{}{}) | ||||
| 	if err != ErrUnsupportedKey { | ||||
| 		t.Errorf("err = %q; want %q", err, ErrUnsupportedKey) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										329
									
								
								vendor/golang.org/x/crypto/acme/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								vendor/golang.org/x/crypto/acme/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,329 @@ | ||||
| // Copyright 2016 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 ( | ||||
| 	"crypto" | ||||
| 	"crypto/x509" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // ACME server response statuses used to describe Authorization and Challenge states. | ||||
| const ( | ||||
| 	StatusUnknown    = "unknown" | ||||
| 	StatusPending    = "pending" | ||||
| 	StatusProcessing = "processing" | ||||
| 	StatusValid      = "valid" | ||||
| 	StatusInvalid    = "invalid" | ||||
| 	StatusRevoked    = "revoked" | ||||
| ) | ||||
|  | ||||
| // CRLReasonCode identifies the reason for a certificate revocation. | ||||
| type CRLReasonCode int | ||||
|  | ||||
| // CRL reason codes as defined in RFC 5280. | ||||
| const ( | ||||
| 	CRLReasonUnspecified          CRLReasonCode = 0 | ||||
| 	CRLReasonKeyCompromise        CRLReasonCode = 1 | ||||
| 	CRLReasonCACompromise         CRLReasonCode = 2 | ||||
| 	CRLReasonAffiliationChanged   CRLReasonCode = 3 | ||||
| 	CRLReasonSuperseded           CRLReasonCode = 4 | ||||
| 	CRLReasonCessationOfOperation CRLReasonCode = 5 | ||||
| 	CRLReasonCertificateHold      CRLReasonCode = 6 | ||||
| 	CRLReasonRemoveFromCRL        CRLReasonCode = 8 | ||||
| 	CRLReasonPrivilegeWithdrawn   CRLReasonCode = 9 | ||||
| 	CRLReasonAACompromise         CRLReasonCode = 10 | ||||
| ) | ||||
|  | ||||
| // ErrUnsupportedKey is returned when an unsupported key type is encountered. | ||||
| var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported") | ||||
|  | ||||
| // Error is an ACME error, defined in Problem Details for HTTP APIs doc | ||||
| // http://tools.ietf.org/html/draft-ietf-appsawg-http-problem. | ||||
| type Error struct { | ||||
| 	// StatusCode is The HTTP status code generated by the origin server. | ||||
| 	StatusCode int | ||||
| 	// ProblemType is a URI reference that identifies the problem type, | ||||
| 	// typically in a "urn:acme:error:xxx" form. | ||||
| 	ProblemType string | ||||
| 	// Detail is a human-readable explanation specific to this occurrence of the problem. | ||||
| 	Detail string | ||||
| 	// Header is the original server error response headers. | ||||
| 	// It may be nil. | ||||
| 	Header http.Header | ||||
| } | ||||
|  | ||||
| func (e *Error) Error() string { | ||||
| 	return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail) | ||||
| } | ||||
|  | ||||
| // AuthorizationError indicates that an authorization for an identifier | ||||
| // did not succeed. | ||||
| // It contains all errors from Challenge items of the failed Authorization. | ||||
| type AuthorizationError struct { | ||||
| 	// URI uniquely identifies the failed Authorization. | ||||
| 	URI string | ||||
|  | ||||
| 	// Identifier is an AuthzID.Value of the failed Authorization. | ||||
| 	Identifier string | ||||
|  | ||||
| 	// Errors is a collection of non-nil error values of Challenge items | ||||
| 	// of the failed Authorization. | ||||
| 	Errors []error | ||||
| } | ||||
|  | ||||
| func (a *AuthorizationError) Error() string { | ||||
| 	e := make([]string, len(a.Errors)) | ||||
| 	for i, err := range a.Errors { | ||||
| 		e[i] = err.Error() | ||||
| 	} | ||||
| 	return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; ")) | ||||
| } | ||||
|  | ||||
| // RateLimit reports whether err represents a rate limit error and | ||||
| // any Retry-After duration returned by the server. | ||||
| // | ||||
| // See the following for more details on rate limiting: | ||||
| // https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-5.6 | ||||
| func RateLimit(err error) (time.Duration, bool) { | ||||
| 	e, ok := err.(*Error) | ||||
| 	if !ok { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	// Some CA implementations may return incorrect values. | ||||
| 	// Use case-insensitive comparison. | ||||
| 	if !strings.HasSuffix(strings.ToLower(e.ProblemType), ":ratelimited") { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	if e.Header == nil { | ||||
| 		return 0, true | ||||
| 	} | ||||
| 	return retryAfter(e.Header.Get("Retry-After"), 0), true | ||||
| } | ||||
|  | ||||
| // Account is a user account. It is associated with a private key. | ||||
| type Account struct { | ||||
| 	// URI is the account unique ID, which is also a URL used to retrieve | ||||
| 	// account data from the CA. | ||||
| 	URI string | ||||
|  | ||||
| 	// Contact is a slice of contact info used during registration. | ||||
| 	Contact []string | ||||
|  | ||||
| 	// The terms user has agreed to. | ||||
| 	// A value not matching CurrentTerms indicates that the user hasn't agreed | ||||
| 	// to the actual Terms of Service of the CA. | ||||
| 	AgreedTerms string | ||||
|  | ||||
| 	// Actual terms of a CA. | ||||
| 	CurrentTerms string | ||||
|  | ||||
| 	// Authz is the authorization URL used to initiate a new authz flow. | ||||
| 	Authz string | ||||
|  | ||||
| 	// Authorizations is a URI from which a list of authorizations | ||||
| 	// granted to this account can be fetched via a GET request. | ||||
| 	Authorizations string | ||||
|  | ||||
| 	// Certificates is a URI from which a list of certificates | ||||
| 	// issued for this account can be fetched via a GET request. | ||||
| 	Certificates string | ||||
| } | ||||
|  | ||||
| // Directory is ACME server discovery data. | ||||
| type Directory struct { | ||||
| 	// RegURL is an account endpoint URL, allowing for creating new | ||||
| 	// and modifying existing accounts. | ||||
| 	RegURL string | ||||
|  | ||||
| 	// AuthzURL is used to initiate Identifier Authorization flow. | ||||
| 	AuthzURL string | ||||
|  | ||||
| 	// CertURL is a new certificate issuance endpoint URL. | ||||
| 	CertURL string | ||||
|  | ||||
| 	// RevokeURL is used to initiate a certificate revocation flow. | ||||
| 	RevokeURL string | ||||
|  | ||||
| 	// Term is a URI identifying the current terms of service. | ||||
| 	Terms string | ||||
|  | ||||
| 	// Website is an HTTP or HTTPS URL locating a website | ||||
| 	// providing more information about the ACME server. | ||||
| 	Website string | ||||
|  | ||||
| 	// CAA consists of lowercase hostname elements, which the ACME server | ||||
| 	// recognises as referring to itself for the purposes of CAA record validation | ||||
| 	// as defined in RFC6844. | ||||
| 	CAA []string | ||||
| } | ||||
|  | ||||
| // Challenge encodes a returned CA challenge. | ||||
| // Its Error field may be non-nil if the challenge is part of an Authorization | ||||
| // with StatusInvalid. | ||||
| type Challenge struct { | ||||
| 	// Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01". | ||||
| 	Type string | ||||
|  | ||||
| 	// URI is where a challenge response can be posted to. | ||||
| 	URI string | ||||
|  | ||||
| 	// Token is a random value that uniquely identifies the challenge. | ||||
| 	Token string | ||||
|  | ||||
| 	// Status identifies the status of this challenge. | ||||
| 	Status string | ||||
|  | ||||
| 	// Error indicates the reason for an authorization failure | ||||
| 	// when this challenge was used. | ||||
| 	// The type of a non-nil value is *Error. | ||||
| 	Error error | ||||
| } | ||||
|  | ||||
| // Authorization encodes an authorization response. | ||||
| type Authorization struct { | ||||
| 	// URI uniquely identifies a authorization. | ||||
| 	URI string | ||||
|  | ||||
| 	// Status identifies the status of an authorization. | ||||
| 	Status string | ||||
|  | ||||
| 	// Identifier is what the account is authorized to represent. | ||||
| 	Identifier AuthzID | ||||
|  | ||||
| 	// Challenges that the client needs to fulfill in order to prove possession | ||||
| 	// of the identifier (for pending authorizations). | ||||
| 	// For final authorizations, the challenges that were used. | ||||
| 	Challenges []*Challenge | ||||
|  | ||||
| 	// A collection of sets of challenges, each of which would be sufficient | ||||
| 	// to prove possession of the identifier. | ||||
| 	// Clients must complete a set of challenges that covers at least one set. | ||||
| 	// Challenges are identified by their indices in the challenges array. | ||||
| 	// If this field is empty, the client needs to complete all challenges. | ||||
| 	Combinations [][]int | ||||
| } | ||||
|  | ||||
| // AuthzID is an identifier that an account is authorized to represent. | ||||
| type AuthzID struct { | ||||
| 	Type  string // The type of identifier, e.g. "dns". | ||||
| 	Value string // The identifier itself, e.g. "example.org". | ||||
| } | ||||
|  | ||||
| // wireAuthz is ACME JSON representation of Authorization objects. | ||||
| type wireAuthz struct { | ||||
| 	Status       string | ||||
| 	Challenges   []wireChallenge | ||||
| 	Combinations [][]int | ||||
| 	Identifier   struct { | ||||
| 		Type  string | ||||
| 		Value string | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (z *wireAuthz) authorization(uri string) *Authorization { | ||||
| 	a := &Authorization{ | ||||
| 		URI:          uri, | ||||
| 		Status:       z.Status, | ||||
| 		Identifier:   AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value}, | ||||
| 		Combinations: z.Combinations, // shallow copy | ||||
| 		Challenges:   make([]*Challenge, len(z.Challenges)), | ||||
| 	} | ||||
| 	for i, v := range z.Challenges { | ||||
| 		a.Challenges[i] = v.challenge() | ||||
| 	} | ||||
| 	return a | ||||
| } | ||||
|  | ||||
| func (z *wireAuthz) error(uri string) *AuthorizationError { | ||||
| 	err := &AuthorizationError{ | ||||
| 		URI:        uri, | ||||
| 		Identifier: z.Identifier.Value, | ||||
| 	} | ||||
| 	for _, raw := range z.Challenges { | ||||
| 		if raw.Error != nil { | ||||
| 			err.Errors = append(err.Errors, raw.Error.error(nil)) | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // wireChallenge is ACME JSON challenge representation. | ||||
| type wireChallenge struct { | ||||
| 	URI    string `json:"uri"` | ||||
| 	Type   string | ||||
| 	Token  string | ||||
| 	Status string | ||||
| 	Error  *wireError | ||||
| } | ||||
|  | ||||
| func (c *wireChallenge) challenge() *Challenge { | ||||
| 	v := &Challenge{ | ||||
| 		URI:    c.URI, | ||||
| 		Type:   c.Type, | ||||
| 		Token:  c.Token, | ||||
| 		Status: c.Status, | ||||
| 	} | ||||
| 	if v.Status == "" { | ||||
| 		v.Status = StatusPending | ||||
| 	} | ||||
| 	if c.Error != nil { | ||||
| 		v.Error = c.Error.error(nil) | ||||
| 	} | ||||
| 	return v | ||||
| } | ||||
|  | ||||
| // wireError is a subset of fields of the Problem Details object | ||||
| // as described in https://tools.ietf.org/html/rfc7807#section-3.1. | ||||
| type wireError struct { | ||||
| 	Status int | ||||
| 	Type   string | ||||
| 	Detail string | ||||
| } | ||||
|  | ||||
| func (e *wireError) error(h http.Header) *Error { | ||||
| 	return &Error{ | ||||
| 		StatusCode:  e.Status, | ||||
| 		ProblemType: e.Type, | ||||
| 		Detail:      e.Detail, | ||||
| 		Header:      h, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // CertOption is an optional argument type for the TLSSNIxChallengeCert methods for | ||||
| // customizing a temporary certificate for TLS-SNI challenges. | ||||
| type CertOption interface { | ||||
| 	privateCertOpt() | ||||
| } | ||||
|  | ||||
| // WithKey creates an option holding a private/public key pair. | ||||
| // The private part signs a certificate, and the public part represents the signee. | ||||
| func WithKey(key crypto.Signer) CertOption { | ||||
| 	return &certOptKey{key} | ||||
| } | ||||
|  | ||||
| type certOptKey struct { | ||||
| 	key crypto.Signer | ||||
| } | ||||
|  | ||||
| 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, | ||||
| // 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 { | ||||
| 	return (*certOptTemplate)(t) | ||||
| } | ||||
|  | ||||
| type certOptTemplate x509.Certificate | ||||
|  | ||||
| func (*certOptTemplate) privateCertOpt() {} | ||||
							
								
								
									
										63
									
								
								vendor/golang.org/x/crypto/acme/types_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/golang.org/x/crypto/acme/types_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| // Copyright 2017 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 ( | ||||
| 	"errors" | ||||
| 	"net/http" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestRateLimit(t *testing.T) { | ||||
| 	now := time.Date(2017, 04, 27, 10, 0, 0, 0, time.UTC) | ||||
| 	f := timeNow | ||||
| 	defer func() { timeNow = f }() | ||||
| 	timeNow = func() time.Time { return now } | ||||
|  | ||||
| 	h120, hTime := http.Header{}, http.Header{} | ||||
| 	h120.Set("Retry-After", "120") | ||||
| 	hTime.Set("Retry-After", "Tue Apr 27 11:00:00 2017") | ||||
|  | ||||
| 	err1 := &Error{ | ||||
| 		ProblemType: "urn:ietf:params:acme:error:nolimit", | ||||
| 		Header:      h120, | ||||
| 	} | ||||
| 	err2 := &Error{ | ||||
| 		ProblemType: "urn:ietf:params:acme:error:rateLimited", | ||||
| 		Header:      h120, | ||||
| 	} | ||||
| 	err3 := &Error{ | ||||
| 		ProblemType: "urn:ietf:params:acme:error:rateLimited", | ||||
| 		Header:      nil, | ||||
| 	} | ||||
| 	err4 := &Error{ | ||||
| 		ProblemType: "urn:ietf:params:acme:error:rateLimited", | ||||
| 		Header:      hTime, | ||||
| 	} | ||||
|  | ||||
| 	tt := []struct { | ||||
| 		err error | ||||
| 		res time.Duration | ||||
| 		ok  bool | ||||
| 	}{ | ||||
| 		{nil, 0, false}, | ||||
| 		{errors.New("dummy"), 0, false}, | ||||
| 		{err1, 0, false}, | ||||
| 		{err2, 2 * time.Minute, true}, | ||||
| 		{err3, 0, true}, | ||||
| 		{err4, time.Hour, true}, | ||||
| 	} | ||||
| 	for i, test := range tt { | ||||
| 		res, ok := RateLimit(test.err) | ||||
| 		if ok != test.ok { | ||||
| 			t.Errorf("%d: RateLimit(%+v): ok = %v; want %v", i, test.err, ok, test.ok) | ||||
| 			continue | ||||
| 		} | ||||
| 		if res != test.res { | ||||
| 			t.Errorf("%d: RateLimit(%+v) = %v; want %v", i, test.err, res, test.res) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										228
									
								
								vendor/golang.org/x/crypto/argon2/argon2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								vendor/golang.org/x/crypto/argon2/argon2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | ||||
| // Copyright 2017 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 argon2 implements the key derivation function Argon2. | ||||
| // Argon2 was selected as the winner of the Password Hashing Competition and can | ||||
| // be used to derive cryptographic keys from passwords. | ||||
| // Argon2 is specfifed at https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf | ||||
| package argon2 | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"sync" | ||||
|  | ||||
| 	"golang.org/x/crypto/blake2b" | ||||
| ) | ||||
|  | ||||
| // The Argon2 version implemented by this package. | ||||
| const Version = 0x13 | ||||
|  | ||||
| const ( | ||||
| 	argon2d = iota | ||||
| 	argon2i | ||||
| 	argon2id | ||||
| ) | ||||
|  | ||||
| // Key derives a key from the password, salt, and cost parameters using Argon2i | ||||
| // returning a byte slice of length keyLen that can be used as cryptographic key. | ||||
| // The CPU cost and parallism degree must be greater than zero. | ||||
| // | ||||
| // For example, you can get a derived key for e.g. AES-256 (which needs a 32-byte key) by doing: | ||||
| // `key := argon2.Key([]byte("some password"), salt, 4, 32*1024, 4, 32)` | ||||
| // | ||||
| // The recommended parameters for interactive logins as of 2017 are time=4, memory=32*1024. | ||||
| // The number of threads can be adjusted to the numbers of available CPUs. | ||||
| // The time parameter specifies the number of passes over the memory and the memory | ||||
| // parameter specifies the size of the memory in KiB. For example memory=32*1024 sets the | ||||
| // memory cost to ~32 MB. | ||||
| // The cost parameters should be increased as memory latency and CPU parallelism increases. | ||||
| // Remember to get a good random salt. | ||||
| func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte { | ||||
| 	return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen) | ||||
| } | ||||
|  | ||||
| func deriveKey(mode int, password, salt, secret, data []byte, time, memory uint32, threads uint8, keyLen uint32) []byte { | ||||
| 	if time < 1 { | ||||
| 		panic("argon2: number of rounds too small") | ||||
| 	} | ||||
| 	if threads < 1 { | ||||
| 		panic("argon2: parallelism degree too low") | ||||
| 	} | ||||
| 	h0 := initHash(password, salt, secret, data, time, memory, uint32(threads), keyLen, mode) | ||||
|  | ||||
| 	memory = memory / (syncPoints * uint32(threads)) * (syncPoints * uint32(threads)) | ||||
| 	if memory < 2*syncPoints*uint32(threads) { | ||||
| 		memory = 2 * syncPoints * uint32(threads) | ||||
| 	} | ||||
| 	B := initBlocks(&h0, memory, uint32(threads)) | ||||
| 	processBlocks(B, time, memory, uint32(threads), mode) | ||||
| 	return extractKey(B, memory, uint32(threads), keyLen) | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	blockLength = 128 | ||||
| 	syncPoints  = 4 | ||||
| ) | ||||
|  | ||||
| type block [blockLength]uint64 | ||||
|  | ||||
| func initHash(password, salt, key, data []byte, time, memory, threads, keyLen uint32, mode int) [blake2b.Size + 8]byte { | ||||
| 	var ( | ||||
| 		h0     [blake2b.Size + 8]byte | ||||
| 		params [24]byte | ||||
| 		tmp    [4]byte | ||||
| 	) | ||||
|  | ||||
| 	b2, _ := blake2b.New512(nil) | ||||
| 	binary.LittleEndian.PutUint32(params[0:4], threads) | ||||
| 	binary.LittleEndian.PutUint32(params[4:8], keyLen) | ||||
| 	binary.LittleEndian.PutUint32(params[8:12], memory) | ||||
| 	binary.LittleEndian.PutUint32(params[12:16], time) | ||||
| 	binary.LittleEndian.PutUint32(params[16:20], uint32(Version)) | ||||
| 	binary.LittleEndian.PutUint32(params[20:24], uint32(mode)) | ||||
| 	b2.Write(params[:]) | ||||
| 	binary.LittleEndian.PutUint32(tmp[:], uint32(len(password))) | ||||
| 	b2.Write(tmp[:]) | ||||
| 	b2.Write(password) | ||||
| 	binary.LittleEndian.PutUint32(tmp[:], uint32(len(salt))) | ||||
| 	b2.Write(tmp[:]) | ||||
| 	b2.Write(salt) | ||||
| 	binary.LittleEndian.PutUint32(tmp[:], uint32(len(key))) | ||||
| 	b2.Write(tmp[:]) | ||||
| 	b2.Write(key) | ||||
| 	binary.LittleEndian.PutUint32(tmp[:], uint32(len(data))) | ||||
| 	b2.Write(tmp[:]) | ||||
| 	b2.Write(data) | ||||
| 	b2.Sum(h0[:0]) | ||||
| 	return h0 | ||||
| } | ||||
|  | ||||
| func initBlocks(h0 *[blake2b.Size + 8]byte, memory, threads uint32) []block { | ||||
| 	var block0 [1024]byte | ||||
| 	B := make([]block, memory) | ||||
| 	for lane := uint32(0); lane < threads; lane++ { | ||||
| 		j := lane * (memory / threads) | ||||
| 		binary.LittleEndian.PutUint32(h0[blake2b.Size+4:], lane) | ||||
|  | ||||
| 		binary.LittleEndian.PutUint32(h0[blake2b.Size:], 0) | ||||
| 		blake2bHash(block0[:], h0[:]) | ||||
| 		for i := range B[j+0] { | ||||
| 			B[j+0][i] = binary.LittleEndian.Uint64(block0[i*8:]) | ||||
| 		} | ||||
|  | ||||
| 		binary.LittleEndian.PutUint32(h0[blake2b.Size:], 1) | ||||
| 		blake2bHash(block0[:], h0[:]) | ||||
| 		for i := range B[j+1] { | ||||
| 			B[j+1][i] = binary.LittleEndian.Uint64(block0[i*8:]) | ||||
| 		} | ||||
| 	} | ||||
| 	return B | ||||
| } | ||||
|  | ||||
| func processBlocks(B []block, time, memory, threads uint32, mode int) { | ||||
| 	lanes := memory / threads | ||||
| 	segments := lanes / syncPoints | ||||
|  | ||||
| 	processSegment := func(n, slice, lane uint32, wg *sync.WaitGroup) { | ||||
| 		var addresses, in, zero block | ||||
| 		if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) { | ||||
| 			in[0] = uint64(n) | ||||
| 			in[1] = uint64(lane) | ||||
| 			in[2] = uint64(slice) | ||||
| 			in[3] = uint64(memory) | ||||
| 			in[4] = uint64(time) | ||||
| 			in[5] = uint64(mode) | ||||
| 		} | ||||
|  | ||||
| 		index := uint32(0) | ||||
| 		if n == 0 && slice == 0 { | ||||
| 			index = 2 // we have already generated the first two blocks | ||||
| 			if mode == argon2i || mode == argon2id { | ||||
| 				in[6]++ | ||||
| 				processBlock(&addresses, &in, &zero) | ||||
| 				processBlock(&addresses, &addresses, &zero) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		offset := lane*lanes + slice*segments + index | ||||
| 		var random uint64 | ||||
| 		for index < segments { | ||||
| 			prev := offset - 1 | ||||
| 			if index == 0 && slice == 0 { | ||||
| 				prev += lanes // last block in lane | ||||
| 			} | ||||
| 			if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) { | ||||
| 				if index%blockLength == 0 { | ||||
| 					in[6]++ | ||||
| 					processBlock(&addresses, &in, &zero) | ||||
| 					processBlock(&addresses, &addresses, &zero) | ||||
| 				} | ||||
| 				random = addresses[index%blockLength] | ||||
| 			} else { | ||||
| 				random = B[prev][0] | ||||
| 			} | ||||
| 			newOffset := indexAlpha(random, lanes, segments, threads, n, slice, lane, index) | ||||
| 			processBlockXOR(&B[offset], &B[prev], &B[newOffset]) | ||||
| 			index, offset = index+1, offset+1 | ||||
| 		} | ||||
| 		wg.Done() | ||||
| 	} | ||||
|  | ||||
| 	for n := uint32(0); n < time; n++ { | ||||
| 		for slice := uint32(0); slice < syncPoints; slice++ { | ||||
| 			var wg sync.WaitGroup | ||||
| 			for lane := uint32(0); lane < threads; lane++ { | ||||
| 				wg.Add(1) | ||||
| 				go processSegment(n, slice, lane, &wg) | ||||
| 			} | ||||
| 			wg.Wait() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| func extractKey(B []block, memory, threads, keyLen uint32) []byte { | ||||
| 	lanes := memory / threads | ||||
| 	for lane := uint32(0); lane < threads-1; lane++ { | ||||
| 		for i, v := range B[(lane*lanes)+lanes-1] { | ||||
| 			B[memory-1][i] ^= v | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var block [1024]byte | ||||
| 	for i, v := range B[memory-1] { | ||||
| 		binary.LittleEndian.PutUint64(block[i*8:], v) | ||||
| 	} | ||||
| 	key := make([]byte, keyLen) | ||||
| 	blake2bHash(key, block[:]) | ||||
| 	return key | ||||
| } | ||||
|  | ||||
| func indexAlpha(rand uint64, lanes, segments, threads, n, slice, lane, index uint32) uint32 { | ||||
| 	refLane := uint32(rand>>32) % threads | ||||
| 	if n == 0 && slice == 0 { | ||||
| 		refLane = lane | ||||
| 	} | ||||
| 	m, s := 3*segments, ((slice+1)%syncPoints)*segments | ||||
| 	if lane == refLane { | ||||
| 		m += index | ||||
| 	} | ||||
| 	if n == 0 { | ||||
| 		m, s = slice*segments, 0 | ||||
| 		if slice == 0 || lane == refLane { | ||||
| 			m += index | ||||
| 		} | ||||
| 	} | ||||
| 	if index == 0 || lane == refLane { | ||||
| 		m-- | ||||
| 	} | ||||
| 	return phi(rand, uint64(m), uint64(s), refLane, lanes) | ||||
| } | ||||
|  | ||||
| func phi(rand, m, s uint64, lane, lanes uint32) uint32 { | ||||
| 	p := rand & 0xFFFFFFFF | ||||
| 	p = (p * p) >> 32 | ||||
| 	p = (p * m) >> 32 | ||||
| 	return lane*lanes + uint32((s+m-(p+1))%uint64(lanes)) | ||||
| } | ||||
							
								
								
									
										233
									
								
								vendor/golang.org/x/crypto/argon2/argon2_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								vendor/golang.org/x/crypto/argon2/argon2_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,233 @@ | ||||
| // Copyright 2017 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 argon2 | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/hex" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	genKatPassword = []byte{ | ||||
| 		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||||
| 		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||||
| 		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||||
| 		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||||
| 	} | ||||
| 	genKatSalt   = []byte{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} | ||||
| 	genKatSecret = []byte{0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03} | ||||
| 	genKatAAD    = []byte{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04} | ||||
| ) | ||||
|  | ||||
| func TestArgon2(t *testing.T) { | ||||
| 	defer func(sse4 bool) { useSSE4 = sse4 }(useSSE4) | ||||
|  | ||||
| 	if useSSE4 { | ||||
| 		t.Log("SSE4.1 version") | ||||
| 		testArgon2i(t) | ||||
| 		testArgon2d(t) | ||||
| 		testArgon2id(t) | ||||
| 		useSSE4 = false | ||||
| 	} | ||||
| 	t.Log("generic version") | ||||
| 	testArgon2i(t) | ||||
| 	testArgon2d(t) | ||||
| 	testArgon2id(t) | ||||
| } | ||||
|  | ||||
| func testArgon2d(t *testing.T) { | ||||
| 	want := []byte{ | ||||
| 		0x51, 0x2b, 0x39, 0x1b, 0x6f, 0x11, 0x62, 0x97, | ||||
| 		0x53, 0x71, 0xd3, 0x09, 0x19, 0x73, 0x42, 0x94, | ||||
| 		0xf8, 0x68, 0xe3, 0xbe, 0x39, 0x84, 0xf3, 0xc1, | ||||
| 		0xa1, 0x3a, 0x4d, 0xb9, 0xfa, 0xbe, 0x4a, 0xcb, | ||||
| 	} | ||||
| 	hash := deriveKey(argon2d, genKatPassword, genKatSalt, genKatSecret, genKatAAD, 3, 32, 4, 32) | ||||
| 	if !bytes.Equal(hash, want) { | ||||
| 		t.Errorf("derived key does not match - got: %s , want: %s", hex.EncodeToString(hash), hex.EncodeToString(want)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testArgon2i(t *testing.T) { | ||||
| 	want := []byte{ | ||||
| 		0xc8, 0x14, 0xd9, 0xd1, 0xdc, 0x7f, 0x37, 0xaa, | ||||
| 		0x13, 0xf0, 0xd7, 0x7f, 0x24, 0x94, 0xbd, 0xa1, | ||||
| 		0xc8, 0xde, 0x6b, 0x01, 0x6d, 0xd3, 0x88, 0xd2, | ||||
| 		0x99, 0x52, 0xa4, 0xc4, 0x67, 0x2b, 0x6c, 0xe8, | ||||
| 	} | ||||
| 	hash := deriveKey(argon2i, genKatPassword, genKatSalt, genKatSecret, genKatAAD, 3, 32, 4, 32) | ||||
| 	if !bytes.Equal(hash, want) { | ||||
| 		t.Errorf("derived key does not match - got: %s , want: %s", hex.EncodeToString(hash), hex.EncodeToString(want)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testArgon2id(t *testing.T) { | ||||
| 	want := []byte{ | ||||
| 		0x0d, 0x64, 0x0d, 0xf5, 0x8d, 0x78, 0x76, 0x6c, | ||||
| 		0x08, 0xc0, 0x37, 0xa3, 0x4a, 0x8b, 0x53, 0xc9, | ||||
| 		0xd0, 0x1e, 0xf0, 0x45, 0x2d, 0x75, 0xb6, 0x5e, | ||||
| 		0xb5, 0x25, 0x20, 0xe9, 0x6b, 0x01, 0xe6, 0x59, | ||||
| 	} | ||||
| 	hash := deriveKey(argon2id, genKatPassword, genKatSalt, genKatSecret, genKatAAD, 3, 32, 4, 32) | ||||
| 	if !bytes.Equal(hash, want) { | ||||
| 		t.Errorf("derived key does not match - got: %s , want: %s", hex.EncodeToString(hash), hex.EncodeToString(want)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestVectors(t *testing.T) { | ||||
| 	password, salt := []byte("password"), []byte("somesalt") | ||||
| 	for i, v := range testVectors { | ||||
| 		want, err := hex.DecodeString(v.hash) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("Test %d: failed to decode hash: %v", i, err) | ||||
| 		} | ||||
| 		hash := deriveKey(v.mode, password, salt, nil, nil, v.time, v.memory, v.threads, uint32(len(want))) | ||||
| 		if !bytes.Equal(hash, want) { | ||||
| 			t.Errorf("Test %d - got: %s want: %s", i, hex.EncodeToString(hash), hex.EncodeToString(want)) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func benchmarkArgon2(mode int, time, memory uint32, threads uint8, keyLen uint32, b *testing.B) { | ||||
| 	password := []byte("password") | ||||
| 	salt := []byte("choosing random salts is hard") | ||||
| 	b.ReportAllocs() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		deriveKey(mode, password, salt, nil, nil, time, memory, threads, keyLen) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkArgon2i(b *testing.B) { | ||||
| 	b.Run(" Time: 3 Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2i, 3, 32*1024, 1, 32, b) }) | ||||
| 	b.Run(" Time: 4 Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2i, 4, 32*1024, 1, 32, b) }) | ||||
| 	b.Run(" Time: 5 Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2i, 5, 32*1024, 1, 32, b) }) | ||||
| 	b.Run(" Time: 3 Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2i, 3, 64*1024, 4, 32, b) }) | ||||
| 	b.Run(" Time: 4 Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2i, 4, 64*1024, 4, 32, b) }) | ||||
| 	b.Run(" Time: 5 Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2i, 5, 64*1024, 4, 32, b) }) | ||||
| } | ||||
|  | ||||
| func BenchmarkArgon2d(b *testing.B) { | ||||
| 	b.Run(" Time: 3, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2d, 3, 32*1024, 1, 32, b) }) | ||||
| 	b.Run(" Time: 4, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2d, 4, 32*1024, 1, 32, b) }) | ||||
| 	b.Run(" Time: 5, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2d, 5, 32*1024, 1, 32, b) }) | ||||
| 	b.Run(" Time: 3, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2d, 3, 64*1024, 4, 32, b) }) | ||||
| 	b.Run(" Time: 4, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2d, 4, 64*1024, 4, 32, b) }) | ||||
| 	b.Run(" Time: 5, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2d, 5, 64*1024, 4, 32, b) }) | ||||
| } | ||||
|  | ||||
| func BenchmarkArgon2id(b *testing.B) { | ||||
| 	b.Run(" Time: 3, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2id, 3, 32*1024, 1, 32, b) }) | ||||
| 	b.Run(" Time: 4, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2id, 4, 32*1024, 1, 32, b) }) | ||||
| 	b.Run(" Time: 5, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2id, 5, 32*1024, 1, 32, b) }) | ||||
| 	b.Run(" Time: 3, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2id, 3, 64*1024, 4, 32, b) }) | ||||
| 	b.Run(" Time: 4, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2id, 4, 64*1024, 4, 32, b) }) | ||||
| 	b.Run(" Time: 5, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2id, 5, 64*1024, 4, 32, b) }) | ||||
| } | ||||
|  | ||||
| // Generated with the CLI of https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf | ||||
| var testVectors = []struct { | ||||
| 	mode         int | ||||
| 	time, memory uint32 | ||||
| 	threads      uint8 | ||||
| 	hash         string | ||||
| }{ | ||||
| 	{ | ||||
| 		mode: argon2i, time: 1, memory: 64, threads: 1, | ||||
| 		hash: "b9c401d1844a67d50eae3967dc28870b22e508092e861a37", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2d, time: 1, memory: 64, threads: 1, | ||||
| 		hash: "8727405fd07c32c78d64f547f24150d3f2e703a89f981a19", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2id, time: 1, memory: 64, threads: 1, | ||||
| 		hash: "655ad15eac652dc59f7170a7332bf49b8469be1fdb9c28bb", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2i, time: 2, memory: 64, threads: 1, | ||||
| 		hash: "8cf3d8f76a6617afe35fac48eb0b7433a9a670ca4a07ed64", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2d, time: 2, memory: 64, threads: 1, | ||||
| 		hash: "3be9ec79a69b75d3752acb59a1fbb8b295a46529c48fbb75", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2id, time: 2, memory: 64, threads: 1, | ||||
| 		hash: "068d62b26455936aa6ebe60060b0a65870dbfa3ddf8d41f7", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2i, time: 2, memory: 64, threads: 2, | ||||
| 		hash: "2089f3e78a799720f80af806553128f29b132cafe40d059f", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2d, time: 2, memory: 64, threads: 2, | ||||
| 		hash: "68e2462c98b8bc6bb60ec68db418ae2c9ed24fc6748a40e9", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2id, time: 2, memory: 64, threads: 2, | ||||
| 		hash: "350ac37222f436ccb5c0972f1ebd3bf6b958bf2071841362", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2i, time: 3, memory: 256, threads: 2, | ||||
| 		hash: "f5bbf5d4c3836af13193053155b73ec7476a6a2eb93fd5e6", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2d, time: 3, memory: 256, threads: 2, | ||||
| 		hash: "f4f0669218eaf3641f39cc97efb915721102f4b128211ef2", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2id, time: 3, memory: 256, threads: 2, | ||||
| 		hash: "4668d30ac4187e6878eedeacf0fd83c5a0a30db2cc16ef0b", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2i, time: 4, memory: 4096, threads: 4, | ||||
| 		hash: "a11f7b7f3f93f02ad4bddb59ab62d121e278369288a0d0e7", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2d, time: 4, memory: 4096, threads: 4, | ||||
| 		hash: "935598181aa8dc2b720914aa6435ac8d3e3a4210c5b0fb2d", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2id, time: 4, memory: 4096, threads: 4, | ||||
| 		hash: "145db9733a9f4ee43edf33c509be96b934d505a4efb33c5a", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2i, time: 4, memory: 1024, threads: 8, | ||||
| 		hash: "0cdd3956aa35e6b475a7b0c63488822f774f15b43f6e6e17", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2d, time: 4, memory: 1024, threads: 8, | ||||
| 		hash: "83604fc2ad0589b9d055578f4d3cc55bc616df3578a896e9", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2id, time: 4, memory: 1024, threads: 8, | ||||
| 		hash: "8dafa8e004f8ea96bf7c0f93eecf67a6047476143d15577f", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2i, time: 2, memory: 64, threads: 3, | ||||
| 		hash: "5cab452fe6b8479c8661def8cd703b611a3905a6d5477fe6", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2d, time: 2, memory: 64, threads: 3, | ||||
| 		hash: "22474a423bda2ccd36ec9afd5119e5c8949798cadf659f51", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2id, time: 2, memory: 64, threads: 3, | ||||
| 		hash: "4a15b31aec7c2590b87d1f520be7d96f56658172deaa3079", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2i, time: 3, memory: 1024, threads: 6, | ||||
| 		hash: "d236b29c2b2a09babee842b0dec6aa1e83ccbdea8023dced", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2d, time: 3, memory: 1024, threads: 6, | ||||
| 		hash: "a3351b0319a53229152023d9206902f4ef59661cdca89481", | ||||
| 	}, | ||||
| 	{ | ||||
| 		mode: argon2id, time: 3, memory: 1024, threads: 6, | ||||
| 		hash: "1640b932f4b60e272f5d2207b9a9c626ffa1bd88d2349016", | ||||
| 	}, | ||||
| } | ||||
							
								
								
									
										53
									
								
								vendor/golang.org/x/crypto/argon2/blake2b.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								vendor/golang.org/x/crypto/argon2/blake2b.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| // Copyright 2017 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 argon2 | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"hash" | ||||
|  | ||||
| 	"golang.org/x/crypto/blake2b" | ||||
| ) | ||||
|  | ||||
| // blake2bHash computes an arbitrary long hash value of in | ||||
| // and writes the hash to out. | ||||
| func blake2bHash(out []byte, in []byte) { | ||||
| 	var b2 hash.Hash | ||||
| 	if n := len(out); n < blake2b.Size { | ||||
| 		b2, _ = blake2b.New(n, nil) | ||||
| 	} else { | ||||
| 		b2, _ = blake2b.New512(nil) | ||||
| 	} | ||||
|  | ||||
| 	var buffer [blake2b.Size]byte | ||||
| 	binary.LittleEndian.PutUint32(buffer[:4], uint32(len(out))) | ||||
| 	b2.Write(buffer[:4]) | ||||
| 	b2.Write(in) | ||||
|  | ||||
| 	if len(out) <= blake2b.Size { | ||||
| 		b2.Sum(out[:0]) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	outLen := len(out) | ||||
| 	b2.Sum(buffer[:0]) | ||||
| 	b2.Reset() | ||||
| 	copy(out, buffer[:32]) | ||||
| 	out = out[32:] | ||||
| 	for len(out) > blake2b.Size { | ||||
| 		b2.Write(buffer[:]) | ||||
| 		b2.Sum(buffer[:0]) | ||||
| 		copy(out, buffer[:32]) | ||||
| 		out = out[32:] | ||||
| 		b2.Reset() | ||||
| 	} | ||||
|  | ||||
| 	if outLen%blake2b.Size > 0 { // outLen > 64 | ||||
| 		r := ((outLen + 31) / 32) - 2 // ⌈τ /32⌉-2 | ||||
| 		b2, _ = blake2b.New(outLen-32*r, nil) | ||||
| 	} | ||||
| 	b2.Write(buffer[:]) | ||||
| 	b2.Sum(out[:0]) | ||||
| } | ||||
							
								
								
									
										61
									
								
								vendor/golang.org/x/crypto/argon2/blamka_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								vendor/golang.org/x/crypto/argon2/blamka_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| // Copyright 2017 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 amd64,!gccgo,!appengine | ||||
|  | ||||
| package argon2 | ||||
|  | ||||
| func init() { | ||||
| 	useSSE4 = supportsSSE4() | ||||
| } | ||||
|  | ||||
| //go:noescape | ||||
| func supportsSSE4() bool | ||||
|  | ||||
| //go:noescape | ||||
| func mixBlocksSSE2(out, a, b, c *block) | ||||
|  | ||||
| //go:noescape | ||||
| func xorBlocksSSE2(out, a, b, c *block) | ||||
|  | ||||
| //go:noescape | ||||
| func blamkaSSE4(b *block) | ||||
|  | ||||
| func processBlockSSE(out, in1, in2 *block, xor bool) { | ||||
| 	var t block | ||||
| 	mixBlocksSSE2(&t, in1, in2, &t) | ||||
| 	if useSSE4 { | ||||
| 		blamkaSSE4(&t) | ||||
| 	} else { | ||||
| 		for i := 0; i < blockLength; i += 16 { | ||||
| 			blamkaGeneric( | ||||
| 				&t[i+0], &t[i+1], &t[i+2], &t[i+3], | ||||
| 				&t[i+4], &t[i+5], &t[i+6], &t[i+7], | ||||
| 				&t[i+8], &t[i+9], &t[i+10], &t[i+11], | ||||
| 				&t[i+12], &t[i+13], &t[i+14], &t[i+15], | ||||
| 			) | ||||
| 		} | ||||
| 		for i := 0; i < blockLength/8; i += 2 { | ||||
| 			blamkaGeneric( | ||||
| 				&t[i], &t[i+1], &t[16+i], &t[16+i+1], | ||||
| 				&t[32+i], &t[32+i+1], &t[48+i], &t[48+i+1], | ||||
| 				&t[64+i], &t[64+i+1], &t[80+i], &t[80+i+1], | ||||
| 				&t[96+i], &t[96+i+1], &t[112+i], &t[112+i+1], | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
| 	if xor { | ||||
| 		xorBlocksSSE2(out, in1, in2, &t) | ||||
| 	} else { | ||||
| 		mixBlocksSSE2(out, in1, in2, &t) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func processBlock(out, in1, in2 *block) { | ||||
| 	processBlockSSE(out, in1, in2, false) | ||||
| } | ||||
|  | ||||
| func processBlockXOR(out, in1, in2 *block) { | ||||
| 	processBlockSSE(out, in1, in2, true) | ||||
| } | ||||
							
								
								
									
										252
									
								
								vendor/golang.org/x/crypto/argon2/blamka_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								vendor/golang.org/x/crypto/argon2/blamka_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,252 @@ | ||||
| // Copyright 2017 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 amd64,!gccgo,!appengine | ||||
|  | ||||
| #include "textflag.h" | ||||
|  | ||||
| DATA ·c40<>+0x00(SB)/8, $0x0201000706050403 | ||||
| DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b | ||||
| GLOBL ·c40<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·c48<>+0x00(SB)/8, $0x0100070605040302 | ||||
| DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a | ||||
| GLOBL ·c48<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| #define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \ | ||||
| 	MOVO       v4, t1; \ | ||||
| 	MOVO       v5, v4; \ | ||||
| 	MOVO       t1, v5; \ | ||||
| 	MOVO       v6, t1; \ | ||||
| 	PUNPCKLQDQ v6, t2; \ | ||||
| 	PUNPCKHQDQ v7, v6; \ | ||||
| 	PUNPCKHQDQ t2, v6; \ | ||||
| 	PUNPCKLQDQ v7, t2; \ | ||||
| 	MOVO       t1, v7; \ | ||||
| 	MOVO       v2, t1; \ | ||||
| 	PUNPCKHQDQ t2, v7; \ | ||||
| 	PUNPCKLQDQ v3, t2; \ | ||||
| 	PUNPCKHQDQ t2, v2; \ | ||||
| 	PUNPCKLQDQ t1, t2; \ | ||||
| 	PUNPCKHQDQ t2, v3 | ||||
|  | ||||
| #define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \ | ||||
| 	MOVO       v4, t1; \ | ||||
| 	MOVO       v5, v4; \ | ||||
| 	MOVO       t1, v5; \ | ||||
| 	MOVO       v2, t1; \ | ||||
| 	PUNPCKLQDQ v2, t2; \ | ||||
| 	PUNPCKHQDQ v3, v2; \ | ||||
| 	PUNPCKHQDQ t2, v2; \ | ||||
| 	PUNPCKLQDQ v3, t2; \ | ||||
| 	MOVO       t1, v3; \ | ||||
| 	MOVO       v6, t1; \ | ||||
| 	PUNPCKHQDQ t2, v3; \ | ||||
| 	PUNPCKLQDQ v7, t2; \ | ||||
| 	PUNPCKHQDQ t2, v6; \ | ||||
| 	PUNPCKLQDQ t1, t2; \ | ||||
| 	PUNPCKHQDQ t2, v7 | ||||
|  | ||||
| #define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, t0, c40, c48) \ | ||||
| 	MOVO    v0, t0;        \ | ||||
| 	PMULULQ v2, t0;        \ | ||||
| 	PADDQ   v2, v0;        \ | ||||
| 	PADDQ   t0, v0;        \ | ||||
| 	PADDQ   t0, v0;        \ | ||||
| 	PXOR    v0, v6;        \ | ||||
| 	PSHUFD  $0xB1, v6, v6; \ | ||||
| 	MOVO    v4, t0;        \ | ||||
| 	PMULULQ v6, t0;        \ | ||||
| 	PADDQ   v6, v4;        \ | ||||
| 	PADDQ   t0, v4;        \ | ||||
| 	PADDQ   t0, v4;        \ | ||||
| 	PXOR    v4, v2;        \ | ||||
| 	PSHUFB  c40, v2;       \ | ||||
| 	MOVO    v0, t0;        \ | ||||
| 	PMULULQ v2, t0;        \ | ||||
| 	PADDQ   v2, v0;        \ | ||||
| 	PADDQ   t0, v0;        \ | ||||
| 	PADDQ   t0, v0;        \ | ||||
| 	PXOR    v0, v6;        \ | ||||
| 	PSHUFB  c48, v6;       \ | ||||
| 	MOVO    v4, t0;        \ | ||||
| 	PMULULQ v6, t0;        \ | ||||
| 	PADDQ   v6, v4;        \ | ||||
| 	PADDQ   t0, v4;        \ | ||||
| 	PADDQ   t0, v4;        \ | ||||
| 	PXOR    v4, v2;        \ | ||||
| 	MOVO    v2, t0;        \ | ||||
| 	PADDQ   v2, t0;        \ | ||||
| 	PSRLQ   $63, v2;       \ | ||||
| 	PXOR    t0, v2;        \ | ||||
| 	MOVO    v1, t0;        \ | ||||
| 	PMULULQ v3, t0;        \ | ||||
| 	PADDQ   v3, v1;        \ | ||||
| 	PADDQ   t0, v1;        \ | ||||
| 	PADDQ   t0, v1;        \ | ||||
| 	PXOR    v1, v7;        \ | ||||
| 	PSHUFD  $0xB1, v7, v7; \ | ||||
| 	MOVO    v5, t0;        \ | ||||
| 	PMULULQ v7, t0;        \ | ||||
| 	PADDQ   v7, v5;        \ | ||||
| 	PADDQ   t0, v5;        \ | ||||
| 	PADDQ   t0, v5;        \ | ||||
| 	PXOR    v5, v3;        \ | ||||
| 	PSHUFB  c40, v3;       \ | ||||
| 	MOVO    v1, t0;        \ | ||||
| 	PMULULQ v3, t0;        \ | ||||
| 	PADDQ   v3, v1;        \ | ||||
| 	PADDQ   t0, v1;        \ | ||||
| 	PADDQ   t0, v1;        \ | ||||
| 	PXOR    v1, v7;        \ | ||||
| 	PSHUFB  c48, v7;       \ | ||||
| 	MOVO    v5, t0;        \ | ||||
| 	PMULULQ v7, t0;        \ | ||||
| 	PADDQ   v7, v5;        \ | ||||
| 	PADDQ   t0, v5;        \ | ||||
| 	PADDQ   t0, v5;        \ | ||||
| 	PXOR    v5, v3;        \ | ||||
| 	MOVO    v3, t0;        \ | ||||
| 	PADDQ   v3, t0;        \ | ||||
| 	PSRLQ   $63, v3;       \ | ||||
| 	PXOR    t0, v3 | ||||
|  | ||||
| #define LOAD_MSG_0(block, off) \ | ||||
| 	MOVOU 8*(off+0)(block), X0;  \ | ||||
| 	MOVOU 8*(off+2)(block), X1;  \ | ||||
| 	MOVOU 8*(off+4)(block), X2;  \ | ||||
| 	MOVOU 8*(off+6)(block), X3;  \ | ||||
| 	MOVOU 8*(off+8)(block), X4;  \ | ||||
| 	MOVOU 8*(off+10)(block), X5; \ | ||||
| 	MOVOU 8*(off+12)(block), X6; \ | ||||
| 	MOVOU 8*(off+14)(block), X7 | ||||
|  | ||||
| #define STORE_MSG_0(block, off) \ | ||||
| 	MOVOU X0, 8*(off+0)(block);  \ | ||||
| 	MOVOU X1, 8*(off+2)(block);  \ | ||||
| 	MOVOU X2, 8*(off+4)(block);  \ | ||||
| 	MOVOU X3, 8*(off+6)(block);  \ | ||||
| 	MOVOU X4, 8*(off+8)(block);  \ | ||||
| 	MOVOU X5, 8*(off+10)(block); \ | ||||
| 	MOVOU X6, 8*(off+12)(block); \ | ||||
| 	MOVOU X7, 8*(off+14)(block) | ||||
|  | ||||
| #define LOAD_MSG_1(block, off) \ | ||||
| 	MOVOU 8*off+0*8(block), X0;  \ | ||||
| 	MOVOU 8*off+16*8(block), X1; \ | ||||
| 	MOVOU 8*off+32*8(block), X2; \ | ||||
| 	MOVOU 8*off+48*8(block), X3; \ | ||||
| 	MOVOU 8*off+64*8(block), X4; \ | ||||
| 	MOVOU 8*off+80*8(block), X5; \ | ||||
| 	MOVOU 8*off+96*8(block), X6; \ | ||||
| 	MOVOU 8*off+112*8(block), X7 | ||||
|  | ||||
| #define STORE_MSG_1(block, off) \ | ||||
| 	MOVOU X0, 8*off+0*8(block);  \ | ||||
| 	MOVOU X1, 8*off+16*8(block); \ | ||||
| 	MOVOU X2, 8*off+32*8(block); \ | ||||
| 	MOVOU X3, 8*off+48*8(block); \ | ||||
| 	MOVOU X4, 8*off+64*8(block); \ | ||||
| 	MOVOU X5, 8*off+80*8(block); \ | ||||
| 	MOVOU X6, 8*off+96*8(block); \ | ||||
| 	MOVOU X7, 8*off+112*8(block) | ||||
|  | ||||
| #define BLAMKA_ROUND_0(block, off, t0, t1, c40, c48) \ | ||||
| 	LOAD_MSG_0(block, off);                                   \ | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \ | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, t0, t1);                  \ | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \ | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, t0, t1);              \ | ||||
| 	STORE_MSG_0(block, off) | ||||
|  | ||||
| #define BLAMKA_ROUND_1(block, off, t0, t1, c40, c48) \ | ||||
| 	LOAD_MSG_1(block, off);                                   \ | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \ | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, t0, t1);                  \ | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \ | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, t0, t1);              \ | ||||
| 	STORE_MSG_1(block, off) | ||||
|  | ||||
| // func blamkaSSE4(b *block) | ||||
| TEXT ·blamkaSSE4(SB), 4, $0-8 | ||||
| 	MOVQ b+0(FP), AX | ||||
|  | ||||
| 	MOVOU ·c40<>(SB), X10 | ||||
| 	MOVOU ·c48<>(SB), X11 | ||||
|  | ||||
| 	BLAMKA_ROUND_0(AX, 0, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_0(AX, 16, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_0(AX, 32, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_0(AX, 48, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_0(AX, 64, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_0(AX, 80, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_0(AX, 96, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_0(AX, 112, X8, X9, X10, X11) | ||||
|  | ||||
| 	BLAMKA_ROUND_1(AX, 0, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_1(AX, 2, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_1(AX, 4, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_1(AX, 6, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_1(AX, 8, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_1(AX, 10, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_1(AX, 12, X8, X9, X10, X11) | ||||
| 	BLAMKA_ROUND_1(AX, 14, X8, X9, X10, X11) | ||||
| 	RET | ||||
|  | ||||
| // func mixBlocksSSE2(out, a, b, c *block) | ||||
| TEXT ·mixBlocksSSE2(SB), 4, $0-32 | ||||
| 	MOVQ out+0(FP), DX | ||||
| 	MOVQ a+8(FP), AX | ||||
| 	MOVQ b+16(FP), BX | ||||
| 	MOVQ a+24(FP), CX | ||||
| 	MOVQ $128, BP | ||||
|  | ||||
| loop: | ||||
| 	MOVOU 0(AX), X0 | ||||
| 	MOVOU 0(BX), X1 | ||||
| 	MOVOU 0(CX), X2 | ||||
| 	PXOR  X1, X0 | ||||
| 	PXOR  X2, X0 | ||||
| 	MOVOU X0, 0(DX) | ||||
| 	ADDQ  $16, AX | ||||
| 	ADDQ  $16, BX | ||||
| 	ADDQ  $16, CX | ||||
| 	ADDQ  $16, DX | ||||
| 	SUBQ  $2, BP | ||||
| 	JA    loop | ||||
| 	RET | ||||
|  | ||||
| // func xorBlocksSSE2(out, a, b, c *block) | ||||
| TEXT ·xorBlocksSSE2(SB), 4, $0-32 | ||||
| 	MOVQ out+0(FP), DX | ||||
| 	MOVQ a+8(FP), AX | ||||
| 	MOVQ b+16(FP), BX | ||||
| 	MOVQ a+24(FP), CX | ||||
| 	MOVQ $128, BP | ||||
|  | ||||
| loop: | ||||
| 	MOVOU 0(AX), X0 | ||||
| 	MOVOU 0(BX), X1 | ||||
| 	MOVOU 0(CX), X2 | ||||
| 	MOVOU 0(DX), X3 | ||||
| 	PXOR  X1, X0 | ||||
| 	PXOR  X2, X0 | ||||
| 	PXOR  X3, X0 | ||||
| 	MOVOU X0, 0(DX) | ||||
| 	ADDQ  $16, AX | ||||
| 	ADDQ  $16, BX | ||||
| 	ADDQ  $16, CX | ||||
| 	ADDQ  $16, DX | ||||
| 	SUBQ  $2, BP | ||||
| 	JA    loop | ||||
| 	RET | ||||
|  | ||||
| // func supportsSSE4() bool | ||||
| TEXT ·supportsSSE4(SB), 4, $0-1 | ||||
| 	MOVL $1, AX | ||||
| 	CPUID | ||||
| 	SHRL $19, CX       // Bit 19 indicates SSE4 support | ||||
| 	ANDL $1, CX        // CX != 0 if support SSE4 | ||||
| 	MOVB CX, ret+0(FP) | ||||
| 	RET | ||||
							
								
								
									
										163
									
								
								vendor/golang.org/x/crypto/argon2/blamka_generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								vendor/golang.org/x/crypto/argon2/blamka_generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | ||||
| // Copyright 2017 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 argon2 | ||||
|  | ||||
| var useSSE4 bool | ||||
|  | ||||
| func processBlockGeneric(out, in1, in2 *block, xor bool) { | ||||
| 	var t block | ||||
| 	for i := range t { | ||||
| 		t[i] = in1[i] ^ in2[i] | ||||
| 	} | ||||
| 	for i := 0; i < blockLength; i += 16 { | ||||
| 		blamkaGeneric( | ||||
| 			&t[i+0], &t[i+1], &t[i+2], &t[i+3], | ||||
| 			&t[i+4], &t[i+5], &t[i+6], &t[i+7], | ||||
| 			&t[i+8], &t[i+9], &t[i+10], &t[i+11], | ||||
| 			&t[i+12], &t[i+13], &t[i+14], &t[i+15], | ||||
| 		) | ||||
| 	} | ||||
| 	for i := 0; i < blockLength/8; i += 2 { | ||||
| 		blamkaGeneric( | ||||
| 			&t[i], &t[i+1], &t[16+i], &t[16+i+1], | ||||
| 			&t[32+i], &t[32+i+1], &t[48+i], &t[48+i+1], | ||||
| 			&t[64+i], &t[64+i+1], &t[80+i], &t[80+i+1], | ||||
| 			&t[96+i], &t[96+i+1], &t[112+i], &t[112+i+1], | ||||
| 		) | ||||
| 	} | ||||
| 	if xor { | ||||
| 		for i := range t { | ||||
| 			out[i] ^= in1[i] ^ in2[i] ^ t[i] | ||||
| 		} | ||||
| 	} else { | ||||
| 		for i := range t { | ||||
| 			out[i] = in1[i] ^ in2[i] ^ t[i] | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func blamkaGeneric(t00, t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15 *uint64) { | ||||
| 	v00, v01, v02, v03 := *t00, *t01, *t02, *t03 | ||||
| 	v04, v05, v06, v07 := *t04, *t05, *t06, *t07 | ||||
| 	v08, v09, v10, v11 := *t08, *t09, *t10, *t11 | ||||
| 	v12, v13, v14, v15 := *t12, *t13, *t14, *t15 | ||||
|  | ||||
| 	v00 += v04 + 2*uint64(uint32(v00))*uint64(uint32(v04)) | ||||
| 	v12 ^= v00 | ||||
| 	v12 = v12>>32 | v12<<32 | ||||
| 	v08 += v12 + 2*uint64(uint32(v08))*uint64(uint32(v12)) | ||||
| 	v04 ^= v08 | ||||
| 	v04 = v04>>24 | v04<<40 | ||||
|  | ||||
| 	v00 += v04 + 2*uint64(uint32(v00))*uint64(uint32(v04)) | ||||
| 	v12 ^= v00 | ||||
| 	v12 = v12>>16 | v12<<48 | ||||
| 	v08 += v12 + 2*uint64(uint32(v08))*uint64(uint32(v12)) | ||||
| 	v04 ^= v08 | ||||
| 	v04 = v04>>63 | v04<<1 | ||||
|  | ||||
| 	v01 += v05 + 2*uint64(uint32(v01))*uint64(uint32(v05)) | ||||
| 	v13 ^= v01 | ||||
| 	v13 = v13>>32 | v13<<32 | ||||
| 	v09 += v13 + 2*uint64(uint32(v09))*uint64(uint32(v13)) | ||||
| 	v05 ^= v09 | ||||
| 	v05 = v05>>24 | v05<<40 | ||||
|  | ||||
| 	v01 += v05 + 2*uint64(uint32(v01))*uint64(uint32(v05)) | ||||
| 	v13 ^= v01 | ||||
| 	v13 = v13>>16 | v13<<48 | ||||
| 	v09 += v13 + 2*uint64(uint32(v09))*uint64(uint32(v13)) | ||||
| 	v05 ^= v09 | ||||
| 	v05 = v05>>63 | v05<<1 | ||||
|  | ||||
| 	v02 += v06 + 2*uint64(uint32(v02))*uint64(uint32(v06)) | ||||
| 	v14 ^= v02 | ||||
| 	v14 = v14>>32 | v14<<32 | ||||
| 	v10 += v14 + 2*uint64(uint32(v10))*uint64(uint32(v14)) | ||||
| 	v06 ^= v10 | ||||
| 	v06 = v06>>24 | v06<<40 | ||||
|  | ||||
| 	v02 += v06 + 2*uint64(uint32(v02))*uint64(uint32(v06)) | ||||
| 	v14 ^= v02 | ||||
| 	v14 = v14>>16 | v14<<48 | ||||
| 	v10 += v14 + 2*uint64(uint32(v10))*uint64(uint32(v14)) | ||||
| 	v06 ^= v10 | ||||
| 	v06 = v06>>63 | v06<<1 | ||||
|  | ||||
| 	v03 += v07 + 2*uint64(uint32(v03))*uint64(uint32(v07)) | ||||
| 	v15 ^= v03 | ||||
| 	v15 = v15>>32 | v15<<32 | ||||
| 	v11 += v15 + 2*uint64(uint32(v11))*uint64(uint32(v15)) | ||||
| 	v07 ^= v11 | ||||
| 	v07 = v07>>24 | v07<<40 | ||||
|  | ||||
| 	v03 += v07 + 2*uint64(uint32(v03))*uint64(uint32(v07)) | ||||
| 	v15 ^= v03 | ||||
| 	v15 = v15>>16 | v15<<48 | ||||
| 	v11 += v15 + 2*uint64(uint32(v11))*uint64(uint32(v15)) | ||||
| 	v07 ^= v11 | ||||
| 	v07 = v07>>63 | v07<<1 | ||||
|  | ||||
| 	v00 += v05 + 2*uint64(uint32(v00))*uint64(uint32(v05)) | ||||
| 	v15 ^= v00 | ||||
| 	v15 = v15>>32 | v15<<32 | ||||
| 	v10 += v15 + 2*uint64(uint32(v10))*uint64(uint32(v15)) | ||||
| 	v05 ^= v10 | ||||
| 	v05 = v05>>24 | v05<<40 | ||||
|  | ||||
| 	v00 += v05 + 2*uint64(uint32(v00))*uint64(uint32(v05)) | ||||
| 	v15 ^= v00 | ||||
| 	v15 = v15>>16 | v15<<48 | ||||
| 	v10 += v15 + 2*uint64(uint32(v10))*uint64(uint32(v15)) | ||||
| 	v05 ^= v10 | ||||
| 	v05 = v05>>63 | v05<<1 | ||||
|  | ||||
| 	v01 += v06 + 2*uint64(uint32(v01))*uint64(uint32(v06)) | ||||
| 	v12 ^= v01 | ||||
| 	v12 = v12>>32 | v12<<32 | ||||
| 	v11 += v12 + 2*uint64(uint32(v11))*uint64(uint32(v12)) | ||||
| 	v06 ^= v11 | ||||
| 	v06 = v06>>24 | v06<<40 | ||||
|  | ||||
| 	v01 += v06 + 2*uint64(uint32(v01))*uint64(uint32(v06)) | ||||
| 	v12 ^= v01 | ||||
| 	v12 = v12>>16 | v12<<48 | ||||
| 	v11 += v12 + 2*uint64(uint32(v11))*uint64(uint32(v12)) | ||||
| 	v06 ^= v11 | ||||
| 	v06 = v06>>63 | v06<<1 | ||||
|  | ||||
| 	v02 += v07 + 2*uint64(uint32(v02))*uint64(uint32(v07)) | ||||
| 	v13 ^= v02 | ||||
| 	v13 = v13>>32 | v13<<32 | ||||
| 	v08 += v13 + 2*uint64(uint32(v08))*uint64(uint32(v13)) | ||||
| 	v07 ^= v08 | ||||
| 	v07 = v07>>24 | v07<<40 | ||||
|  | ||||
| 	v02 += v07 + 2*uint64(uint32(v02))*uint64(uint32(v07)) | ||||
| 	v13 ^= v02 | ||||
| 	v13 = v13>>16 | v13<<48 | ||||
| 	v08 += v13 + 2*uint64(uint32(v08))*uint64(uint32(v13)) | ||||
| 	v07 ^= v08 | ||||
| 	v07 = v07>>63 | v07<<1 | ||||
|  | ||||
| 	v03 += v04 + 2*uint64(uint32(v03))*uint64(uint32(v04)) | ||||
| 	v14 ^= v03 | ||||
| 	v14 = v14>>32 | v14<<32 | ||||
| 	v09 += v14 + 2*uint64(uint32(v09))*uint64(uint32(v14)) | ||||
| 	v04 ^= v09 | ||||
| 	v04 = v04>>24 | v04<<40 | ||||
|  | ||||
| 	v03 += v04 + 2*uint64(uint32(v03))*uint64(uint32(v04)) | ||||
| 	v14 ^= v03 | ||||
| 	v14 = v14>>16 | v14<<48 | ||||
| 	v09 += v14 + 2*uint64(uint32(v09))*uint64(uint32(v14)) | ||||
| 	v04 ^= v09 | ||||
| 	v04 = v04>>63 | v04<<1 | ||||
|  | ||||
| 	*t00, *t01, *t02, *t03 = v00, v01, v02, v03 | ||||
| 	*t04, *t05, *t06, *t07 = v04, v05, v06, v07 | ||||
| 	*t08, *t09, *t10, *t11 = v08, v09, v10, v11 | ||||
| 	*t12, *t13, *t14, *t15 = v12, v13, v14, v15 | ||||
| } | ||||
							
								
								
									
										15
									
								
								vendor/golang.org/x/crypto/argon2/blamka_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/golang.org/x/crypto/argon2/blamka_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| // Copyright 2017 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 !amd64 appengine gccgo | ||||
|  | ||||
| package argon2 | ||||
|  | ||||
| func processBlock(out, in1, in2 *block) { | ||||
| 	processBlockGeneric(out, in1, in2, false) | ||||
| } | ||||
|  | ||||
| func processBlockXOR(out, in1, in2 *block) { | ||||
| 	processBlockGeneric(out, in1, in2, true) | ||||
| } | ||||
							
								
								
									
										35
									
								
								vendor/golang.org/x/crypto/bcrypt/base64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/golang.org/x/crypto/bcrypt/base64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // Copyright 2011 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 bcrypt | ||||
|  | ||||
| import "encoding/base64" | ||||
|  | ||||
| const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | ||||
|  | ||||
| var bcEncoding = base64.NewEncoding(alphabet) | ||||
|  | ||||
| func base64Encode(src []byte) []byte { | ||||
| 	n := bcEncoding.EncodedLen(len(src)) | ||||
| 	dst := make([]byte, n) | ||||
| 	bcEncoding.Encode(dst, src) | ||||
| 	for dst[n-1] == '=' { | ||||
| 		n-- | ||||
| 	} | ||||
| 	return dst[:n] | ||||
| } | ||||
|  | ||||
| func base64Decode(src []byte) ([]byte, error) { | ||||
| 	numOfEquals := 4 - (len(src) % 4) | ||||
| 	for i := 0; i < numOfEquals; i++ { | ||||
| 		src = append(src, '=') | ||||
| 	} | ||||
|  | ||||
| 	dst := make([]byte, bcEncoding.DecodedLen(len(src))) | ||||
| 	n, err := bcEncoding.Decode(dst, src) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return dst[:n], nil | ||||
| } | ||||
							
								
								
									
										295
									
								
								vendor/golang.org/x/crypto/bcrypt/bcrypt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								vendor/golang.org/x/crypto/bcrypt/bcrypt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,295 @@ | ||||
| // Copyright 2011 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 bcrypt implements Provos and Mazières's bcrypt adaptive hashing | ||||
| // algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf | ||||
| package bcrypt // import "golang.org/x/crypto/bcrypt" | ||||
|  | ||||
| // The code is a port of Provos and Mazières's C implementation. | ||||
| import ( | ||||
| 	"crypto/rand" | ||||
| 	"crypto/subtle" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"golang.org/x/crypto/blowfish" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	MinCost     int = 4  // the minimum allowable cost as passed in to GenerateFromPassword | ||||
| 	MaxCost     int = 31 // the maximum allowable cost as passed in to GenerateFromPassword | ||||
| 	DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword | ||||
| ) | ||||
|  | ||||
| // The error returned from CompareHashAndPassword when a password and hash do | ||||
| // not match. | ||||
| var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password") | ||||
|  | ||||
| // The error returned from CompareHashAndPassword when a hash is too short to | ||||
| // be a bcrypt hash. | ||||
| var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password") | ||||
|  | ||||
| // The error returned from CompareHashAndPassword when a hash was created with | ||||
| // a bcrypt algorithm newer than this implementation. | ||||
| type HashVersionTooNewError byte | ||||
|  | ||||
| func (hv HashVersionTooNewError) Error() string { | ||||
| 	return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion) | ||||
| } | ||||
|  | ||||
| // The error returned from CompareHashAndPassword when a hash starts with something other than '$' | ||||
| type InvalidHashPrefixError byte | ||||
|  | ||||
| func (ih InvalidHashPrefixError) Error() string { | ||||
| 	return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih)) | ||||
| } | ||||
|  | ||||
| type InvalidCostError int | ||||
|  | ||||
| func (ic InvalidCostError) Error() string { | ||||
| 	return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost)) | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	majorVersion       = '2' | ||||
| 	minorVersion       = 'a' | ||||
| 	maxSaltSize        = 16 | ||||
| 	maxCryptedHashSize = 23 | ||||
| 	encodedSaltSize    = 22 | ||||
| 	encodedHashSize    = 31 | ||||
| 	minHashSize        = 59 | ||||
| ) | ||||
|  | ||||
| // magicCipherData is an IV for the 64 Blowfish encryption calls in | ||||
| // bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes. | ||||
| var magicCipherData = []byte{ | ||||
| 	0x4f, 0x72, 0x70, 0x68, | ||||
| 	0x65, 0x61, 0x6e, 0x42, | ||||
| 	0x65, 0x68, 0x6f, 0x6c, | ||||
| 	0x64, 0x65, 0x72, 0x53, | ||||
| 	0x63, 0x72, 0x79, 0x44, | ||||
| 	0x6f, 0x75, 0x62, 0x74, | ||||
| } | ||||
|  | ||||
| type hashed struct { | ||||
| 	hash  []byte | ||||
| 	salt  []byte | ||||
| 	cost  int // allowed range is MinCost to MaxCost | ||||
| 	major byte | ||||
| 	minor byte | ||||
| } | ||||
|  | ||||
| // GenerateFromPassword returns the bcrypt hash of the password at the given | ||||
| // cost. If the cost given is less than MinCost, the cost will be set to | ||||
| // DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, | ||||
| // to compare the returned hashed password with its cleartext version. | ||||
| func GenerateFromPassword(password []byte, cost int) ([]byte, error) { | ||||
| 	p, err := newFromPassword(password, cost) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return p.Hash(), nil | ||||
| } | ||||
|  | ||||
| // CompareHashAndPassword compares a bcrypt hashed password with its possible | ||||
| // plaintext equivalent. Returns nil on success, or an error on failure. | ||||
| func CompareHashAndPassword(hashedPassword, password []byte) error { | ||||
| 	p, err := newFromHash(hashedPassword) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	otherHash, err := bcrypt(password, p.cost, p.salt) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor} | ||||
| 	if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return ErrMismatchedHashAndPassword | ||||
| } | ||||
|  | ||||
| // Cost returns the hashing cost used to create the given hashed | ||||
| // password. When, in the future, the hashing cost of a password system needs | ||||
| // to be increased in order to adjust for greater computational power, this | ||||
| // function allows one to establish which passwords need to be updated. | ||||
| func Cost(hashedPassword []byte) (int, error) { | ||||
| 	p, err := newFromHash(hashedPassword) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return p.cost, nil | ||||
| } | ||||
|  | ||||
| func newFromPassword(password []byte, cost int) (*hashed, error) { | ||||
| 	if cost < MinCost { | ||||
| 		cost = DefaultCost | ||||
| 	} | ||||
| 	p := new(hashed) | ||||
| 	p.major = majorVersion | ||||
| 	p.minor = minorVersion | ||||
|  | ||||
| 	err := checkCost(cost) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	p.cost = cost | ||||
|  | ||||
| 	unencodedSalt := make([]byte, maxSaltSize) | ||||
| 	_, err = io.ReadFull(rand.Reader, unencodedSalt) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	p.salt = base64Encode(unencodedSalt) | ||||
| 	hash, err := bcrypt(password, p.cost, p.salt) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	p.hash = hash | ||||
| 	return p, err | ||||
| } | ||||
|  | ||||
| func newFromHash(hashedSecret []byte) (*hashed, error) { | ||||
| 	if len(hashedSecret) < minHashSize { | ||||
| 		return nil, ErrHashTooShort | ||||
| 	} | ||||
| 	p := new(hashed) | ||||
| 	n, err := p.decodeVersion(hashedSecret) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	hashedSecret = hashedSecret[n:] | ||||
| 	n, err = p.decodeCost(hashedSecret) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	hashedSecret = hashedSecret[n:] | ||||
|  | ||||
| 	// The "+2" is here because we'll have to append at most 2 '=' to the salt | ||||
| 	// when base64 decoding it in expensiveBlowfishSetup(). | ||||
| 	p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2) | ||||
| 	copy(p.salt, hashedSecret[:encodedSaltSize]) | ||||
|  | ||||
| 	hashedSecret = hashedSecret[encodedSaltSize:] | ||||
| 	p.hash = make([]byte, len(hashedSecret)) | ||||
| 	copy(p.hash, hashedSecret) | ||||
|  | ||||
| 	return p, nil | ||||
| } | ||||
|  | ||||
| func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) { | ||||
| 	cipherData := make([]byte, len(magicCipherData)) | ||||
| 	copy(cipherData, magicCipherData) | ||||
|  | ||||
| 	c, err := expensiveBlowfishSetup(password, uint32(cost), salt) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	for i := 0; i < 24; i += 8 { | ||||
| 		for j := 0; j < 64; j++ { | ||||
| 			c.Encrypt(cipherData[i:i+8], cipherData[i:i+8]) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Bug compatibility with C bcrypt implementations. We only encode 23 of | ||||
| 	// the 24 bytes encrypted. | ||||
| 	hsh := base64Encode(cipherData[:maxCryptedHashSize]) | ||||
| 	return hsh, nil | ||||
| } | ||||
|  | ||||
| func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) { | ||||
| 	csalt, err := base64Decode(salt) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// Bug compatibility with C bcrypt implementations. They use the trailing | ||||
| 	// NULL in the key string during expansion. | ||||
| 	// We copy the key to prevent changing the underlying array. | ||||
| 	ckey := append(key[:len(key):len(key)], 0) | ||||
|  | ||||
| 	c, err := blowfish.NewSaltedCipher(ckey, csalt) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var i, rounds uint64 | ||||
| 	rounds = 1 << cost | ||||
| 	for i = 0; i < rounds; i++ { | ||||
| 		blowfish.ExpandKey(ckey, c) | ||||
| 		blowfish.ExpandKey(csalt, c) | ||||
| 	} | ||||
|  | ||||
| 	return c, nil | ||||
| } | ||||
|  | ||||
| func (p *hashed) Hash() []byte { | ||||
| 	arr := make([]byte, 60) | ||||
| 	arr[0] = '$' | ||||
| 	arr[1] = p.major | ||||
| 	n := 2 | ||||
| 	if p.minor != 0 { | ||||
| 		arr[2] = p.minor | ||||
| 		n = 3 | ||||
| 	} | ||||
| 	arr[n] = '$' | ||||
| 	n++ | ||||
| 	copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost))) | ||||
| 	n += 2 | ||||
| 	arr[n] = '$' | ||||
| 	n++ | ||||
| 	copy(arr[n:], p.salt) | ||||
| 	n += encodedSaltSize | ||||
| 	copy(arr[n:], p.hash) | ||||
| 	n += encodedHashSize | ||||
| 	return arr[:n] | ||||
| } | ||||
|  | ||||
| func (p *hashed) decodeVersion(sbytes []byte) (int, error) { | ||||
| 	if sbytes[0] != '$' { | ||||
| 		return -1, InvalidHashPrefixError(sbytes[0]) | ||||
| 	} | ||||
| 	if sbytes[1] > majorVersion { | ||||
| 		return -1, HashVersionTooNewError(sbytes[1]) | ||||
| 	} | ||||
| 	p.major = sbytes[1] | ||||
| 	n := 3 | ||||
| 	if sbytes[2] != '$' { | ||||
| 		p.minor = sbytes[2] | ||||
| 		n++ | ||||
| 	} | ||||
| 	return n, nil | ||||
| } | ||||
|  | ||||
| // sbytes should begin where decodeVersion left off. | ||||
| func (p *hashed) decodeCost(sbytes []byte) (int, error) { | ||||
| 	cost, err := strconv.Atoi(string(sbytes[0:2])) | ||||
| 	if err != nil { | ||||
| 		return -1, err | ||||
| 	} | ||||
| 	err = checkCost(cost) | ||||
| 	if err != nil { | ||||
| 		return -1, err | ||||
| 	} | ||||
| 	p.cost = cost | ||||
| 	return 3, nil | ||||
| } | ||||
|  | ||||
| func (p *hashed) String() string { | ||||
| 	return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor) | ||||
| } | ||||
|  | ||||
| func checkCost(cost int) error { | ||||
| 	if cost < MinCost || cost > MaxCost { | ||||
| 		return InvalidCostError(cost) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										243
									
								
								vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,243 @@ | ||||
| // Copyright 2011 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 bcrypt | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestBcryptingIsEasy(t *testing.T) { | ||||
| 	pass := []byte("mypassword") | ||||
| 	hp, err := GenerateFromPassword(pass, 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("GenerateFromPassword error: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if CompareHashAndPassword(hp, pass) != nil { | ||||
| 		t.Errorf("%v should hash %s correctly", hp, pass) | ||||
| 	} | ||||
|  | ||||
| 	notPass := "notthepass" | ||||
| 	err = CompareHashAndPassword(hp, []byte(notPass)) | ||||
| 	if err != ErrMismatchedHashAndPassword { | ||||
| 		t.Errorf("%v and %s should be mismatched", hp, notPass) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestBcryptingIsCorrect(t *testing.T) { | ||||
| 	pass := []byte("allmine") | ||||
| 	salt := []byte("XajjQvNhvvRt5GSeFk1xFe") | ||||
| 	expectedHash := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga") | ||||
|  | ||||
| 	hash, err := bcrypt(pass, 10, salt) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("bcrypt blew up: %v", err) | ||||
| 	} | ||||
| 	if !bytes.HasSuffix(expectedHash, hash) { | ||||
| 		t.Errorf("%v should be the suffix of %v", hash, expectedHash) | ||||
| 	} | ||||
|  | ||||
| 	h, err := newFromHash(expectedHash) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Unable to parse %s: %v", string(expectedHash), err) | ||||
| 	} | ||||
|  | ||||
| 	// This is not the safe way to compare these hashes. We do this only for | ||||
| 	// testing clarity. Use bcrypt.CompareHashAndPassword() | ||||
| 	if err == nil && !bytes.Equal(expectedHash, h.Hash()) { | ||||
| 		t.Errorf("Parsed hash %v should equal %v", h.Hash(), expectedHash) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestVeryShortPasswords(t *testing.T) { | ||||
| 	key := []byte("k") | ||||
| 	salt := []byte("XajjQvNhvvRt5GSeFk1xFe") | ||||
| 	_, err := bcrypt(key, 10, salt) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("One byte key resulted in error: %s", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestTooLongPasswordsWork(t *testing.T) { | ||||
| 	salt := []byte("XajjQvNhvvRt5GSeFk1xFe") | ||||
| 	// One byte over the usual 56 byte limit that blowfish has | ||||
| 	tooLongPass := []byte("012345678901234567890123456789012345678901234567890123456") | ||||
| 	tooLongExpected := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C") | ||||
| 	hash, err := bcrypt(tooLongPass, 10, salt) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("bcrypt blew up on long password: %v", err) | ||||
| 	} | ||||
| 	if !bytes.HasSuffix(tooLongExpected, hash) { | ||||
| 		t.Errorf("%v should be the suffix of %v", hash, tooLongExpected) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type InvalidHashTest struct { | ||||
| 	err  error | ||||
| 	hash []byte | ||||
| } | ||||
|  | ||||
| var invalidTests = []InvalidHashTest{ | ||||
| 	{ErrHashTooShort, []byte("$2a$10$fooo")}, | ||||
| 	{ErrHashTooShort, []byte("$2a")}, | ||||
| 	{HashVersionTooNewError('3'), []byte("$3a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")}, | ||||
| 	{InvalidHashPrefixError('%'), []byte("%2a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")}, | ||||
| 	{InvalidCostError(32), []byte("$2a$32$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")}, | ||||
| } | ||||
|  | ||||
| func TestInvalidHashErrors(t *testing.T) { | ||||
| 	check := func(name string, expected, err error) { | ||||
| 		if err == nil { | ||||
| 			t.Errorf("%s: Should have returned an error", name) | ||||
| 		} | ||||
| 		if err != nil && err != expected { | ||||
| 			t.Errorf("%s gave err %v but should have given %v", name, err, expected) | ||||
| 		} | ||||
| 	} | ||||
| 	for _, iht := range invalidTests { | ||||
| 		_, err := newFromHash(iht.hash) | ||||
| 		check("newFromHash", iht.err, err) | ||||
| 		err = CompareHashAndPassword(iht.hash, []byte("anything")) | ||||
| 		check("CompareHashAndPassword", iht.err, err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestUnpaddedBase64Encoding(t *testing.T) { | ||||
| 	original := []byte{101, 201, 101, 75, 19, 227, 199, 20, 239, 236, 133, 32, 30, 109, 243, 30} | ||||
| 	encodedOriginal := []byte("XajjQvNhvvRt5GSeFk1xFe") | ||||
|  | ||||
| 	encoded := base64Encode(original) | ||||
|  | ||||
| 	if !bytes.Equal(encodedOriginal, encoded) { | ||||
| 		t.Errorf("Encoded %v should have equaled %v", encoded, encodedOriginal) | ||||
| 	} | ||||
|  | ||||
| 	decoded, err := base64Decode(encodedOriginal) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("base64Decode blew up: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if !bytes.Equal(decoded, original) { | ||||
| 		t.Errorf("Decoded %v should have equaled %v", decoded, original) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCost(t *testing.T) { | ||||
| 	suffix := "XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C" | ||||
| 	for _, vers := range []string{"2a", "2"} { | ||||
| 		for _, cost := range []int{4, 10} { | ||||
| 			s := fmt.Sprintf("$%s$%02d$%s", vers, cost, suffix) | ||||
| 			h := []byte(s) | ||||
| 			actual, err := Cost(h) | ||||
| 			if err != nil { | ||||
| 				t.Errorf("Cost, error: %s", err) | ||||
| 				continue | ||||
| 			} | ||||
| 			if actual != cost { | ||||
| 				t.Errorf("Cost, expected: %d, actual: %d", cost, actual) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	_, err := Cost([]byte("$a$a$" + suffix)) | ||||
| 	if err == nil { | ||||
| 		t.Errorf("Cost, malformed but no error returned") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCostValidationInHash(t *testing.T) { | ||||
| 	if testing.Short() { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	pass := []byte("mypassword") | ||||
|  | ||||
| 	for c := 0; c < MinCost; c++ { | ||||
| 		p, _ := newFromPassword(pass, c) | ||||
| 		if p.cost != DefaultCost { | ||||
| 			t.Errorf("newFromPassword should default costs below %d to %d, but was %d", MinCost, DefaultCost, p.cost) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	p, _ := newFromPassword(pass, 14) | ||||
| 	if p.cost != 14 { | ||||
| 		t.Errorf("newFromPassword should default cost to 14, but was %d", p.cost) | ||||
| 	} | ||||
|  | ||||
| 	hp, _ := newFromHash(p.Hash()) | ||||
| 	if p.cost != hp.cost { | ||||
| 		t.Errorf("newFromHash should maintain the cost at %d, but was %d", p.cost, hp.cost) | ||||
| 	} | ||||
|  | ||||
| 	_, err := newFromPassword(pass, 32) | ||||
| 	if err == nil { | ||||
| 		t.Fatalf("newFromPassword: should return a cost error") | ||||
| 	} | ||||
| 	if err != InvalidCostError(32) { | ||||
| 		t.Errorf("newFromPassword: should return cost error, got %#v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCostReturnsWithLeadingZeroes(t *testing.T) { | ||||
| 	hp, _ := newFromPassword([]byte("abcdefgh"), 7) | ||||
| 	cost := hp.Hash()[4:7] | ||||
| 	expected := []byte("07$") | ||||
|  | ||||
| 	if !bytes.Equal(expected, cost) { | ||||
| 		t.Errorf("single digit costs in hash should have leading zeros: was %v instead of %v", cost, expected) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMinorNotRequired(t *testing.T) { | ||||
| 	noMinorHash := []byte("$2$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga") | ||||
| 	h, err := newFromHash(noMinorHash) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("No minor hash blew up: %s", err) | ||||
| 	} | ||||
| 	if h.minor != 0 { | ||||
| 		t.Errorf("Should leave minor version at 0, but was %d", h.minor) | ||||
| 	} | ||||
|  | ||||
| 	if !bytes.Equal(noMinorHash, h.Hash()) { | ||||
| 		t.Errorf("Should generate hash %v, but created %v", noMinorHash, h.Hash()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkEqual(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	passwd := []byte("somepasswordyoulike") | ||||
| 	hash, _ := GenerateFromPassword(passwd, 10) | ||||
| 	b.StartTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		CompareHashAndPassword(hash, passwd) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkGeneration(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	passwd := []byte("mylongpassword1234") | ||||
| 	b.StartTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		GenerateFromPassword(passwd, 10) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // See Issue https://github.com/golang/go/issues/20425. | ||||
| func TestNoSideEffectsFromCompare(t *testing.T) { | ||||
| 	source := []byte("passw0rd123456") | ||||
| 	password := source[:len(source)-6] | ||||
| 	token := source[len(source)-6:] | ||||
| 	want := make([]byte, len(source)) | ||||
| 	copy(want, source) | ||||
|  | ||||
| 	wantHash := []byte("$2a$10$LK9XRuhNxHHCvjX3tdkRKei1QiCDUKrJRhZv7WWZPuQGRUM92rOUa") | ||||
| 	_ = CompareHashAndPassword(wantHash, password) | ||||
|  | ||||
| 	got := bytes.Join([][]byte{password, token}, []byte("")) | ||||
| 	if !bytes.Equal(got, want) { | ||||
| 		t.Errorf("got=%q want=%q", got, want) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										221
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,221 @@ | ||||
| // Copyright 2016 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 blake2b implements the BLAKE2b hash algorithm defined by RFC 7693 | ||||
| // and the extendable output function (XOF) BLAKE2Xb. | ||||
| // | ||||
| // For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf | ||||
| // and for BLAKE2Xb see https://blake2.net/blake2x.pdf | ||||
| // | ||||
| // If you aren't sure which function you need, use BLAKE2b (Sum512 or New512). | ||||
| // If you need a secret-key MAC (message authentication code), use the New512 | ||||
| // function with a non-nil key. | ||||
| // | ||||
| // BLAKE2X is a construction to compute hash values larger than 64 bytes. It | ||||
| // can produce hash values between 0 and 4 GiB. | ||||
| package blake2b | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"hash" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// The blocksize of BLAKE2b in bytes. | ||||
| 	BlockSize = 128 | ||||
| 	// The hash size of BLAKE2b-512 in bytes. | ||||
| 	Size = 64 | ||||
| 	// The hash size of BLAKE2b-384 in bytes. | ||||
| 	Size384 = 48 | ||||
| 	// The hash size of BLAKE2b-256 in bytes. | ||||
| 	Size256 = 32 | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	useAVX2 bool | ||||
| 	useAVX  bool | ||||
| 	useSSE4 bool | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	errKeySize  = errors.New("blake2b: invalid key size") | ||||
| 	errHashSize = errors.New("blake2b: invalid hash size") | ||||
| ) | ||||
|  | ||||
| var iv = [8]uint64{ | ||||
| 	0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, | ||||
| 	0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, | ||||
| } | ||||
|  | ||||
| // Sum512 returns the BLAKE2b-512 checksum of the data. | ||||
| func Sum512(data []byte) [Size]byte { | ||||
| 	var sum [Size]byte | ||||
| 	checkSum(&sum, Size, data) | ||||
| 	return sum | ||||
| } | ||||
|  | ||||
| // Sum384 returns the BLAKE2b-384 checksum of the data. | ||||
| func Sum384(data []byte) [Size384]byte { | ||||
| 	var sum [Size]byte | ||||
| 	var sum384 [Size384]byte | ||||
| 	checkSum(&sum, Size384, data) | ||||
| 	copy(sum384[:], sum[:Size384]) | ||||
| 	return sum384 | ||||
| } | ||||
|  | ||||
| // Sum256 returns the BLAKE2b-256 checksum of the data. | ||||
| func Sum256(data []byte) [Size256]byte { | ||||
| 	var sum [Size]byte | ||||
| 	var sum256 [Size256]byte | ||||
| 	checkSum(&sum, Size256, data) | ||||
| 	copy(sum256[:], sum[:Size256]) | ||||
| 	return sum256 | ||||
| } | ||||
|  | ||||
| // New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil | ||||
| // key turns the hash into a MAC. The key must between zero and 64 bytes long. | ||||
| func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) } | ||||
|  | ||||
| // New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil | ||||
| // key turns the hash into a MAC. The key must between zero and 64 bytes long. | ||||
| func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) } | ||||
|  | ||||
| // New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil | ||||
| // key turns the hash into a MAC. The key must between zero and 64 bytes long. | ||||
| func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) } | ||||
|  | ||||
| // New returns a new hash.Hash computing the BLAKE2b checksum with a custom length. | ||||
| // A non-nil key turns the hash into a MAC. The key must between zero and 64 bytes long. | ||||
| // The hash size can be a value between 1 and 64 but it is highly recommended to use | ||||
| // values equal or greater than: | ||||
| // - 32 if BLAKE2b is used as a hash function (The key is zero bytes long). | ||||
| // - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long). | ||||
| func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) } | ||||
|  | ||||
| func newDigest(hashSize int, key []byte) (*digest, error) { | ||||
| 	if hashSize < 1 || hashSize > Size { | ||||
| 		return nil, errHashSize | ||||
| 	} | ||||
| 	if len(key) > Size { | ||||
| 		return nil, errKeySize | ||||
| 	} | ||||
| 	d := &digest{ | ||||
| 		size:   hashSize, | ||||
| 		keyLen: len(key), | ||||
| 	} | ||||
| 	copy(d.key[:], key) | ||||
| 	d.Reset() | ||||
| 	return d, nil | ||||
| } | ||||
|  | ||||
| func checkSum(sum *[Size]byte, hashSize int, data []byte) { | ||||
| 	h := iv | ||||
| 	h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24) | ||||
| 	var c [2]uint64 | ||||
|  | ||||
| 	if length := len(data); length > BlockSize { | ||||
| 		n := length &^ (BlockSize - 1) | ||||
| 		if length == n { | ||||
| 			n -= BlockSize | ||||
| 		} | ||||
| 		hashBlocks(&h, &c, 0, data[:n]) | ||||
| 		data = data[n:] | ||||
| 	} | ||||
|  | ||||
| 	var block [BlockSize]byte | ||||
| 	offset := copy(block[:], data) | ||||
| 	remaining := uint64(BlockSize - offset) | ||||
| 	if c[0] < remaining { | ||||
| 		c[1]-- | ||||
| 	} | ||||
| 	c[0] -= remaining | ||||
|  | ||||
| 	hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) | ||||
|  | ||||
| 	for i, v := range h[:(hashSize+7)/8] { | ||||
| 		binary.LittleEndian.PutUint64(sum[8*i:], v) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type digest struct { | ||||
| 	h      [8]uint64 | ||||
| 	c      [2]uint64 | ||||
| 	size   int | ||||
| 	block  [BlockSize]byte | ||||
| 	offset int | ||||
|  | ||||
| 	key    [BlockSize]byte | ||||
| 	keyLen int | ||||
| } | ||||
|  | ||||
| func (d *digest) BlockSize() int { return BlockSize } | ||||
|  | ||||
| func (d *digest) Size() int { return d.size } | ||||
|  | ||||
| func (d *digest) Reset() { | ||||
| 	d.h = iv | ||||
| 	d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24) | ||||
| 	d.offset, d.c[0], d.c[1] = 0, 0, 0 | ||||
| 	if d.keyLen > 0 { | ||||
| 		d.block = d.key | ||||
| 		d.offset = BlockSize | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (d *digest) Write(p []byte) (n int, err error) { | ||||
| 	n = len(p) | ||||
|  | ||||
| 	if d.offset > 0 { | ||||
| 		remaining := BlockSize - d.offset | ||||
| 		if n <= remaining { | ||||
| 			d.offset += copy(d.block[d.offset:], p) | ||||
| 			return | ||||
| 		} | ||||
| 		copy(d.block[d.offset:], p[:remaining]) | ||||
| 		hashBlocks(&d.h, &d.c, 0, d.block[:]) | ||||
| 		d.offset = 0 | ||||
| 		p = p[remaining:] | ||||
| 	} | ||||
|  | ||||
| 	if length := len(p); length > BlockSize { | ||||
| 		nn := length &^ (BlockSize - 1) | ||||
| 		if length == nn { | ||||
| 			nn -= BlockSize | ||||
| 		} | ||||
| 		hashBlocks(&d.h, &d.c, 0, p[:nn]) | ||||
| 		p = p[nn:] | ||||
| 	} | ||||
|  | ||||
| 	if len(p) > 0 { | ||||
| 		d.offset += copy(d.block[:], p) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (d *digest) Sum(sum []byte) []byte { | ||||
| 	var hash [Size]byte | ||||
| 	d.finalize(&hash) | ||||
| 	return append(sum, hash[:d.size]...) | ||||
| } | ||||
|  | ||||
| func (d *digest) finalize(hash *[Size]byte) { | ||||
| 	var block [BlockSize]byte | ||||
| 	copy(block[:], d.block[:d.offset]) | ||||
| 	remaining := uint64(BlockSize - d.offset) | ||||
|  | ||||
| 	c := d.c | ||||
| 	if c[0] < remaining { | ||||
| 		c[1]-- | ||||
| 	} | ||||
| 	c[0] -= remaining | ||||
|  | ||||
| 	h := d.h | ||||
| 	hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) | ||||
|  | ||||
| 	for i, v := range h { | ||||
| 		binary.LittleEndian.PutUint64(hash[8*i:], v) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										43
									
								
								vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| // Copyright 2016 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build go1.7,amd64,!gccgo,!appengine | ||||
|  | ||||
| package blake2b | ||||
|  | ||||
| func init() { | ||||
| 	useAVX2 = supportsAVX2() | ||||
| 	useAVX = supportsAVX() | ||||
| 	useSSE4 = supportsSSE4() | ||||
| } | ||||
|  | ||||
| //go:noescape | ||||
| func supportsSSE4() bool | ||||
|  | ||||
| //go:noescape | ||||
| func supportsAVX() bool | ||||
|  | ||||
| //go:noescape | ||||
| func supportsAVX2() bool | ||||
|  | ||||
| //go:noescape | ||||
| func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) | ||||
|  | ||||
| //go:noescape | ||||
| func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) | ||||
|  | ||||
| //go:noescape | ||||
| func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) | ||||
|  | ||||
| func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { | ||||
| 	if useAVX2 { | ||||
| 		hashBlocksAVX2(h, c, flag, blocks) | ||||
| 	} else if useAVX { | ||||
| 		hashBlocksAVX(h, c, flag, blocks) | ||||
| 	} else if useSSE4 { | ||||
| 		hashBlocksSSE4(h, c, flag, blocks) | ||||
| 	} else { | ||||
| 		hashBlocksGeneric(h, c, flag, blocks) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										762
									
								
								vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										762
									
								
								vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,762 @@ | ||||
| // Copyright 2016 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build go1.7,amd64,!gccgo,!appengine | ||||
|  | ||||
| #include "textflag.h" | ||||
|  | ||||
| DATA ·AVX2_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 | ||||
| DATA ·AVX2_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b | ||||
| DATA ·AVX2_iv0<>+0x10(SB)/8, $0x3c6ef372fe94f82b | ||||
| DATA ·AVX2_iv0<>+0x18(SB)/8, $0xa54ff53a5f1d36f1 | ||||
| GLOBL ·AVX2_iv0<>(SB), (NOPTR+RODATA), $32 | ||||
|  | ||||
| DATA ·AVX2_iv1<>+0x00(SB)/8, $0x510e527fade682d1 | ||||
| DATA ·AVX2_iv1<>+0x08(SB)/8, $0x9b05688c2b3e6c1f | ||||
| DATA ·AVX2_iv1<>+0x10(SB)/8, $0x1f83d9abfb41bd6b | ||||
| DATA ·AVX2_iv1<>+0x18(SB)/8, $0x5be0cd19137e2179 | ||||
| GLOBL ·AVX2_iv1<>(SB), (NOPTR+RODATA), $32 | ||||
|  | ||||
| DATA ·AVX2_c40<>+0x00(SB)/8, $0x0201000706050403 | ||||
| DATA ·AVX2_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b | ||||
| DATA ·AVX2_c40<>+0x10(SB)/8, $0x0201000706050403 | ||||
| DATA ·AVX2_c40<>+0x18(SB)/8, $0x0a09080f0e0d0c0b | ||||
| GLOBL ·AVX2_c40<>(SB), (NOPTR+RODATA), $32 | ||||
|  | ||||
| DATA ·AVX2_c48<>+0x00(SB)/8, $0x0100070605040302 | ||||
| DATA ·AVX2_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a | ||||
| DATA ·AVX2_c48<>+0x10(SB)/8, $0x0100070605040302 | ||||
| DATA ·AVX2_c48<>+0x18(SB)/8, $0x09080f0e0d0c0b0a | ||||
| GLOBL ·AVX2_c48<>(SB), (NOPTR+RODATA), $32 | ||||
|  | ||||
| DATA ·AVX_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 | ||||
| DATA ·AVX_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b | ||||
| GLOBL ·AVX_iv0<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·AVX_iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b | ||||
| DATA ·AVX_iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 | ||||
| GLOBL ·AVX_iv1<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·AVX_iv2<>+0x00(SB)/8, $0x510e527fade682d1 | ||||
| DATA ·AVX_iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f | ||||
| GLOBL ·AVX_iv2<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·AVX_iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b | ||||
| DATA ·AVX_iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 | ||||
| GLOBL ·AVX_iv3<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·AVX_c40<>+0x00(SB)/8, $0x0201000706050403 | ||||
| DATA ·AVX_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b | ||||
| GLOBL ·AVX_c40<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302 | ||||
| DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a | ||||
| GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| #define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39 | ||||
| #define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93 | ||||
| #define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e | ||||
| #define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93 | ||||
| #define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39 | ||||
|  | ||||
| #define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \ | ||||
| 	VPADDQ  m0, Y0, Y0;   \ | ||||
| 	VPADDQ  Y1, Y0, Y0;   \ | ||||
| 	VPXOR   Y0, Y3, Y3;   \ | ||||
| 	VPSHUFD $-79, Y3, Y3; \ | ||||
| 	VPADDQ  Y3, Y2, Y2;   \ | ||||
| 	VPXOR   Y2, Y1, Y1;   \ | ||||
| 	VPSHUFB c40, Y1, Y1;  \ | ||||
| 	VPADDQ  m1, Y0, Y0;   \ | ||||
| 	VPADDQ  Y1, Y0, Y0;   \ | ||||
| 	VPXOR   Y0, Y3, Y3;   \ | ||||
| 	VPSHUFB c48, Y3, Y3;  \ | ||||
| 	VPADDQ  Y3, Y2, Y2;   \ | ||||
| 	VPXOR   Y2, Y1, Y1;   \ | ||||
| 	VPADDQ  Y1, Y1, t;    \ | ||||
| 	VPSRLQ  $63, Y1, Y1;  \ | ||||
| 	VPXOR   t, Y1, Y1;    \ | ||||
| 	VPERMQ_0x39_Y1_Y1;    \ | ||||
| 	VPERMQ_0x4E_Y2_Y2;    \ | ||||
| 	VPERMQ_0x93_Y3_Y3;    \ | ||||
| 	VPADDQ  m2, Y0, Y0;   \ | ||||
| 	VPADDQ  Y1, Y0, Y0;   \ | ||||
| 	VPXOR   Y0, Y3, Y3;   \ | ||||
| 	VPSHUFD $-79, Y3, Y3; \ | ||||
| 	VPADDQ  Y3, Y2, Y2;   \ | ||||
| 	VPXOR   Y2, Y1, Y1;   \ | ||||
| 	VPSHUFB c40, Y1, Y1;  \ | ||||
| 	VPADDQ  m3, Y0, Y0;   \ | ||||
| 	VPADDQ  Y1, Y0, Y0;   \ | ||||
| 	VPXOR   Y0, Y3, Y3;   \ | ||||
| 	VPSHUFB c48, Y3, Y3;  \ | ||||
| 	VPADDQ  Y3, Y2, Y2;   \ | ||||
| 	VPXOR   Y2, Y1, Y1;   \ | ||||
| 	VPADDQ  Y1, Y1, t;    \ | ||||
| 	VPSRLQ  $63, Y1, Y1;  \ | ||||
| 	VPXOR   t, Y1, Y1;    \ | ||||
| 	VPERMQ_0x39_Y3_Y3;    \ | ||||
| 	VPERMQ_0x4E_Y2_Y2;    \ | ||||
| 	VPERMQ_0x93_Y1_Y1 | ||||
|  | ||||
| #define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E | ||||
| #define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26 | ||||
| #define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E | ||||
| #define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36 | ||||
| #define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E | ||||
|  | ||||
| #define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n | ||||
| #define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n | ||||
| #define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n | ||||
| #define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n | ||||
| #define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n | ||||
|  | ||||
| #define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01 | ||||
| #define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01 | ||||
| #define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01 | ||||
| #define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01 | ||||
| #define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01 | ||||
|  | ||||
| #define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01 | ||||
| #define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01 | ||||
| #define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01 | ||||
| #define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01 | ||||
| #define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01 | ||||
|  | ||||
| #define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8 | ||||
| #define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01 | ||||
|  | ||||
| // load msg: Y12 = (i0, i1, i2, i3) | ||||
| // i0, i1, i2, i3 must not be 0 | ||||
| #define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \ | ||||
| 	VMOVQ_SI_X12(i0*8);           \ | ||||
| 	VMOVQ_SI_X11(i2*8);           \ | ||||
| 	VPINSRQ_1_SI_X12(i1*8);       \ | ||||
| 	VPINSRQ_1_SI_X11(i3*8);       \ | ||||
| 	VINSERTI128 $1, X11, Y12, Y12 | ||||
|  | ||||
| // load msg: Y13 = (i0, i1, i2, i3) | ||||
| // i0, i1, i2, i3 must not be 0 | ||||
| #define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \ | ||||
| 	VMOVQ_SI_X13(i0*8);           \ | ||||
| 	VMOVQ_SI_X11(i2*8);           \ | ||||
| 	VPINSRQ_1_SI_X13(i1*8);       \ | ||||
| 	VPINSRQ_1_SI_X11(i3*8);       \ | ||||
| 	VINSERTI128 $1, X11, Y13, Y13 | ||||
|  | ||||
| // load msg: Y14 = (i0, i1, i2, i3) | ||||
| // i0, i1, i2, i3 must not be 0 | ||||
| #define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \ | ||||
| 	VMOVQ_SI_X14(i0*8);           \ | ||||
| 	VMOVQ_SI_X11(i2*8);           \ | ||||
| 	VPINSRQ_1_SI_X14(i1*8);       \ | ||||
| 	VPINSRQ_1_SI_X11(i3*8);       \ | ||||
| 	VINSERTI128 $1, X11, Y14, Y14 | ||||
|  | ||||
| // load msg: Y15 = (i0, i1, i2, i3) | ||||
| // i0, i1, i2, i3 must not be 0 | ||||
| #define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \ | ||||
| 	VMOVQ_SI_X15(i0*8);           \ | ||||
| 	VMOVQ_SI_X11(i2*8);           \ | ||||
| 	VPINSRQ_1_SI_X15(i1*8);       \ | ||||
| 	VPINSRQ_1_SI_X11(i3*8);       \ | ||||
| 	VINSERTI128 $1, X11, Y15, Y15 | ||||
|  | ||||
| #define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \ | ||||
| 	VMOVQ_SI_X12_0;                   \ | ||||
| 	VMOVQ_SI_X11(4*8);                \ | ||||
| 	VPINSRQ_1_SI_X12(2*8);            \ | ||||
| 	VPINSRQ_1_SI_X11(6*8);            \ | ||||
| 	VINSERTI128 $1, X11, Y12, Y12;    \ | ||||
| 	LOAD_MSG_AVX2_Y13(1, 3, 5, 7);    \ | ||||
| 	LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \ | ||||
| 	LOAD_MSG_AVX2_Y15(9, 11, 13, 15) | ||||
|  | ||||
| #define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \ | ||||
| 	LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \ | ||||
| 	LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \ | ||||
| 	VMOVQ_SI_X11(11*8);              \ | ||||
| 	VPSHUFD     $0x4E, 0*8(SI), X14; \ | ||||
| 	VPINSRQ_1_SI_X11(5*8);           \ | ||||
| 	VINSERTI128 $1, X11, Y14, Y14;   \ | ||||
| 	LOAD_MSG_AVX2_Y15(12, 2, 7, 3) | ||||
|  | ||||
| #define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \ | ||||
| 	VMOVQ_SI_X11(5*8);              \ | ||||
| 	VMOVDQU     11*8(SI), X12;      \ | ||||
| 	VPINSRQ_1_SI_X11(15*8);         \ | ||||
| 	VINSERTI128 $1, X11, Y12, Y12;  \ | ||||
| 	VMOVQ_SI_X13(8*8);              \ | ||||
| 	VMOVQ_SI_X11(2*8);              \ | ||||
| 	VPINSRQ_1_SI_X13_0;             \ | ||||
| 	VPINSRQ_1_SI_X11(13*8);         \ | ||||
| 	VINSERTI128 $1, X11, Y13, Y13;  \ | ||||
| 	LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \ | ||||
| 	LOAD_MSG_AVX2_Y15(14, 6, 1, 4) | ||||
|  | ||||
| #define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \ | ||||
| 	LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \ | ||||
| 	LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \ | ||||
| 	LOAD_MSG_AVX2_Y14(2, 5, 4, 15);  \ | ||||
| 	VMOVQ_SI_X15(6*8);               \ | ||||
| 	VMOVQ_SI_X11_0;                  \ | ||||
| 	VPINSRQ_1_SI_X15(10*8);          \ | ||||
| 	VPINSRQ_1_SI_X11(8*8);           \ | ||||
| 	VINSERTI128 $1, X11, Y15, Y15 | ||||
|  | ||||
| #define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \ | ||||
| 	LOAD_MSG_AVX2_Y12(9, 5, 2, 10);  \ | ||||
| 	VMOVQ_SI_X13_0;                  \ | ||||
| 	VMOVQ_SI_X11(4*8);               \ | ||||
| 	VPINSRQ_1_SI_X13(7*8);           \ | ||||
| 	VPINSRQ_1_SI_X11(15*8);          \ | ||||
| 	VINSERTI128 $1, X11, Y13, Y13;   \ | ||||
| 	LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \ | ||||
| 	LOAD_MSG_AVX2_Y15(1, 12, 8, 13) | ||||
|  | ||||
| #define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \ | ||||
| 	VMOVQ_SI_X12(2*8);                \ | ||||
| 	VMOVQ_SI_X11_0;                   \ | ||||
| 	VPINSRQ_1_SI_X12(6*8);            \ | ||||
| 	VPINSRQ_1_SI_X11(8*8);            \ | ||||
| 	VINSERTI128 $1, X11, Y12, Y12;    \ | ||||
| 	LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \ | ||||
| 	LOAD_MSG_AVX2_Y14(4, 7, 15, 1);   \ | ||||
| 	LOAD_MSG_AVX2_Y15(13, 5, 14, 9) | ||||
|  | ||||
| #define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \ | ||||
| 	LOAD_MSG_AVX2_Y12(12, 1, 14, 4);  \ | ||||
| 	LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \ | ||||
| 	VMOVQ_SI_X14_0;                   \ | ||||
| 	VPSHUFD     $0x4E, 8*8(SI), X11;  \ | ||||
| 	VPINSRQ_1_SI_X14(6*8);            \ | ||||
| 	VINSERTI128 $1, X11, Y14, Y14;    \ | ||||
| 	LOAD_MSG_AVX2_Y15(7, 3, 2, 11) | ||||
|  | ||||
| #define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \ | ||||
| 	LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \ | ||||
| 	LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \ | ||||
| 	LOAD_MSG_AVX2_Y14(5, 15, 8, 2);  \ | ||||
| 	VMOVQ_SI_X15_0;                  \ | ||||
| 	VMOVQ_SI_X11(6*8);               \ | ||||
| 	VPINSRQ_1_SI_X15(4*8);           \ | ||||
| 	VPINSRQ_1_SI_X11(10*8);          \ | ||||
| 	VINSERTI128 $1, X11, Y15, Y15 | ||||
|  | ||||
| #define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \ | ||||
| 	VMOVQ_SI_X12(6*8);              \ | ||||
| 	VMOVQ_SI_X11(11*8);             \ | ||||
| 	VPINSRQ_1_SI_X12(14*8);         \ | ||||
| 	VPINSRQ_1_SI_X11_0;             \ | ||||
| 	VINSERTI128 $1, X11, Y12, Y12;  \ | ||||
| 	LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \ | ||||
| 	VMOVQ_SI_X11(1*8);              \ | ||||
| 	VMOVDQU     12*8(SI), X14;      \ | ||||
| 	VPINSRQ_1_SI_X11(10*8);         \ | ||||
| 	VINSERTI128 $1, X11, Y14, Y14;  \ | ||||
| 	VMOVQ_SI_X15(2*8);              \ | ||||
| 	VMOVDQU     4*8(SI), X11;       \ | ||||
| 	VPINSRQ_1_SI_X15(7*8);          \ | ||||
| 	VINSERTI128 $1, X11, Y15, Y15 | ||||
|  | ||||
| #define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \ | ||||
| 	LOAD_MSG_AVX2_Y12(10, 8, 7, 1);  \ | ||||
| 	VMOVQ_SI_X13(2*8);               \ | ||||
| 	VPSHUFD     $0x4E, 5*8(SI), X11; \ | ||||
| 	VPINSRQ_1_SI_X13(4*8);           \ | ||||
| 	VINSERTI128 $1, X11, Y13, Y13;   \ | ||||
| 	LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \ | ||||
| 	VMOVQ_SI_X15(11*8);              \ | ||||
| 	VMOVQ_SI_X11(12*8);              \ | ||||
| 	VPINSRQ_1_SI_X15(14*8);          \ | ||||
| 	VPINSRQ_1_SI_X11_0;              \ | ||||
| 	VINSERTI128 $1, X11, Y15, Y15 | ||||
|  | ||||
| // func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) | ||||
| TEXT ·hashBlocksAVX2(SB), 4, $320-48 // frame size = 288 + 32 byte alignment | ||||
| 	MOVQ h+0(FP), AX | ||||
| 	MOVQ c+8(FP), BX | ||||
| 	MOVQ flag+16(FP), CX | ||||
| 	MOVQ blocks_base+24(FP), SI | ||||
| 	MOVQ blocks_len+32(FP), DI | ||||
|  | ||||
| 	MOVQ SP, DX | ||||
| 	MOVQ SP, R9 | ||||
| 	ADDQ $31, R9 | ||||
| 	ANDQ $~31, R9 | ||||
| 	MOVQ R9, SP | ||||
|  | ||||
| 	MOVQ CX, 16(SP) | ||||
| 	XORQ CX, CX | ||||
| 	MOVQ CX, 24(SP) | ||||
|  | ||||
| 	VMOVDQU ·AVX2_c40<>(SB), Y4 | ||||
| 	VMOVDQU ·AVX2_c48<>(SB), Y5 | ||||
|  | ||||
| 	VMOVDQU 0(AX), Y8 | ||||
| 	VMOVDQU 32(AX), Y9 | ||||
| 	VMOVDQU ·AVX2_iv0<>(SB), Y6 | ||||
| 	VMOVDQU ·AVX2_iv1<>(SB), Y7 | ||||
|  | ||||
| 	MOVQ 0(BX), R8 | ||||
| 	MOVQ 8(BX), R9 | ||||
| 	MOVQ R9, 8(SP) | ||||
|  | ||||
| loop: | ||||
| 	ADDQ $128, R8 | ||||
| 	MOVQ R8, 0(SP) | ||||
| 	CMPQ R8, $128 | ||||
| 	JGE  noinc | ||||
| 	INCQ R9 | ||||
| 	MOVQ R9, 8(SP) | ||||
|  | ||||
| noinc: | ||||
| 	VMOVDQA Y8, Y0 | ||||
| 	VMOVDQA Y9, Y1 | ||||
| 	VMOVDQA Y6, Y2 | ||||
| 	VPXOR   0(SP), Y7, Y3 | ||||
|  | ||||
| 	LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() | ||||
| 	VMOVDQA Y12, 32(SP) | ||||
| 	VMOVDQA Y13, 64(SP) | ||||
| 	VMOVDQA Y14, 96(SP) | ||||
| 	VMOVDQA Y15, 128(SP) | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
| 	LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() | ||||
| 	VMOVDQA Y12, 160(SP) | ||||
| 	VMOVDQA Y13, 192(SP) | ||||
| 	VMOVDQA Y14, 224(SP) | ||||
| 	VMOVDQA Y15, 256(SP) | ||||
|  | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
| 	LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
| 	LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
| 	LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
| 	LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
| 	LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
| 	LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
| 	LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
| 	LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() | ||||
| 	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) | ||||
|  | ||||
| 	ROUND_AVX2(32(SP), 64(SP), 96(SP), 128(SP), Y10, Y4, Y5) | ||||
| 	ROUND_AVX2(160(SP), 192(SP), 224(SP), 256(SP), Y10, Y4, Y5) | ||||
|  | ||||
| 	VPXOR Y0, Y8, Y8 | ||||
| 	VPXOR Y1, Y9, Y9 | ||||
| 	VPXOR Y2, Y8, Y8 | ||||
| 	VPXOR Y3, Y9, Y9 | ||||
|  | ||||
| 	LEAQ 128(SI), SI | ||||
| 	SUBQ $128, DI | ||||
| 	JNE  loop | ||||
|  | ||||
| 	MOVQ R8, 0(BX) | ||||
| 	MOVQ R9, 8(BX) | ||||
|  | ||||
| 	VMOVDQU Y8, 0(AX) | ||||
| 	VMOVDQU Y9, 32(AX) | ||||
| 	VZEROUPPER | ||||
|  | ||||
| 	MOVQ DX, SP | ||||
| 	RET | ||||
|  | ||||
| #define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA | ||||
| #define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB | ||||
| #define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF | ||||
| #define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD | ||||
| #define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE | ||||
|  | ||||
| #define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7 | ||||
| #define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF | ||||
| #define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7 | ||||
| #define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF | ||||
| #define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7 | ||||
| #define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7 | ||||
| #define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF | ||||
| #define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF | ||||
|  | ||||
| #define SHUFFLE_AVX() \ | ||||
| 	VMOVDQA X6, X13;         \ | ||||
| 	VMOVDQA X2, X14;         \ | ||||
| 	VMOVDQA X4, X6;          \ | ||||
| 	VPUNPCKLQDQ_X13_X13_X15; \ | ||||
| 	VMOVDQA X5, X4;          \ | ||||
| 	VMOVDQA X6, X5;          \ | ||||
| 	VPUNPCKHQDQ_X15_X7_X6;   \ | ||||
| 	VPUNPCKLQDQ_X7_X7_X15;   \ | ||||
| 	VPUNPCKHQDQ_X15_X13_X7;  \ | ||||
| 	VPUNPCKLQDQ_X3_X3_X15;   \ | ||||
| 	VPUNPCKHQDQ_X15_X2_X2;   \ | ||||
| 	VPUNPCKLQDQ_X14_X14_X15; \ | ||||
| 	VPUNPCKHQDQ_X15_X3_X3;   \ | ||||
|  | ||||
| #define SHUFFLE_AVX_INV() \ | ||||
| 	VMOVDQA X2, X13;         \ | ||||
| 	VMOVDQA X4, X14;         \ | ||||
| 	VPUNPCKLQDQ_X2_X2_X15;   \ | ||||
| 	VMOVDQA X5, X4;          \ | ||||
| 	VPUNPCKHQDQ_X15_X3_X2;   \ | ||||
| 	VMOVDQA X14, X5;         \ | ||||
| 	VPUNPCKLQDQ_X3_X3_X15;   \ | ||||
| 	VMOVDQA X6, X14;         \ | ||||
| 	VPUNPCKHQDQ_X15_X13_X3;  \ | ||||
| 	VPUNPCKLQDQ_X7_X7_X15;   \ | ||||
| 	VPUNPCKHQDQ_X15_X6_X6;   \ | ||||
| 	VPUNPCKLQDQ_X14_X14_X15; \ | ||||
| 	VPUNPCKHQDQ_X15_X7_X7;   \ | ||||
|  | ||||
| #define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ | ||||
| 	VPADDQ  m0, v0, v0;   \ | ||||
| 	VPADDQ  v2, v0, v0;   \ | ||||
| 	VPADDQ  m1, v1, v1;   \ | ||||
| 	VPADDQ  v3, v1, v1;   \ | ||||
| 	VPXOR   v0, v6, v6;   \ | ||||
| 	VPXOR   v1, v7, v7;   \ | ||||
| 	VPSHUFD $-79, v6, v6; \ | ||||
| 	VPSHUFD $-79, v7, v7; \ | ||||
| 	VPADDQ  v6, v4, v4;   \ | ||||
| 	VPADDQ  v7, v5, v5;   \ | ||||
| 	VPXOR   v4, v2, v2;   \ | ||||
| 	VPXOR   v5, v3, v3;   \ | ||||
| 	VPSHUFB c40, v2, v2;  \ | ||||
| 	VPSHUFB c40, v3, v3;  \ | ||||
| 	VPADDQ  m2, v0, v0;   \ | ||||
| 	VPADDQ  v2, v0, v0;   \ | ||||
| 	VPADDQ  m3, v1, v1;   \ | ||||
| 	VPADDQ  v3, v1, v1;   \ | ||||
| 	VPXOR   v0, v6, v6;   \ | ||||
| 	VPXOR   v1, v7, v7;   \ | ||||
| 	VPSHUFB c48, v6, v6;  \ | ||||
| 	VPSHUFB c48, v7, v7;  \ | ||||
| 	VPADDQ  v6, v4, v4;   \ | ||||
| 	VPADDQ  v7, v5, v5;   \ | ||||
| 	VPXOR   v4, v2, v2;   \ | ||||
| 	VPXOR   v5, v3, v3;   \ | ||||
| 	VPADDQ  v2, v2, t0;   \ | ||||
| 	VPSRLQ  $63, v2, v2;  \ | ||||
| 	VPXOR   t0, v2, v2;   \ | ||||
| 	VPADDQ  v3, v3, t0;   \ | ||||
| 	VPSRLQ  $63, v3, v3;  \ | ||||
| 	VPXOR   t0, v3, v3 | ||||
|  | ||||
| // load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7) | ||||
| // i0, i1, i2, i3, i4, i5, i6, i7 must not be 0 | ||||
| #define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \ | ||||
| 	VMOVQ_SI_X12(i0*8);     \ | ||||
| 	VMOVQ_SI_X13(i2*8);     \ | ||||
| 	VMOVQ_SI_X14(i4*8);     \ | ||||
| 	VMOVQ_SI_X15(i6*8);     \ | ||||
| 	VPINSRQ_1_SI_X12(i1*8); \ | ||||
| 	VPINSRQ_1_SI_X13(i3*8); \ | ||||
| 	VPINSRQ_1_SI_X14(i5*8); \ | ||||
| 	VPINSRQ_1_SI_X15(i7*8) | ||||
|  | ||||
| // load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7) | ||||
| #define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \ | ||||
| 	VMOVQ_SI_X12_0;        \ | ||||
| 	VMOVQ_SI_X13(4*8);     \ | ||||
| 	VMOVQ_SI_X14(1*8);     \ | ||||
| 	VMOVQ_SI_X15(5*8);     \ | ||||
| 	VPINSRQ_1_SI_X12(2*8); \ | ||||
| 	VPINSRQ_1_SI_X13(6*8); \ | ||||
| 	VPINSRQ_1_SI_X14(3*8); \ | ||||
| 	VPINSRQ_1_SI_X15(7*8) | ||||
|  | ||||
| // load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3) | ||||
| #define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \ | ||||
| 	VPSHUFD $0x4E, 0*8(SI), X12; \ | ||||
| 	VMOVQ_SI_X13(11*8);          \ | ||||
| 	VMOVQ_SI_X14(12*8);          \ | ||||
| 	VMOVQ_SI_X15(7*8);           \ | ||||
| 	VPINSRQ_1_SI_X13(5*8);       \ | ||||
| 	VPINSRQ_1_SI_X14(2*8);       \ | ||||
| 	VPINSRQ_1_SI_X15(3*8) | ||||
|  | ||||
| // load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13) | ||||
| #define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \ | ||||
| 	VMOVDQU 11*8(SI), X12;  \ | ||||
| 	VMOVQ_SI_X13(5*8);      \ | ||||
| 	VMOVQ_SI_X14(8*8);      \ | ||||
| 	VMOVQ_SI_X15(2*8);      \ | ||||
| 	VPINSRQ_1_SI_X13(15*8); \ | ||||
| 	VPINSRQ_1_SI_X14_0;     \ | ||||
| 	VPINSRQ_1_SI_X15(13*8) | ||||
|  | ||||
| // load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8) | ||||
| #define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \ | ||||
| 	VMOVQ_SI_X12(2*8);      \ | ||||
| 	VMOVQ_SI_X13(4*8);      \ | ||||
| 	VMOVQ_SI_X14(6*8);      \ | ||||
| 	VMOVQ_SI_X15_0;         \ | ||||
| 	VPINSRQ_1_SI_X12(5*8);  \ | ||||
| 	VPINSRQ_1_SI_X13(15*8); \ | ||||
| 	VPINSRQ_1_SI_X14(10*8); \ | ||||
| 	VPINSRQ_1_SI_X15(8*8) | ||||
|  | ||||
| // load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15) | ||||
| #define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \ | ||||
| 	VMOVQ_SI_X12(9*8);      \ | ||||
| 	VMOVQ_SI_X13(2*8);      \ | ||||
| 	VMOVQ_SI_X14_0;         \ | ||||
| 	VMOVQ_SI_X15(4*8);      \ | ||||
| 	VPINSRQ_1_SI_X12(5*8);  \ | ||||
| 	VPINSRQ_1_SI_X13(10*8); \ | ||||
| 	VPINSRQ_1_SI_X14(7*8);  \ | ||||
| 	VPINSRQ_1_SI_X15(15*8) | ||||
|  | ||||
| // load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3) | ||||
| #define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \ | ||||
| 	VMOVQ_SI_X12(2*8);      \ | ||||
| 	VMOVQ_SI_X13_0;         \ | ||||
| 	VMOVQ_SI_X14(12*8);     \ | ||||
| 	VMOVQ_SI_X15(11*8);     \ | ||||
| 	VPINSRQ_1_SI_X12(6*8);  \ | ||||
| 	VPINSRQ_1_SI_X13(8*8);  \ | ||||
| 	VPINSRQ_1_SI_X14(10*8); \ | ||||
| 	VPINSRQ_1_SI_X15(3*8) | ||||
|  | ||||
| // load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11) | ||||
| #define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \ | ||||
| 	MOVQ    0*8(SI), X12;        \ | ||||
| 	VPSHUFD $0x4E, 8*8(SI), X13; \ | ||||
| 	MOVQ    7*8(SI), X14;        \ | ||||
| 	MOVQ    2*8(SI), X15;        \ | ||||
| 	VPINSRQ_1_SI_X12(6*8);       \ | ||||
| 	VPINSRQ_1_SI_X14(3*8);       \ | ||||
| 	VPINSRQ_1_SI_X15(11*8) | ||||
|  | ||||
| // load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8) | ||||
| #define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \ | ||||
| 	MOVQ 6*8(SI), X12;      \ | ||||
| 	MOVQ 11*8(SI), X13;     \ | ||||
| 	MOVQ 15*8(SI), X14;     \ | ||||
| 	MOVQ 3*8(SI), X15;      \ | ||||
| 	VPINSRQ_1_SI_X12(14*8); \ | ||||
| 	VPINSRQ_1_SI_X13_0;     \ | ||||
| 	VPINSRQ_1_SI_X14(9*8);  \ | ||||
| 	VPINSRQ_1_SI_X15(8*8) | ||||
|  | ||||
| // load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10) | ||||
| #define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \ | ||||
| 	MOVQ 5*8(SI), X12;      \ | ||||
| 	MOVQ 8*8(SI), X13;      \ | ||||
| 	MOVQ 0*8(SI), X14;      \ | ||||
| 	MOVQ 6*8(SI), X15;      \ | ||||
| 	VPINSRQ_1_SI_X12(15*8); \ | ||||
| 	VPINSRQ_1_SI_X13(2*8);  \ | ||||
| 	VPINSRQ_1_SI_X14(4*8);  \ | ||||
| 	VPINSRQ_1_SI_X15(10*8) | ||||
|  | ||||
| // load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5) | ||||
| #define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \ | ||||
| 	VMOVDQU 12*8(SI), X12;  \ | ||||
| 	MOVQ    1*8(SI), X13;   \ | ||||
| 	MOVQ    2*8(SI), X14;   \ | ||||
| 	VPINSRQ_1_SI_X13(10*8); \ | ||||
| 	VPINSRQ_1_SI_X14(7*8);  \ | ||||
| 	VMOVDQU 4*8(SI), X15 | ||||
|  | ||||
| // load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0) | ||||
| #define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \ | ||||
| 	MOVQ 15*8(SI), X12;     \ | ||||
| 	MOVQ 3*8(SI), X13;      \ | ||||
| 	MOVQ 11*8(SI), X14;     \ | ||||
| 	MOVQ 12*8(SI), X15;     \ | ||||
| 	VPINSRQ_1_SI_X12(9*8);  \ | ||||
| 	VPINSRQ_1_SI_X13(13*8); \ | ||||
| 	VPINSRQ_1_SI_X14(14*8); \ | ||||
| 	VPINSRQ_1_SI_X15_0 | ||||
|  | ||||
| // func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) | ||||
| TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment | ||||
| 	MOVQ h+0(FP), AX | ||||
| 	MOVQ c+8(FP), BX | ||||
| 	MOVQ flag+16(FP), CX | ||||
| 	MOVQ blocks_base+24(FP), SI | ||||
| 	MOVQ blocks_len+32(FP), DI | ||||
|  | ||||
| 	MOVQ SP, BP | ||||
| 	MOVQ SP, R9 | ||||
| 	ADDQ $15, R9 | ||||
| 	ANDQ $~15, R9 | ||||
| 	MOVQ R9, SP | ||||
|  | ||||
| 	VMOVDQU ·AVX_c40<>(SB), X0 | ||||
| 	VMOVDQU ·AVX_c48<>(SB), X1 | ||||
| 	VMOVDQA X0, X8 | ||||
| 	VMOVDQA X1, X9 | ||||
|  | ||||
| 	VMOVDQU ·AVX_iv3<>(SB), X0 | ||||
| 	VMOVDQA X0, 0(SP) | ||||
| 	XORQ    CX, 0(SP)          // 0(SP) = ·AVX_iv3 ^ (CX || 0) | ||||
|  | ||||
| 	VMOVDQU 0(AX), X10 | ||||
| 	VMOVDQU 16(AX), X11 | ||||
| 	VMOVDQU 32(AX), X2 | ||||
| 	VMOVDQU 48(AX), X3 | ||||
|  | ||||
| 	MOVQ 0(BX), R8 | ||||
| 	MOVQ 8(BX), R9 | ||||
|  | ||||
| loop: | ||||
| 	ADDQ $128, R8 | ||||
| 	CMPQ R8, $128 | ||||
| 	JGE  noinc | ||||
| 	INCQ R9 | ||||
|  | ||||
| noinc: | ||||
| 	VMOVQ_R8_X15 | ||||
| 	VPINSRQ_1_R9_X15 | ||||
|  | ||||
| 	VMOVDQA X10, X0 | ||||
| 	VMOVDQA X11, X1 | ||||
| 	VMOVDQU ·AVX_iv0<>(SB), X4 | ||||
| 	VMOVDQU ·AVX_iv1<>(SB), X5 | ||||
| 	VMOVDQU ·AVX_iv2<>(SB), X6 | ||||
|  | ||||
| 	VPXOR   X15, X6, X6 | ||||
| 	VMOVDQA 0(SP), X7 | ||||
|  | ||||
| 	LOAD_MSG_AVX_0_2_4_6_1_3_5_7() | ||||
| 	VMOVDQA X12, 16(SP) | ||||
| 	VMOVDQA X13, 32(SP) | ||||
| 	VMOVDQA X14, 48(SP) | ||||
| 	VMOVDQA X15, 64(SP) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15) | ||||
| 	VMOVDQA X12, 80(SP) | ||||
| 	VMOVDQA X13, 96(SP) | ||||
| 	VMOVDQA X14, 112(SP) | ||||
| 	VMOVDQA X15, 128(SP) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6) | ||||
| 	VMOVDQA X12, 144(SP) | ||||
| 	VMOVDQA X13, 160(SP) | ||||
| 	VMOVDQA X14, 176(SP) | ||||
| 	VMOVDQA X15, 192(SP) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX_1_0_11_5_12_2_7_3() | ||||
| 	VMOVDQA X12, 208(SP) | ||||
| 	VMOVDQA X13, 224(SP) | ||||
| 	VMOVDQA X14, 240(SP) | ||||
| 	VMOVDQA X15, 256(SP) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	LOAD_MSG_AVX_11_12_5_15_8_0_2_13() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX_2_5_4_15_6_10_0_8() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	LOAD_MSG_AVX_9_5_2_10_0_7_4_15() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	LOAD_MSG_AVX_2_6_0_8_12_10_11_3() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX_0_6_9_8_7_3_2_11() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX_5_15_8_2_0_4_6_10() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	LOAD_MSG_AVX_6_14_11_0_15_9_3_8() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX_12_13_1_10_2_7_4_5() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5) | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	LOAD_MSG_AVX_15_9_3_13_11_14_12_0() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X15, X8, X9) | ||||
| 	SHUFFLE_AVX() | ||||
| 	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X15, X8, X9) | ||||
| 	SHUFFLE_AVX_INV() | ||||
|  | ||||
| 	VMOVDQU 32(AX), X14 | ||||
| 	VMOVDQU 48(AX), X15 | ||||
| 	VPXOR   X0, X10, X10 | ||||
| 	VPXOR   X1, X11, X11 | ||||
| 	VPXOR   X2, X14, X14 | ||||
| 	VPXOR   X3, X15, X15 | ||||
| 	VPXOR   X4, X10, X10 | ||||
| 	VPXOR   X5, X11, X11 | ||||
| 	VPXOR   X6, X14, X2 | ||||
| 	VPXOR   X7, X15, X3 | ||||
| 	VMOVDQU X2, 32(AX) | ||||
| 	VMOVDQU X3, 48(AX) | ||||
|  | ||||
| 	LEAQ 128(SI), SI | ||||
| 	SUBQ $128, DI | ||||
| 	JNE  loop | ||||
|  | ||||
| 	VMOVDQU X10, 0(AX) | ||||
| 	VMOVDQU X11, 16(AX) | ||||
|  | ||||
| 	MOVQ R8, 0(BX) | ||||
| 	MOVQ R9, 8(BX) | ||||
| 	VZEROUPPER | ||||
|  | ||||
| 	MOVQ BP, SP | ||||
| 	RET | ||||
|  | ||||
| // func supportsAVX2() bool | ||||
| TEXT ·supportsAVX2(SB), 4, $0-1 | ||||
| 	MOVQ runtime·support_avx2(SB), AX | ||||
| 	MOVB AX, ret+0(FP) | ||||
| 	RET | ||||
|  | ||||
| // func supportsAVX() bool | ||||
| TEXT ·supportsAVX(SB), 4, $0-1 | ||||
| 	MOVQ runtime·support_avx(SB), AX | ||||
| 	MOVB AX, ret+0(FP) | ||||
| 	RET | ||||
							
								
								
									
										25
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| // Copyright 2016 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build !go1.7,amd64,!gccgo,!appengine | ||||
|  | ||||
| package blake2b | ||||
|  | ||||
| func init() { | ||||
| 	useSSE4 = supportsSSE4() | ||||
| } | ||||
|  | ||||
| //go:noescape | ||||
| func supportsSSE4() bool | ||||
|  | ||||
| //go:noescape | ||||
| func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) | ||||
|  | ||||
| func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { | ||||
| 	if useSSE4 { | ||||
| 		hashBlocksSSE4(h, c, flag, blocks) | ||||
| 	} else { | ||||
| 		hashBlocksGeneric(h, c, flag, blocks) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										290
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,290 @@ | ||||
| // Copyright 2016 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 amd64,!gccgo,!appengine | ||||
|  | ||||
| #include "textflag.h" | ||||
|  | ||||
| DATA ·iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 | ||||
| DATA ·iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b | ||||
| GLOBL ·iv0<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b | ||||
| DATA ·iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 | ||||
| GLOBL ·iv1<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·iv2<>+0x00(SB)/8, $0x510e527fade682d1 | ||||
| DATA ·iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f | ||||
| GLOBL ·iv2<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b | ||||
| DATA ·iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 | ||||
| GLOBL ·iv3<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·c40<>+0x00(SB)/8, $0x0201000706050403 | ||||
| DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b | ||||
| GLOBL ·c40<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| DATA ·c48<>+0x00(SB)/8, $0x0100070605040302 | ||||
| DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a | ||||
| GLOBL ·c48<>(SB), (NOPTR+RODATA), $16 | ||||
|  | ||||
| #define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \ | ||||
| 	MOVO       v4, t1; \ | ||||
| 	MOVO       v5, v4; \ | ||||
| 	MOVO       t1, v5; \ | ||||
| 	MOVO       v6, t1; \ | ||||
| 	PUNPCKLQDQ v6, t2; \ | ||||
| 	PUNPCKHQDQ v7, v6; \ | ||||
| 	PUNPCKHQDQ t2, v6; \ | ||||
| 	PUNPCKLQDQ v7, t2; \ | ||||
| 	MOVO       t1, v7; \ | ||||
| 	MOVO       v2, t1; \ | ||||
| 	PUNPCKHQDQ t2, v7; \ | ||||
| 	PUNPCKLQDQ v3, t2; \ | ||||
| 	PUNPCKHQDQ t2, v2; \ | ||||
| 	PUNPCKLQDQ t1, t2; \ | ||||
| 	PUNPCKHQDQ t2, v3 | ||||
|  | ||||
| #define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \ | ||||
| 	MOVO       v4, t1; \ | ||||
| 	MOVO       v5, v4; \ | ||||
| 	MOVO       t1, v5; \ | ||||
| 	MOVO       v2, t1; \ | ||||
| 	PUNPCKLQDQ v2, t2; \ | ||||
| 	PUNPCKHQDQ v3, v2; \ | ||||
| 	PUNPCKHQDQ t2, v2; \ | ||||
| 	PUNPCKLQDQ v3, t2; \ | ||||
| 	MOVO       t1, v3; \ | ||||
| 	MOVO       v6, t1; \ | ||||
| 	PUNPCKHQDQ t2, v3; \ | ||||
| 	PUNPCKLQDQ v7, t2; \ | ||||
| 	PUNPCKHQDQ t2, v6; \ | ||||
| 	PUNPCKLQDQ t1, t2; \ | ||||
| 	PUNPCKHQDQ t2, v7 | ||||
|  | ||||
| #define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ | ||||
| 	PADDQ  m0, v0;        \ | ||||
| 	PADDQ  m1, v1;        \ | ||||
| 	PADDQ  v2, v0;        \ | ||||
| 	PADDQ  v3, v1;        \ | ||||
| 	PXOR   v0, v6;        \ | ||||
| 	PXOR   v1, v7;        \ | ||||
| 	PSHUFD $0xB1, v6, v6; \ | ||||
| 	PSHUFD $0xB1, v7, v7; \ | ||||
| 	PADDQ  v6, v4;        \ | ||||
| 	PADDQ  v7, v5;        \ | ||||
| 	PXOR   v4, v2;        \ | ||||
| 	PXOR   v5, v3;        \ | ||||
| 	PSHUFB c40, v2;       \ | ||||
| 	PSHUFB c40, v3;       \ | ||||
| 	PADDQ  m2, v0;        \ | ||||
| 	PADDQ  m3, v1;        \ | ||||
| 	PADDQ  v2, v0;        \ | ||||
| 	PADDQ  v3, v1;        \ | ||||
| 	PXOR   v0, v6;        \ | ||||
| 	PXOR   v1, v7;        \ | ||||
| 	PSHUFB c48, v6;       \ | ||||
| 	PSHUFB c48, v7;       \ | ||||
| 	PADDQ  v6, v4;        \ | ||||
| 	PADDQ  v7, v5;        \ | ||||
| 	PXOR   v4, v2;        \ | ||||
| 	PXOR   v5, v3;        \ | ||||
| 	MOVOU  v2, t0;        \ | ||||
| 	PADDQ  v2, t0;        \ | ||||
| 	PSRLQ  $63, v2;       \ | ||||
| 	PXOR   t0, v2;        \ | ||||
| 	MOVOU  v3, t0;        \ | ||||
| 	PADDQ  v3, t0;        \ | ||||
| 	PSRLQ  $63, v3;       \ | ||||
| 	PXOR   t0, v3 | ||||
|  | ||||
| #define LOAD_MSG(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7) \ | ||||
| 	MOVQ   i0*8(src), m0;     \ | ||||
| 	PINSRQ $1, i1*8(src), m0; \ | ||||
| 	MOVQ   i2*8(src), m1;     \ | ||||
| 	PINSRQ $1, i3*8(src), m1; \ | ||||
| 	MOVQ   i4*8(src), m2;     \ | ||||
| 	PINSRQ $1, i5*8(src), m2; \ | ||||
| 	MOVQ   i6*8(src), m3;     \ | ||||
| 	PINSRQ $1, i7*8(src), m3 | ||||
|  | ||||
| // func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) | ||||
| TEXT ·hashBlocksSSE4(SB), 4, $288-48 // frame size = 272 + 16 byte alignment | ||||
| 	MOVQ h+0(FP), AX | ||||
| 	MOVQ c+8(FP), BX | ||||
| 	MOVQ flag+16(FP), CX | ||||
| 	MOVQ blocks_base+24(FP), SI | ||||
| 	MOVQ blocks_len+32(FP), DI | ||||
|  | ||||
| 	MOVQ SP, BP | ||||
| 	MOVQ SP, R9 | ||||
| 	ADDQ $15, R9 | ||||
| 	ANDQ $~15, R9 | ||||
| 	MOVQ R9, SP | ||||
|  | ||||
| 	MOVOU ·iv3<>(SB), X0 | ||||
| 	MOVO  X0, 0(SP) | ||||
| 	XORQ  CX, 0(SP)     // 0(SP) = ·iv3 ^ (CX || 0) | ||||
|  | ||||
| 	MOVOU ·c40<>(SB), X13 | ||||
| 	MOVOU ·c48<>(SB), X14 | ||||
|  | ||||
| 	MOVOU 0(AX), X12 | ||||
| 	MOVOU 16(AX), X15 | ||||
|  | ||||
| 	MOVQ 0(BX), R8 | ||||
| 	MOVQ 8(BX), R9 | ||||
|  | ||||
| loop: | ||||
| 	ADDQ $128, R8 | ||||
| 	CMPQ R8, $128 | ||||
| 	JGE  noinc | ||||
| 	INCQ R9 | ||||
|  | ||||
| noinc: | ||||
| 	MOVQ R8, X8 | ||||
| 	PINSRQ $1, R9, X8 | ||||
|  | ||||
| 	MOVO X12, X0 | ||||
| 	MOVO X15, X1 | ||||
| 	MOVOU 32(AX), X2 | ||||
| 	MOVOU 48(AX), X3 | ||||
| 	MOVOU ·iv0<>(SB), X4 | ||||
| 	MOVOU ·iv1<>(SB), X5 | ||||
| 	MOVOU ·iv2<>(SB), X6 | ||||
|  | ||||
| 	PXOR X8, X6 | ||||
| 	MOVO 0(SP), X7 | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7) | ||||
| 	MOVO X8, 16(SP) | ||||
| 	MOVO X9, 32(SP) | ||||
| 	MOVO X10, 48(SP) | ||||
| 	MOVO X11, 64(SP) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 8, 10, 12, 14, 9, 11, 13, 15) | ||||
| 	MOVO X8, 80(SP) | ||||
| 	MOVO X9, 96(SP) | ||||
| 	MOVO X10, 112(SP) | ||||
| 	MOVO X11, 128(SP) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6) | ||||
| 	MOVO X8, 144(SP) | ||||
| 	MOVO X9, 160(SP) | ||||
| 	MOVO X10, 176(SP) | ||||
| 	MOVO X11, 192(SP) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 1, 0, 11, 5, 12, 2, 7, 3) | ||||
| 	MOVO X8, 208(SP) | ||||
| 	MOVO X9, 224(SP) | ||||
| 	MOVO X10, 240(SP) | ||||
| 	MOVO X11, 256(SP) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 10, 3, 7, 9, 14, 6, 1, 4) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 2, 5, 4, 15, 6, 10, 0, 8) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 14, 11, 6, 3, 1, 12, 8, 13) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 4, 7, 15, 1, 13, 5, 14, 9) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 0, 6, 9, 8, 7, 3, 2, 11) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 5, 15, 8, 2, 0, 4, 6, 10) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 12, 13, 1, 10, 2, 7, 4, 5) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	LOAD_MSG(X8, X9, X10, X11, SI, 15, 9, 3, 13, 11, 14, 12, 0) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X11, X13, X14) | ||||
| 	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
| 	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X11, X13, X14) | ||||
| 	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) | ||||
|  | ||||
| 	MOVOU 32(AX), X10 | ||||
| 	MOVOU 48(AX), X11 | ||||
| 	PXOR  X0, X12 | ||||
| 	PXOR  X1, X15 | ||||
| 	PXOR  X2, X10 | ||||
| 	PXOR  X3, X11 | ||||
| 	PXOR  X4, X12 | ||||
| 	PXOR  X5, X15 | ||||
| 	PXOR  X6, X10 | ||||
| 	PXOR  X7, X11 | ||||
| 	MOVOU X10, 32(AX) | ||||
| 	MOVOU X11, 48(AX) | ||||
|  | ||||
| 	LEAQ 128(SI), SI | ||||
| 	SUBQ $128, DI | ||||
| 	JNE  loop | ||||
|  | ||||
| 	MOVOU X12, 0(AX) | ||||
| 	MOVOU X15, 16(AX) | ||||
|  | ||||
| 	MOVQ R8, 0(BX) | ||||
| 	MOVQ R9, 8(BX) | ||||
|  | ||||
| 	MOVQ BP, SP | ||||
| 	RET | ||||
|  | ||||
| // func supportsSSE4() bool | ||||
| TEXT ·supportsSSE4(SB), 4, $0-1 | ||||
| 	MOVL $1, AX | ||||
| 	CPUID | ||||
| 	SHRL $19, CX  // Bit 19 indicates SSE4 support | ||||
| 	ANDL $1, CX  // CX != 0 if support SSE4 | ||||
| 	MOVB CX, ret+0(FP) | ||||
| 	RET | ||||
							
								
								
									
										179
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,179 @@ | ||||
| // Copyright 2016 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 blake2b | ||||
|  | ||||
| import "encoding/binary" | ||||
|  | ||||
| // the precomputed values for BLAKE2b | ||||
| // there are 12 16-byte arrays - one for each round | ||||
| // the entries are calculated from the sigma constants. | ||||
| var precomputed = [12][16]byte{ | ||||
| 	{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, | ||||
| 	{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, | ||||
| 	{11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4}, | ||||
| 	{7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8}, | ||||
| 	{9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13}, | ||||
| 	{2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9}, | ||||
| 	{12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11}, | ||||
| 	{13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10}, | ||||
| 	{6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5}, | ||||
| 	{10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0}, | ||||
| 	{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, // equal to the first | ||||
| 	{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, // equal to the second | ||||
| } | ||||
|  | ||||
| func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { | ||||
| 	var m [16]uint64 | ||||
| 	c0, c1 := c[0], c[1] | ||||
|  | ||||
| 	for i := 0; i < len(blocks); { | ||||
| 		c0 += BlockSize | ||||
| 		if c0 < BlockSize { | ||||
| 			c1++ | ||||
| 		} | ||||
|  | ||||
| 		v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7] | ||||
| 		v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7] | ||||
| 		v12 ^= c0 | ||||
| 		v13 ^= c1 | ||||
| 		v14 ^= flag | ||||
|  | ||||
| 		for j := range m { | ||||
| 			m[j] = binary.LittleEndian.Uint64(blocks[i:]) | ||||
| 			i += 8 | ||||
| 		} | ||||
|  | ||||
| 		for j := range precomputed { | ||||
| 			s := &(precomputed[j]) | ||||
|  | ||||
| 			v0 += m[s[0]] | ||||
| 			v0 += v4 | ||||
| 			v12 ^= v0 | ||||
| 			v12 = v12<<(64-32) | v12>>32 | ||||
| 			v8 += v12 | ||||
| 			v4 ^= v8 | ||||
| 			v4 = v4<<(64-24) | v4>>24 | ||||
| 			v1 += m[s[1]] | ||||
| 			v1 += v5 | ||||
| 			v13 ^= v1 | ||||
| 			v13 = v13<<(64-32) | v13>>32 | ||||
| 			v9 += v13 | ||||
| 			v5 ^= v9 | ||||
| 			v5 = v5<<(64-24) | v5>>24 | ||||
| 			v2 += m[s[2]] | ||||
| 			v2 += v6 | ||||
| 			v14 ^= v2 | ||||
| 			v14 = v14<<(64-32) | v14>>32 | ||||
| 			v10 += v14 | ||||
| 			v6 ^= v10 | ||||
| 			v6 = v6<<(64-24) | v6>>24 | ||||
| 			v3 += m[s[3]] | ||||
| 			v3 += v7 | ||||
| 			v15 ^= v3 | ||||
| 			v15 = v15<<(64-32) | v15>>32 | ||||
| 			v11 += v15 | ||||
| 			v7 ^= v11 | ||||
| 			v7 = v7<<(64-24) | v7>>24 | ||||
|  | ||||
| 			v0 += m[s[4]] | ||||
| 			v0 += v4 | ||||
| 			v12 ^= v0 | ||||
| 			v12 = v12<<(64-16) | v12>>16 | ||||
| 			v8 += v12 | ||||
| 			v4 ^= v8 | ||||
| 			v4 = v4<<(64-63) | v4>>63 | ||||
| 			v1 += m[s[5]] | ||||
| 			v1 += v5 | ||||
| 			v13 ^= v1 | ||||
| 			v13 = v13<<(64-16) | v13>>16 | ||||
| 			v9 += v13 | ||||
| 			v5 ^= v9 | ||||
| 			v5 = v5<<(64-63) | v5>>63 | ||||
| 			v2 += m[s[6]] | ||||
| 			v2 += v6 | ||||
| 			v14 ^= v2 | ||||
| 			v14 = v14<<(64-16) | v14>>16 | ||||
| 			v10 += v14 | ||||
| 			v6 ^= v10 | ||||
| 			v6 = v6<<(64-63) | v6>>63 | ||||
| 			v3 += m[s[7]] | ||||
| 			v3 += v7 | ||||
| 			v15 ^= v3 | ||||
| 			v15 = v15<<(64-16) | v15>>16 | ||||
| 			v11 += v15 | ||||
| 			v7 ^= v11 | ||||
| 			v7 = v7<<(64-63) | v7>>63 | ||||
|  | ||||
| 			v0 += m[s[8]] | ||||
| 			v0 += v5 | ||||
| 			v15 ^= v0 | ||||
| 			v15 = v15<<(64-32) | v15>>32 | ||||
| 			v10 += v15 | ||||
| 			v5 ^= v10 | ||||
| 			v5 = v5<<(64-24) | v5>>24 | ||||
| 			v1 += m[s[9]] | ||||
| 			v1 += v6 | ||||
| 			v12 ^= v1 | ||||
| 			v12 = v12<<(64-32) | v12>>32 | ||||
| 			v11 += v12 | ||||
| 			v6 ^= v11 | ||||
| 			v6 = v6<<(64-24) | v6>>24 | ||||
| 			v2 += m[s[10]] | ||||
| 			v2 += v7 | ||||
| 			v13 ^= v2 | ||||
| 			v13 = v13<<(64-32) | v13>>32 | ||||
| 			v8 += v13 | ||||
| 			v7 ^= v8 | ||||
| 			v7 = v7<<(64-24) | v7>>24 | ||||
| 			v3 += m[s[11]] | ||||
| 			v3 += v4 | ||||
| 			v14 ^= v3 | ||||
| 			v14 = v14<<(64-32) | v14>>32 | ||||
| 			v9 += v14 | ||||
| 			v4 ^= v9 | ||||
| 			v4 = v4<<(64-24) | v4>>24 | ||||
|  | ||||
| 			v0 += m[s[12]] | ||||
| 			v0 += v5 | ||||
| 			v15 ^= v0 | ||||
| 			v15 = v15<<(64-16) | v15>>16 | ||||
| 			v10 += v15 | ||||
| 			v5 ^= v10 | ||||
| 			v5 = v5<<(64-63) | v5>>63 | ||||
| 			v1 += m[s[13]] | ||||
| 			v1 += v6 | ||||
| 			v12 ^= v1 | ||||
| 			v12 = v12<<(64-16) | v12>>16 | ||||
| 			v11 += v12 | ||||
| 			v6 ^= v11 | ||||
| 			v6 = v6<<(64-63) | v6>>63 | ||||
| 			v2 += m[s[14]] | ||||
| 			v2 += v7 | ||||
| 			v13 ^= v2 | ||||
| 			v13 = v13<<(64-16) | v13>>16 | ||||
| 			v8 += v13 | ||||
| 			v7 ^= v8 | ||||
| 			v7 = v7<<(64-63) | v7>>63 | ||||
| 			v3 += m[s[15]] | ||||
| 			v3 += v4 | ||||
| 			v14 ^= v3 | ||||
| 			v14 = v14<<(64-16) | v14>>16 | ||||
| 			v9 += v14 | ||||
| 			v4 ^= v9 | ||||
| 			v4 = v4<<(64-63) | v4>>63 | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		h[0] ^= v0 ^ v8 | ||||
| 		h[1] ^= v1 ^ v9 | ||||
| 		h[2] ^= v2 ^ v10 | ||||
| 		h[3] ^= v3 ^ v11 | ||||
| 		h[4] ^= v4 ^ v12 | ||||
| 		h[5] ^= v5 ^ v13 | ||||
| 		h[6] ^= v6 ^ v14 | ||||
| 		h[7] ^= v7 ^ v15 | ||||
| 	} | ||||
| 	c[0], c[1] = c0, c1 | ||||
| } | ||||
							
								
								
									
										11
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| // Copyright 2016 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 !amd64 appengine gccgo | ||||
|  | ||||
| package blake2b | ||||
|  | ||||
| func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { | ||||
| 	hashBlocksGeneric(h, c, flag, blocks) | ||||
| } | ||||
							
								
								
									
										798
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										798
									
								
								vendor/golang.org/x/crypto/blake2b/blake2b_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,798 @@ | ||||
| // Copyright 2016 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 blake2b | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func fromHex(s string) []byte { | ||||
| 	b, err := hex.DecodeString(s) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func TestHashes(t *testing.T) { | ||||
| 	defer func(sse4, avx, avx2 bool) { | ||||
| 		useSSE4, useAVX, useAVX2 = sse4, avx, avx2 | ||||
| 	}(useSSE4, useAVX, useAVX2) | ||||
|  | ||||
| 	if useAVX2 { | ||||
| 		t.Log("AVX2 version") | ||||
| 		testHashes(t) | ||||
| 		useAVX2 = false | ||||
| 	} | ||||
| 	if useAVX { | ||||
| 		t.Log("AVX version") | ||||
| 		testHashes(t) | ||||
| 		useAVX = false | ||||
| 	} | ||||
| 	if useSSE4 { | ||||
| 		t.Log("SSE4 version") | ||||
| 		testHashes(t) | ||||
| 		useSSE4 = false | ||||
| 	} | ||||
| 	t.Log("generic version") | ||||
| 	testHashes(t) | ||||
| } | ||||
|  | ||||
| func TestHashes2X(t *testing.T) { | ||||
| 	defer func(sse4, avx, avx2 bool) { | ||||
| 		useSSE4, useAVX, useAVX2 = sse4, avx, avx2 | ||||
| 	}(useSSE4, useAVX, useAVX2) | ||||
|  | ||||
| 	if useAVX2 { | ||||
| 		t.Log("AVX2 version") | ||||
| 		testHashes2X(t) | ||||
| 		useAVX2 = false | ||||
| 	} | ||||
| 	if useAVX { | ||||
| 		t.Log("AVX version") | ||||
| 		testHashes2X(t) | ||||
| 		useAVX = false | ||||
| 	} | ||||
| 	if useSSE4 { | ||||
| 		t.Log("SSE4 version") | ||||
| 		testHashes2X(t) | ||||
| 		useSSE4 = false | ||||
| 	} | ||||
| 	t.Log("generic version") | ||||
| 	testHashes2X(t) | ||||
| } | ||||
|  | ||||
| func testHashes(t *testing.T) { | ||||
| 	key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f") | ||||
|  | ||||
| 	input := make([]byte, 255) | ||||
| 	for i := range input { | ||||
| 		input[i] = byte(i) | ||||
| 	} | ||||
|  | ||||
| 	for i, expectedHex := range hashes { | ||||
| 		h, err := New512(key) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("#%d: error from New512: %v", i, err) | ||||
| 		} | ||||
|  | ||||
| 		h.Write(input[:i]) | ||||
| 		sum := h.Sum(nil) | ||||
|  | ||||
| 		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex { | ||||
| 			t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex) | ||||
| 		} | ||||
|  | ||||
| 		h.Reset() | ||||
| 		for j := 0; j < i; j++ { | ||||
| 			h.Write(input[j : j+1]) | ||||
| 		} | ||||
|  | ||||
| 		sum = h.Sum(sum[:0]) | ||||
| 		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex { | ||||
| 			t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testHashes2X(t *testing.T) { | ||||
| 	key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f") | ||||
|  | ||||
| 	input := make([]byte, 256) | ||||
| 	for i := range input { | ||||
| 		input[i] = byte(i) | ||||
| 	} | ||||
|  | ||||
| 	for i, expectedHex := range hashes2X { | ||||
| 		length := uint32(len(expectedHex) / 2) | ||||
| 		sum := make([]byte, int(length)) | ||||
|  | ||||
| 		h, err := NewXOF(length, key) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("#%d: error from NewXOF: %v", i, err) | ||||
| 		} | ||||
|  | ||||
| 		if _, err := h.Write(input); err != nil { | ||||
| 			t.Fatalf("#%d (single write): error from Write: %v", i, err) | ||||
| 		} | ||||
| 		if _, err := h.Read(sum); err != nil { | ||||
| 			t.Fatalf("#%d (single write): error from Read: %v", i, err) | ||||
| 		} | ||||
| 		if n, err := h.Read(sum); n != 0 || err != io.EOF { | ||||
| 			t.Fatalf("#%d (single write): Read did not return (0, io.EOF) after exhaustion, got (%v, %v)", i, n, err) | ||||
| 		} | ||||
| 		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex { | ||||
| 			t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex) | ||||
| 		} | ||||
|  | ||||
| 		h.Reset() | ||||
| 		for j := 0; j < len(input); j++ { | ||||
| 			h.Write(input[j : j+1]) | ||||
| 		} | ||||
| 		for j := 0; j < len(sum); j++ { | ||||
| 			h = h.Clone() | ||||
| 			if _, err := h.Read(sum[j : j+1]); err != nil { | ||||
| 				t.Fatalf("#%d (byte-by-byte) - Read %d: error from Read: %v", i, j, err) | ||||
| 			} | ||||
| 		} | ||||
| 		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex { | ||||
| 			t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	h, err := NewXOF(OutputLengthUnknown, key) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("#unknown length: error from NewXOF: %v", err) | ||||
| 	} | ||||
| 	if _, err := h.Write(input); err != nil { | ||||
| 		t.Fatalf("#unknown length: error from Write: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	var result [64]byte | ||||
| 	if n, err := h.Read(result[:]); err != nil { | ||||
| 		t.Fatalf("#unknown length: error from Read: %v", err) | ||||
| 	} else if n != len(result) { | ||||
| 		t.Fatalf("#unknown length: Read returned %d bytes, want %d", n, len(result)) | ||||
| 	} | ||||
|  | ||||
| 	const expected = "3dbba8516da76bf7330055c66ea36cf1005e92714262b24d9710f51d9e126406e1bcd6497059f9331f1091c3634b695428d475ed432f987040575520a1c29f5e" | ||||
| 	if fmt.Sprintf("%x", result) != expected { | ||||
| 		t.Fatalf("#unknown length: bad result %x, wanted %s", result, expected) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func generateSequence(out []byte, seed uint32) { | ||||
| 	a := 0xDEAD4BAD * seed // prime | ||||
| 	b := uint32(1) | ||||
|  | ||||
| 	for i := range out { // fill the buf | ||||
| 		a, b = b, a+b | ||||
| 		out[i] = byte(b >> 24) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func computeMAC(msg []byte, hashSize int, key []byte) (sum []byte) { | ||||
| 	var h hash.Hash | ||||
| 	switch hashSize { | ||||
| 	case Size: | ||||
| 		h, _ = New512(key) | ||||
| 	case Size384: | ||||
| 		h, _ = New384(key) | ||||
| 	case Size256: | ||||
| 		h, _ = New256(key) | ||||
| 	case 20: | ||||
| 		h, _ = newDigest(20, key) | ||||
| 	default: | ||||
| 		panic("unexpected hashSize") | ||||
| 	} | ||||
|  | ||||
| 	h.Write(msg) | ||||
| 	return h.Sum(sum) | ||||
| } | ||||
|  | ||||
| func computeHash(msg []byte, hashSize int) (sum []byte) { | ||||
| 	switch hashSize { | ||||
| 	case Size: | ||||
| 		hash := Sum512(msg) | ||||
| 		return hash[:] | ||||
| 	case Size384: | ||||
| 		hash := Sum384(msg) | ||||
| 		return hash[:] | ||||
| 	case Size256: | ||||
| 		hash := Sum256(msg) | ||||
| 		return hash[:] | ||||
| 	case 20: | ||||
| 		var hash [64]byte | ||||
| 		checkSum(&hash, 20, msg) | ||||
| 		return hash[:20] | ||||
| 	default: | ||||
| 		panic("unexpected hashSize") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Test function from RFC 7693. | ||||
| func TestSelfTest(t *testing.T) { | ||||
| 	hashLens := [4]int{20, 32, 48, 64} | ||||
| 	msgLens := [6]int{0, 3, 128, 129, 255, 1024} | ||||
|  | ||||
| 	msg := make([]byte, 1024) | ||||
| 	key := make([]byte, 64) | ||||
|  | ||||
| 	h, _ := New256(nil) | ||||
| 	for _, hashSize := range hashLens { | ||||
| 		for _, msgLength := range msgLens { | ||||
| 			generateSequence(msg[:msgLength], uint32(msgLength)) // unkeyed hash | ||||
|  | ||||
| 			md := computeHash(msg[:msgLength], hashSize) | ||||
| 			h.Write(md) | ||||
|  | ||||
| 			generateSequence(key[:], uint32(hashSize)) // keyed hash | ||||
| 			md = computeMAC(msg[:msgLength], hashSize, key[:hashSize]) | ||||
| 			h.Write(md) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	sum := h.Sum(nil) | ||||
| 	expected := [32]byte{ | ||||
| 		0xc2, 0x3a, 0x78, 0x00, 0xd9, 0x81, 0x23, 0xbd, | ||||
| 		0x10, 0xf5, 0x06, 0xc6, 0x1e, 0x29, 0xda, 0x56, | ||||
| 		0x03, 0xd7, 0x63, 0xb8, 0xbb, 0xad, 0x2e, 0x73, | ||||
| 		0x7f, 0x5e, 0x76, 0x5a, 0x7b, 0xcc, 0xd4, 0x75, | ||||
| 	} | ||||
| 	if !bytes.Equal(sum, expected[:]) { | ||||
| 		t.Fatalf("got %x, wanted %x", sum, expected) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Benchmarks | ||||
|  | ||||
| func benchmarkSum(b *testing.B, size int) { | ||||
| 	data := make([]byte, size) | ||||
| 	b.SetBytes(int64(size)) | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		Sum512(data) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func benchmarkWrite(b *testing.B, size int) { | ||||
| 	data := make([]byte, size) | ||||
| 	h, _ := New512(nil) | ||||
| 	b.SetBytes(int64(size)) | ||||
| 	b.ResetTimer() | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		h.Write(data) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkWrite128(b *testing.B) { benchmarkWrite(b, 128) } | ||||
| func BenchmarkWrite1K(b *testing.B)  { benchmarkWrite(b, 1024) } | ||||
|  | ||||
| func BenchmarkSum128(b *testing.B) { benchmarkSum(b, 128) } | ||||
| func BenchmarkSum1K(b *testing.B)  { benchmarkSum(b, 1024) } | ||||
|  | ||||
| // These values were taken from https://blake2.net/blake2b-test.txt. | ||||
| var hashes = []string{ | ||||
| 	"10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568", | ||||
| 	"961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd", | ||||
| 	"da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965", | ||||
| 	"33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1", | ||||
| 	"beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac", | ||||
| 	"098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb", | ||||
| 	"6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f", | ||||
| 	"7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52", | ||||
| 	"380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9", | ||||
| 	"60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637", | ||||
| 	"4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd", | ||||
| 	"f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b", | ||||
| 	"962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563", | ||||
| 	"43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355", | ||||
| 	"dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6", | ||||
| 	"6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e", | ||||
| 	"a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93", | ||||
| 	"f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1", | ||||
| 	"95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670", | ||||
| 	"04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9", | ||||
| 	"ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c", | ||||
| 	"9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd", | ||||
| 	"4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152", | ||||
| 	"64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9", | ||||
| 	"5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f", | ||||
| 	"7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b", | ||||
| 	"f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764", | ||||
| 	"86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d", | ||||
| 	"10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55", | ||||
| 	"b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b", | ||||
| 	"c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e", | ||||
| 	"eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7", | ||||
| 	"86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991", | ||||
| 	"5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347", | ||||
| 	"ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82", | ||||
| 	"7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42", | ||||
| 	"940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327", | ||||
| 	"2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760", | ||||
| 	"d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252", | ||||
| 	"b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55", | ||||
| 	"4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1", | ||||
| 	"258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee", | ||||
| 	"79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa", | ||||
| 	"8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7", | ||||
| 	"c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071", | ||||
| 	"b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4", | ||||
| 	"7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf", | ||||
| 	"a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d", | ||||
| 	"41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8", | ||||
| 	"14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487", | ||||
| 	"d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c", | ||||
| 	"e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2", | ||||
| 	"feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa", | ||||
| 	"462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33", | ||||
| 	"d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d", | ||||
| 	"e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e", | ||||
| 	"f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2", | ||||
| 	"30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4", | ||||
| 	"f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2", | ||||
| 	"0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a", | ||||
| 	"08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564", | ||||
| 	"d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f", | ||||
| 	"dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9", | ||||
| 	"bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa", | ||||
| 	"65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022", | ||||
| 	"939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c", | ||||
| 	"c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc", | ||||
| 	"987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f", | ||||
| 	"ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b", | ||||
| 	"49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866", | ||||
| 	"da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d", | ||||
| 	"d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8", | ||||
| 	"2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4", | ||||
| 	"e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3", | ||||
| 	"dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e", | ||||
| 	"d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745", | ||||
| 	"b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545", | ||||
| 	"6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063", | ||||
| 	"f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd", | ||||
| 	"cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a", | ||||
| 	"fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed", | ||||
| 	"5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd", | ||||
| 	"9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275", | ||||
| 	"af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897", | ||||
| 	"48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430", | ||||
| 	"0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab", | ||||
| 	"06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f", | ||||
| 	"1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46", | ||||
| 	"3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29", | ||||
| 	"04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab", | ||||
| 	"9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8", | ||||
| 	"ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a", | ||||
| 	"8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec", | ||||
| 	"fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79", | ||||
| 	"28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24", | ||||
| 	"ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b", | ||||
| 	"b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5", | ||||
| 	"31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463", | ||||
| 	"bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4", | ||||
| 	"f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3", | ||||
| 	"8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9", | ||||
| 	"c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d", | ||||
| 	"4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4", | ||||
| 	"c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a", | ||||
| 	"ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6", | ||||
| 	"82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73", | ||||
| 	"2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6", | ||||
| 	"16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6", | ||||
| 	"78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3", | ||||
| 	"0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa", | ||||
| 	"f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3", | ||||
| 	"2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b", | ||||
| 	"227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f", | ||||
| 	"1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc", | ||||
| 	"5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200", | ||||
| 	"dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6", | ||||
| 	"02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8", | ||||
| 	"64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f", | ||||
| 	"f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a", | ||||
| 	"e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e", | ||||
| 	"e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935", | ||||
| 	"85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74", | ||||
| 	"aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0", | ||||
| 	"7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c", | ||||
| 	"de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145", | ||||
| 	"aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f", | ||||
| 	"c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0", | ||||
| 	"76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb", | ||||
| 	"72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4", | ||||
| 	"64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91", | ||||
| 	"12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89", | ||||
| 	"60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444", | ||||
| 	"a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a", | ||||
| 	"b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414", | ||||
| 	"fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49", | ||||
| 	"34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b", | ||||
| 	"3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0", | ||||
| 	"ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469", | ||||
| 	"022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3", | ||||
| 	"e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd", | ||||
| 	"94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8", | ||||
| 	"31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21", | ||||
| 	"91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989", | ||||
| 	"d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1", | ||||
| 	"d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399", | ||||
| 	"7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0", | ||||
| 	"58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723", | ||||
| 	"27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff", | ||||
| 	"3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc", | ||||
| 	"eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38", | ||||
| 	"c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a", | ||||
| 	"8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051", | ||||
| 	"24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca", | ||||
| 	"5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4", | ||||
| 	"e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677", | ||||
| 	"bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1", | ||||
| 	"d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce", | ||||
| 	"50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347", | ||||
| 	"0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91", | ||||
| 	"1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209", | ||||
| 	"e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659", | ||||
| 	"b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381", | ||||
| 	"72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56", | ||||
| 	"c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7", | ||||
| 	"c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f", | ||||
| 	"6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972", | ||||
| 	"3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe", | ||||
| 	"c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e", | ||||
| 	"8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be", | ||||
| 	"28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8", | ||||
| 	"2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc", | ||||
| 	"66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8", | ||||
| 	"f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0", | ||||
| 	"8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc", | ||||
| 	"3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979", | ||||
| 	"06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29", | ||||
| 	"c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d", | ||||
| 	"4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108", | ||||
| 	"898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45", | ||||
| 	"ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4", | ||||
| 	"3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267", | ||||
| 	"95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d", | ||||
| 	"227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb", | ||||
| 	"5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813", | ||||
| 	"7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc", | ||||
| 	"062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29", | ||||
| 	"f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc", | ||||
| 	"ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16", | ||||
| 	"c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1", | ||||
| 	"15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c", | ||||
| 	"89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7", | ||||
| 	"e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a", | ||||
| 	"8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa", | ||||
| 	"da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e", | ||||
| 	"f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc", | ||||
| 	"11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5", | ||||
| 	"b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a", | ||||
| 	"ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3", | ||||
| 	"29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc", | ||||
| 	"3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d", | ||||
| 	"3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff", | ||||
| 	"07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb", | ||||
| 	"b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4", | ||||
| 	"7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc", | ||||
| 	"1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902", | ||||
| 	"106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e", | ||||
| 	"0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08", | ||||
| 	"521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816", | ||||
| 	"1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406", | ||||
| 	"5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4", | ||||
| 	"b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d", | ||||
| 	"bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d", | ||||
| 	"65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900", | ||||
| 	"ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06", | ||||
| 	"e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01", | ||||
| 	"3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0", | ||||
| 	"fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94", | ||||
| 	"951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02", | ||||
| 	"8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492", | ||||
| 	"16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2", | ||||
| 	"c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c", | ||||
| 	"72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb", | ||||
| 	"c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077", | ||||
| 	"c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727", | ||||
| 	"f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd", | ||||
| 	"348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c", | ||||
| 	"5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0", | ||||
| 	"2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403", | ||||
| 	"b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391", | ||||
| 	"64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8", | ||||
| 	"0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605", | ||||
| 	"f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9", | ||||
| 	"3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d", | ||||
| 	"d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe", | ||||
| 	"cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe", | ||||
| 	"98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1", | ||||
| 	"771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3", | ||||
| 	"c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb", | ||||
| 	"8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b", | ||||
| 	"1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef", | ||||
| 	"af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253", | ||||
| 	"29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec", | ||||
| 	"a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a", | ||||
| 	"0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473", | ||||
| 	"b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837", | ||||
| 	"74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a", | ||||
| 	"3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1", | ||||
| 	"58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d", | ||||
| 	"9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9", | ||||
| 	"b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537", | ||||
| 	"1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7", | ||||
| 	"4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2", | ||||
| 	"695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338", | ||||
| 	"a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15", | ||||
| 	"d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9", | ||||
| 	"142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461", | ||||
| } | ||||
|  | ||||
| var hashes2X = []string{ | ||||
| 	"64", | ||||
| 	"f457", | ||||
| 	"e8c045", | ||||
| 	"a74c6d0d", | ||||
| 	"eb02ae482a", | ||||
| 	"be65b981275e", | ||||
| 	"8540ccd083a455", | ||||
| 	"074a02fa58d7c7c0", | ||||
| 	"da6da05e10db3022b6", | ||||
| 	"542a5aae2f28f2c3b68c", | ||||
| 	"ca3af2afc4afe891da78b1", | ||||
| 	"e0f66b8dcebf4edc85f12c85", | ||||
| 	"744224d383733b3fa2c53bfcf5", | ||||
| 	"b09b653e85b72ef5cdf8fcfa95f3", | ||||
| 	"dd51877f31f1cf7b9f68bbb09064a3", | ||||
| 	"f5ebf68e7ebed6ad445ffc0c47e82650", | ||||
| 	"ebdcfe03bcb7e21a9091202c5938c0a1bb", | ||||
| 	"860fa5a72ff92efafc48a89df1632a4e2809", | ||||
| 	"0d6d49daa26ae2818041108df3ce0a4db48c8d", | ||||
| 	"e5d7e1bc5715f5ae991e4043e39533af5d53e47f", | ||||
| 	"5232028a43b9d4dfa7f37439b49495926481ab8a29", | ||||
| 	"c118803c922f9ae2397fb676a2ab7603dd9c29c21fe4", | ||||
| 	"2af924f48b9bd7076bfd68794bba6402e2a7ae048de3ea", | ||||
| 	"61255ac38231087c79ea1a0fa14538c26be1c851b6f318c0", | ||||
| 	"f9712b8e42f0532162822f142cb946c40369f2f0e77b6b186e", | ||||
| 	"76da0b89558df66f9b1e66a61d1e795b178ce77a359087793ff2", | ||||
| 	"9036fd1eb32061bdecebc4a32aa524b343b8098a16768ee774d93c", | ||||
| 	"f4ce5a05934e125d159678bea521f585574bcf9572629f155f63efcc", | ||||
| 	"5e1c0d9fae56393445d3024d6b82692d1339f7b5936f68b062c691d3bf", | ||||
| 	"538e35f3e11111d7c4bab69f83b30ade4f67addf1f45cdd2ac74bf299509", | ||||
| 	"17572c4dcbb17faf8785f3bba9f6903895394352eae79b01ebd758377694cc", | ||||
| 	"29f6bb55de7f8868e053176c878c9fe6c2055c4c5413b51ab0386c277fdbac75", | ||||
| 	"bad026c8b2bd3d294907f2280a7145253ec2117d76e3800357be6d431b16366e41", | ||||
| 	"386b7cb6e0fd4b27783125cbe80065af8eb9981fafc3ed18d8120863d972fa7427d9", | ||||
| 	"06e8e6e26e756fff0b83b226dce974c21f970e44fb5b3e5bbada6e4b12f81cca666f48", | ||||
| 	"2f9bd300244f5bc093ba6dcdb4a89fa29da22b1de9d2c9762af919b5fedf6998fbda305b", | ||||
| 	"cf6bdcc46d788074511f9e8f0a4b86704365b2d3f98340b8db53920c385b959a38c8869ae7", | ||||
| 	"1171e603e5cdeb4cda8fd7890222dd8390ede87b6f3284cac0f0d832d8250c9200715af7913d", | ||||
| 	"bda7b2ad5d02bd35ffb009bdd72b7d7bc9c28b3a32f32b0ba31d6cbd3ee87c60b7b98c03404621", | ||||
| 	"2001455324e748503aa08eff2fb2e52ae0170e81a6e9368ada054a36ca340fb779393fb045ac72b3", | ||||
| 	"45f0761aefafbf87a68f9f1f801148d9bba52616ad5ee8e8ac9207e9846a782f487d5cca8b20355a18", | ||||
| 	"3a7e05708be62f087f17b41ac9f20e4ef8115c5ab6d08e84d46af8c273fb46d3ce1aabebae5eea14e018", | ||||
| 	"ea318da9d042ca337ccdfb2bee3e96ecb8f907876c8d143e8e44569178353c2e593e4a82c265931ba1dd79", | ||||
| 	"e0f7c08f5bd712f87094b04528fadb283d83c9ceb82a3e39ec31c19a42a1a1c3bee5613b5640abe069b0d690", | ||||
| 	"d35e63fb1f3f52ab8f7c6cd7c8247e9799042e53922fbaea808ab979fa0c096588cfea3009181d2f93002dfc11", | ||||
| 	"b8b0ab69e3ae55a8699eb481dd665b6a2424c89bc6b7cca02d15fdf1b9854139cab49d34de498b50b2c7e8b910cf", | ||||
| 	"fb65e3222a2950eae1701d4cdd4736266f65bf2c0d2e77968996eadb60ef74fb786f6234973a2524bdfe32d100aa0e", | ||||
| 	"f28b4bb3a2e2c4d5c01a23ff134558559a2d3d704b75402983ee4e0f71d273ae056842c4153b18ee5c47e2bfa54313d4", | ||||
| 	"7bb78794e58a53c3e4b1aeb161e756af051583d14e0a5a3205e094b7c9a8cf62d098fa9ea1db12f330a51ab9852c17f983", | ||||
| 	"a879a8ebae4d0987789bcc58ec3448e35ba1fa1ee58c668d8295aba4eaeaf2762b053a677e25404f635a53037996974d418a", | ||||
| 	"695865b353ec701ecc1cb38f3154489eed0d39829fc192bb68db286d20fa0a64235cde5639137819f7e99f86bd89afcef84a0f", | ||||
| 	"a6ec25f369f71176952fb9b33305dc768589a6070463ee4c35996e1ced4964a865a5c3dc8f0d809eab71366450de702318e4834d", | ||||
| 	"604749f7bfadb069a036409ffac5ba291fa05be8cba2f141554132f56d9bcb88d1ce12f2004cd3ade1aa66a26e6ef64e327514096d", | ||||
| 	"daf9fa7dc2464a899533594e7916fc9bc585bd29dd60c930f3bfa78bc47f6c8439448043a45119fc9228c15bce5fd24f46baf9de736b", | ||||
| 	"943ea5647a8666763084da6a6f15dcf0e8dc24f27fd0d9194805d25180fe3a6d98f4b2b5e0d6a04e9b41869817030f16ae975dd41fc35c", | ||||
| 	"af4f73cbfc093760dfeb52d57ef45207bbd1a515f5523404e5d95a73c237d97ae65bd195b472de6d514c2c448b12fafc282166da132258e9", | ||||
| 	"605f4ed72ed7f5046a342fe4cf6808100d4632e610d59f7ebb016e367d0ff0a95cf45b02c727ba71f147e95212f52046804d376c918cadd260", | ||||
| 	"3750d8ab0a6b13f78e51d321dfd1aa801680e958de45b7b977d05732ee39f856b27cb2bcce8fbf3db6666d35e21244c2881fdcc27fbfea6b1672", | ||||
| 	"8f1b929e80ab752b58abe9731b7b34eb61369536995abef1c0980d93903c1880da3637d367456895f0cb4769d6de3a979e38ed6f5f6ac4d48e9b32", | ||||
| 	"d8469b7aa538b36cdc711a591d60dafecca22bd421973a70e2deef72f69d8014a6f0064eabfbebf5383cbb90f452c6e113d2110e4b1092c54a38b857", | ||||
| 	"7d1f1ad2029f4880e1898af8289c23bc933a40863cc4ab697fead79c58b6b8e25b68cf5324579b0fe879fe7a12e6d03907f0140dfe7b29d33d6109ecf1", | ||||
| 	"87a77aca6d551642288a0dff66078225ae39d288801607429d6725ca949eed7a6f199dd8a65523b4ee7cfa4187400e96597bfffc3e38ade0ae0ab88536a9", | ||||
| 	"e101f43179d8e8546e5ce6a96d7556b7e6b9d4a7d00e7aade5579d085d527ce34a9329551ebcaf6ba946949bbe38e30a62ae344c1950b4bde55306b3bac432", | ||||
| 	"4324561d76c370ef35ac36a4adf8f3773a50d86504bd284f71f7ce9e2bc4c1f1d34a7fb2d67561d101955d448b67577eb30dfee96a95c7f921ef53e20be8bc44", | ||||
| 	"78f0ed6e220b3da3cc9381563b2f72c8dc830cb0f39a48c6ae479a6a78dcfa94002631dec467e9e9b47cc8f0887eb680e340aec3ec009d4a33d241533c76c8ca8c", | ||||
| 	"9f6589c31a472e0a736f4eb22b6c70a9d332cc15304ccb66a6b97cd051b6ed82f8990e1d9bee2e4bb1c3c45e550ae0e7b96e93ae23f2fb8f63b309131e72b36cba6a", | ||||
| 	"c138077ee4ed3d7ffa85ba851dfdf6e9843fc1dc00889d117237bfaad9aa757192f73556b959f98e6d24886ce48869f2a01a48c371785f12b6484eb2078f08c22066e1", | ||||
| 	"f83e7c9e0954a500576ea1fc90a3db2cbd7994eaef647dab5b34e88ab9dc0b47addbc807b21c8e6dd3d0bd357f008471d4f3e0abb18450e1d4919e03a34545b9643f870e", | ||||
| 	"3277a11f2628544fc66f50428f1ad56bcba6ee36ba2ca6ecdf7e255effc0c30235c039d13e01f04cf1efe95b5c2033ab72adda30994b62f2851d17c9920eadca9a251752dc", | ||||
| 	"c2a834281a06fe7b730d3a03f90761daf02714c066e33fc07e1f59ac801ec2f4433486b5a2da8faa51a0cf3c34e29b2960cd0013378938dbd47c3a3d12d70db01d7d06c3e91e", | ||||
| 	"47680182924a51cabe142a6175c9253e8ba7ea579ece8d9bcb78b1e9ca00db844fa08abcf41702bd758ee2c608d9612fed50e85854469cb4ef3038acf1e35b6ba4390561d8ae82", | ||||
| 	"cec45830cd71869e83b109a99a3cd7d935f83a95de7c582f3adbd34e4938fa2f3f922f52f14f169c38cc6618d3f306a8a4d607b345b8a9c48017136fbf825aecf7b620e85f837fae", | ||||
| 	"46fb53c70ab105079d5d78dc60eaa30d938f26e4d0b9df122e21ec85deda94744c1daf8038b8a6652d1ff3e7e15376f5abd30e564784a999f665078340d66b0e939e0c2ef03f9c08bb", | ||||
| 	"7b0dcb52791a170cc52f2e8b95d8956f325c3751d3ef3b2b83b41d82d4496b46228a750d02b71a96012e56b0720949ca77dc68be9b1ef1ad6d6a5ceb86bf565cb972279039e209dddcdc", | ||||
| 	"7153fd43e6b05f5e1a4401e0fef954a737ed142ec2f60bc4daeef9ce73ea1b40a0fcaf1a1e03a3513f930dd5335723632f59f7297fe3a98b68e125eadf478eb045ed9fc4ee566d13f537f5", | ||||
| 	"c7f569c79c801dab50e9d9ca6542f25774b3841e49c83efe0b89109f569509ce7887bc0d2b57b50320eb81fab9017f16c4c870e59edb6c26620d93748500231d70a36f48a7c60747ca2d5986", | ||||
| 	"0a81e0c547648595adca65623ce783411aac7f7d30c3ad269efafab288e7186f6895261972f5137877669c550f34f5128850ebb50e1884814ea1055ee29a866afd04b2087abed02d9592573428", | ||||
| 	"6a7b6769e1f1c95314b0c7fe77013567891bd23416374f23e4f43e27bc4c55cfada13b53b1581948e07fb96a50676baa2756db0988077b0f27d36ac088e0ff0fe72eda1e8eb4b8facff3218d9af0", | ||||
| 	"a399474595cb1ccab6107f18e80f03b1707745c7bf769fc9f260094dc9f8bc6fe09271cb0b131ebb2acd073de4a6521c8368e664278be86be216d1622393f23435fae4fbc6a2e7c961282a777c2d75", | ||||
| 	"4f0fc590b2755a515ae6b46e9628092369d9c8e589e3239320639aa8f7aa44f8111c7c4b3fdbe6e55e036fbf5ebc9c0aa87a4e66851c11e86f6cbf0bd9eb1c98a378c7a7d3af900f55ee108b59bc9e5c", | ||||
| 	"ed96a046f08dd675107331d267379c6fce3c352a9f8d7b243008a74cb4e9410836afaabe871dab6038ca94ce5f6d41fa922ce08aba58169f94cfc86d9f688f396abd24c11a6a9b0830572105a477c33e92", | ||||
| 	"379955f539abf0eb2972ee99ed9546c4bbee363403991833005dc27904c271ef22a799bc32cb39f08d2e4ba6717d55153feb692d7c5efae70890bf29d96df02333c7b05ccc314e4835b018fec9141a82c745", | ||||
| 	"e16cc8d41b96547ede0d0cf4d908c5fa393399daa4a9696e76a4c1f6a2a9fef70f17fb53551a8145ed88f18db8fe780a079d94732437023f7c1d1849ef69ad536a76204239e8ba5d97e507c36c7d042f87fe0e", | ||||
| 	"a81de50750ece3f84536728f227208bf01ec5b7721579d007de72c88ee20663318332efe5bc7c09ad1fa8342be51f0609046ccf760a7957a7d8dc88941adb93666a4521ebe76618e5ddc2dd3261493d400b50073", | ||||
| 	"b72c5fb7c7f60d243928fa41a2d711157b96aef290185c64b4de3dcfa3d644da67a8f37c2ac55caad79ec695a473e8b481f658c497edb8a191526592b11a412282d2a4010c90ef4647bd6ce745ebc9244a71d4876b", | ||||
| 	"9550703877079c90e200e830f277b605624954c549e729c359ee01ee2b07741ecc4255cb37f96682dafcdbaade1063e2c5ccbd1918fb669926a67744101fb6de3ac016be4c74165a1e5a696b704ba2ebf4a953d44b95", | ||||
| 	"a17eb44d4de502dc04a80d5a5e9507d17f27c96467f24c79b06bc98a4c410741d4ac2db98ec02c2a976d788531f1a4451b6c6204cef6dae1b6ebbcd0bde23e6fffb02754043c8fd3c783d90a670b16879ce68b5554fe1c", | ||||
| 	"41d3ea1eaba5be4a206732dbb5b70b79b66a6e5908795ad4fb7cf9e67efb13f06fef8f90acb080ce082aadec6a1b543af759ab63fa6f1d3941186482b0c2b312f1151ea8386253a13ed3708093279b8eb04185636488b226", | ||||
| 	"5e7cdd8373dc42a243c96013cd29df9283b5f28bb50453a903c85e2ce57f35861bf93f03029072b70dac0804e7d51fd0c578c8d9fa619f1e9ce3d8044f65d55634dba611280c1d5cfb59c836a595c803124f696b07ddfac718", | ||||
| 	"26a14c4aa168907cb5de0d12a82e1373a128fb21f2ed11feba108b1bebce934ad63ed89f4ed7ea5e0bc8846e4fc10142f82de0bebd39d68f7874f615c3a9c896bab34190e85df05aaa316e14820b5e478d838fa89dfc94a7fc1e", | ||||
| 	"0211dfc3c35881adc170e4ba6daab1b702dff88933db9a6829a76b8f4a7c2a6d658117132a974f0a0b3a38ceea1efc2488da21905345909e1d859921dc2b5054f09bce8eeb91fa2fc6d048ce00b9cd655e6aafbdaa3a2f19270a16", | ||||
| 	"ddf015b01b68c4f5f72c3145d54049867d99ee6bef24282abf0eecdb506e295bacf8f23ffa65a4cd891f76a046b9dd82cae43a8d01e18a8dff3b50aeb92672be69d7c087ec1fa2d3b2a39196ea5b49b7baede37a586fea71aded587f", | ||||
| 	"6ee721f71ca4dd5c9ce7873c5c04c6ce76a2c824b984251c15535afc96adc9a4d48ca314bfeb6b8ee65092f14cf2a7ca9614e1dcf24c2a7f0f0c11207d3d8aed4af92873b56e8b9ba2fbd659c3f4ca90fa24f113f74a37181bf0fdf758", | ||||
| 	"689bd150e65ac123612524f720f54def78c095eaab8a87b8bcc72b443408e3227f5c8e2bd5af9bcac684d497bc3e41b7a022c28fb5458b95e8dfa2e8caccde0492936ff1902476bb7b4ef2125b19aca2cd3384d922d9f36dddbcd96ae0d6", | ||||
| 	"3a3c0ef066fa4390ec76ad6be1dc9c31ddf45fef43fbfa1f49b439caa2eb9f3042253a9853e96a9cf86b4f873785a5d2c5d3b05f6501bc876e09031188e05f48937bf3c9b667d14800db62437590b84ce96aa70bb5141ee2ea41b55a6fd944", | ||||
| 	"741ce384e5e0edaebb136701ce38b3d33215415197758ae81235307a4115777d4dab23891db530c6d28f63a957428391421f742789a0e04c99c828373d9903b64dd57f26b3a38b67df829ae243feef731ead0abfca049924667fdec49d40f665", | ||||
| 	"a513f450d66cd5a48a115aee862c65b26e836f35a5eb6894a80519e2cd96cc4cad8ed7eb922b4fc9bbc55c973089d627b1da9c3a95f6c019ef1d47143cc545b15e4244424be28199c51a5efc7234dcd94e72d229897c392af85f523c2633427825", | ||||
| 	"71f1554d2d49bb7bd9e62e71fa049fb54a2c097032f61ebda669b3e1d4593962e47fc62a0ab5d85706aebd6a2f9a192c88aa1ee2f6a46710cf4af6d3c25b7e68ad5c3db23ac009c8f13625ff85dc8e50a9a1b2682d3329330b973ec8cbb7bb73b2bd", | ||||
| 	"167cc1067bc08a8d2c1a0c10041ebe1fc327b37043f6bd8f1c63569e9d36ded58519e66b162f34b6d8f1107ef1e3de199d97b36b44141a1fc4f49b883f40507ff11f909a017869dc8a2357fc7336ae68703d25f75710b0ff5f9765321c0fa53a51675c", | ||||
| 	"cb859b35dc70e264efaad2a809fea1e71cd4a3f924be3b5a13f8687a1166b538c40b2ad51d5c3e47b0de482497382673140f547068ff0b3b0fb7501209e1bf36082509ae85f60bb98fd02ac50d883a1a8daa704952d83c1f6da60c9624bc7c99912930bf", | ||||
| 	"afb1f0c6b7125b04fa2578dd40f60cb411b35ebc7026c702e25b3f0ae3d4695d44cfdf37cb755691dd9c365edadf21ee44245620e6a24d4c2497135b37cd7ac67e3bd0aaee9f63f107746f9b88859ea902bc7d6895406aa2161f480cad56327d0a5bba2836", | ||||
| 	"13e9c0522587460d90c7cb354604de8f1bf850e75b4b176bda92862d35ec810861f7d5e7ff6ba9302f2c2c8642ff8b7776a2f53665790f570fcef3cac069a90d50db42227331c4affb33d6c040d75b9aeafc9086eb83ced38bb02c759e95ba08c92b17031288", | ||||
| 	"0549812d62d3ed497307673a4806a21060987a4dbbf43d352b9b170a29240954cf04bc3e1e250476e6800b79e843a8bd8253b7d743de01ab336e978d4bea384eaff700ce020691647411b10a60acacb6f8837fb08ad666b8dcc9eaa87ccb42aef6914a3f3bc30a", | ||||
| 	"3a263efbe1f2d463f20526e1d0fd735035fd3f808925f058b32c4d8788aeeab9b8ce233b3c34894731cd73361f465bd350395aebcabd2fb63010298ca025d849c1fa3cd573309b74d7f824bbfe383f09db24bcc565f636b877333206a6ad70815c3bef5574c5fc1c", | ||||
| 	"3c6a7d8a84ef7e3eaa812fc1eb8e85105467230d2c9e4562edbfd808f4d1ac15d16b786cc6a02959c2bc17149c2ce74c6f85ee5ef22a8a96b9be1f197cffd214c1ab02a06a9227f37cd432579f8c28ff2b5ac91cca8ffe6240932739d56788c354e92c591e1dd76499", | ||||
| 	"b571859294b02af17541a0b5e899a5f67d6f5e36d38255bc417486e69240db56b09cf2607fbf4f95d085a779358a8a8b41f36503438c1860c8f361ce0f2783a08b21bd7232b50ca6d35428335272a5c05b436b2631d8d5c84d60e8040083768ce56a250727fb0579dd5c", | ||||
| 	"98ee1b7269d2a0dd490ca38d447279870ea55326571a1b430adbb2cf65c492131136f504145df3ab113a13abfb72c33663266b8bc9c458db4bf5d7ef03e1d3b8a99d5de0c024be8fabc8dc4f5dac82a0342d8ed65c329e7018d6997e69e29a01350516c86beaf153da65ac", | ||||
| 	"41c5c95f088df320d35269e5bf86d10248f17aec6776f0fe653f1c356aae409788c938befeb67c86d1c8870e8099ca0ce61a80fbb5a6654c44529368f70fc9b9c2f912f5092047d0ffc339577d24142300e34948e086f62e23ecaca410d24f8a36b5c8c5a80e0926bc8aa16a", | ||||
| 	"9f93c41f533b2a82a4df893c78faaaa793c1506974ba2a604cd33101713ca4adfd30819ffd8403402b8d40aff78106f3357f3e2c24312c0d3603a17184d7b999fc9908d14d50192aebabd90d05073da7af4be37dd3d81c90acc80e8333df546f17ab6874f1ec204392d1c0571e", | ||||
| 	"3da5207245ac270a915fc91cdb314e5a2577c4f8e269c4e701f0d7493ba716de79935918b917a2bd5db98050dbd1eb3894b65fac5abf13e075abebc011e651c03cafb6127147771a5c8418223e1548137a89206635c26ca9c235ccc108dc25cf846e4732444bd0c2782b197b262b", | ||||
| 	"96011af3965bb941dc8f749932ea484eccb9ba94e34b39f24c1e80410f96ce1d4f6e0aa5be606def4f54301e930493d4b55d484d93ab9dd4dc2c9cfb79345363af31ad42f4bd1aa6c77b8afc9f0d551bef7570b13b927afe3e7ac4de7603a0876d5edb1ad9be05e9ee8b53941e8f59", | ||||
| 	"51dbbf2a7ca224e524e3454fe82ddc901fafd2120fa8603bc343f129484e9600f688586e040566de0351d1693829045232d04ff31aa6b80125c763faab2a9b233313d931903dcfaba490538b06e4688a35886dc24cdd32a13875e6acf45454a8eb8a315ab95e608ad8b6a49aef0e299a", | ||||
| 	"5a6a422529e22104681e8b18d64bc0463a45df19ae2633751c7aae412c250f8fb2cd5e1270d3d0cf009c8aa69688ccd4e2b6536f5747a5bc479b20c135bf4e89d33a26118705a614c6be7ecfe766932471ad4ba01c4f045b1abb5070f90ec78439a27a1788db9327d1c32f939e5fb1d5ba", | ||||
| 	"5d26c983642093cb12ff0afabd87b7c56e211d01844ad6da3f623b9f20a0c968034299f2a65e6673530c5980a532beb831c7d0697d12760445986681076dfb6fae5f3a4d8f17a0db5008ce8619f566d2cfe4cf2a6d6f9c3664e3a48564a351c0b3c945c5ee24587521e4112c57e318be1b6a", | ||||
| 	"52641dbc6e36be4d905d8d60311e303e8e859cc47901ce30d6f67f152343e3c4030e3a33463793c19effd81fb7c4d631a9479a7505a983a052b1e948ce093b30efa595fab3a00f4cef9a2f664ceeb07ec61719212d58966bca9f00a7d7a8cb4024cf6476bab7fbccee5fd4e7c3f5e2b2975aa2", | ||||
| 	"a34ce135b37bf3db1c4aaa4878b4499bd2ee17b85578fcaf605d41e1826b45fdaa1b083d8235dc642787f11469a5493e36806504fe2a2063905e821475e2d5ee217057950370492f5024995e77b82aa51b4f5bd8ea24dc71e0a8a640b0592c0d80c24a726169cf0a10b40944747113d03b52708c", | ||||
| 	"46b3cdf4946e15a5334fc3244d6680f5fc132afa67bf43bfade23d0c9e0ec64e7dab76faaeca1870c05f96b7d019411d8b0873d9fed04fa5057c039d5949a4d592827f619471359d6171691cfa8a5d7cb07ef2804f6ccad4821c56d4988bea7765f660f09ef87405f0a80bcf8559efa111f2a0b419", | ||||
| 	"8b9fc21691477f11252fca050b121c5334eb4280aa11659e267297de1fec2b2294c7ccee9b59a149b9930b08bd320d3943130930a7d931b71d2f10234f4480c67f1de883d9894ada5ed5071660e221d78ae402f1f05af47761e13fec979f2671e3c63fb0ae7aa1327cf9b8313adab90794a52686bbc4", | ||||
| 	"cd6598924ce847de7ff45b20ac940aa6292a8a99b56a74eddc24f2cfb45797188614a21d4e8867e23ff75afd7cd324248d58fcf1ddc73fbd115dfa8c09e62022fab540a59f87c989c12a86ded05130939f00cd2f3b512963dfe0289f0e54acad881c1027d2a0292138fdee902d67d9669c0ca1034a9456", | ||||
| 	"594e1cd7337248704e691854af0fdb021067ddf7832b049ba7b684438c32b029eded2df2c89a6ff5f2f2c311522ae2dc6db5a815afc60637b15ec24ef9541f1550409db2a006da3affffe548a1eaee7bd114e9b805d0756c8e90c4dc33cb05226bc2b393b18d953f8730d4c7ae693159cdba758ad28964e2", | ||||
| 	"1f0d292453f04406ada8be4c161b82e3cdd69099a8637659e0ee40b8f6da46005cfc6085db9804852decfbe9f7b4dda019a7112612895a144ed430a960c8b2f5458d3d56b7f427cee6358915aee7146278aed2a0296cdd929e4d21ef95a3adf8b7a6beba673cdccdbdcfb2474711732d972ad054b2dc64f38d", | ||||
| 	"b65a72d4e1f9f9f75911cc46ad0806b9b18c87d105332a3fe183f45f063a746c892dc6c4b9181b1485b3e3a2cc3b453eba2d4c39d6905a774ed3fb755468beb190925ecd8e57ecb0d985125741650c6b6a1b2a3a50e93e3892c21d47ed5884eed83aa94e1602288f2f49fe286624de9d01fcb54433a0dc4ad70b", | ||||
| 	"705ce0ffa469250782aff725248fc88fe98eb76659e8407edc1c4842c9867d61fe64fb86f74e980598b92bc213d06f337bd5654fc28643c7ba769a4c31563427543c00808b627a19c90d86c322f33566ce020121cc322229c3337943d46f68ef939d613dcef0077269f88151d6398b6b009abb763410b154ad76a3", | ||||
| 	"7fa881ce87498440ab6af13854f0d851a7e0404de33896999a9b3292a5d2f5b3ad033530c558168fe5d2fdb9b89a2354c46cf32a0e612afc6c6485d789511bfef26800c74bf1a4cfbe30bda310d5f6029c3dccdedb6149e4971274e276dccfabd63bc4b9955e8303feb57f8a688db55ecb4b33d1f9fe1b3a8ba7ac32", | ||||
| 	"23a98f71c01c0408ae16843dc03be7db0aeaf055f951709d4e0dfdf64fffbffaf900ee592ee10929648e56f6c1e9f5be5793f7df66453eb56502c7c56c0f0c88da77abc8fa371e434104627ef7c663c49f40998dbad63fa6c7aa4fac17ae138d8bbe081f9bd168cd33c1fbc92fa35ed687679f48a64b87db1fe5bae675", | ||||
| 	"7b8970b6a33237e5a7bcb39272703edb92285c55842b30b9a48834b1b507cc02a6764739f2f7ee6ae02a7b715a1c455e59e8c77a1ae98abb10161853f1234d20da99016588cd8602d6b7ec7e177d4011edfa61e6b3766a3c6f8d6e9eac893c568903eb6e6aba9c4725774f6b4343b7acaa6c031593a36eef6c72806ff309", | ||||
| 	"f7f4d328ba108b7b1de4443e889a985ed52f485f3ca4e0c246aa5526590cbed344e9f4fe53e4eea0e761c82324649206ca8c2b45152157d4115e68c818644b03b65bb47ad79f94d37cb03c1d953b74c2b8adfa0e1c418bda9c518ddcd7050e0f149044740a2b16479413b63fc13c36144f80c73687513dca761ba8642a8ae0", | ||||
| 	"2d7dc80c19a1d12d5fe3963569547a5d1d3e821e6f06c5d5e2c09401f946c9f7e13cd019f2f9a878b62dd850453b6294b99ccaa068e542993524b0f63832d48e865be31e8ec1ee103c718340c904b32efb69170b67f038d50a3252794b1b4076c0620621ab3d91215d55ffea99f23d54e161a90d8d4902fda5931d9f6a27146a", | ||||
| 	"77dff4c7ad30c954338c4b23639dae4b275086cbe654d401a2343528065e4c9f1f2eca22aa025d49ca823e76fdbb35df78b1e5075ff2c82b680bca385c6d57f7ea7d1030bb392527b25dd73e9eeff97bea397cf3b9dda0c817a9c870ed12c006cc054968c64000e0da874e9b7d7d621b0679866912243ea096c7b38a1344e98f74", | ||||
| 	"83bed0d556798f2b419f7056e6d3ffada06e939b95a688d0ec8c6ac5ea45ab73a4cf01043e0a170766e21395f27ab4b78c435f5f0dfe6e93ab80df38610e41158429ddf20296f53a06a017723359fe22dc08b5da33f0800a4fe50118e8d7eab2f83a85cd764bf8a166903bd0e9dcfeeceba44ff4ca4439846458d31ea2bb564645d1", | ||||
| 	"ea12cf5a113543e39504123036f15a5bafa9c555562469f99cd29996a4dfaaab2a34b00557ccf15f37fc0cc1b3be427e725f2cd952e50af7970dda9200cd5ce252b1f29c40067fea3027ed686190803b59d834179d1b8f5b55abe55ad174b2a1188f7753ec0ae2fc01316e7d498b68ee3598a0e9baaaa664a60f7fb4f90edbed494ad7", | ||||
| 	"55266358332d8d9e68bd13432088beadf95833aab67a0eb3b10650414255f299e2670c3e1a5b2976159a46c72a7ce57d59b7be14c15798e09ed50fa312a431b0264d7a1396aa6168bde897e208ece53d2cfc83786113b1e6eac5e9bb98984abb6c8d64eebb991903254abc650c999bb9958a5d7937434b869bc940e21b9dc1cc8982f2ba", | ||||
| 	"4d6104ded730aefe02873f4c741232c8234a6d66d85393aff57fbf56ba6347666988dfc4d58f3cc895a0da598822edeee4533d24ec0ee292fd5e1ad04898ffbc1ff4bef14dec220babcb0f28fffe32a6e2c28aaaac16442bf4feb02917d18bb3a415d84fa9358d5a9852688d846c92271911f934181c30f82434d915f93f155a1ffbf0b125", | ||||
| 	"eb5f579a4c476af554aac11e5719d378549497e613b35a929d6f36bb8831d7a466aa76de9be24ebb55543f1c13924f64cfd648a5b3fa90387315c16174dbf1e9a183c196d9bb8f84af65f1f8212429aadc11ef2426d07d4716062b85c8d5d2dff8e21b9e62b7fa7dbd57d72633054b464fb28583a56ca13ccc5ddc74dae942492f31731e7046", | ||||
| 	"ebddec3dcaf18063e45a76ebeac39af85a1adc2818881ccce48c106288f5988365cca2b4b1d7f037322da46840f42bebdcbc7193838d426e101087d8cea03aaff743d573eb4f4e9a71a2c884390769a6503874125d194bee8d46a3a0d5e4fcf28ff8465887d8e9df771d70157e75df3642b331d2778ceb32ceba868640171ab7a5d22eede1ee44", | ||||
| 	"26d87ec70b57691e3bb359633d3ddba17f029d62cdfe977f5fd42274d79b444a32494d1c01e9f72d03cce78c806df96e93ea78da3a054209924ed765edc4d570f66168dc25ee3114e4017e387440349c8f0a94804761c3055f88e4fda2a49b860b1486a9609095f6250f268b6a4d1aecc03a505632ebf0b9dc22d0755a736faf7ad7000858b5864b", | ||||
| 	"3880f5cc2d08fa70ef44b1f263fcf534d062a298c1bd5ee2eee8c3265806c4ce50b004f3a1fc1fa5b024aaac7f528c023c8181f67c6e1c357425dc4d573bd46b93a542afa3a19bdb140a2ce666e1a01f5c4d2dcd681fa9f5839b797813c394738d5ee4971386c12c7c117d17c7bec324b760aa30cda9ab2aa850284ba6fa97946f710f02449d1883c6", | ||||
| 	"3317d2f452105dd3f4a96f9257af8285a80be58066b50f6f54bd633749b49f6ab9d57d45652d2ae852a2f6940cd5ec3159dd7f333358b12f502325df38843508faf7e246352d201280babd90b14fbf7722641c3601d0e458474439973c611bb5502fd0eb3078f87124ca7e1a016fcb6cfeff65f6a565985aca7122cfa8c5a11da0cb47797c5132333179", | ||||
| 	"f2c5c955d0224e784a46b9125f8fef8a5e1271e145eb08bbbd07ca8e1cfc848cef14fa3b36221ac62006403dbb7f7d77958ccc54a8566c837858b809f3e310ace8ca682515bc655d2a397cab238a663b464d511f02dc5d033dad4cb5e0e519e94a54b62a3896e460ec70e5716b5921bf8396aa86a60123e6287e34570bb01bdc602e113670bf498af2ff10", | ||||
| 	"180e275205691a83630cf4b0c7b80e6df8fad6ef1c23ba8013d2f09aef7abade1827f23af230de90676240b4b3b0673f8afdea0327330055041741f65560d90348de696d34ca80dfe8afae582fe4879d4594b80e9408fb53e800e01ca58552b905c365e7f1416e51c080f517d6bbd30e64ae1535d59decdc76c6624d737868f49f2f719da39ba1344d59eab9", | ||||
| 	"c517a84e4631a7f65ace170d1e5c2fdb259841535d88da323e68c0883e6af7b041cfe05908815a5a9d1b14fa712c2c16fadcf1ca54d3aa954d411240df331b2aebdfb65aced84d0b8aace56ec0aa7c13ec7d75ca883b6bcf6db74c9e98463c484a8262684f29910373430651f90ecffe18b072170e61ee58de20e2a6ff67b3ab00fccbb80af943f20b56b98107", | ||||
| 	"d1a56a5ee990e02b84b5862fde62f69ec07567be2d7ccb769a461c4989d11fdda6c945d942fb8b2da795ed97e43a5b7dbdde7f8fd2ff7154544336d5c50fb7380341e660d4898c7fbc39b2b782f28defac6873523c7c1de8e52c65e4395c686ba483c35a220b0416d46357a063fa4c33fa9c52d5c207a1304ae141c791e62ba6a7374ed922b8dd94079b72b69302", | ||||
| 	"4720b88d6bfb1ab43958e26827730d852d9ec30173ebd0fe0d273edcece2e788558984cd9306fe5978086a5cb6d37975755d2a3daeb16f99a8a11544b8247a8b7ed5587afc5bea1daf85dcea5703c5905cf56ae7cc76408ccabb8fcc25cacc5ff456db3f62fa559c45b9c71505eb5073df1f10fc4c9060843f0cd68bbb4e8edfb48d0fd81d9c21e53b28a2aae4f7ba", | ||||
| 	"f4639b511db9e092823d47d2947efacbaae0e5b912dec3b284d2350b9262f3a51796a0cd9f8bc5a65879d6578ec24a060e293100c2e12ad82d5b2a0e9d22965858030e7cdf2ab3562bfa8ac084c6e8237aa22f54b94c4e92d69f22169ced6c85a293f5e16bfc326153bf629cdd6393675c6627cd949cd367eef02e0f54779f4d5210197698e4754a5fe490a3a7521c1c", | ||||
| 	"3d9e7a860a718565e3670c29079ce80e381969fea91017cfd5952e0d8a4a79bb08e2cd1e26161f30ee03a24891d1bfa8c212861b51618d07429fb48000ff87ef09c6fca526567777e9c076d58a642d5c521b1caa5fb0fb3a4b8982dc14a444732b72b239b8f01fc8ba8ee86b3013b5d3e98a92b2aeaecd4879fca5d5e9e0bd880dbfffa6f96f94f3998812aac6a714f331", | ||||
| 	"4d9bf551d7fd531e7482e2ec875c0651b0bcc6caa738f7497befd11e67ae0e036c9d7ae4301cc3c7906f0d0e1ed4738753f414f9b3cd9b8a71176e325c4c74ce020680ecbfb146889597f5b40487e93f974cd866817fb9fb24c7c7c16177e6e120bfe349e83aa82ba40e59e917565788658a2b254f25cf99bc65070b3794cea2259eb10e42bb54852cba3110baa773dcd70c", | ||||
| 	"b91f65ab5bc059bfa5b43b6ebae243b1c46826f3da061338b5af02b2da76bb5ebad2b426de3c3134a633499c7c36a120369727cb48a0c6cbab0acecdda137057159aa117a5d687c4286868f561a272e0c18966b2fec3e55d75abea818ce2d339e26adc005c2658493fe06271ad0cc33fcb25065e6a2a286af45a518aee5e2532f81ec9256f93ff2d0d41c9b9a2efdb1a2af899", | ||||
| 	"736f6e387acb9acbee026a6080f8a9eb8dbb5d7c54ac7053ce75dd184b2cb7b942e22a3497419ddb3a04cf9e4eb9340a1a6f9474c06ee1dcfc8513979fee1fc4768087617fd424f4d65f54782c787a1d2de6efc81534343e855f20b3f3589027a5436201eee747d45b9b8375e4294d72ab6a52e04dfbb2914db92ee58f134b026527ed52d4f794459e02a43a17b0d51ea69bd7f3", | ||||
| 	"9242d3eb31d26d923b99d66954cfade94f25a18912e6356810b63b971ae74bb53bc58b3c01424208ea1e0b1499936daea27e63d904f9ed65fdf69de40780a3027b2e89d94bdf214f585472613ce328f628f4f0d56217dfb53db5f7a07f54c8d71db16e27de7cdb8d23988837b49b65c12f1771d979e8b192c9f4a16b8d9fba917bcf74ce5a82aac2075608ba6c2d485fa59864b9de", | ||||
| 	"5da68704f4b592d41f08aca08f62d85e2e2466e5f3be010315d11d113db674c4b98764a509a2f5aacc7ae72c9deff2bcc42810b47f64d429b35745b9efff0b18c58653461e968aaa3c2c7fc455bc5771a8f10cd184be831040df767201ab8d32cb9a58c89afbebecb524502c9b940c1b838f8361bbcde90d272715017f67609ea39b20fac985332d82daaa023999e3f8bfa5f3758bb8", | ||||
| 	"71ea2af9c8ac2e5ae44a176662882e01027ca3cdb41ec2c6785606a07d7231cd4a2bded7155c2feef3d44d8fd42afa73265cef826f6e03aa761c5c51d5b1f129ddc27503ff50d9c2d748322df4b13dd5cdc7d46381528ab22b79b0049011e4d2e57fe2735e0d58d8d56e92c75dbeac8c76c4239d7f3f24fb56697593b3e4afa6671d5bbc96c079a1c154fe20212ade67b05d49ceaa7a84", | ||||
| 	"1d133170582fa4bff59a21953ebbc01bc202d43cd79c083d1f5c02fa15a43a0f519e36acb710bdabac880f04bc003800641c2487930de9c03c0e0deb347fa815efca0a38c6c5de694db698743bc955581f6a945deec4ae988ef7cdf40498b77796ddea3fae0ea844891ab751c7ee20917c5a4af53cd4ebd82170078f41ada2795e6eea17593fa90cbf5290a1095e299fc7f507f360f187cd", | ||||
| 	"5ec4ac45d48fc15c72471d795066bdf8e99a483d5fdd599511b9cdc408de7c0616491b73924d0266da34a495331a935c4b8884f57d7ad8cce4cbe586875aa52482215ed39d7626cce55d50349c7767981c8bd6890f132a196184247343566fc972b86fe3c5369d6a6519e9f07942f0522b77ad01c751dcf7defe31e471a0ec00963765dd8518144a3b8c3c978ad108056516a25dbe3092e73c", | ||||
| 	"0d5e74b78290c689f2b3cfea45fc9b6a84c822639cd438a7f05c07c374adced42cdc12d2a9233a4ffe80307efc1ac13cb04300e165f8d90dd01c0ea955e7657332c6e86ad6b43e78ba4c13c675aed83192d8427866fb6484e6a3071b2369a46fba9005f31232da7ffec7952f831aaaddf63e225263531c2cf387f8cc14fa856c8795137142c3a52ffa69b8e30ebc88ce3bbc227597bcc8dddd89", | ||||
| 	"a0fe36f983259921dc2fa7d89002b3066241d63bfc2448caf7e10522a35562be0bfedc3dce49cfce2e614a04d4c64cfc0ab898873a7fc26928dc1927c009d12f6f9b7a278205d3d0057604f4ac746f8b9287c3bc6b929832bf253b6586192ac43fdd29ba585dbd9059aab9c6ff6000a7867c67fec1457b733f6b620881166b8fed92bc8d84f0426002e7be7fcd6ee0abf3755e2babfe5636ca0b37", | ||||
| 	"1d29b6d8eca793bb801becf90b7d7de215b17618ec32340da4bac707cdbb58b951d5036ec02e105d83b5960e2a72002d19b7fa8e1128cc7c5049ed1f76b82a59eac6ed09e56eb73d9ade38a6739f0e07155afa6ec0d9f5cf13c4b30f5f9a465b162a9c3ba04b5a0b3363c2a63f13f2a3b57c590ec6aa7f64f4dcf7f1582d0ca157eb3b3e53b20e306b1f24e9bda87397d413f01b453ceffeca1fb1e7", | ||||
| 	"6a2860c110cd0fc5a19bcaafcd30762ee10242d34739638e716bd89fd537ea4dc630e6f85d1bd88a25ad3892ca554c232c9830bd56980c9f08d378d28f7fa6fa7df4fcbf6ad98b1adfff3ec1f63310e50f920c99a5200b8e64c2c2ca249399a149942261f737d5d72da949e914c024d57c4b639cb89990fed2b38a37e5bcd24d17ca12dfcd36ce04691fd03c32f6ed5de2a2191ed7c826375ba81f78d0", | ||||
| 	"7132aa291ddc9210c60dbe7eb3c19f9053f2dd74742cf57fdc5df98312adbf4710a73245de4a0c3b24e21ab8b466a77ae29d15500d5142555ef3088cbccbe685ed9119a10755148f0b9f0dbcf02b2b9bcadc8517c88346ea4e78285e9cbab122f824cc18faf53b742a87c008bb6aa47eed8e1c8709b8c2b9adb4cc4f07fb423e5830a8e503ab4f7945a2a02ab0a019b65d4fd71dc364d07bdc6e637990e3", | ||||
| 	"3e664da330f2c6007bff0d5101d88288aaacd3c07913c09e871cce16e55a39fde1ce4db6b8379977c46cce08983ca686778afe0a77a41baf447854b9aa286c398c2b83c95a127b053101b6799c1638e5efd67273b2618df6ec0b96d8d040e8c1ee01a99b9b5c8fe63fea2f749e6c90d31f6fae4e1469ac09884c4fe1a8539acb313f42c941224a0e79c059e18affc2bcb6724975c436f7bf949ebdd8aef51c", | ||||
| 	"7a6ea63a271eb49470f5ce77519ed61ae9b2f1be07a96855726bc3df1d0723af3a703fdfc2e739c9d31d25814daf661a23558b50982e66ee37ad880f5c8f11c8130fac8a5d0250583700d5a324894fae6d61993f6bf9327214f8674649f355b23fd634940b2c467973a839e659169c773119919f5b81ee171edb2e5f6940d7551f9e5a70625d9ea88711ad0ed8ab2da720ad358bef954456cb2d5636425717c2", | ||||
| 	"c5106bbda114168c449172e49590c7eeb827fa4e1a2a7a87a3c1f721a9047d0c0a50fbf244731be1b7eb1a2ef30f5ae846a9f38f0df44f32af61b68dbdcd0226e741dfb6ef81a2503691af5e4b3171f48c59ba4ef91eba344b5b697f261df7bbbb734ca6e6daebaa4a179feb17002823281b8534d55a6531c59305f6e3fd3fa63b747bcf0deb654c392a02fe687a269effb1238f38bcaea6b208b221c45fe7fbe7", | ||||
| 	"597716a5ebeebc4bf524c15518816f0b5dcda39cc833c3d66b6368ce39f3fd02ceba8d12072bfe6137c68d3acd50c849873150928b320b4fbc31c1456679ea1d0acaeeabf666d1f1bad3e6b9312c5cbdecf9b799d3e30b0316bed5f41245107b693366accc8b2bcef2a6be54209ffabc0bb6f93377abdcd57d1b25a89e046f16d8fd00f99d1c0cd247aafa72234386ae484510c084ee609f08aad32a005a0a5710cb", | ||||
| 	"0771ffe789f4135704b6970b617bae41666bc9a6939d47bd04282e140d5a861c44cf05e0aa57190f5b02e298f1431265a365d29e3127d6fccd86ec0df600e26bcdda2d8f487d2e4b38fbb20f1667591f9b5730930788f2691b9ee1564829d1ada15fffc53e785e0c5e5dd11705a5a71e390ca66f4a592785be188fefe89b4bd085b2024b22a210cb7f4a71c2ad215f082ec63746c7367c22aedb5601f513d9f1ffc1f3", | ||||
| 	"be6556c94313739c115895a7bad2b620c0708e24f0390daa55521c31d2c6782acf41156271238885c367a57c72b4fe999c160e804ad58d8e565edbce14a2dd90e443eb80626b3eab9d7ab75d6f8a062d7ca89b7af8eb292c98eaf87ad1dfd0db103d1bb6188bd7e7a63502153cf3ce23d43b60c5782602bac8ad92fb2324f5a79453898c5de18415639ecc5c7974d3077f76fc1df5b956723bb19a624d7ea3ec13ba3d86", | ||||
| 	"4bc33729f14cd2f1dc2ff459abee8f6860dda1062845e4adab78b53c835d106bdfa35dd9e77219eaef403d4e80488ca6bd1c93dd76ef9d543fbb7c8904dccc5f71509a6214f73d0f4e467c3e038ea639b29e7fc442ee29f57117740576188ada15a739827c647a46b0271817ab235c023c30c90f2115e5c90cd8501e7b286962fc66ffc3fe7e8978746168314908a41998bd83a1eeffda9d714b864f4d490fdeb9c7a6edfa", | ||||
| 	"ab12faea205b3d3a803cf6cb32b9698c32301a1e7f7c6c23a20174c95e98b7c3cfe93fffb3c970face8f5751312a261741141b948d777b8a2ea286fe69fc8ac84d34116a4674bb09a1a0b6af90a748e511749de4697908f4acb22be08e96ebc58ab1690acf73914286c198a2b57f1dd70ea8a52325d3045b8bdfe9a09792521526b7564a2a5fcd01e291f1f8894017ce7d3e8a5dba15332fb410fcfc8d62195a48a9e7c86fc4", | ||||
| 	"7d421e59a567af70594757a49809a9c22e07fe14061090b9a041875bb77933deae36c823a9b47044fa0599187c75426b6b5ed94982ab1af7882d9e952eca399ee80a8903c4bc8ebe7a0fb035b6b26a2a013536e57fa9c94b16f8c2753c9dd79fb568f638966b06da81ce87cd77ac0793b7a36c45b8687c995bf4414d28289dbee977e77bf05d931b4feaa359a397ca41be529910077c8d498e0e8fb06e8e660cc6ebf07b77a02f", | ||||
| 	"0c18ab727725d62fd3a2714b7185c09faca130438eff1675b38beca7f93a6962d7b98cb300ea33067a2035cdd694348784aa2eda2f16c731eca119a050d3b3ce7d5c0fd6c234354a1da98c0642451922f670984d035f8c6f35031d6188bbeb31a95e99e21b26f6eb5e2af3c7f8eea426357b3b5f83e0029f4c4732bca366c9aa625748297f039327c276cd8d9c9bf692a47af098aa50ca97b99961bef8bc2a7a802e0b8cfdb84319", | ||||
| 	"92d5909d18a8b2b9971cd1627b461e98a74ba377186a6a9df5bd133635250b300abccb2254cacb775df6d99f7c7d0952653c28e6909b9f9a45adce691f7adc1afffcd9b06e49f775364cc2c62825b9c1a86089080e26b57e732aac98d80d009bfe50df01b95205aa07ed8ec5c873da3b92d00d53af825aa64b3c634c5ece40bff152c331222d3453fd92e0ca17cef19ecb96a6eed4961b627aca48b12fecd091754f770d52ba861546", | ||||
| 	"802f22e4a388e874927fef24c797408254e03910bab5bf372320207f8067f2b1ea543917d4a27df89f5bf936ba12e04302bde23119533d0976beca9e20cc16b4dbf17a2ddc44b66aba76c61ad59d5e90de02a88327ead0a8b75463a1a68e307a6e2e53ecc1986274b9ee80bc9f3140671d5285bc5fb57b281042a8978a1175900c6073fd7bd740122956602c1aa773dd2896674d0a6beab24454b107f7c847acb31a0d332b4dfc5e3f2f", | ||||
| 	"3844fe65db11c92fb90bf15e2e0cd216b5b5be91604baf3b84a0ca480e41ecfaca3709b32f8c6e8761406a635b88eec91e075c48799a16ca08f295d9766d74475c47f3f2a274eae8a6ee1d191a7f37ee413a4bf42cad52acd5564a651715ae42ac2cddd52f819c692ecdef52ecb763270322cdca7bd5aef71428fa73e844568b96b43c89bf1ed42a0abf209ffad0eeec286c6f141e8af073ba4adfbbdeda253752ae36c9957dfc905b4c49", | ||||
| 	"329377f7bf3c8d74991a7d61b0cf39baff5d485d79751b0d5ad017d23bec570fb19810105bab79ab5acb102ab972165224d4ec888ec7de5148077fa9c1bb6820e0d91ae4e2591a21fec2f820606ce4bafc1e377f8dc3a5bd1a9e2772a57abccd0b757164d768872c91d02789545ab5b203f688d71dd08522a3fd2f5bcd7df507aebf1ca27ddff0a82afb7aa9c180008f49d1325adf97d047e77238fc75f56356de4e87d8c961575c9f6362c9", | ||||
| 	"f7f269929b0d71ea8eef7120e55ccba691c582dd534692abef35c0fe9dec7dae973cd9702e5ad420d278fe0e653fdcb22fdcb63148109ec7e94f2d0750b28157dd1764376ae10fdb0a4aef3b304bd82793e0595f941226a2d72abbc929f53134dc495b0d65ced409914f94c2523f3dfbbdeeac84ae247ab5d1b9ea33dce1a808885a55be1f3683b46f4be73d9b62eec2585f690056858dfc427aabf591cd276724885bcd4c00b93bb51fb7484d", | ||||
| 	"ac022309aa2c4d7fb628255b8b7fb4c3e3ae64b1cb65e0de711a6def1653d95d8088871cb8905fe8ae76423604988a8f77589f3f776dc1e4b30dbe9dd262b2187db02518a132d219bd1a06ebac13132b5164b6c420b37dd2ccee7d69b3b7fa12e54f0a53b853d490a68379ea1fa2d79762830ffb71bf86aab506b51f85c4b6a41b69325c7d0c7aa85b93b7144489d213e8f33dbb879fce22849865337b620b155cb2d2d36a68832889e30194d36d", | ||||
| 	"d009c2b78a8f02e5e5dbb586ef71fc324b375092e15913ca1a5bfd22d516baadb96867bee3562e77c4a4852344a1a76c30728be5e22400b4cc41711f66754c246a520498d8c24f0205b9c873748dbeb67fe1ad099ad04cf89f4b517f0aa481136d9f6de2d727df01c6aa4099da59d4382b51e25fd47c33d9842c32b62331e50794bfe8b61b3ba9de1b8b704779c6d65edff3af00f121ab4a7ea384edabe47c6d0098a48991f387ca4444135ec59d46", | ||||
| 	"c00bab36cce69899817d1425016d222d7303197ed3e3fdcac744705e7f178a1ac745968900f69299163e19b3161f3e0a4cc55aa2e4e71e0ee6ac427d1f4d14e063f68d303ddfbb18118335cfa7a6a90d99c38319ee76f7a884846a9e0b68030bf28e78bfbd56359b9368842814da42b04cb0e307d5d846dc22f049147bae31b9a956d17676a8cc348dafa3cabc2007a30e730e3894dddf9999fb8819086311f0703e141613ed6dcd7af8510e2dc435b0", | ||||
| 	"c9789152a9fc29698d49ed95f09bd11b75f18a8c5615a73dbe54ae5e550027fd0ae6a8b60667040c1b12de3d1ee3f6bf061c78c951a3210effc912e19f482dd4de152063c588c44903bc11761706fd935afa040df085b08144d83d0dde32b46ab52f4fae98ac116c7ff11d7f553450c2e37b9c5f0b1dd9e0b8640a24cba6f2a5246c41f197f46e3dc8a29131c79bef3351c6e277a0a34442274d546ccd058891277473d668420f121750d19cd684267405", | ||||
| 	"06a15a0731ce52557e368bcbaa11ef3399299e36fb9f2eda6e5726907c1d29c5c6fc581405ba48c7e2e522206a8f128d7c1c939d1132a00bd7d6366aa82724e968964eb2e373563f607dfa649590dcf5589114df69da5547fef8d1604cc4c6de1ed5783c8746918a4dd31168d6bc8784cd0c769206bd803d6ca8557b66748770402b075ef44b38157d4c0da7c6281725a2065d087b1f7b23455fa673bdeeba45b983311c44eabe9ef4b7bde3420ae9881863", | ||||
| 	"d08aacef2d7a41aec09473bd8a44f628e15addb7b9e5b77a1e09c8ab4942f379a0bfcb324d580b774666f18ae78dd36710824ff12393f059068fe4b559c53662c2b0e6c69e23785c8f32554e837ec1714bee902e60737b639dd933af4f68cb9d7de77e1f3b28e5b122891afce62b79acd5b1ab4ba411662cc77d806449e69c5a45a143b742d98ac84a0826d68433b9b700ace6cd472ba2d58a90847f42ce9c43f38ffc017db4bf40450b2eee1f4594dc740c0f", | ||||
| 	"6a6058b0a498b7ea76a93c646eb9b8629f0cba4a0c726420c5f67ba9b0412cade356abdf0a4fb94384bad32ce0d5dd9e23dcaae1d6f28ff8683616b30f1392890c67b3a2c04b360893b801f127e527e4da82e239f4c878da13f4a4f1c76db07190e77ec123995168102fb274434a2d1e12913b9b5cbab4aacaad2bd89d88b3ca2b8e60dacf7c22c9379097ff60880f552e320ca3b571994f52534470feee2b39e0dadb5cd88257a3e459a4cc6f12f17b8d54e1bb", | ||||
| 	"adeced01fc5671531cbb45679f5ddd42b3a95151677b6125aaf6f5e8f82fbabaa5ecf7c3552c2458587224f0042870f178f5fca5465250e75d71352e652eeed23cdb7f915f5ebb44099b6db116ca1be45530ac8ed32b7f161d60ed4397ad3d7d649ae6bf75ca5bec891d8e595605be9764f3a03965e1fe0eaffbf212e3df4f0fa35e08ff9d0091e6d4ac4748edfe43b611085a6ffec163014655fdd839fd9e81b63b1fa8cae4ec335ec343289758e389a79ceedfae", | ||||
| 	"d014592f3a83ba40af366f137c674724916c3cdd3f6cf9d4c5c7c8d6d51ebf26e315e2c12b3546be56fb52382904046ecbd2f5b883aa4ff473de6f0c26ab862c3fa34bf3d880cc1911ce39a4088c6617c179dc5faf68a2c488bbde12d67b50f73abcfab0e3b062e68c95363e11f5f1de8ec36ed01ea21442518089045df67d346135283ad5b3fff80cf57f20876849f6db9fa139728358415a90610f69ec720fc92d8234e3e122551e9df2c644c4a2c4e3734d07de8e", | ||||
| 	"c0d0c37838873ba8757d6e41b409605043bc1635edcd731219587676d94217e9f0ab44b71de25000661ce7303b7015f45e6eaa7b7ebef92b8f4a34c902c908d2172185505fa33aca5a41be83079316cdfdd430fc2c45f505f85d867e6d516f7e1bf19c001d9f43018968aab65ec031b3801399231c83ec9e622dab5629922a6b424cab938c135ff7310501c2c02971bfd2f577e25904d1a618baf0859f77f4e8b1d0cde9544e95ec52ff710c0672fdb3d891feeea2b017", | ||||
| 	"7022e7f00902219ba97baa0e940e8ac7727f58955aa068c29680fac4a16bcd812c03eeb5adbcfe867a7f7c6b5d89f4641adb9173b76a1a8438866f9b4f640ce2aedf5f1080c890bcf515b4be4e3e512352f1e5323c62ec46cb73f3d71be8235fee55a154763f7c3f9aeb61ffd28f4cd93d3310f608e2133586bf1ab3f102de96f64c68a4668de8acb2a76a7ce0cddddc8fa3df5e9d230823da16ed9ebb402d36e38e6e018795e5a71517ecab5f9ca472b9ced8ff69d2d195", | ||||
| 	"acaf4baf3681ab865ab9abfae41697141ead9d5e98523c2e0e1eeb6373dd15405242a3393611e19b693cabaa4e45ac866cc66663a6e898dc73095a4132d43fb78ff7166724f06562fc6c546c78f2d5087467fcfb780478ec871ac38d9516c2f62bdb66c00218747e959b24f1f1795fafe39ee4109a1f84e3f82e96436a3f8e2c74ef1a665b0daaa459c7a80757b52c905e2fb4e30c4a3f882e87bce35d70e2925a1671205c28c89886a49e045e31434abaab4a7aed077ff22c", | ||||
| 	"84cb6ec8a2da4f6c3b15edf77f9af9e44e13d67acc17b24bd4c7a33980f37050c0301ba3aa15ad92efe842cd3ebd3636cf945bb1f199fe0682037b9dacf86f162dadabfa625239c37f8b8db9901df0e618ff56fa62a57499f7ba83baebc085eaf3dda850835520344a67e09419368d81012168e5de5ea45158397af9a5c6a1657b26f319b66f816cd2c28996547d697e8df2bb163ccb9dda4d6691dffd102a13667ab9cde60ffbfb872187d9c425a7f67c1d9fffff9276ed0aeb", | ||||
| 	"6a52c9bbbba454c14540b2be58230d78ecbeb391646a0c6fcce2f789086a78364b81ae85d5396d7cfa8b46bda41e3083ec5cf7b4c47dc601c8a697df52f557defca248506dbebab25657f5a561d09625b7f4b2f0119a12beeac087efc9d350a735c35d2431c1da7dda99befb17f41a3dc4da0f00bb95366be128538ce27763d81f832fe3c1d4efc07b5b08ad8dc9e65fb5e48546664e18cb2d3bb3fe1f56fa7aae718c5e3bbdeaf70e15023f6a25b72a2d177fcfd04211d40664fe", | ||||
| 	"c3c4d3b31f1f5f9538923df3478c84fffaef411520a542da9a220ee4132eabb9d718b5076fb2f985485e8ba058330aed27ddfd3afa3db34aa60301088caec3d0053828c0c2bc87e2e61db5ea5a29f62fdad9c8b5fc5063ec4ee865e5b2e35fac0c7a835d5f57a1b1079833c25fc38fcb14311c54f8a3bd251bca19342d69e5785f9c2e43cf189d421c76c8e8db925d70fa0fae5ee3a28c4047c23a2b8a167ce53f35ced33bec822b88b06f41558c47d4fed1bfa3e21eb060df4d8ba1", | ||||
| 	"8d55e92136992ba23856c1aea109766fc44772477efc932b3194af2265e433ed77d63b44d2a1cff2e8680eff120a430fe012f0f09c6201d546e13ad46fc4ce910eab27bb1569879abed2d9c37fae9f1267c2216ec5debcb20d4de58461a621e6ce8946899de81c0add44d35e27b7982a97f2a5e6314901caebe41dbba35f48bc9244ca6dca2bdde7306435892f287036df088633a070c2e385815ab3e2bfc1a47c05a5b9fe0e80dd6e38e4713a70c8f82bd32475eea8400c7bc67f59cf", | ||||
| 	"5016284e20362610fa05ca9d789cad25f6d43263787e7e085476764ce4a8908ce99b262b375e9d106170b1bec1f473d5e777e0c1896533040e39c8c1465e07907ef5860e14e4d8310013e35f12090e0bfc687474b1f15f3dd2033a0edac5246102da4deec7e188c3517d84d9c2a0a4497a4c5f82a30f1ba009e45ee6eb3ab4368c720ea6feee428ffd2c4cc52debb8d634a64176572c72368f94a66689f23f8a01218f532117af5a8060d140e7ca435a92882fcb5630ebe14a4805f1dc83", | ||||
| 	"05456ec59b8d41bbd736727976b96b38c43827f9e16169be673ff37870c2ecd5f0d1ea1a136be4cc7b047a02a4421d484fd2a12ece418e42ee391a13a0b1df5a0162b29ab70d3fe3e04ba6ab26b37d62b7cf05a5e2f033611bf970b8e1f30e198e483e740fa9618c1e8677e07b61296b94a9787a68fba622d7653b5568f4a8628025939b0f74389ea8fced6098c065bf2a869fd8e07d705eadb53006be2abb716a3114ceb0236d7e916f037cb954cf977720855d12be76d900ca124a2a66bb", | ||||
| 	"eb6f60b83fcee77060ff346aaf6ec34d82a8af469947d3b5074cde8eb26566eb1fa039bcc707738df1e95869bd827c246e88436f0614d9834ead5392ef376105c4a9f370071cdeaaff6ca0f18b74c3a48d19a717253c49bd9009ccbfdd5728a08b7d112a2ed8dbafbbb46d7a75dc9a05e09bfde1a0a92d74a51887f9d123d7896e9f9d0057b660ed7d55454c069d3c5260411db4cdc67e7b74f680d7ac4b9dcc2f8baf72e15e6b3cafebcdf449a6436ed2c398b675f79c644747c57553bf7ea2", | ||||
| 	"187a88e88514f6c4157c1ba40b442baae1ae563a6c989277443b12a219aa484cb9fa8adbb9a29d429f50155321b15664926317477079c7060dfdaa84c1d74bba78892c34e6f21ad35208d2ae622012401696bff5cd57b6485944b3db7b9071fa5f57fbfb1085d91bb9cff5808d662cdc6c8157249478262c44b7fbc397ed42a4977b202e817717bfccc9f0467294062313f7705251ed09573f16d23429361fada259dfb300369c4198f07341b38e84d02cdb74af5de6aab1fc2026208ea7c418c0", | ||||
| 	"be31bc96606d0fab007e5caeded2f1c9f747c759777e9b6eef962bed49e45a1d4fc993e279d024915e600865ecb087b960584be18c41114d3c43f92169b9e0e1f85a0ebcd4e196376ccdc920e66103cd3b1c58407d0aafd0e003c4e341a1daddb9f4faba974362a32f35db83384b05ae8e3322d728893861afd8b1c940de5a17f691e763ce4969b6d94f67fb4a0235d100225bd8602f291388f0ca4a568748ad0d6040f1262eac2aede6cd27419bb78a394c1ffad72c262be8c3f9d9619d633e51d0", | ||||
| 	"4d83d85ca838b4518588f2a90228a4dd18f14dd5b4c012d26298a97d848abbd825d221d02cceb6e8c701b4ad00e1dee4889b5c533e4bb60f1f41a4a61ee5478be2c1b1016c30345afd7a5253668260515e70751f22c8b4022d7fe4877d7bbce90b46531507dd3e89549e7fd58ea28f4cb23d33662bd003c1345ba94cc4b06867f778957901a8c441bee0f3b12e16463a51f7e50690356971dd73a686a49fda1eae46c9d54fba262811d698025d0ee053f1c58591c3bb3cbde69de0b31549ef5b69cf10", | ||||
| 	"cdeb07d36dc5f9a1cd717a9e9cca37a2ce93caa298eee63571f7d6c5fde2a11c666cf53cf2dcb41ca2ea2319e7230ca68e38c647905928713a13982bf47fe33d7095ebd50b2df976208920a43eb2e29b942f32467403c45cea18bf44e0f6aeb155b48a8e5c471fec972a9d62f7ae093d2758f0aaec7ca50cb4725bfa219f1a3a46ad6bde7361f445f86b94d66b8ece080e56c510250693a5d0ea0ae87b4421860b853bcf0381eae4f1bf7c5c0472a93ad18407bc88475ab8560d344a921d3e86a02da397", | ||||
| 	"a598fad52852c5d51ae3b10528fc1f722e21d44fbd42ae5acdf20e85a28532e646a223d27fd907bfd38eb8bb75175636892f8242877aab89e8c0824d368f3339ce7a82aa4e5af6db1f3b588a4d667a00f67bee37cfd2724dde06d2909fb9e58d892f4cfd2c4ca85acdf8256f5458b030a6bda151154ff2e6d7a8da90b54a2884c8a99fab5a4ac211ff23dc0975f4f592fd1b6b9dc7783bdcd2d4ca4e68d2902f2013e122cb62e2bff6b0a98ec55ba25837e21f1cfe67739b568d43e6413dab2bd1dc471e5a", | ||||
| 	"17b68c74c9fe4926e8102070916a4e381b9fe25f5973c9bd4b04ce25749fc18931f37a65a356d3f5e5a1ef125d546f4f0ea797c15fb2efea6fbfcc5739c564693d47adeb12dcb3d98a2830719b13247792cb2491dca159a28138c6cff925aca42f4fdb02e73fbd508ec49b25c60703a7595a3e8f44b155b371d525e48e7e5dc84ac7b17c52bf5e526a67e7187234a2f19f57c548c70fc0b27183df73ffa53fa58b658034c896fa791ae9a7fd2620f5e46ce84c842a6e60e9324ae4db224ffc87d9617cb85ca2", | ||||
| 	"b9e4267ea39e1de1fed0579f93bb351007c9f8fcdd811053fae33f09e2753d7428f04e1a9efcd45ea701a5d87a35b3afb2e6b65365dee6ead0bbb611b7797b212ac688653f542e604a39df277f12514ddfee3b4e27b98395c2cd97a203f1f1153c50327965770802ec2c9783edc428271762b275471e7ac65ac36523df28b0d7e6e6ccc7674268a132a63411fc82c0738dbb68af003b769a0bf9e6587b36476cb465350fee13f88ea355d47ffac7b0f964f4139db11b7642cb8d75fe1bc74d859b6d9e884f75ac", | ||||
| 	"8ca704fe7208fe5f9c23110c0b3b4eee0ef632cae82bda68d8db2436ad409aa05cf159223586e1e6d8bdae9f316ea786809fbe7fe81ec61c61552d3a83cd6beaf652d1263862664df6aae321d0323440430f400f291c3efbe5d5c690b0cc6b0bf871b3933befb40bc870e2ee1ebb68025a2dcc11b68daadef6be29b5f21e440374301bde1e80dcfade4c9d681480e65ec494a6af48df232c3d51447b9d06be714949249c44c43cf73ed13ef0d533e770284e51369d94ae241a5fb2f163893071b2b4c118aeaf9eae", | ||||
| 	"4fd8dd01012bb4df82bf42e0683f998e6f52dd9c5617bae33f867d6c0b69798cead8179346d70acc941abbbdd26e3229d5651361d2252c72ff22db2938d06ff6fc29a42fdf800ae967d06479bc7bbb8e71f40b1190a4b7189ffc9a7096cdb76d40aec424e1388e1eb7ef4ac3b34f3f089da8fda7d1927f5d775c0b2801d22dd1265c973158f640cec93edfed06dc80b20ef8c496b98289d54d46ccd205951cbb0f4e7daeb866b60bacb483411e4382b6f04d472843186bd0e31fbaa93e5c901ec028efafeb45fc551a", | ||||
| 	"e9ee1b22b04b321a5fdd8301627011f583887d77560fb0f35552e207561f81e38ac58a0d0aeaf832d1ee72d913720d01f75574e9a321864fe95f4d0d8f0b8db97649a53e71e940aede5c40b4b9105daa42a6fb2811b61209247534cbaf830b07abe338d75d2f5f4eb1c3cf151e9edabe2c8d5f6fff08fac1495ef48160b100d30dcb0676700bcceb28723a29980ab0766a93abb8cb3d1963007db8458ed99b689d2a7c28c788743c80e8c1239b20982c81dadd0eed6740c65fbc4ef15c7b5569cb9fc997c6550a34b3b2", | ||||
| 	"ec01e3a60964360f7f23ab0b22e021815765ad706f242265ebc19a2bb9e4eac94393952dcf61aae47682671a10f9165f0b20adf83a6706bfbdcf04c6faba6114653a35584267267873291c6fe7ff5f7695243143421509502c8875aafa9e9afe5be5ef2c851c7f35d69be5d3896000ccdbbfab5c238bb34d607cfe2d55d748880545b4aa7ca61137992925189025c62654b1f20d49c3ccd75aa73ce99cd7258dabedd6480a9f5185531fc0118beb68cc0a9cd182f6973287cf9252e12be5b619f15c25b65c71b7a316ebfd", | ||||
| 	"db51a2f84704b78414093aa93708ec5e78573595c6e3a16c9e15744fa0f98ec78a1b3ed1e16f9717c01f6cab1bff0d56367ffc516c2e33261074935e0735ccf0d018744b4d28450f9a4db0dcf7ff504d3183aa967f76a507357948da9018fc38f150db53e2df6cea14466f03792f8bc11bdb5266dd6d508cde9e12ff04305c0295de29de19d491ad86e766774bb517e7e65befb1c5e2c267f013e235d8483e177214f89978b4cdc81aa7eff8b39f2825ad3a1b6ac1424e30edd49b067d770f16e74dd7a9c3af2ad74289a676", | ||||
| 	"00e40f30ae3746edad0f5dd03d0e640933cf3d1694804c1e1ed6399ac36611d405196ee48f129344a8512feda16a354517871322bd5d9c6a1b592933eab531923efb393ffb23d9109cbe1075cebfa5fb917b40df028a621460ff6783c798792cb1d9635b5a6f84ec13918fa302924649b5c7fcb1f7007f0d2f06e9cfd7c27491e565a96c68a0c3644f92cd8f38857258c33801c5d537a83dfe583cba59d7eec7e394199c0a2660a62fabe3ed2099d57f315a6cd8de1a4ade29d977f15d65759cff433e5ac0c182aef3761163e1", | ||||
| 	"3c5ea24d0d9b618294a263f062b2414a722be4eb10dfc346a6ec3b821d7396eba61cd6ef33618b04cd087a811f299d4606820227f16000d7c839062b96d3e3f59cd1a082448d13fc8f56b3fa7fb5f66d0350aa3b72dd7c165d590282f7da2e12cfe9e60e1796122bb8c2d40fdc2997af634b9c6b127a893dfb3467909378300db3da911be1d7b616bb8e0572433e65527e15d936500a2c60e9f9909dcf22ab5e4b6700f0238c205b4a813626fac3d945bab2637fb08203044a73d20c9a3fcf7c3fc4eb7807c3276dd5f73ce89597", | ||||
| 	"9271aeeebfac46f4de85df78f1bfd36136aa8905e15835c9e1941176f71e3aa5b1b131843d40479735e23e182a2bd71f66f6149dccb7ed8c16469079dc8590bbf165374951785f4531f7e7361de62f936cfb23a2b5bdf186632e7042a0dd451fdc9b7208f923f3a5f250ae590ec348c63a16c3aacaf7379f53b5dd4152dcd40d23e683e2156e64c592ffc07e2cd6bbeebef4dd590b2f6b2bcbf08fcd111c079f5c4033adb6c17574f8756ecd87be27eff1d7c8e8d0324438d59ae171d5a17128fbcb5533d921bd044a2038a5046b33", | ||||
| 	"4e3e533d5bcb15793d1b9d0468aaee801f32fdb486b11027183553a09ddbee8213924296f2815dc61577297459e834bf1c7a53f87d43782209e589b8295219ba7073a8fff18ad647fdb474fa39e1faa69911bf83438d5f64fe52f38ce6a991f25812c8f548de7bf2fdea7e9b4782beb4011d3567184c817521a2ba0ebad75b892f7f8e35d68b099827a1b08a84ec5e8125651d6f260295684d0ab1011a9209d2bdeb75128bf5364774d7df91e0746b7b08bda9185035f4f226e7d0a1946fcaa9c607a66b185d8546aac2800e85b74e67", | ||||
| 	"b5d89fa2d94531093365d1259cc6fe8827fea48e6374c8b9a8c4d2209c280fa5c44958a1847222a692a59e6aa2696e6cdc8a543dd89b0ce03bc293b4e78d6ef48e1839694ccd5c65661143095c705b07e3ced84a0f5959114dd89deb956ab3fac8130eb4a878278205b801ae41a29e34146192308c4e759b374757b0c3b00319bce92a1b95a4d2ee179fd6714ff96155d26f693a5bc973f84ac8b3b91e3926276297532d98b46992a3f104c08100bf1671c43134bac280c617da711e90a0100137525375ebb12802a428885ae7fce6514a", | ||||
| 	"40e3d8048fc10650cb8a7fc2e7113e26dec34f9ca2d5129cd10a8e8e44d113d61ee48c7d003e19fd307fc6debd70feb30243f298c510ccc4418355ce143066f067ad7c6de7288c3080e7ad46a23c8d34deb55a43e652fe90444ad3c57d3ec1e1c489d63ef915a24bc74a7925a0a7b1e1523f21ca8fee78df24e3d0a68d0013423db97c280799a0618229c0f2c167289a891e5c8d6661ab21285951c31710e3b5fe55f6347fe16d9b40507948a59252efeb616df83e5c098b07d0a7247cd371daff0e50491c582503fd89f79ba94d6af9ed76", | ||||
| 	"1fa444de01dd3901e2b4684e3d7a799ffa02d85afd35fb30fe4c9d672837bee6dd8a3b8608b4bb5e589220ad5a854f46b46e41c6d57ad124a46beab4169ff69fee7e3838a6165e19dad8eb5d7bf53d4edd3cd2769daf219510a02fdd2afe0c0e1da3cd30fcd1aa88b68965586f07a25a1720fbd90a096ea30fc8e945e3637d7857c8a9c0ab4154ffb2000e57b5f9adfa4e4eaf8065bc3c2b2e75f495963325588785a6ce417dcddffd299873b15dcccca128d63cd4eeeadb64cda28099a9ad7c80d34844901f26b88b00b9aafeb2f90286d29d", | ||||
| 	"fde0a0d9d813983bd1f55cf778a003a2023b34a555322ab280584537bc6bdd844d22a7d6066c18da83ec09f3d8d5a1aab4be0d5ce19b436052f6e259a4b49017a1f47f1fe2bf115d5bc8599fb216351c60dd6b1bedb2e6f4dcadf424b833501b6f099cbfad9e2290680fb69c25032b42a6274f7cb9b5c5950401354838a45f7cb77b95bf54718e2f3d3d9fb91eb2311903980277396398d9736d8e92fd838594ac8a537c6c529db5a8a4f89290e6ba6f20ac0e5ed6fef40901d0e0e8e3e502990811f9acaae555dd54eb1bcd96b513e2fe751bec", | ||||
| 	"9f8e0caec87858599f5ab29bff86da78a841a918a023a111098687ecdf2747612d3f3809d9ca400b878bd4f92c43a1004f1c17c7f19a3cd1ce449bd2b23aff551623c37dd8c0be56bf3fd857b500c2b9f9ccea62481944090a3cf3b6ee81d9af8eeb60f65ef150f9fa4d3ed6ce4762d3d4f174ee8ccd460c25cafac0ea5ec8a6a4b2f9e8c0520cb7061155e532cb65f188b01e4b9086db951f504b060c296b326b3fc1c590498ecce594f828f4a10ea416675720ae505295d38a791bd0e93f428448a8f4c1fc0af53604a9e8255384d29ae5c334e2", | ||||
| 	"33d1e683a4c97ee6bbaa5f9df1a88cb53b7f3c157b6045d70a56fda0ccbd3a1fa1f049cd564da072b53f415bf5fb843771c1d2551fd075d33377362b2f7c0645f9723123d11975991db8a2b518f02e2c7c30342a044754290bae2c77496d755e5981f12e6b0a0174280b958bf11ed628a9062775993ced04bf752ea8d165e3ac2177d7cd1b9371c44efa98f0b3e68602a839d384eec007979f46429dafb138cbc231ad928a9f65f7d66fac77416395e8f1debaaf76ec2e4e03e8674102cd26f614739f3ec9f949033df1fb97e87c2326d65aef94ed5f", | ||||
| 	"180048f09d0b480887af7fd548a85abf605440c1ddde6afe4c30c30670233f7bf928f43b4681f59279ebbda5e8f8f2a1abefdee129e18ac60f9224e90b38b0aabd01308e0a27f41b6fb2ee07ee176ec9048c5fe33c3f7c791469c81f30e28170585b9f3e7e3c8c2e9d74370cb4518f13bf2dee048cbd98ffa32d85e43bcc64a626b40efb51ce712925fdd6fee006dc68b88004a81549d2121986dd1966084cd654a7c6686b3bae32afbd9625e09344e85cf9611ea08dfce835a2e5b3726e69ae8a76a97db60fcc539944ba4b1e8449e4d9802ae99fae86", | ||||
| 	"13c0bc2f5eb887cd90eae426143764cf82b3545998c386007cca871890912217aa143ac4ed4ddb5a7495b704aa4de18419b8664b15bc26cfc6596a4d2ae408f98b47a566476d5802d594ba84c2f538def9d016661f6404bb2337a3932a24f6e30073a6c9c274b940c62c727242e24466084a3ea336365d71ea8fa6499c0ea8d59eea505f1126b99c795023c4963aa0d99323d0391e8701110edf551b2d3799e1063ca443f1add162156e445502ca1a052fe70c289838593b58839fc63de128a03e2bbf389e22ae0cf957fd03315ee407b096cc1cfd92dee6", | ||||
| 	"6f1eb607d679efef065df08987a1174aab41bdac8aece7726dfa65805d6fff5b3d17a672d96b770dc32165f144f0f7324822a5c87563b7cd9e37a742ae83ef245d09006d91576f435a03476f509ea2936636232f66aa7f6cdf1ac187bbd1fcb8e20f8791866e60ed96c73374c12ac16795e999b891c64507d2dbd97e5fc29fac750ad27f2937cbcd29fdafccf27ab22453834d475f6186eaf975a36fad5c8bd61c21da554e1ded46c4c39765dcf5c8f5ccfb49b6a4dc562c919d0c7d8940ec536ab2448ec3c9a9c8b0e8fd4870cad9de2577c7b0c38563f355", | ||||
| 	"dcdd993c94d3acbc555f464871a32c5da6f13b3d5bbc3e34429705e8ad2e76393fdd96a69a94acb652f5dc3c120d41187e9aa919669f727c4868013b0cb6acc165c1b7706c52248e15c3bf81eb6c147619467945c7c48fa14a73e7c3d5bec91706c567145342a026c9d97eff97ec672c5debb9df1a998083b0b0081d65c517b3e5634c95e347e781aa30ca1c8af815e2e494d844e847fdcb41622894a518dc36571123a40bfdbe8c4f4cff44d83c61dd9dcd24c464c53b395edb31efee9f3aa080e87cdc3d22d613ae84a53c9249c32c96f9a3bc4629bb126a70", | ||||
| 	"49971f9823e63c3a72574d977953329e813b22a8387cd13f56d8ea77a5d1a8a20012632d1d8732bbcb9f756b9675aab5db927beacab7ca263e5718b8dfa7b2eed9a91bf5ed163b16139d45f7b8cc7e3f7bdda6202106f67dfb23b7c315ee3e17a09d466b1e6b13e7c7428184a979f5358667b4fa8bd40bcc8ea46058db44587a85377ac46bf155136c09ac58cb6c27f28e17028c91e7e8f74d5b500e56293b316974f02b9d9ea205d9b6ac4cfb74eb8eb0c944577fd2f41316368307beab3e327bf7dbaa0a4428836ec4e895dea635234abeaf113ceeadac33c7a3", | ||||
| 	"c57a9cc958cee983599b04fe694f15fb470fcbc53e4bfcc00a27351b12d5d2434444253ad4184e87b81b738922ffd7ff1dc1e54f39c5518b49fb8fe50d63e3935f99e4bd125e8dc0ba8a17fd62de709339a43fabe15cf86d96a54010112170c340cfac4132182eed7301402bc7c8276089dec38488af145cb6222525894658f03501204b7a66aba0be1b557b28a2f652d66f7313ed825ecc4d8596c1be7420d4425b86a1a90a5b7f30d0f24e0d1aae0eb619ca457a71699e44be612a4011c597ee80b94d5507e429d7fc6af22579cd6ad642723b05ef169fade526fb", | ||||
| 	"0568a672cd1ecbaa947045b712e2ac27995392fbef8f9488f79803cbee561c212287f080eca95adb5ba42739d78e3ba667f06045d87850d3a0499358649caa257ad29f1a9c511e7054db20554d15cbb55ff854afa45cae475c729cea72ede953522031865bc02b95589ed4d9841c552a8cc94904a93ed09ed77222f6c178195056be59bc4e96a815adf534e6b466fb47e262ff79c803c157a21b6e2269c2e0abeb494113cd868d8466e82d4b2f6a28b73645853d96bc9242515d803e33294848d3fe42fdff68da53c03491636beede47ff1399dd3d54a5e914d55d7adf", | ||||
| 	"3f19f61a4cd085796731ac9f85a75a8bce77031932c31762d87d8b8d07b8bd19ff78d6b7d1bd1e87f3a4f41aad03b6c4d17a6cbc86be55f7c8b88ada047bb04f8d49f1c34bcf81cc0f3389ad01a758fc7eeb0072aa9ad1481992bfdde82e438e75590a4423832dfbe3756e2229ea873bc3606e6d72174cb2163bf40b5d49c81009dab85ecc03e311351bbf96e32c030a2b276a7698cb25bc2c967acb3213161a1fdde7d912cd6a804490f8056c47da1333f6e35c41e749c2c23919cb9af5eec5652e6e072b034fb1682e9aaa194a9c0bd456ea0b008d14dbce37967a7a8e", | ||||
| 	"705f98f632d99d3651793825c38dc4deda56c59eac539da6a0159c83131cf8ab6f2ee0c3b74111fde351f7aa1a8c500a0cecab17c212d2c58ca09eae608c8eefc922b9902ef8d6832f799ba48c3c28aa702b3242107edeba01daafe424406a3822965056cfe8783455a671e93b1e2eae2321364f1871471c82124df33bc09e1b52882bd7e1c4c7d0b2f3dd4a28c2a002a43246768af0700f9659de99d62167be93177aabf19d678e79e9c726ac510d94e74873eda99620a3961930cd91937c88a06d8153d64fd60da7ca38cf26d1d4f04a0df273f52127c53fdc593f0f8df9", | ||||
| 	"ea6f8e977c954657b45f25480ff42c36c7a10c77caa26eb1c907062e24fbca5aebc65cacca0de10abea8c78322f08672e13d8ac16996eca1aa17402eaea4c1cc6c800b22dc18cb8d620192d74bac02c07b5cfa61e513c7f28b7e29b9700e0e442720bf4c669d4995da19d19f841d9eb68cc74153592591e3bf059ef616b95305aa453b32fe99a91afb35bd482cf2b7aa42702837a53be3c38883d2963020e347556f841254ec6b85854485fe8c520b05f2ea67a9bf3981555c20991e2bacd4db5b418228b6002d8d41c025cb472bf5443aaa885974a408ea7f2e3f932c600deb", | ||||
| 	"408190134ed06556811b1af808ab2d986aff152a28de2c41a2207c0ccc18125ac20f48384de89ea7c80cda1da14e60cc1599943646b4c0082bbcda2d9fa55a13e9df2934edf15eb4fd41f25fa3dd706ab6de522ed351b106321e494e7a27d5f7caf44ec6fadf1122d227eefc0f57aefc140d2c63d07dcbfd65790b1099745ed042cfd1548242076b98e616b76ff0d53db5179df8dd62c06a36a8b9e95a671e2a9b9dd3fb187a31ae5828d218ec5851913e0b52e2532bd4bf9e7b349f32de2b6d5d3cdf9f372d49617b6220c93c05962327e99a0480488443349f0fd54c1860f7c8", | ||||
| 	"5f9e5c6f38573a85010a9d84d33f29c057003b2645e3ea6f72cbc7af95d197ce6a06b13fea81722853e6991791b8b15091cd066f5ed913592ed3d3af5370d39ba22beeb2a582a414b16824b77e194a094c2afdcc09aa73ce36f4943cca5ae32c5017dc398801dd92a47382d9327c9f6cffd38ca4167cd836f7855fc5ff048d8efba378cdde224905a0425e6b1de061fc951c5e624a5153b008ad41160a710b3ff2081748d5e02deb9f841f4fc6cf4a15153dd4fe874fd447482696283e79ee0e6bc8c1c0409baa5ab02c5209c319e3169b2476149c0c6e541c6197ca46e004eef533", | ||||
| 	"218c6b3508aec69574f2b5039b30b942b72a8349d05f48ff945bbbe5c8957d5a6199492a6bf54bab821c9377e2edfa4c908384664d2c80112d5e805d66e0a551b941021be17dd20bd825bea9a3b6afb1b8c605805b3bda58750f03ea5c953a698494b425d8980c69f34d1c3f6b5866e8717031152a127215c256e08873c21b0f5cc85875d0f7c94601659150c04cd5fe5d381ba29983a2d94fcd3a65a94c53c7279cd000dddd4253d8cff8d7f6ace10247fe3bc30d63ba4bb54f557b3d22a3924369430d71ab37b701e9500bda70b5a643704858beed4726a889b6c9c91584194c68f1", | ||||
| 	"dac26aa7273fc25d6e044c79fc2bfa46e59892a42bbca59a86826c91e76ab03e4bd9f7c0b5f08d1931d88b36ea77d94f7ba67cd4f1d3086e529427201119096ae066ae6f170940830ed7900de7bb9d66e09788287403a4ecc93c6da975d2fb08e918840a236c15f5d3a8f7375c2eeebbf6f01a6e7f29ca2b8d42df158414c320777433663c59fdcd1f39ca68e3473db721be7ce8c6dba5fddc024f94fedb286b0477581d451313ca8c737484daf60d67f9b2d56d4bcc271f7e9ae958c7f258efbc74d25753e0516f28282461941bf2dcc7dd8c7df6173b89760cefcac07190243ff863fb", | ||||
| 	"c46e6512e6797cc7a54254a1b26b2de29aa83d6c4b1ea5a2786fbcec388270625b12635eae39e1fba013f8a65219421bca8b52a8ddfd431cda60299bdf160734d5a7450ec79620058522702174ae451b9bfa7c4a455fbbee3e1d048c7d4bac5131018228f137c8e130440c7059b4f15eaa34ce872a851a16ce86f982df78a00be4d564da2003a450ddee9ab43ea876b8b4b65c84f0b39265fd5456417afb5bc54997c986e66fc222f2123ba5e719c4d6b9a177b188277df384f1125821cf19d5248cef0be183ccdc84ac194506f740ed2188b2689ea4c9236a9e9e3a2fff85b6af4e9b49a3", | ||||
| 	"1ccd4d278d67b65cf2564ecd4de1b55fe07adc80e1f735fe2f08ea53fd3977323689122c29c798957abaff6aba09bdcbf661d77f4dc8913ab1fe2bef38846166e3834785e7105d746484eff8c656af5d8c7854abc1c62b7fadb65521dc6f793d978bda9838eb3800417d32e8a24d8c8cb1d18a5de6ca79d9e1b0ff9aa25e6218fe944cf18666fecc1e31334b390260dbe0997539e1b02f6366b2aea4f4a21efe04f4b97568fcb39e59919d5ebac6543d5d0f48fc66b923c34aac377dc95c20329b837b6ed5e8d9a3d2089cd0d8f025658006ff41cbdaccca618822ca590ab155253f8bc1c7f5", | ||||
| 	"9875209588395ee3c9fdd793fd48717cc84c8c3ea622b2ccc4a1be4448e6034b7810569855255031f10be5ffd714b05f9ce01972d712d40abf03d4d0ce175813a7a668f761324996093fc2aa5912f7fc2abdadd8775d2b4d9ad492216293381460ed8f6db3d641d1525f4242c348bbfe504c704f215dc461de51b5c75c1aae967936963848f16c673eca5e78dfd47eb19001d52d1bcf96c98956dad5ddf594a5da757e7ca35f2f69803b784e66ac5a58b75c228b8266ec592505e5d1ca87d81225738855f15bc0914677e81593fd409e77d159f8a908f67788de9eb06c5561547aada96c47c535", | ||||
| 	"40c90e375e366f3756d89091eb3eed9fe0fbfc5638700af4617d358812bac53124a2205dd6756456787d49cd6a35e302479a0992288f47532e4ea7ab62fc5ad5adc690a5d9a446f7e035ad4641bd8dae83946aee3338ec984ccb5cc633e1409f2531eeffe05532a8b0062ba99454c9aeabf8ecb94db195af7032bfebc22912f49d39330add47ff8fa5720612d697f0b602738930e060a1bb214efc5e292224cf34e29deaea6b1b1ff847e94ecc997325ac38df61db45d82bf0e74a664d2fe085c20b04c39e90d6a170b68d2f1d373f00c731c524456ada73d659aaac9df3191a7a3865083343fc13", | ||||
| 	"e8800d82e072210ca6d7fa2472028974780b76aad4bcb9ad362422dd05ae3232668251d164daa375a43b26a38cce28dbeb3dee1a4a579f70d0fe7febb29b5ece8aa836e050fb3d188c63aa9c3c0da6c717d86458a6096b5effceb964efdec7035960c09ccd10dea3c5f1c7f9f478d5887ebbe2e15c5ff85dbacbc444bb951c4eec7abecb89ed80187e409e2972ffe1a5f01562af109f2cf09471cf72cf83a3bb8f4e2ef38ed0e326b698296394e5b2718a5000c01425708e8ad0461e62462d8819c2377f13ab1be2c7c9f33dc06fe23cad27b87569f2ce2e56e4b2c60c7b1b3d370841d89ebdc1f192", | ||||
| 	"796d6d1447d5b7e8c55cd8b2f8b7010db39f27565f907e3fc0e464ea2d4bb52b37f10e7c6dcfc59231b9cdee12c32aeb4adbc42b86e86eb6defb5b69e6ca75e1f4d0dae3e124e5a1b8b6697f7e10b0403f1f0a5ff848eef3752837a9ba17780f16a9a709188a8d5b89a2fa74adb2e651163b1c2b3d261e225c9158dcd9eb7ac3d6704cee290cdff6bcb3cb90cee030aa0d19d4693655c3c30ac6fc06d2ae37787c47126d57ed9a6bef5f8a6c56859aefc08755739a95aac57a4dd916a92ba9f3afbf969df8085949615033365c751a9a3e1a18cee98a69d22e64009bebf8307169b6c61de0617ecfafdf", | ||||
| 	"4f9057183566153cf337b07c3f5556006de54c56b2a1e5326c07aaeabd1886ec6f1641358925db232b2f0dbf75229c796a7395b2f934c1f99090bec1123f3c841b1cb3c5b1ec42ed5408f2940f0c48a9470b852c46d6557853d459cecd2c32bbcd8ee21fa11e385eef0857cba4d8545a61b52a484cdd779db4739fbc7aa9860dcabe0488b98fa0b60c3f7d6153db279000a52ffb573dab37d2ab1896a90e5deb7ac6bbe56239085c325d83a917dc6e8a448425b718c2356b9f3066163555ec444f372e184e02c8c4c69b1c1c2ae2b51e45b98f73d933d18750968945ca85d6bbb22014b4c4015262e3c40d", | ||||
| 	"79dcca7d8b81a61359e4aece21f3df7b99518ce70bd2f57a18bab5e7114af2add0a0cea7f319d69f231f060e0a539d9a23fb3e95451ce8c6340cfb09edf931df84203a39226dd9eb278f11b691ef612585b973daab373e65d11325898badf6732100371fd759960fa8fec373268421d28bffdb9b12a430b92fe4b07566ca0c89e616e49f8fc75ccd9cdc66db820d7c02e109aa5ed86b89770262918a518f90a2292f6b68d68ae03992e4259a17a23c84ec2a417f082b5abf3a26e44d2278ecb8ba9456965303a75f25394d1aaf5544590e74b14d8a4cc4050be2b0ebcfe4d2db6b12a02c68a3bcdda70301f3", | ||||
| 	"848755dc31e25e9a42f9ec12d847d19f292c14c162c9aba49e972cb123b58b8e57bb263a923929833373858594ff52dbc298dbbc078599194e4c07b0e5fc1e10808bbacdb6e93c72b333685cf961f28eb0d5a395c63266b01f130d25db384b356e5da6d01042fc2359581b89c63b3bb2d1ce897fbc9e83fe85d9666cb60e6a8c657f70caad5387b8a045bf91095606802c8424ea8ac52ef29386dc46183378a5fcb2cb927428b8c070f1c42aafd3bc70ca25437807696a46873cfeb7b80ba2ebc3c4272443d445e46343a1465253a9eebd532a0d1d2c18264b91ff45159f245404ae9335f2af55c802772426b4", | ||||
| 	"ecaa6e999ef355a0768730edb835db411829a3764f79d764bb5682af6d00f51b313e017b83fffe2e332cd4a3de0a81d6a52084d5748346a1f81eb9b183ff6d93d05edc00e938d001c90872dfe234e8dd085f639af168af4a07e18f1c56ca6c7c1addffc4a70eb4660666dda0321636c3f83479ad3b64e23d749620413a2ecdcc52ad4e6e63f2b817ce99c15b5d2da3792721d7158297cce65e0c04fe810d7e2434b969e4c7892b3840623e153576356e9a696fd9e7a801c25de621a7849da3f99158d3d09bf039f43c510c8ffb00fa3e9a3c12d2c8062dd25b8dabe53d8581e30427e81c3dfc2d455352487e1255", | ||||
| 	"23a3fe80e3636313fdf922a1359514d9f31775e1adf24285e8001c04dbce866df055edf25b506e18953492a173ba5aa0c1ec758123406a97025ba9b6b7a97eb14734424d1a7841ec0eaeba0051d6e9734263bea1af9895a3b8c83d8c854da2ae7832bdd7c285b73f8113c3821cced38b3656b4e6369a9f8327cd368f04128f1d78b6b4260f55995277feffa15e34532cd0306c1f47354667c17018ee012a791af2dbbc7afc92c388008c601740cccbbe66f1eb06ea657e9d478066c2bd2093ab62cd94abadc002722f50968e8acf361658fc64f50685a5b1b004888b3b4f64a4ddb67bec7e4ac64c9ee8deeda896b9", | ||||
| 	"758f3567cd992228386a1c01930f7c52a9dcce28fdc1aaa54b0fed97d9a54f1df805f31bac12d559e90a2063cd7df8311a148f6904f78c5440f75e49877c0c0855d59c7f7ee52837e6ef3e54a568a7b38a0d5b896e298c8e46a56d24d8cabda8aeff85a622a3e7c87483ba921f34156defd185f608e2241224286e38121a162c2ba7604f68484717196f6628861a948180e8f06c6cc1ec66d032cf8d16da039cd74277cde31e535bc1692a44046e16881c954af3cd91dc49b443a3680e4bc42a954a46ebd1368b1398edd7580f935514b15c7fbfa9b40048a35122283af731f5e460aa85b66e65f49a9d158699bd2870", | ||||
| 	"fe511e86971cea2b6af91b2afa898d9b067fa71780790bb409189f5debe719f405e16acf7c4306a6e6ac5cd535290efe088943b9e6c5d25bfc508023c1b105d20d57252fee8cdbddb4d34a6ec2f72e8d55be55afcafd2e922ab8c31888bec4e816d04f0b2cd23df6e04720969c5152b3563c6da37e4608554cc7b8715bc10aba6a2e3b6fbcd35408df0dd73a9076bfad32b741fcdb0edfb563b3f753508b9b26f0a91673255f9bcda2b9a120f6bfa0632b6551ca517d846a747b66ebda1b2170891ece94c19ce8bf682cc94afdf0053fba4e4f0530935c07cdd6f879c999a8c4328ef6d3e0a37974a230ada83910604337", | ||||
| 	"a6024f5b959698c0de45f4f29e1803f99dc8112989c536e5a1337e281bc856ff721e986de183d7b0ea9eb61166830ae5d6d6bc857dc833ff189b52889b8e2bd3f35b4937624d9b36dc5f19db44f0772508029784c7dac9568d28609058bc437e2f79f95b12307d8a8fb042d7fd6ee910a9e8df609ede3283f958ba918a9925a0b1d0f9f9f232062315f28a52cbd60e71c09d83e0f6600f508f0ae8ad7642c080ffc618fcd2314e26f67f1529342569f6df37017f7e3b2dac32ad88d56d175ab22205ee7e3ee94720d76933a21132e110fefbb0689a3adbaa4c685f43652136d09b3a359b5c671e38f11915cb5612db2ae294", | ||||
| 	"af6de0e227bd78494acb559ddf34d8a7d55a03912384831be21c38376f39cda8a864aff7a48aed758f6bdf777779a669068a75ce82a06f6b3325c855ed83daf5513a078a61f7dc6c1622a633367e5f3a33e765c8ec5d8d54f48494006fdbf8922063e5340013e312871b7f8f8e5ea439c0d4cb78e2f19dd11f010729b692c65dd0d347f0ce53de9d849224666ea2f6487f1c6f953e8f9dbfd3d6de291c3e9d045e633cfd83c89d2f2327d0b2f31f72ac1604a3db1febc5f22cad08153278047210cc2894582c251a014c652e3951593e70e52a5d7451be8924b64f85c8247dab6268d24710b39fc1c07b4ac829fbda34ed79b5", | ||||
| 	"d7314e8b1ff82100b8f5870da62b61c31ab37ace9e6a7b6f7d294571523783c1fdedcbc00dd487dd6f848c34aab493507d07071b5eb59d1a2346068c7f356755fbde3d2cab67514f8c3a12d6ff9f96a977a9ac9263491bd33122a904da5386b943d35a6ba383932df07f259b6b45f69e9b27b4ca124fb3ae143d709853eed86690bc2754d5f8865c355a44b5279d8eb31cdc00f7407fb5f5b34edc57fc7ace943565da2222dc80632ccf42f2f125ceb19714ea964c2e50603c9f8960c3f27c2ed0e18a559931c4352bd7422109a28c5e145003f55c9b7c664fdc985168868950396eaf6fefc7b73d815c1aca721d7c67da632925", | ||||
| 	"2928b55c0e4d0f5cb4b60af59e9a702e3d616a8cf427c8bb03981fb8c29026d8f7d89161f36c11654f9a5e8ccb703595a58d671ecdc22c6a784abe363158682be4643002a7da5c9d268a30ea9a8d4cc24f562ab59f55c2b43af7dbcecc7e5ebe7494e82d74145a1e7d442125eb0431c5ea0939b27afa47f8ca97849f341f707660c7fbe49b7a0712fbcb6f7562ae2961425f27c7779c7534ecdeb8047ff3cb89a25159f3e1cefe42f9ef16426241f2c4d62c11d7ac43c4500dfcd184436bb4ef33260366f875230f26d81613c334dbda4736ba9d1d2966502914ec01bbe72d885606ec11da7a2cb01b29d35eebedbb0ecc73ed6c35", | ||||
| 	"fd993f50e8a68c7b2c7f87511ce65b93c0aa94dcbdf2c9cca93816f0f3b2ab34c62c586fc507b4900a34cf9d0517e0fe10a89d154c5419c1f5e38de00e8834fe3dc1032abdeb10729a81655a69a12856a78ca6e12110580de879b086fd6608726541cfa9616326bdd36064bc0d1e5f9c93b41278bff6a13b2494b81e238c0c45aea1b07d855e8f3fe1478e373bd9d3957cf8a5e5b9003386793d994c7c575cff2322e2428cbbaa4f47560316ae3354a7478842ff7cc5dcbacb6e871e72b36f06d63a9aaeb9044cfb7974afdc238a5816f537dcf33ee40b4e1a5eb3cff2402b46d548264e133008d284f11b7e4e450bc3c5ff9f79b9c4", | ||||
| 	"8df21892f5fc303b0de4adef1970186db6fe71bb3ea3094922e13afcfabf1d0be009f36d6f6310c5f9fda51f1a946507a055b645c296370440e5e83d8e906a2fb51f2b42de8856a81a4f28a73a8825c68ea08e5e366730bce8047011cb7d6d9be8c6f4211308fad21856284d5bc47d199988e0abf5badf8693ceeed0a2d98e8ae94b7775a42925edb1f697ffbd8e806af23145054a85e071819cca4cd48875290ca65e5ee72a9a54ff9f19c10ef4adaf8d04c9a9afcc73853fc128bbebc61f78702787c966ca6e1b1a0e4dab646acdfcd3c6bf3e5cfbec5ebe3e06c8abaa1de56e48421d87c46b5c78030afcafd91f27e7d7c85eb4872b", | ||||
| 	"48ec6ec520f8e593d7b3f653eb15553de246723b81a6d0c3221aaa42a37420fba98a23796338dff5f845dce6d5a449be5ecc1887356619270461087e08d05fb60433a83d7bd00c002b09ea210b428965124b9b27d9105a71c826c1a2491cfd60e4cfa86c2da0c7100a8dc1c3f2f94b280d54e01e043acf0e966200d9fa8a41daf3b9382820786c75cadbb8841a1b2be5b6cbeb64878e4a231ae063a99b4e2308960ef0c8e2a16bb3545cc43bdf171493fb89a84f47e7973dc60cf75aeeca71e0a7ebe17d161d4fb9fe009941cc438f16a5bae6c99fcad08cac486eb2a48060b023d8730bf1d82fe60a2f036e6f52a5bff95f43bbe088933f", | ||||
| 	"f4d84ed3e564c102600a795eaa9b1eaf4ad12f1a4deca1d042a0a2750ddf6201db03073d8bf553cb9dde48a1b0083827a609f7242b86584cc180964ae794b12ce55661e00e36a6ba4dbc389e6a5a85f1b45df9af7ead1b0a54db56e68639b9d438a91504e82c35d40c7bc7e048a53ac0b04accd0dadf4ac9884b0ca0e3cb5ba4336e3581be4c4760a553823ffa283a1120d4e145af56a59f2533903650f0b9e9ad9fe2e8a3c3c3dd03a1fcb709032c8835324839c735b0c051d0cbd8b5d867617c11023432e4bd275d3d0eb98a0b6cf58071a5b712922f2bc751ac7c2588c447444cde2f37a8ea5ec126425bf517e0d17c9e2999f52fee14b3", | ||||
| 	"2ccea21bac9c2b70d3923309cbf2d7cb7abd1fcc8b8b002688870a80029c62397350c3c898194e5deea360bb963d26d485cb7963f8167586976ec0556950b2e86135f4a2800991ce8473bfd44a3c5e937a48b5e355ba5141bccf2131a83988d9d2a9e8e7635a956105b3512c05ef708139ced51d7a4e204c12d8a49a21e8dc6de2629a2fd092326885d9f218745fe09f6d91fb6afce250a30a63689534b6be1f26899ffa3767d835cf586aa47776700f94241bc999b1e3deefe188f37ff734f5f16ee6a00914323dc7b8a143c9137cdcc5cd08ae9566f04bb2941532674c97dff6ffa5ce3405ef8e5d27ec403114253dd6394c0167d72a0044c5", | ||||
| 	"2b681c6398aee63bf862770341648bbcd31d7de7903c5903fe3d9469311320bb24d914f2af0cdca199c97214c7c679dc32a2800ba484a03c010ea6be3bb9f2c87e30a98b606050b8a3f297f12b8f92caaeceb3e844652115934874e0a1ab093a73d759b53f6a6c3096940dd22c2bb96ce6820a7b9c6d71a208de9892aa6a7209b0fff56a0cafea52b952cdd6f5752cff3309d448800b4e4c878aa595595b56b12b83fcd6ca89520c7da664e449d7b4438fc455888aad5de0fad9a06eed14afd3513b5ebbffe01775549b701181bd26370764f56eba52fdb24286ad1ac0f5418a7c429f7dfc7f3168437fa8eed7a2ed7c723a485e4c3ed14dea2e07", | ||||
| 	"aadfd505a89f4aade2c3018258a7e039401b1fc6a7f3d87910dddbb880d372ec8a13c70d92245de5b8e5f9a285c33b99dc82fa2b22decee72b93a72211656ad7a52696c8e570f78be28c0e427a371dafde856e8d5ed24f83b0660b51e7fac05d93a8666dfde6def59af863f80f3e5f6801182c87422203df390dcb736b8f830052a8832eeeb0b4e27e732aaf793d166b5a3ec7745aeef3766937c2b75a276bddd145f6010c29d035e343e267cb2d828436876ec3a7ebe3b6347d4172f7a99d6821ce152e039e53deb33340b324c7f068ffb94b3cde35a8eaa12d15c3806a7ad0acec3e8c7078c1d32a28fd3eec9f32cb86e4c22166ff69e83785e851", | ||||
| 	"1605b8cce529a9d6262fd4390d9e4ae5e14e0adc0ec89b028ef68dd0f373ea259aaa96f2967091dd0874c0105385e9e6da9ca68297c31afa44ef834535fb302ce5b4e49edacbbdf359fe1228a8172495b3e57014c27edd58b685110980056c50c398a64f4923f2d720b4df16d75cb36b4233660694182099c35028a972519c24764fc94e18e582b24deb3491535fc06b83837c7958522800e822201d694af0bd0aa3834e17d4b1ba36f470905ae5f8bbeeb6c4c8604d8af02baa347b07086d6989867ddd5e8e8ed7740c3469bfa2810519c55c6add1332c4c54ee9097961d6741cb12a09713a0d07645f784f42f5ad94b48b836b34263130b0483f15e3", | ||||
| 	"ff9c6125b2f60bfd6c2427b279df070e430075096647599bdc68c531152c58e13858b82385d78c856092d6c74106e87ccf51ac7e673936332d9b223444eaa0e762ee258d8a733d3a515ec68ed73285e5ca183ae3278b4820b0ab2797feb1e7d8cc864df585dfb5ebe02a993325a9ad5e2d7d49d3132cf66013898351d044e0fe908ccdfeeebf651983601e3673a1f92d36510c0cc19b2e75856db8e4a41f92a51efa66d6cc22e414944c2c34a5a89ccde0be76f51410824e330d8e7c613194338c93732e8aea651fca18bcf1ac1824340c5553aff1e58d4ab8d7c8842b4712021e517cd6c140f6743c69c7bee05b10a8f24050a8caa4f96d1664909c5a06", | ||||
| 	"6e85c2f8e1fdc3aaeb969da1258cb504bbf0070cd03d23b3fb5ee08feea5ee2e0ee1c71a5d0f4f701b351f4e4b4d74cb1e2ae6184814f77b62d2f08134b7236ebf6b67d8a6c9f01b4248b30667c555f5d8646dbfe291151b23c9c9857e33a4d5c847be29a5ee7b402e03bac02d1a4319acc0dd8f25e9c7a266f5e5c896cc11b5b238df96a0963ae806cb277abc515c298a3e61a3036b177acf87a56ca4478c4c6d0d468913de602ec891318bbaf52c97a77c35c5b7d164816cf24e4c4b0b5f45853882f716d61eb947a45ce2efa78f1c70a918512af1ad536cbe6148083385b34e207f5f690d7a954021e4b5f4258a385fd8a87809a481f34202af4caccb82", | ||||
| 	"1e9b2c454e9de3a2d723d850331037dbf54133dbe27488ff757dd255833a27d8eb8a128ad12d0978b6884e25737086a704fb289aaaccf930d5b582ab4df1f55f0c429b6875edec3fe45464fa74164be056a55e243c4222c586bec5b18f39036aa903d98180f24f83d09a454dfa1e03a60e6a3ba4613e99c35f874d790174ee48a557f4f021ade4d1b278d7997ef094569b37b3db0505951e9ee8400adaea275c6db51b325ee730c69df97745b556ae41cd98741e28aa3a49544541eeb3da1b1e8fa4e8e9100d66dd0c7f5e2c271b1ecc077de79c462b9fe4c273543ecd82a5bea63c5acc01eca5fb780c7d7c8c9fe208ae8bd50cad1769693d92c6c8649d20d8", | ||||
| } | ||||
							
								
								
									
										177
									
								
								vendor/golang.org/x/crypto/blake2b/blake2x.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								vendor/golang.org/x/crypto/blake2b/blake2x.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | ||||
| // Copyright 2017 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 blake2b | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| // XOF defines the interface to hash functions that | ||||
| // support arbitrary-length output. | ||||
| type XOF interface { | ||||
| 	// Write absorbs more data into the hash's state. It panics if called | ||||
| 	// after Read. | ||||
| 	io.Writer | ||||
|  | ||||
| 	// Read reads more output from the hash. It returns io.EOF if the limit | ||||
| 	// has been reached. | ||||
| 	io.Reader | ||||
|  | ||||
| 	// Clone returns a copy of the XOF in its current state. | ||||
| 	Clone() XOF | ||||
|  | ||||
| 	// Reset resets the XOF to its initial state. | ||||
| 	Reset() | ||||
| } | ||||
|  | ||||
| // OutputLengthUnknown can be used as the size argument to NewXOF to indicate | ||||
| // the the length of the output is not known in advance. | ||||
| const OutputLengthUnknown = 0 | ||||
|  | ||||
| // magicUnknownOutputLength is a magic value for the output size that indicates | ||||
| // an unknown number of output bytes. | ||||
| const magicUnknownOutputLength = (1 << 32) - 1 | ||||
|  | ||||
| // maxOutputLength is the absolute maximum number of bytes to produce when the | ||||
| // number of output bytes is unknown. | ||||
| const maxOutputLength = (1 << 32) * 64 | ||||
|  | ||||
| // NewXOF creates a new variable-output-length hash. The hash either produce a | ||||
| // known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes | ||||
| // (size == OutputLengthUnknown). In the latter case, an absolute limit of | ||||
| // 256GiB applies. | ||||
| // | ||||
| // A non-nil key turns the hash into a MAC. The key must between | ||||
| // zero and 32 bytes long. | ||||
| func NewXOF(size uint32, key []byte) (XOF, error) { | ||||
| 	if len(key) > Size { | ||||
| 		return nil, errKeySize | ||||
| 	} | ||||
| 	if size == magicUnknownOutputLength { | ||||
| 		// 2^32-1 indicates an unknown number of bytes and thus isn't a | ||||
| 		// valid length. | ||||
| 		return nil, errors.New("blake2b: XOF length too large") | ||||
| 	} | ||||
| 	if size == OutputLengthUnknown { | ||||
| 		size = magicUnknownOutputLength | ||||
| 	} | ||||
| 	x := &xof{ | ||||
| 		d: digest{ | ||||
| 			size:   Size, | ||||
| 			keyLen: len(key), | ||||
| 		}, | ||||
| 		length: size, | ||||
| 	} | ||||
| 	copy(x.d.key[:], key) | ||||
| 	x.Reset() | ||||
| 	return x, nil | ||||
| } | ||||
|  | ||||
| type xof struct { | ||||
| 	d                digest | ||||
| 	length           uint32 | ||||
| 	remaining        uint64 | ||||
| 	cfg, root, block [Size]byte | ||||
| 	offset           int | ||||
| 	nodeOffset       uint32 | ||||
| 	readMode         bool | ||||
| } | ||||
|  | ||||
| func (x *xof) Write(p []byte) (n int, err error) { | ||||
| 	if x.readMode { | ||||
| 		panic("blake2b: write to XOF after read") | ||||
| 	} | ||||
| 	return x.d.Write(p) | ||||
| } | ||||
|  | ||||
| func (x *xof) Clone() XOF { | ||||
| 	clone := *x | ||||
| 	return &clone | ||||
| } | ||||
|  | ||||
| func (x *xof) Reset() { | ||||
| 	x.cfg[0] = byte(Size) | ||||
| 	binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length | ||||
| 	binary.LittleEndian.PutUint32(x.cfg[12:], x.length)    // XOF length | ||||
| 	x.cfg[17] = byte(Size)                                 // inner hash size | ||||
|  | ||||
| 	x.d.Reset() | ||||
| 	x.d.h[1] ^= uint64(x.length) << 32 | ||||
|  | ||||
| 	x.remaining = uint64(x.length) | ||||
| 	if x.remaining == magicUnknownOutputLength { | ||||
| 		x.remaining = maxOutputLength | ||||
| 	} | ||||
| 	x.offset, x.nodeOffset = 0, 0 | ||||
| 	x.readMode = false | ||||
| } | ||||
|  | ||||
| func (x *xof) Read(p []byte) (n int, err error) { | ||||
| 	if !x.readMode { | ||||
| 		x.d.finalize(&x.root) | ||||
| 		x.readMode = true | ||||
| 	} | ||||
|  | ||||
| 	if x.remaining == 0 { | ||||
| 		return 0, io.EOF | ||||
| 	} | ||||
|  | ||||
| 	n = len(p) | ||||
| 	if uint64(n) > x.remaining { | ||||
| 		n = int(x.remaining) | ||||
| 		p = p[:n] | ||||
| 	} | ||||
|  | ||||
| 	if x.offset > 0 { | ||||
| 		blockRemaining := Size - x.offset | ||||
| 		if n < blockRemaining { | ||||
| 			x.offset += copy(p, x.block[x.offset:]) | ||||
| 			x.remaining -= uint64(n) | ||||
| 			return | ||||
| 		} | ||||
| 		copy(p, x.block[x.offset:]) | ||||
| 		p = p[blockRemaining:] | ||||
| 		x.offset = 0 | ||||
| 		x.remaining -= uint64(blockRemaining) | ||||
| 	} | ||||
|  | ||||
| 	for len(p) >= Size { | ||||
| 		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset) | ||||
| 		x.nodeOffset++ | ||||
|  | ||||
| 		x.d.initConfig(&x.cfg) | ||||
| 		x.d.Write(x.root[:]) | ||||
| 		x.d.finalize(&x.block) | ||||
|  | ||||
| 		copy(p, x.block[:]) | ||||
| 		p = p[Size:] | ||||
| 		x.remaining -= uint64(Size) | ||||
| 	} | ||||
|  | ||||
| 	if todo := len(p); todo > 0 { | ||||
| 		if x.remaining < uint64(Size) { | ||||
| 			x.cfg[0] = byte(x.remaining) | ||||
| 		} | ||||
| 		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset) | ||||
| 		x.nodeOffset++ | ||||
|  | ||||
| 		x.d.initConfig(&x.cfg) | ||||
| 		x.d.Write(x.root[:]) | ||||
| 		x.d.finalize(&x.block) | ||||
|  | ||||
| 		x.offset = copy(p, x.block[:todo]) | ||||
| 		x.remaining -= uint64(todo) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (d *digest) initConfig(cfg *[Size]byte) { | ||||
| 	d.offset, d.c[0], d.c[1] = 0, 0, 0 | ||||
| 	for i := range d.h { | ||||
| 		d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:]) | ||||
| 	} | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user