├── .gitignore ├── Godeps ├── Godeps.json ├── Readme └── _workspace │ ├── .gitignore │ └── src │ ├── github.com │ └── Sirupsen │ │ └── logrus │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── entry.go │ │ ├── entry_test.go │ │ ├── examples │ │ ├── basic │ │ │ └── basic.go │ │ └── hook │ │ │ └── hook.go │ │ ├── exported.go │ │ ├── formatter.go │ │ ├── formatter_bench_test.go │ │ ├── hook_test.go │ │ ├── hooks.go │ │ ├── hooks │ │ ├── airbrake │ │ │ ├── airbrake.go │ │ │ └── airbrake_test.go │ │ ├── papertrail │ │ │ ├── README.md │ │ │ ├── papertrail.go │ │ │ └── papertrail_test.go │ │ ├── sentry │ │ │ ├── README.md │ │ │ ├── sentry.go │ │ │ └── sentry_test.go │ │ └── syslog │ │ │ ├── README.md │ │ │ ├── syslog.go │ │ │ └── syslog_test.go │ │ ├── json_formatter.go │ │ ├── json_formatter_test.go │ │ ├── logger.go │ │ ├── logrus.go │ │ ├── logrus_test.go │ │ ├── terminal_darwin.go │ │ ├── terminal_freebsd.go │ │ ├── terminal_linux.go │ │ ├── terminal_notwindows.go │ │ ├── terminal_openbsd.go │ │ ├── terminal_windows.go │ │ ├── text_formatter.go │ │ ├── text_formatter_test.go │ │ └── writer.go │ └── golang.org │ └── x │ └── crypto │ └── ssh │ ├── agent │ ├── client.go │ ├── client_test.go │ ├── forward.go │ ├── keyring.go │ ├── server.go │ ├── server_test.go │ └── testdata_test.go │ ├── benchmark_test.go │ ├── buffer.go │ ├── buffer_test.go │ ├── certs.go │ ├── certs_test.go │ ├── channel.go │ ├── cipher.go │ ├── cipher_test.go │ ├── client.go │ ├── client_auth.go │ ├── client_auth_test.go │ ├── client_test.go │ ├── common.go │ ├── connection.go │ ├── doc.go │ ├── example_test.go │ ├── handshake.go │ ├── handshake_test.go │ ├── kex.go │ ├── kex_test.go │ ├── keys.go │ ├── keys_test.go │ ├── mac.go │ ├── mempipe_test.go │ ├── messages.go │ ├── messages_test.go │ ├── mux.go │ ├── mux_test.go │ ├── server.go │ ├── session.go │ ├── session_test.go │ ├── tcpip.go │ ├── tcpip_test.go │ ├── terminal │ ├── terminal.go │ ├── terminal_test.go │ ├── util.go │ ├── util_bsd.go │ ├── util_linux.go │ └── util_windows.go │ ├── test │ ├── agent_unix_test.go │ ├── cert_test.go │ ├── doc.go │ ├── forward_unix_test.go │ ├── session_test.go │ ├── tcpip_test.go │ ├── test_unix_test.go │ └── testdata_test.go │ ├── testdata │ ├── doc.go │ └── keys.go │ ├── testdata_test.go │ ├── transport.go │ └── transport_test.go ├── LICENSE ├── README.md ├── blacklist.go ├── blacklist ├── dsa-1024 ├── rsa-1023 ├── rsa-1024 ├── rsa-2047 ├── rsa-2048 ├── rsa-4096 └── rsa-8192 ├── key.go ├── main.go └── server.go /.gitignore: -------------------------------------------------------------------------------- 1 | checkmysshkey 2 | -------------------------------------------------------------------------------- /Godeps/Godeps.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportPath": "github.com/mattbostock/sshkeycheck", 3 | "GoVersion": "go1.4.2", 4 | "Deps": [ 5 | { 6 | "ImportPath": "github.com/Sirupsen/logrus", 7 | "Comment": "v0.6.6-5-gecc16b3", 8 | "Rev": "ecc16b3b2a583f3d5308ed4a3a4ce5cf45dbc68b" 9 | }, 10 | { 11 | "ImportPath": "golang.org/x/crypto/ssh", 12 | "Rev": "1351f936d976c60a0a48d728281922cf63eafb8d" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /Godeps/_workspace/.gitignore: -------------------------------------------------------------------------------- 1 | /pkg 2 | /bin 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/.gitignore: -------------------------------------------------------------------------------- 1 | logrus 2 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.2 4 | - 1.3 5 | - 1.4 6 | - tip 7 | install: 8 | - go get -t ./... 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Simon Eskildsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | "time" 9 | ) 10 | 11 | // An entry is the final or intermediate Logrus logging entry. It contains all 12 | // the fields passed with WithField{,s}. It's finally logged when Debug, Info, 13 | // Warn, Error, Fatal or Panic is called on it. These objects can be reused and 14 | // passed around as much as you wish to avoid field duplication. 15 | type Entry struct { 16 | Logger *Logger 17 | 18 | // Contains all the fields set by the user. 19 | Data Fields 20 | 21 | // Time at which the log entry was created 22 | Time time.Time 23 | 24 | // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic 25 | Level Level 26 | 27 | // Message passed to Debug, Info, Warn, Error, Fatal or Panic 28 | Message string 29 | } 30 | 31 | func NewEntry(logger *Logger) *Entry { 32 | return &Entry{ 33 | Logger: logger, 34 | // Default is three fields, give a little extra room 35 | Data: make(Fields, 5), 36 | } 37 | } 38 | 39 | // Returns a reader for the entry, which is a proxy to the formatter. 40 | func (entry *Entry) Reader() (*bytes.Buffer, error) { 41 | serialized, err := entry.Logger.Formatter.Format(entry) 42 | return bytes.NewBuffer(serialized), err 43 | } 44 | 45 | // Returns the string representation from the reader and ultimately the 46 | // formatter. 47 | func (entry *Entry) String() (string, error) { 48 | reader, err := entry.Reader() 49 | if err != nil { 50 | return "", err 51 | } 52 | 53 | return reader.String(), err 54 | } 55 | 56 | // Add a single field to the Entry. 57 | func (entry *Entry) WithField(key string, value interface{}) *Entry { 58 | return entry.WithFields(Fields{key: value}) 59 | } 60 | 61 | // Add a map of fields to the Entry. 62 | func (entry *Entry) WithFields(fields Fields) *Entry { 63 | data := Fields{} 64 | for k, v := range entry.Data { 65 | data[k] = v 66 | } 67 | for k, v := range fields { 68 | data[k] = v 69 | } 70 | return &Entry{Logger: entry.Logger, Data: data} 71 | } 72 | 73 | func (entry *Entry) log(level Level, msg string) { 74 | entry.Time = time.Now() 75 | entry.Level = level 76 | entry.Message = msg 77 | 78 | if err := entry.Logger.Hooks.Fire(level, entry); err != nil { 79 | entry.Logger.mu.Lock() 80 | fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) 81 | entry.Logger.mu.Unlock() 82 | } 83 | 84 | reader, err := entry.Reader() 85 | if err != nil { 86 | entry.Logger.mu.Lock() 87 | fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) 88 | entry.Logger.mu.Unlock() 89 | } 90 | 91 | entry.Logger.mu.Lock() 92 | defer entry.Logger.mu.Unlock() 93 | 94 | _, err = io.Copy(entry.Logger.Out, reader) 95 | if err != nil { 96 | fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) 97 | } 98 | 99 | // To avoid Entry#log() returning a value that only would make sense for 100 | // panic() to use in Entry#Panic(), we avoid the allocation by checking 101 | // directly here. 102 | if level <= PanicLevel { 103 | panic(entry) 104 | } 105 | } 106 | 107 | func (entry *Entry) Debug(args ...interface{}) { 108 | if entry.Logger.Level >= DebugLevel { 109 | entry.log(DebugLevel, fmt.Sprint(args...)) 110 | } 111 | } 112 | 113 | func (entry *Entry) Print(args ...interface{}) { 114 | entry.Info(args...) 115 | } 116 | 117 | func (entry *Entry) Info(args ...interface{}) { 118 | if entry.Logger.Level >= InfoLevel { 119 | entry.log(InfoLevel, fmt.Sprint(args...)) 120 | } 121 | } 122 | 123 | func (entry *Entry) Warn(args ...interface{}) { 124 | if entry.Logger.Level >= WarnLevel { 125 | entry.log(WarnLevel, fmt.Sprint(args...)) 126 | } 127 | } 128 | 129 | func (entry *Entry) Warning(args ...interface{}) { 130 | entry.Warn(args...) 131 | } 132 | 133 | func (entry *Entry) Error(args ...interface{}) { 134 | if entry.Logger.Level >= ErrorLevel { 135 | entry.log(ErrorLevel, fmt.Sprint(args...)) 136 | } 137 | } 138 | 139 | func (entry *Entry) Fatal(args ...interface{}) { 140 | if entry.Logger.Level >= FatalLevel { 141 | entry.log(FatalLevel, fmt.Sprint(args...)) 142 | } 143 | os.Exit(1) 144 | } 145 | 146 | func (entry *Entry) Panic(args ...interface{}) { 147 | if entry.Logger.Level >= PanicLevel { 148 | entry.log(PanicLevel, fmt.Sprint(args...)) 149 | } 150 | panic(fmt.Sprint(args...)) 151 | } 152 | 153 | // Entry Printf family functions 154 | 155 | func (entry *Entry) Debugf(format string, args ...interface{}) { 156 | if entry.Logger.Level >= DebugLevel { 157 | entry.Debug(fmt.Sprintf(format, args...)) 158 | } 159 | } 160 | 161 | func (entry *Entry) Infof(format string, args ...interface{}) { 162 | if entry.Logger.Level >= InfoLevel { 163 | entry.Info(fmt.Sprintf(format, args...)) 164 | } 165 | } 166 | 167 | func (entry *Entry) Printf(format string, args ...interface{}) { 168 | entry.Infof(format, args...) 169 | } 170 | 171 | func (entry *Entry) Warnf(format string, args ...interface{}) { 172 | if entry.Logger.Level >= WarnLevel { 173 | entry.Warn(fmt.Sprintf(format, args...)) 174 | } 175 | } 176 | 177 | func (entry *Entry) Warningf(format string, args ...interface{}) { 178 | entry.Warnf(format, args...) 179 | } 180 | 181 | func (entry *Entry) Errorf(format string, args ...interface{}) { 182 | if entry.Logger.Level >= ErrorLevel { 183 | entry.Error(fmt.Sprintf(format, args...)) 184 | } 185 | } 186 | 187 | func (entry *Entry) Fatalf(format string, args ...interface{}) { 188 | if entry.Logger.Level >= FatalLevel { 189 | entry.Fatal(fmt.Sprintf(format, args...)) 190 | } 191 | } 192 | 193 | func (entry *Entry) Panicf(format string, args ...interface{}) { 194 | if entry.Logger.Level >= PanicLevel { 195 | entry.Panic(fmt.Sprintf(format, args...)) 196 | } 197 | } 198 | 199 | // Entry Println family functions 200 | 201 | func (entry *Entry) Debugln(args ...interface{}) { 202 | if entry.Logger.Level >= DebugLevel { 203 | entry.Debug(entry.sprintlnn(args...)) 204 | } 205 | } 206 | 207 | func (entry *Entry) Infoln(args ...interface{}) { 208 | if entry.Logger.Level >= InfoLevel { 209 | entry.Info(entry.sprintlnn(args...)) 210 | } 211 | } 212 | 213 | func (entry *Entry) Println(args ...interface{}) { 214 | entry.Infoln(args...) 215 | } 216 | 217 | func (entry *Entry) Warnln(args ...interface{}) { 218 | if entry.Logger.Level >= WarnLevel { 219 | entry.Warn(entry.sprintlnn(args...)) 220 | } 221 | } 222 | 223 | func (entry *Entry) Warningln(args ...interface{}) { 224 | entry.Warnln(args...) 225 | } 226 | 227 | func (entry *Entry) Errorln(args ...interface{}) { 228 | if entry.Logger.Level >= ErrorLevel { 229 | entry.Error(entry.sprintlnn(args...)) 230 | } 231 | } 232 | 233 | func (entry *Entry) Fatalln(args ...interface{}) { 234 | if entry.Logger.Level >= FatalLevel { 235 | entry.Fatal(entry.sprintlnn(args...)) 236 | } 237 | } 238 | 239 | func (entry *Entry) Panicln(args ...interface{}) { 240 | if entry.Logger.Level >= PanicLevel { 241 | entry.Panic(entry.sprintlnn(args...)) 242 | } 243 | } 244 | 245 | // Sprintlnn => Sprint no newline. This is to get the behavior of how 246 | // fmt.Sprintln where spaces are always added between operands, regardless of 247 | // their type. Instead of vendoring the Sprintln implementation to spare a 248 | // string allocation, we do the simplest thing. 249 | func (entry *Entry) sprintlnn(args ...interface{}) string { 250 | msg := fmt.Sprintln(args...) 251 | return msg[:len(msg)-1] 252 | } 253 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/entry_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestEntryPanicln(t *testing.T) { 12 | errBoom := fmt.Errorf("boom time") 13 | 14 | defer func() { 15 | p := recover() 16 | assert.NotNil(t, p) 17 | 18 | switch pVal := p.(type) { 19 | case *Entry: 20 | assert.Equal(t, "kaboom", pVal.Message) 21 | assert.Equal(t, errBoom, pVal.Data["err"]) 22 | default: 23 | t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) 24 | } 25 | }() 26 | 27 | logger := New() 28 | logger.Out = &bytes.Buffer{} 29 | entry := NewEntry(logger) 30 | entry.WithField("err", errBoom).Panicln("kaboom") 31 | } 32 | 33 | func TestEntryPanicf(t *testing.T) { 34 | errBoom := fmt.Errorf("boom again") 35 | 36 | defer func() { 37 | p := recover() 38 | assert.NotNil(t, p) 39 | 40 | switch pVal := p.(type) { 41 | case *Entry: 42 | assert.Equal(t, "kaboom true", pVal.Message) 43 | assert.Equal(t, errBoom, pVal.Data["err"]) 44 | default: 45 | t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) 46 | } 47 | }() 48 | 49 | logger := New() 50 | logger.Out = &bytes.Buffer{} 51 | entry := NewEntry(logger) 52 | entry.WithField("err", errBoom).Panicf("kaboom %v", true) 53 | } 54 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/basic/basic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | ) 6 | 7 | var log = logrus.New() 8 | 9 | func init() { 10 | log.Formatter = new(logrus.JSONFormatter) 11 | log.Formatter = new(logrus.TextFormatter) // default 12 | log.Level = logrus.DebugLevel 13 | } 14 | 15 | func main() { 16 | defer func() { 17 | err := recover() 18 | if err != nil { 19 | log.WithFields(logrus.Fields{ 20 | "omg": true, 21 | "err": err, 22 | "number": 100, 23 | }).Fatal("The ice breaks!") 24 | } 25 | }() 26 | 27 | log.WithFields(logrus.Fields{ 28 | "animal": "walrus", 29 | "number": 8, 30 | }).Debug("Started observing beach") 31 | 32 | log.WithFields(logrus.Fields{ 33 | "animal": "walrus", 34 | "size": 10, 35 | }).Info("A group of walrus emerges from the ocean") 36 | 37 | log.WithFields(logrus.Fields{ 38 | "omg": true, 39 | "number": 122, 40 | }).Warn("The group's number increased tremendously!") 41 | 42 | log.WithFields(logrus.Fields{ 43 | "temperature": -4, 44 | }).Debug("Temperature changes") 45 | 46 | log.WithFields(logrus.Fields{ 47 | "animal": "orca", 48 | "size": 9009, 49 | }).Panic("It's over 9000!") 50 | } 51 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/hook/hook.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | "github.com/Sirupsen/logrus/hooks/airbrake" 6 | ) 7 | 8 | var log = logrus.New() 9 | 10 | func init() { 11 | log.Formatter = new(logrus.TextFormatter) // default 12 | log.Hooks.Add(airbrake.NewHook("https://example.com", "xyz", "development")) 13 | } 14 | 15 | func main() { 16 | log.WithFields(logrus.Fields{ 17 | "animal": "walrus", 18 | "size": 10, 19 | }).Info("A group of walrus emerges from the ocean") 20 | 21 | log.WithFields(logrus.Fields{ 22 | "omg": true, 23 | "number": 122, 24 | }).Warn("The group's number increased tremendously!") 25 | 26 | log.WithFields(logrus.Fields{ 27 | "omg": true, 28 | "number": 100, 29 | }).Fatal("The ice breaks!") 30 | } 31 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | var ( 8 | // std is the name of the standard logger in stdlib `log` 9 | std = New() 10 | ) 11 | 12 | func StandardLogger() *Logger { 13 | return std 14 | } 15 | 16 | // SetOutput sets the standard logger output. 17 | func SetOutput(out io.Writer) { 18 | std.mu.Lock() 19 | defer std.mu.Unlock() 20 | std.Out = out 21 | } 22 | 23 | // SetFormatter sets the standard logger formatter. 24 | func SetFormatter(formatter Formatter) { 25 | std.mu.Lock() 26 | defer std.mu.Unlock() 27 | std.Formatter = formatter 28 | } 29 | 30 | // SetLevel sets the standard logger level. 31 | func SetLevel(level Level) { 32 | std.mu.Lock() 33 | defer std.mu.Unlock() 34 | std.Level = level 35 | } 36 | 37 | // GetLevel returns the standard logger level. 38 | func GetLevel() Level { 39 | std.mu.Lock() 40 | defer std.mu.Unlock() 41 | return std.Level 42 | } 43 | 44 | // AddHook adds a hook to the standard logger hooks. 45 | func AddHook(hook Hook) { 46 | std.mu.Lock() 47 | defer std.mu.Unlock() 48 | std.Hooks.Add(hook) 49 | } 50 | 51 | // WithField creates an entry from the standard logger and adds a field to 52 | // it. If you want multiple fields, use `WithFields`. 53 | // 54 | // Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal 55 | // or Panic on the Entry it returns. 56 | func WithField(key string, value interface{}) *Entry { 57 | return std.WithField(key, value) 58 | } 59 | 60 | // WithFields creates an entry from the standard logger and adds multiple 61 | // fields to it. This is simply a helper for `WithField`, invoking it 62 | // once for each field. 63 | // 64 | // Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal 65 | // or Panic on the Entry it returns. 66 | func WithFields(fields Fields) *Entry { 67 | return std.WithFields(fields) 68 | } 69 | 70 | // Debug logs a message at level Debug on the standard logger. 71 | func Debug(args ...interface{}) { 72 | std.Debug(args...) 73 | } 74 | 75 | // Print logs a message at level Info on the standard logger. 76 | func Print(args ...interface{}) { 77 | std.Print(args...) 78 | } 79 | 80 | // Info logs a message at level Info on the standard logger. 81 | func Info(args ...interface{}) { 82 | std.Info(args...) 83 | } 84 | 85 | // Warn logs a message at level Warn on the standard logger. 86 | func Warn(args ...interface{}) { 87 | std.Warn(args...) 88 | } 89 | 90 | // Warning logs a message at level Warn on the standard logger. 91 | func Warning(args ...interface{}) { 92 | std.Warning(args...) 93 | } 94 | 95 | // Error logs a message at level Error on the standard logger. 96 | func Error(args ...interface{}) { 97 | std.Error(args...) 98 | } 99 | 100 | // Panic logs a message at level Panic on the standard logger. 101 | func Panic(args ...interface{}) { 102 | std.Panic(args...) 103 | } 104 | 105 | // Fatal logs a message at level Fatal on the standard logger. 106 | func Fatal(args ...interface{}) { 107 | std.Fatal(args...) 108 | } 109 | 110 | // Debugf logs a message at level Debug on the standard logger. 111 | func Debugf(format string, args ...interface{}) { 112 | std.Debugf(format, args...) 113 | } 114 | 115 | // Printf logs a message at level Info on the standard logger. 116 | func Printf(format string, args ...interface{}) { 117 | std.Printf(format, args...) 118 | } 119 | 120 | // Infof logs a message at level Info on the standard logger. 121 | func Infof(format string, args ...interface{}) { 122 | std.Infof(format, args...) 123 | } 124 | 125 | // Warnf logs a message at level Warn on the standard logger. 126 | func Warnf(format string, args ...interface{}) { 127 | std.Warnf(format, args...) 128 | } 129 | 130 | // Warningf logs a message at level Warn on the standard logger. 131 | func Warningf(format string, args ...interface{}) { 132 | std.Warningf(format, args...) 133 | } 134 | 135 | // Errorf logs a message at level Error on the standard logger. 136 | func Errorf(format string, args ...interface{}) { 137 | std.Errorf(format, args...) 138 | } 139 | 140 | // Panicf logs a message at level Panic on the standard logger. 141 | func Panicf(format string, args ...interface{}) { 142 | std.Panicf(format, args...) 143 | } 144 | 145 | // Fatalf logs a message at level Fatal on the standard logger. 146 | func Fatalf(format string, args ...interface{}) { 147 | std.Fatalf(format, args...) 148 | } 149 | 150 | // Debugln logs a message at level Debug on the standard logger. 151 | func Debugln(args ...interface{}) { 152 | std.Debugln(args...) 153 | } 154 | 155 | // Println logs a message at level Info on the standard logger. 156 | func Println(args ...interface{}) { 157 | std.Println(args...) 158 | } 159 | 160 | // Infoln logs a message at level Info on the standard logger. 161 | func Infoln(args ...interface{}) { 162 | std.Infoln(args...) 163 | } 164 | 165 | // Warnln logs a message at level Warn on the standard logger. 166 | func Warnln(args ...interface{}) { 167 | std.Warnln(args...) 168 | } 169 | 170 | // Warningln logs a message at level Warn on the standard logger. 171 | func Warningln(args ...interface{}) { 172 | std.Warningln(args...) 173 | } 174 | 175 | // Errorln logs a message at level Error on the standard logger. 176 | func Errorln(args ...interface{}) { 177 | std.Errorln(args...) 178 | } 179 | 180 | // Panicln logs a message at level Panic on the standard logger. 181 | func Panicln(args ...interface{}) { 182 | std.Panicln(args...) 183 | } 184 | 185 | // Fatalln logs a message at level Fatal on the standard logger. 186 | func Fatalln(args ...interface{}) { 187 | std.Fatalln(args...) 188 | } 189 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | // The Formatter interface is used to implement a custom Formatter. It takes an 4 | // `Entry`. It exposes all the fields, including the default ones: 5 | // 6 | // * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. 7 | // * `entry.Data["time"]`. The timestamp. 8 | // * `entry.Data["level"]. The level the entry was logged at. 9 | // 10 | // Any additional fields added with `WithField` or `WithFields` are also in 11 | // `entry.Data`. Format is expected to return an array of bytes which are then 12 | // logged to `logger.Out`. 13 | type Formatter interface { 14 | Format(*Entry) ([]byte, error) 15 | } 16 | 17 | // This is to not silently overwrite `time`, `msg` and `level` fields when 18 | // dumping it. If this code wasn't there doing: 19 | // 20 | // logrus.WithField("level", 1).Info("hello") 21 | // 22 | // Would just silently drop the user provided level. Instead with this code 23 | // it'll logged as: 24 | // 25 | // {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} 26 | // 27 | // It's not exported because it's still using Data in an opinionated way. It's to 28 | // avoid code duplication between the two default formatters. 29 | func prefixFieldClashes(data Fields) { 30 | _, ok := data["time"] 31 | if ok { 32 | data["fields.time"] = data["time"] 33 | } 34 | 35 | _, ok = data["msg"] 36 | if ok { 37 | data["fields.msg"] = data["msg"] 38 | } 39 | 40 | _, ok = data["level"] 41 | if ok { 42 | data["fields.level"] = data["level"] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter_bench_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | // smallFields is a small size data set for benchmarking 9 | var smallFields = Fields{ 10 | "foo": "bar", 11 | "baz": "qux", 12 | "one": "two", 13 | "three": "four", 14 | } 15 | 16 | // largeFields is a large size data set for benchmarking 17 | var largeFields = Fields{ 18 | "foo": "bar", 19 | "baz": "qux", 20 | "one": "two", 21 | "three": "four", 22 | "five": "six", 23 | "seven": "eight", 24 | "nine": "ten", 25 | "eleven": "twelve", 26 | "thirteen": "fourteen", 27 | "fifteen": "sixteen", 28 | "seventeen": "eighteen", 29 | "nineteen": "twenty", 30 | "a": "b", 31 | "c": "d", 32 | "e": "f", 33 | "g": "h", 34 | "i": "j", 35 | "k": "l", 36 | "m": "n", 37 | "o": "p", 38 | "q": "r", 39 | "s": "t", 40 | "u": "v", 41 | "w": "x", 42 | "y": "z", 43 | "this": "will", 44 | "make": "thirty", 45 | "entries": "yeah", 46 | } 47 | 48 | func BenchmarkSmallTextFormatter(b *testing.B) { 49 | doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields) 50 | } 51 | 52 | func BenchmarkLargeTextFormatter(b *testing.B) { 53 | doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields) 54 | } 55 | 56 | func BenchmarkSmallColoredTextFormatter(b *testing.B) { 57 | doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields) 58 | } 59 | 60 | func BenchmarkLargeColoredTextFormatter(b *testing.B) { 61 | doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields) 62 | } 63 | 64 | func BenchmarkSmallJSONFormatter(b *testing.B) { 65 | doBenchmark(b, &JSONFormatter{}, smallFields) 66 | } 67 | 68 | func BenchmarkLargeJSONFormatter(b *testing.B) { 69 | doBenchmark(b, &JSONFormatter{}, largeFields) 70 | } 71 | 72 | func doBenchmark(b *testing.B, formatter Formatter, fields Fields) { 73 | entry := &Entry{ 74 | Time: time.Time{}, 75 | Level: InfoLevel, 76 | Message: "message", 77 | Data: fields, 78 | } 79 | var d []byte 80 | var err error 81 | for i := 0; i < b.N; i++ { 82 | d, err = formatter.Format(entry) 83 | if err != nil { 84 | b.Fatal(err) 85 | } 86 | b.SetBytes(int64(len(d))) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hook_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | type TestHook struct { 10 | Fired bool 11 | } 12 | 13 | func (hook *TestHook) Fire(entry *Entry) error { 14 | hook.Fired = true 15 | return nil 16 | } 17 | 18 | func (hook *TestHook) Levels() []Level { 19 | return []Level{ 20 | DebugLevel, 21 | InfoLevel, 22 | WarnLevel, 23 | ErrorLevel, 24 | FatalLevel, 25 | PanicLevel, 26 | } 27 | } 28 | 29 | func TestHookFires(t *testing.T) { 30 | hook := new(TestHook) 31 | 32 | LogAndAssertJSON(t, func(log *Logger) { 33 | log.Hooks.Add(hook) 34 | assert.Equal(t, hook.Fired, false) 35 | 36 | log.Print("test") 37 | }, func(fields Fields) { 38 | assert.Equal(t, hook.Fired, true) 39 | }) 40 | } 41 | 42 | type ModifyHook struct { 43 | } 44 | 45 | func (hook *ModifyHook) Fire(entry *Entry) error { 46 | entry.Data["wow"] = "whale" 47 | return nil 48 | } 49 | 50 | func (hook *ModifyHook) Levels() []Level { 51 | return []Level{ 52 | DebugLevel, 53 | InfoLevel, 54 | WarnLevel, 55 | ErrorLevel, 56 | FatalLevel, 57 | PanicLevel, 58 | } 59 | } 60 | 61 | func TestHookCanModifyEntry(t *testing.T) { 62 | hook := new(ModifyHook) 63 | 64 | LogAndAssertJSON(t, func(log *Logger) { 65 | log.Hooks.Add(hook) 66 | log.WithField("wow", "elephant").Print("test") 67 | }, func(fields Fields) { 68 | assert.Equal(t, fields["wow"], "whale") 69 | }) 70 | } 71 | 72 | func TestCanFireMultipleHooks(t *testing.T) { 73 | hook1 := new(ModifyHook) 74 | hook2 := new(TestHook) 75 | 76 | LogAndAssertJSON(t, func(log *Logger) { 77 | log.Hooks.Add(hook1) 78 | log.Hooks.Add(hook2) 79 | 80 | log.WithField("wow", "elephant").Print("test") 81 | }, func(fields Fields) { 82 | assert.Equal(t, fields["wow"], "whale") 83 | assert.Equal(t, hook2.Fired, true) 84 | }) 85 | } 86 | 87 | type ErrorHook struct { 88 | Fired bool 89 | } 90 | 91 | func (hook *ErrorHook) Fire(entry *Entry) error { 92 | hook.Fired = true 93 | return nil 94 | } 95 | 96 | func (hook *ErrorHook) Levels() []Level { 97 | return []Level{ 98 | ErrorLevel, 99 | } 100 | } 101 | 102 | func TestErrorHookShouldntFireOnInfo(t *testing.T) { 103 | hook := new(ErrorHook) 104 | 105 | LogAndAssertJSON(t, func(log *Logger) { 106 | log.Hooks.Add(hook) 107 | log.Info("test") 108 | }, func(fields Fields) { 109 | assert.Equal(t, hook.Fired, false) 110 | }) 111 | } 112 | 113 | func TestErrorHookShouldFireOnError(t *testing.T) { 114 | hook := new(ErrorHook) 115 | 116 | LogAndAssertJSON(t, func(log *Logger) { 117 | log.Hooks.Add(hook) 118 | log.Error("test") 119 | }, func(fields Fields) { 120 | assert.Equal(t, hook.Fired, true) 121 | }) 122 | } 123 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | // A hook to be fired when logging on the logging levels returned from 4 | // `Levels()` on your implementation of the interface. Note that this is not 5 | // fired in a goroutine or a channel with workers, you should handle such 6 | // functionality yourself if your call is non-blocking and you don't wish for 7 | // the logging calls for levels returned from `Levels()` to block. 8 | type Hook interface { 9 | Levels() []Level 10 | Fire(*Entry) error 11 | } 12 | 13 | // Internal type for storing the hooks on a logger instance. 14 | type levelHooks map[Level][]Hook 15 | 16 | // Add a hook to an instance of logger. This is called with 17 | // `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. 18 | func (hooks levelHooks) Add(hook Hook) { 19 | for _, level := range hook.Levels() { 20 | hooks[level] = append(hooks[level], hook) 21 | } 22 | } 23 | 24 | // Fire all the hooks for the passed level. Used by `entry.log` to fire 25 | // appropriate hooks for a log entry. 26 | func (hooks levelHooks) Fire(level Level, entry *Entry) error { 27 | for _, hook := range hooks[level] { 28 | if err := hook.Fire(entry); err != nil { 29 | return err 30 | } 31 | } 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go: -------------------------------------------------------------------------------- 1 | package airbrake 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/Sirupsen/logrus" 8 | "github.com/tobi/airbrake-go" 9 | ) 10 | 11 | // AirbrakeHook to send exceptions to an exception-tracking service compatible 12 | // with the Airbrake API. 13 | type airbrakeHook struct { 14 | APIKey string 15 | Endpoint string 16 | Environment string 17 | } 18 | 19 | func NewHook(endpoint, apiKey, env string) *airbrakeHook { 20 | return &airbrakeHook{ 21 | APIKey: apiKey, 22 | Endpoint: endpoint, 23 | Environment: env, 24 | } 25 | } 26 | 27 | func (hook *airbrakeHook) Fire(entry *logrus.Entry) error { 28 | airbrake.ApiKey = hook.APIKey 29 | airbrake.Endpoint = hook.Endpoint 30 | airbrake.Environment = hook.Environment 31 | 32 | var notifyErr error 33 | err, ok := entry.Data["error"].(error) 34 | if ok { 35 | notifyErr = err 36 | } else { 37 | notifyErr = errors.New(entry.Message) 38 | } 39 | 40 | airErr := airbrake.Notify(notifyErr) 41 | if airErr != nil { 42 | return fmt.Errorf("Failed to send error to Airbrake: %s", airErr) 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (hook *airbrakeHook) Levels() []logrus.Level { 49 | return []logrus.Level{ 50 | logrus.ErrorLevel, 51 | logrus.FatalLevel, 52 | logrus.PanicLevel, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake_test.go: -------------------------------------------------------------------------------- 1 | package airbrake 2 | 3 | import ( 4 | "encoding/xml" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | "time" 9 | 10 | "github.com/Sirupsen/logrus" 11 | ) 12 | 13 | type notice struct { 14 | Error NoticeError `xml:"error"` 15 | } 16 | type NoticeError struct { 17 | Class string `xml:"class"` 18 | Message string `xml:"message"` 19 | } 20 | 21 | type customErr struct { 22 | msg string 23 | } 24 | 25 | func (e *customErr) Error() string { 26 | return e.msg 27 | } 28 | 29 | const ( 30 | testAPIKey = "abcxyz" 31 | testEnv = "development" 32 | expectedClass = "*airbrake.customErr" 33 | expectedMsg = "foo" 34 | unintendedMsg = "Airbrake will not see this string" 35 | ) 36 | 37 | var ( 38 | noticeError = make(chan NoticeError, 1) 39 | ) 40 | 41 | // TestLogEntryMessageReceived checks if invoking Logrus' log.Error 42 | // method causes an XML payload containing the log entry message is received 43 | // by a HTTP server emulating an Airbrake-compatible endpoint. 44 | func TestLogEntryMessageReceived(t *testing.T) { 45 | log := logrus.New() 46 | ts := startAirbrakeServer(t) 47 | defer ts.Close() 48 | 49 | hook := NewHook(ts.URL, testAPIKey, "production") 50 | log.Hooks.Add(hook) 51 | 52 | log.Error(expectedMsg) 53 | 54 | select { 55 | case received := <-noticeError: 56 | if received.Message != expectedMsg { 57 | t.Errorf("Unexpected message received: %s", received.Message) 58 | } 59 | case <-time.After(time.Second): 60 | t.Error("Timed out; no notice received by Airbrake API") 61 | } 62 | } 63 | 64 | // TestLogEntryMessageReceived confirms that, when passing an error type using 65 | // logrus.Fields, a HTTP server emulating an Airbrake endpoint receives the 66 | // error message returned by the Error() method on the error interface 67 | // rather than the logrus.Entry.Message string. 68 | func TestLogEntryWithErrorReceived(t *testing.T) { 69 | log := logrus.New() 70 | ts := startAirbrakeServer(t) 71 | defer ts.Close() 72 | 73 | hook := NewHook(ts.URL, testAPIKey, "production") 74 | log.Hooks.Add(hook) 75 | 76 | log.WithFields(logrus.Fields{ 77 | "error": &customErr{expectedMsg}, 78 | }).Error(unintendedMsg) 79 | 80 | select { 81 | case received := <-noticeError: 82 | if received.Message != expectedMsg { 83 | t.Errorf("Unexpected message received: %s", received.Message) 84 | } 85 | if received.Class != expectedClass { 86 | t.Errorf("Unexpected error class: %s", received.Class) 87 | } 88 | case <-time.After(time.Second): 89 | t.Error("Timed out; no notice received by Airbrake API") 90 | } 91 | } 92 | 93 | // TestLogEntryWithNonErrorTypeNotReceived confirms that, when passing a 94 | // non-error type using logrus.Fields, a HTTP server emulating an Airbrake 95 | // endpoint receives the logrus.Entry.Message string. 96 | // 97 | // Only error types are supported when setting the 'error' field using 98 | // logrus.WithFields(). 99 | func TestLogEntryWithNonErrorTypeNotReceived(t *testing.T) { 100 | log := logrus.New() 101 | ts := startAirbrakeServer(t) 102 | defer ts.Close() 103 | 104 | hook := NewHook(ts.URL, testAPIKey, "production") 105 | log.Hooks.Add(hook) 106 | 107 | log.WithFields(logrus.Fields{ 108 | "error": expectedMsg, 109 | }).Error(unintendedMsg) 110 | 111 | select { 112 | case received := <-noticeError: 113 | if received.Message != unintendedMsg { 114 | t.Errorf("Unexpected message received: %s", received.Message) 115 | } 116 | case <-time.After(time.Second): 117 | t.Error("Timed out; no notice received by Airbrake API") 118 | } 119 | } 120 | 121 | func startAirbrakeServer(t *testing.T) *httptest.Server { 122 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 123 | var notice notice 124 | if err := xml.NewDecoder(r.Body).Decode(¬ice); err != nil { 125 | t.Error(err) 126 | } 127 | r.Body.Close() 128 | 129 | noticeError <- notice.Error 130 | })) 131 | 132 | return ts 133 | } 134 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md: -------------------------------------------------------------------------------- 1 | # Papertrail Hook for Logrus :walrus: 2 | 3 | [Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts). 4 | 5 | In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible. 6 | 7 | ## Usage 8 | 9 | You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`. 10 | 11 | For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs. 12 | 13 | ```go 14 | import ( 15 | "log/syslog" 16 | "github.com/Sirupsen/logrus" 17 | "github.com/Sirupsen/logrus/hooks/papertrail" 18 | ) 19 | 20 | func main() { 21 | log := logrus.New() 22 | hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME) 23 | 24 | if err == nil { 25 | log.Hooks.Add(hook) 26 | } 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go: -------------------------------------------------------------------------------- 1 | package logrus_papertrail 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | "time" 8 | 9 | "github.com/Sirupsen/logrus" 10 | ) 11 | 12 | const ( 13 | format = "Jan 2 15:04:05" 14 | ) 15 | 16 | // PapertrailHook to send logs to a logging service compatible with the Papertrail API. 17 | type PapertrailHook struct { 18 | Host string 19 | Port int 20 | AppName string 21 | UDPConn net.Conn 22 | } 23 | 24 | // NewPapertrailHook creates a hook to be added to an instance of logger. 25 | func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) { 26 | conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port)) 27 | return &PapertrailHook{host, port, appName, conn}, err 28 | } 29 | 30 | // Fire is called when a log event is fired. 31 | func (hook *PapertrailHook) Fire(entry *logrus.Entry) error { 32 | date := time.Now().Format(format) 33 | msg, _ := entry.String() 34 | payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg) 35 | 36 | bytesWritten, err := hook.UDPConn.Write([]byte(payload)) 37 | if err != nil { 38 | fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err) 39 | return err 40 | } 41 | 42 | return nil 43 | } 44 | 45 | // Levels returns the available logging levels. 46 | func (hook *PapertrailHook) Levels() []logrus.Level { 47 | return []logrus.Level{ 48 | logrus.PanicLevel, 49 | logrus.FatalLevel, 50 | logrus.ErrorLevel, 51 | logrus.WarnLevel, 52 | logrus.InfoLevel, 53 | logrus.DebugLevel, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go: -------------------------------------------------------------------------------- 1 | package logrus_papertrail 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/Sirupsen/logrus" 8 | "github.com/stvp/go-udp-testing" 9 | ) 10 | 11 | func TestWritingToUDP(t *testing.T) { 12 | port := 16661 13 | udp.SetAddr(fmt.Sprintf(":%d", port)) 14 | 15 | hook, err := NewPapertrailHook("localhost", port, "test") 16 | if err != nil { 17 | t.Errorf("Unable to connect to local UDP server.") 18 | } 19 | 20 | log := logrus.New() 21 | log.Hooks.Add(hook) 22 | 23 | udp.ShouldReceive(t, "foo", func() { 24 | log.Info("foo") 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/README.md: -------------------------------------------------------------------------------- 1 | # Sentry Hook for Logrus :walrus: 2 | 3 | [Sentry](https://getsentry.com) provides both self-hosted and hosted 4 | solutions for exception tracking. 5 | Both client and server are 6 | [open source](https://github.com/getsentry/sentry). 7 | 8 | ## Usage 9 | 10 | Every sentry application defined on the server gets a different 11 | [DSN](https://www.getsentry.com/docs/). In the example below replace 12 | `YOUR_DSN` with the one created for your application. 13 | 14 | ```go 15 | import ( 16 | "github.com/Sirupsen/logrus" 17 | "github.com/Sirupsen/logrus/hooks/sentry" 18 | ) 19 | 20 | func main() { 21 | log := logrus.New() 22 | hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{ 23 | logrus.PanicLevel, 24 | logrus.FatalLevel, 25 | logrus.ErrorLevel, 26 | }) 27 | 28 | if err == nil { 29 | log.Hooks.Add(hook) 30 | } 31 | } 32 | ``` 33 | 34 | ## Special fields 35 | 36 | Some logrus fields have a special meaning in this hook, 37 | these are server_name and logger. 38 | When logs are sent to sentry these fields are treated differently. 39 | - server_name (also known as hostname) is the name of the server which 40 | is logging the event (hostname.example.com) 41 | - logger is the part of the application which is logging the event. 42 | In go this usually means setting it to the name of the package. 43 | 44 | ## Timeout 45 | 46 | `Timeout` is the time the sentry hook will wait for a response 47 | from the sentry server. 48 | 49 | If this time elapses with no response from 50 | the server an error will be returned. 51 | 52 | If `Timeout` is set to 0 the SentryHook will not wait for a reply 53 | and will assume a correct delivery. 54 | 55 | The SentryHook has a default timeout of `100 milliseconds` when created 56 | with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field: 57 | 58 | ```go 59 | hook, _ := logrus_sentry.NewSentryHook(...) 60 | hook.Timeout = 20*time.Second 61 | ``` 62 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry.go: -------------------------------------------------------------------------------- 1 | package logrus_sentry 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/Sirupsen/logrus" 8 | "github.com/getsentry/raven-go" 9 | ) 10 | 11 | var ( 12 | severityMap = map[logrus.Level]raven.Severity{ 13 | logrus.DebugLevel: raven.DEBUG, 14 | logrus.InfoLevel: raven.INFO, 15 | logrus.WarnLevel: raven.WARNING, 16 | logrus.ErrorLevel: raven.ERROR, 17 | logrus.FatalLevel: raven.FATAL, 18 | logrus.PanicLevel: raven.FATAL, 19 | } 20 | ) 21 | 22 | func getAndDel(d logrus.Fields, key string) (string, bool) { 23 | var ( 24 | ok bool 25 | v interface{} 26 | val string 27 | ) 28 | if v, ok = d[key]; !ok { 29 | return "", false 30 | } 31 | 32 | if val, ok = v.(string); !ok { 33 | return "", false 34 | } 35 | delete(d, key) 36 | return val, true 37 | } 38 | 39 | // SentryHook delivers logs to a sentry server. 40 | type SentryHook struct { 41 | // Timeout sets the time to wait for a delivery error from the sentry server. 42 | // If this is set to zero the server will not wait for any response and will 43 | // consider the message correctly sent 44 | Timeout time.Duration 45 | 46 | client *raven.Client 47 | levels []logrus.Level 48 | } 49 | 50 | // NewSentryHook creates a hook to be added to an instance of logger 51 | // and initializes the raven client. 52 | // This method sets the timeout to 100 milliseconds. 53 | func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) { 54 | client, err := raven.NewClient(DSN, nil) 55 | if err != nil { 56 | return nil, err 57 | } 58 | return &SentryHook{100 * time.Millisecond, client, levels}, nil 59 | } 60 | 61 | // Called when an event should be sent to sentry 62 | // Special fields that sentry uses to give more information to the server 63 | // are extracted from entry.Data (if they are found) 64 | // These fields are: logger and server_name 65 | func (hook *SentryHook) Fire(entry *logrus.Entry) error { 66 | packet := &raven.Packet{ 67 | Message: entry.Message, 68 | Timestamp: raven.Timestamp(entry.Time), 69 | Level: severityMap[entry.Level], 70 | Platform: "go", 71 | } 72 | 73 | d := entry.Data 74 | 75 | if logger, ok := getAndDel(d, "logger"); ok { 76 | packet.Logger = logger 77 | } 78 | if serverName, ok := getAndDel(d, "server_name"); ok { 79 | packet.ServerName = serverName 80 | } 81 | packet.Extra = map[string]interface{}(d) 82 | 83 | _, errCh := hook.client.Capture(packet, nil) 84 | timeout := hook.Timeout 85 | if timeout != 0 { 86 | timeoutCh := time.After(timeout) 87 | select { 88 | case err := <-errCh: 89 | return err 90 | case <-timeoutCh: 91 | return fmt.Errorf("no response from sentry server in %s", timeout) 92 | } 93 | } 94 | return nil 95 | } 96 | 97 | // Levels returns the available logging levels. 98 | func (hook *SentryHook) Levels() []logrus.Level { 99 | return hook.levels 100 | } 101 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go: -------------------------------------------------------------------------------- 1 | package logrus_sentry 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "net/http/httptest" 9 | "strings" 10 | "testing" 11 | 12 | "github.com/Sirupsen/logrus" 13 | "github.com/getsentry/raven-go" 14 | ) 15 | 16 | const ( 17 | message = "error message" 18 | server_name = "testserver.internal" 19 | logger_name = "test.logger" 20 | ) 21 | 22 | func getTestLogger() *logrus.Logger { 23 | l := logrus.New() 24 | l.Out = ioutil.Discard 25 | return l 26 | } 27 | 28 | func WithTestDSN(t *testing.T, tf func(string, <-chan *raven.Packet)) { 29 | pch := make(chan *raven.Packet, 1) 30 | s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { 31 | defer req.Body.Close() 32 | d := json.NewDecoder(req.Body) 33 | p := &raven.Packet{} 34 | err := d.Decode(p) 35 | if err != nil { 36 | t.Fatal(err.Error()) 37 | } 38 | 39 | pch <- p 40 | })) 41 | defer s.Close() 42 | 43 | fragments := strings.SplitN(s.URL, "://", 2) 44 | dsn := fmt.Sprintf( 45 | "%s://public:secret@%s/sentry/project-id", 46 | fragments[0], 47 | fragments[1], 48 | ) 49 | tf(dsn, pch) 50 | } 51 | 52 | func TestSpecialFields(t *testing.T) { 53 | WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) { 54 | logger := getTestLogger() 55 | 56 | hook, err := NewSentryHook(dsn, []logrus.Level{ 57 | logrus.ErrorLevel, 58 | }) 59 | 60 | if err != nil { 61 | t.Fatal(err.Error()) 62 | } 63 | logger.Hooks.Add(hook) 64 | logger.WithFields(logrus.Fields{ 65 | "server_name": server_name, 66 | "logger": logger_name, 67 | }).Error(message) 68 | 69 | packet := <-pch 70 | if packet.Logger != logger_name { 71 | t.Errorf("logger should have been %s, was %s", logger_name, packet.Logger) 72 | } 73 | 74 | if packet.ServerName != server_name { 75 | t.Errorf("server_name should have been %s, was %s", server_name, packet.ServerName) 76 | } 77 | }) 78 | } 79 | 80 | func TestSentryHandler(t *testing.T) { 81 | WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) { 82 | logger := getTestLogger() 83 | hook, err := NewSentryHook(dsn, []logrus.Level{ 84 | logrus.ErrorLevel, 85 | }) 86 | if err != nil { 87 | t.Fatal(err.Error()) 88 | } 89 | logger.Hooks.Add(hook) 90 | 91 | logger.Error(message) 92 | packet := <-pch 93 | if packet.Message != message { 94 | t.Errorf("message should have been %s, was %s", message, packet.Message) 95 | } 96 | }) 97 | } 98 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md: -------------------------------------------------------------------------------- 1 | # Syslog Hooks for Logrus :walrus: 2 | 3 | ## Usage 4 | 5 | ```go 6 | import ( 7 | "log/syslog" 8 | "github.com/Sirupsen/logrus" 9 | logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" 10 | ) 11 | 12 | func main() { 13 | log := logrus.New() 14 | hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") 15 | 16 | if err == nil { 17 | log.Hooks.Add(hook) 18 | } 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go: -------------------------------------------------------------------------------- 1 | package logrus_syslog 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Sirupsen/logrus" 6 | "log/syslog" 7 | "os" 8 | ) 9 | 10 | // SyslogHook to send logs via syslog. 11 | type SyslogHook struct { 12 | Writer *syslog.Writer 13 | SyslogNetwork string 14 | SyslogRaddr string 15 | } 16 | 17 | // Creates a hook to be added to an instance of logger. This is called with 18 | // `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")` 19 | // `if err == nil { log.Hooks.Add(hook) }` 20 | func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) { 21 | w, err := syslog.Dial(network, raddr, priority, tag) 22 | return &SyslogHook{w, network, raddr}, err 23 | } 24 | 25 | func (hook *SyslogHook) Fire(entry *logrus.Entry) error { 26 | line, err := entry.String() 27 | if err != nil { 28 | fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) 29 | return err 30 | } 31 | 32 | switch entry.Level { 33 | case logrus.PanicLevel: 34 | return hook.Writer.Crit(line) 35 | case logrus.FatalLevel: 36 | return hook.Writer.Crit(line) 37 | case logrus.ErrorLevel: 38 | return hook.Writer.Err(line) 39 | case logrus.WarnLevel: 40 | return hook.Writer.Warning(line) 41 | case logrus.InfoLevel: 42 | return hook.Writer.Info(line) 43 | case logrus.DebugLevel: 44 | return hook.Writer.Debug(line) 45 | default: 46 | return nil 47 | } 48 | } 49 | 50 | func (hook *SyslogHook) Levels() []logrus.Level { 51 | return []logrus.Level{ 52 | logrus.PanicLevel, 53 | logrus.FatalLevel, 54 | logrus.ErrorLevel, 55 | logrus.WarnLevel, 56 | logrus.InfoLevel, 57 | logrus.DebugLevel, 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go: -------------------------------------------------------------------------------- 1 | package logrus_syslog 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | "log/syslog" 6 | "testing" 7 | ) 8 | 9 | func TestLocalhostAddAndPrint(t *testing.T) { 10 | log := logrus.New() 11 | hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") 12 | 13 | if err != nil { 14 | t.Errorf("Unable to connect to local syslog.") 15 | } 16 | 17 | log.Hooks.Add(hook) 18 | 19 | for _, level := range hook.Levels() { 20 | if len(log.Hooks[level]) != 1 { 21 | t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level])) 22 | } 23 | } 24 | 25 | log.Info("Congratulations!") 26 | } 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | type JSONFormatter struct{} 10 | 11 | func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { 12 | data := make(Fields, len(entry.Data)+3) 13 | for k, v := range entry.Data { 14 | // Otherwise errors are ignored by `encoding/json` 15 | // https://github.com/Sirupsen/logrus/issues/137 16 | if err, ok := v.(error); ok { 17 | data[k] = err.Error() 18 | } else { 19 | data[k] = v 20 | } 21 | } 22 | prefixFieldClashes(data) 23 | data["time"] = entry.Time.Format(time.RFC3339) 24 | data["msg"] = entry.Message 25 | data["level"] = entry.Level.String() 26 | 27 | serialized, err := json.Marshal(data) 28 | if err != nil { 29 | return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) 30 | } 31 | return append(serialized, '\n'), nil 32 | } 33 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestErrorNotLost(t *testing.T) { 11 | formatter := &JSONFormatter{} 12 | 13 | b, err := formatter.Format(WithField("error", errors.New("wild walrus"))) 14 | if err != nil { 15 | t.Fatal("Unable to format entry: ", err) 16 | } 17 | 18 | entry := make(map[string]interface{}) 19 | err = json.Unmarshal(b, &entry) 20 | if err != nil { 21 | t.Fatal("Unable to unmarshal formatted entry: ", err) 22 | } 23 | 24 | if entry["error"] != "wild walrus" { 25 | t.Fatal("Error field not set") 26 | } 27 | } 28 | 29 | func TestErrorNotLostOnFieldNotNamedError(t *testing.T) { 30 | formatter := &JSONFormatter{} 31 | 32 | b, err := formatter.Format(WithField("omg", errors.New("wild walrus"))) 33 | if err != nil { 34 | t.Fatal("Unable to format entry: ", err) 35 | } 36 | 37 | entry := make(map[string]interface{}) 38 | err = json.Unmarshal(b, &entry) 39 | if err != nil { 40 | t.Fatal("Unable to unmarshal formatted entry: ", err) 41 | } 42 | 43 | if entry["omg"] != "wild walrus" { 44 | t.Fatal("Error field not set") 45 | } 46 | } 47 | 48 | func TestFieldClashWithTime(t *testing.T) { 49 | formatter := &JSONFormatter{} 50 | 51 | b, err := formatter.Format(WithField("time", "right now!")) 52 | if err != nil { 53 | t.Fatal("Unable to format entry: ", err) 54 | } 55 | 56 | entry := make(map[string]interface{}) 57 | err = json.Unmarshal(b, &entry) 58 | if err != nil { 59 | t.Fatal("Unable to unmarshal formatted entry: ", err) 60 | } 61 | 62 | if entry["fields.time"] != "right now!" { 63 | t.Fatal("fields.time not set to original time field") 64 | } 65 | 66 | if entry["time"] != "0001-01-01T00:00:00Z" { 67 | t.Fatal("time field not set to current time, was: ", entry["time"]) 68 | } 69 | } 70 | 71 | func TestFieldClashWithMsg(t *testing.T) { 72 | formatter := &JSONFormatter{} 73 | 74 | b, err := formatter.Format(WithField("msg", "something")) 75 | if err != nil { 76 | t.Fatal("Unable to format entry: ", err) 77 | } 78 | 79 | entry := make(map[string]interface{}) 80 | err = json.Unmarshal(b, &entry) 81 | if err != nil { 82 | t.Fatal("Unable to unmarshal formatted entry: ", err) 83 | } 84 | 85 | if entry["fields.msg"] != "something" { 86 | t.Fatal("fields.msg not set to original msg field") 87 | } 88 | } 89 | 90 | func TestFieldClashWithLevel(t *testing.T) { 91 | formatter := &JSONFormatter{} 92 | 93 | b, err := formatter.Format(WithField("level", "something")) 94 | if err != nil { 95 | t.Fatal("Unable to format entry: ", err) 96 | } 97 | 98 | entry := make(map[string]interface{}) 99 | err = json.Unmarshal(b, &entry) 100 | if err != nil { 101 | t.Fatal("Unable to unmarshal formatted entry: ", err) 102 | } 103 | 104 | if entry["fields.level"] != "something" { 105 | t.Fatal("fields.level not set to original level field") 106 | } 107 | } 108 | 109 | func TestJSONEntryEndsWithNewline(t *testing.T) { 110 | formatter := &JSONFormatter{} 111 | 112 | b, err := formatter.Format(WithField("level", "something")) 113 | if err != nil { 114 | t.Fatal("Unable to format entry: ", err) 115 | } 116 | 117 | if b[len(b)-1] != '\n' { 118 | t.Fatal("Expected JSON log entry to end with a newline") 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "sync" 7 | ) 8 | 9 | type Logger struct { 10 | // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a 11 | // file, or leave it default which is `os.Stdout`. You can also set this to 12 | // something more adventorous, such as logging to Kafka. 13 | Out io.Writer 14 | // Hooks for the logger instance. These allow firing events based on logging 15 | // levels and log entries. For example, to send errors to an error tracking 16 | // service, log to StatsD or dump the core on fatal errors. 17 | Hooks levelHooks 18 | // All log entries pass through the formatter before logged to Out. The 19 | // included formatters are `TextFormatter` and `JSONFormatter` for which 20 | // TextFormatter is the default. In development (when a TTY is attached) it 21 | // logs with colors, but to a file it wouldn't. You can easily implement your 22 | // own that implements the `Formatter` interface, see the `README` or included 23 | // formatters for examples. 24 | Formatter Formatter 25 | // The logging level the logger should log at. This is typically (and defaults 26 | // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be 27 | // logged. `logrus.Debug` is useful in 28 | Level Level 29 | // Used to sync writing to the log. 30 | mu sync.Mutex 31 | } 32 | 33 | // Creates a new logger. Configuration should be set by changing `Formatter`, 34 | // `Out` and `Hooks` directly on the default logger instance. You can also just 35 | // instantiate your own: 36 | // 37 | // var log = &Logger{ 38 | // Out: os.Stderr, 39 | // Formatter: new(JSONFormatter), 40 | // Hooks: make(levelHooks), 41 | // Level: logrus.DebugLevel, 42 | // } 43 | // 44 | // It's recommended to make this a global instance called `log`. 45 | func New() *Logger { 46 | return &Logger{ 47 | Out: os.Stdout, 48 | Formatter: new(TextFormatter), 49 | Hooks: make(levelHooks), 50 | Level: InfoLevel, 51 | } 52 | } 53 | 54 | // Adds a field to the log entry, note that you it doesn't log until you call 55 | // Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. 56 | // Ff you want multiple fields, use `WithFields`. 57 | func (logger *Logger) WithField(key string, value interface{}) *Entry { 58 | return NewEntry(logger).WithField(key, value) 59 | } 60 | 61 | // Adds a struct of fields to the log entry. All it does is call `WithField` for 62 | // each `Field`. 63 | func (logger *Logger) WithFields(fields Fields) *Entry { 64 | return NewEntry(logger).WithFields(fields) 65 | } 66 | 67 | func (logger *Logger) Debugf(format string, args ...interface{}) { 68 | NewEntry(logger).Debugf(format, args...) 69 | } 70 | 71 | func (logger *Logger) Infof(format string, args ...interface{}) { 72 | NewEntry(logger).Infof(format, args...) 73 | } 74 | 75 | func (logger *Logger) Printf(format string, args ...interface{}) { 76 | NewEntry(logger).Printf(format, args...) 77 | } 78 | 79 | func (logger *Logger) Warnf(format string, args ...interface{}) { 80 | NewEntry(logger).Warnf(format, args...) 81 | } 82 | 83 | func (logger *Logger) Warningf(format string, args ...interface{}) { 84 | NewEntry(logger).Warnf(format, args...) 85 | } 86 | 87 | func (logger *Logger) Errorf(format string, args ...interface{}) { 88 | NewEntry(logger).Errorf(format, args...) 89 | } 90 | 91 | func (logger *Logger) Fatalf(format string, args ...interface{}) { 92 | NewEntry(logger).Fatalf(format, args...) 93 | } 94 | 95 | func (logger *Logger) Panicf(format string, args ...interface{}) { 96 | NewEntry(logger).Panicf(format, args...) 97 | } 98 | 99 | func (logger *Logger) Debug(args ...interface{}) { 100 | NewEntry(logger).Debug(args...) 101 | } 102 | 103 | func (logger *Logger) Info(args ...interface{}) { 104 | NewEntry(logger).Info(args...) 105 | } 106 | 107 | func (logger *Logger) Print(args ...interface{}) { 108 | NewEntry(logger).Info(args...) 109 | } 110 | 111 | func (logger *Logger) Warn(args ...interface{}) { 112 | NewEntry(logger).Warn(args...) 113 | } 114 | 115 | func (logger *Logger) Warning(args ...interface{}) { 116 | NewEntry(logger).Warn(args...) 117 | } 118 | 119 | func (logger *Logger) Error(args ...interface{}) { 120 | NewEntry(logger).Error(args...) 121 | } 122 | 123 | func (logger *Logger) Fatal(args ...interface{}) { 124 | NewEntry(logger).Fatal(args...) 125 | } 126 | 127 | func (logger *Logger) Panic(args ...interface{}) { 128 | NewEntry(logger).Panic(args...) 129 | } 130 | 131 | func (logger *Logger) Debugln(args ...interface{}) { 132 | NewEntry(logger).Debugln(args...) 133 | } 134 | 135 | func (logger *Logger) Infoln(args ...interface{}) { 136 | NewEntry(logger).Infoln(args...) 137 | } 138 | 139 | func (logger *Logger) Println(args ...interface{}) { 140 | NewEntry(logger).Println(args...) 141 | } 142 | 143 | func (logger *Logger) Warnln(args ...interface{}) { 144 | NewEntry(logger).Warnln(args...) 145 | } 146 | 147 | func (logger *Logger) Warningln(args ...interface{}) { 148 | NewEntry(logger).Warnln(args...) 149 | } 150 | 151 | func (logger *Logger) Errorln(args ...interface{}) { 152 | NewEntry(logger).Errorln(args...) 153 | } 154 | 155 | func (logger *Logger) Fatalln(args ...interface{}) { 156 | NewEntry(logger).Fatalln(args...) 157 | } 158 | 159 | func (logger *Logger) Panicln(args ...interface{}) { 160 | NewEntry(logger).Panicln(args...) 161 | } 162 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | ) 7 | 8 | // Fields type, used to pass to `WithFields`. 9 | type Fields map[string]interface{} 10 | 11 | // Level type 12 | type Level uint8 13 | 14 | // Convert the Level to a string. E.g. PanicLevel becomes "panic". 15 | func (level Level) String() string { 16 | switch level { 17 | case DebugLevel: 18 | return "debug" 19 | case InfoLevel: 20 | return "info" 21 | case WarnLevel: 22 | return "warning" 23 | case ErrorLevel: 24 | return "error" 25 | case FatalLevel: 26 | return "fatal" 27 | case PanicLevel: 28 | return "panic" 29 | } 30 | 31 | return "unknown" 32 | } 33 | 34 | // ParseLevel takes a string level and returns the Logrus log level constant. 35 | func ParseLevel(lvl string) (Level, error) { 36 | switch lvl { 37 | case "panic": 38 | return PanicLevel, nil 39 | case "fatal": 40 | return FatalLevel, nil 41 | case "error": 42 | return ErrorLevel, nil 43 | case "warn", "warning": 44 | return WarnLevel, nil 45 | case "info": 46 | return InfoLevel, nil 47 | case "debug": 48 | return DebugLevel, nil 49 | } 50 | 51 | var l Level 52 | return l, fmt.Errorf("not a valid logrus Level: %q", lvl) 53 | } 54 | 55 | // These are the different logging levels. You can set the logging level to log 56 | // on your instance of logger, obtained with `logrus.New()`. 57 | const ( 58 | // PanicLevel level, highest level of severity. Logs and then calls panic with the 59 | // message passed to Debug, Info, ... 60 | PanicLevel Level = iota 61 | // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the 62 | // logging level is set to Panic. 63 | FatalLevel 64 | // ErrorLevel level. Logs. Used for errors that should definitely be noted. 65 | // Commonly used for hooks to send errors to an error tracking service. 66 | ErrorLevel 67 | // WarnLevel level. Non-critical entries that deserve eyes. 68 | WarnLevel 69 | // InfoLevel level. General operational entries about what's going on inside the 70 | // application. 71 | InfoLevel 72 | // DebugLevel level. Usually only enabled when debugging. Very verbose logging. 73 | DebugLevel 74 | ) 75 | 76 | // Won't compile if StdLogger can't be realized by a log.Logger 77 | var _ StdLogger = &log.Logger{} 78 | 79 | // StdLogger is what your logrus-enabled library should take, that way 80 | // it'll accept a stdlib logger and a logrus logger. There's no standard 81 | // interface, this is the closest we get, unfortunately. 82 | type StdLogger interface { 83 | Print(...interface{}) 84 | Printf(string, ...interface{}) 85 | Println(...interface{}) 86 | 87 | Fatal(...interface{}) 88 | Fatalf(string, ...interface{}) 89 | Fatalln(...interface{}) 90 | 91 | Panic(...interface{}) 92 | Panicf(string, ...interface{}) 93 | Panicln(...interface{}) 94 | } 95 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "strconv" 7 | "strings" 8 | "sync" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) { 15 | var buffer bytes.Buffer 16 | var fields Fields 17 | 18 | logger := New() 19 | logger.Out = &buffer 20 | logger.Formatter = new(JSONFormatter) 21 | 22 | log(logger) 23 | 24 | err := json.Unmarshal(buffer.Bytes(), &fields) 25 | assert.Nil(t, err) 26 | 27 | assertions(fields) 28 | } 29 | 30 | func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) { 31 | var buffer bytes.Buffer 32 | 33 | logger := New() 34 | logger.Out = &buffer 35 | logger.Formatter = &TextFormatter{ 36 | DisableColors: true, 37 | } 38 | 39 | log(logger) 40 | 41 | fields := make(map[string]string) 42 | for _, kv := range strings.Split(buffer.String(), " ") { 43 | if !strings.Contains(kv, "=") { 44 | continue 45 | } 46 | kvArr := strings.Split(kv, "=") 47 | key := strings.TrimSpace(kvArr[0]) 48 | val := kvArr[1] 49 | if kvArr[1][0] == '"' { 50 | var err error 51 | val, err = strconv.Unquote(val) 52 | assert.NoError(t, err) 53 | } 54 | fields[key] = val 55 | } 56 | assertions(fields) 57 | } 58 | 59 | func TestPrint(t *testing.T) { 60 | LogAndAssertJSON(t, func(log *Logger) { 61 | log.Print("test") 62 | }, func(fields Fields) { 63 | assert.Equal(t, fields["msg"], "test") 64 | assert.Equal(t, fields["level"], "info") 65 | }) 66 | } 67 | 68 | func TestInfo(t *testing.T) { 69 | LogAndAssertJSON(t, func(log *Logger) { 70 | log.Info("test") 71 | }, func(fields Fields) { 72 | assert.Equal(t, fields["msg"], "test") 73 | assert.Equal(t, fields["level"], "info") 74 | }) 75 | } 76 | 77 | func TestWarn(t *testing.T) { 78 | LogAndAssertJSON(t, func(log *Logger) { 79 | log.Warn("test") 80 | }, func(fields Fields) { 81 | assert.Equal(t, fields["msg"], "test") 82 | assert.Equal(t, fields["level"], "warning") 83 | }) 84 | } 85 | 86 | func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) { 87 | LogAndAssertJSON(t, func(log *Logger) { 88 | log.Infoln("test", "test") 89 | }, func(fields Fields) { 90 | assert.Equal(t, fields["msg"], "test test") 91 | }) 92 | } 93 | 94 | func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) { 95 | LogAndAssertJSON(t, func(log *Logger) { 96 | log.Infoln("test", 10) 97 | }, func(fields Fields) { 98 | assert.Equal(t, fields["msg"], "test 10") 99 | }) 100 | } 101 | 102 | func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { 103 | LogAndAssertJSON(t, func(log *Logger) { 104 | log.Infoln(10, 10) 105 | }, func(fields Fields) { 106 | assert.Equal(t, fields["msg"], "10 10") 107 | }) 108 | } 109 | 110 | func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { 111 | LogAndAssertJSON(t, func(log *Logger) { 112 | log.Infoln(10, 10) 113 | }, func(fields Fields) { 114 | assert.Equal(t, fields["msg"], "10 10") 115 | }) 116 | } 117 | 118 | func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) { 119 | LogAndAssertJSON(t, func(log *Logger) { 120 | log.Info("test", 10) 121 | }, func(fields Fields) { 122 | assert.Equal(t, fields["msg"], "test10") 123 | }) 124 | } 125 | 126 | func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) { 127 | LogAndAssertJSON(t, func(log *Logger) { 128 | log.Info("test", "test") 129 | }, func(fields Fields) { 130 | assert.Equal(t, fields["msg"], "testtest") 131 | }) 132 | } 133 | 134 | func TestWithFieldsShouldAllowAssignments(t *testing.T) { 135 | var buffer bytes.Buffer 136 | var fields Fields 137 | 138 | logger := New() 139 | logger.Out = &buffer 140 | logger.Formatter = new(JSONFormatter) 141 | 142 | localLog := logger.WithFields(Fields{ 143 | "key1": "value1", 144 | }) 145 | 146 | localLog.WithField("key2", "value2").Info("test") 147 | err := json.Unmarshal(buffer.Bytes(), &fields) 148 | assert.Nil(t, err) 149 | 150 | assert.Equal(t, "value2", fields["key2"]) 151 | assert.Equal(t, "value1", fields["key1"]) 152 | 153 | buffer = bytes.Buffer{} 154 | fields = Fields{} 155 | localLog.Info("test") 156 | err = json.Unmarshal(buffer.Bytes(), &fields) 157 | assert.Nil(t, err) 158 | 159 | _, ok := fields["key2"] 160 | assert.Equal(t, false, ok) 161 | assert.Equal(t, "value1", fields["key1"]) 162 | } 163 | 164 | func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) { 165 | LogAndAssertJSON(t, func(log *Logger) { 166 | log.WithField("msg", "hello").Info("test") 167 | }, func(fields Fields) { 168 | assert.Equal(t, fields["msg"], "test") 169 | }) 170 | } 171 | 172 | func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) { 173 | LogAndAssertJSON(t, func(log *Logger) { 174 | log.WithField("msg", "hello").Info("test") 175 | }, func(fields Fields) { 176 | assert.Equal(t, fields["msg"], "test") 177 | assert.Equal(t, fields["fields.msg"], "hello") 178 | }) 179 | } 180 | 181 | func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) { 182 | LogAndAssertJSON(t, func(log *Logger) { 183 | log.WithField("time", "hello").Info("test") 184 | }, func(fields Fields) { 185 | assert.Equal(t, fields["fields.time"], "hello") 186 | }) 187 | } 188 | 189 | func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) { 190 | LogAndAssertJSON(t, func(log *Logger) { 191 | log.WithField("level", 1).Info("test") 192 | }, func(fields Fields) { 193 | assert.Equal(t, fields["level"], "info") 194 | assert.Equal(t, fields["fields.level"], 1) 195 | }) 196 | } 197 | 198 | func TestDefaultFieldsAreNotPrefixed(t *testing.T) { 199 | LogAndAssertText(t, func(log *Logger) { 200 | ll := log.WithField("herp", "derp") 201 | ll.Info("hello") 202 | ll.Info("bye") 203 | }, func(fields map[string]string) { 204 | for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} { 205 | if _, ok := fields[fieldName]; ok { 206 | t.Fatalf("should not have prefixed %q: %v", fieldName, fields) 207 | } 208 | } 209 | }) 210 | } 211 | 212 | func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) { 213 | 214 | var buffer bytes.Buffer 215 | var fields Fields 216 | 217 | logger := New() 218 | logger.Out = &buffer 219 | logger.Formatter = new(JSONFormatter) 220 | 221 | llog := logger.WithField("context", "eating raw fish") 222 | 223 | llog.Info("looks delicious") 224 | 225 | err := json.Unmarshal(buffer.Bytes(), &fields) 226 | assert.NoError(t, err, "should have decoded first message") 227 | assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") 228 | assert.Equal(t, fields["msg"], "looks delicious") 229 | assert.Equal(t, fields["context"], "eating raw fish") 230 | 231 | buffer.Reset() 232 | 233 | llog.Warn("omg it is!") 234 | 235 | err = json.Unmarshal(buffer.Bytes(), &fields) 236 | assert.NoError(t, err, "should have decoded second message") 237 | assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") 238 | assert.Equal(t, fields["msg"], "omg it is!") 239 | assert.Equal(t, fields["context"], "eating raw fish") 240 | assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry") 241 | 242 | } 243 | 244 | func TestConvertLevelToString(t *testing.T) { 245 | assert.Equal(t, "debug", DebugLevel.String()) 246 | assert.Equal(t, "info", InfoLevel.String()) 247 | assert.Equal(t, "warning", WarnLevel.String()) 248 | assert.Equal(t, "error", ErrorLevel.String()) 249 | assert.Equal(t, "fatal", FatalLevel.String()) 250 | assert.Equal(t, "panic", PanicLevel.String()) 251 | } 252 | 253 | func TestParseLevel(t *testing.T) { 254 | l, err := ParseLevel("panic") 255 | assert.Nil(t, err) 256 | assert.Equal(t, PanicLevel, l) 257 | 258 | l, err = ParseLevel("fatal") 259 | assert.Nil(t, err) 260 | assert.Equal(t, FatalLevel, l) 261 | 262 | l, err = ParseLevel("error") 263 | assert.Nil(t, err) 264 | assert.Equal(t, ErrorLevel, l) 265 | 266 | l, err = ParseLevel("warn") 267 | assert.Nil(t, err) 268 | assert.Equal(t, WarnLevel, l) 269 | 270 | l, err = ParseLevel("warning") 271 | assert.Nil(t, err) 272 | assert.Equal(t, WarnLevel, l) 273 | 274 | l, err = ParseLevel("info") 275 | assert.Nil(t, err) 276 | assert.Equal(t, InfoLevel, l) 277 | 278 | l, err = ParseLevel("debug") 279 | assert.Nil(t, err) 280 | assert.Equal(t, DebugLevel, l) 281 | 282 | l, err = ParseLevel("invalid") 283 | assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error()) 284 | } 285 | 286 | func TestGetSetLevelRace(t *testing.T) { 287 | wg := sync.WaitGroup{} 288 | for i := 0; i < 100; i++ { 289 | wg.Add(1) 290 | go func(i int) { 291 | defer wg.Done() 292 | if i%2 == 0 { 293 | SetLevel(InfoLevel) 294 | } else { 295 | GetLevel() 296 | } 297 | }(i) 298 | 299 | } 300 | wg.Wait() 301 | } 302 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_darwin.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2013 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package logrus 7 | 8 | import "syscall" 9 | 10 | const ioctlReadTermios = syscall.TIOCGETA 11 | 12 | type Termios syscall.Termios 13 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_freebsd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin. 3 | */ 4 | package logrus 5 | 6 | import ( 7 | "syscall" 8 | ) 9 | 10 | const ioctlReadTermios = syscall.TIOCGETA 11 | 12 | type Termios struct { 13 | Iflag uint32 14 | Oflag uint32 15 | Cflag uint32 16 | Lflag uint32 17 | Cc [20]uint8 18 | Ispeed uint32 19 | Ospeed uint32 20 | } 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_linux.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2013 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package logrus 7 | 8 | import "syscall" 9 | 10 | const ioctlReadTermios = syscall.TCGETS 11 | 12 | type Termios syscall.Termios 13 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2011 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // +build linux darwin freebsd openbsd 7 | 8 | package logrus 9 | 10 | import ( 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | // IsTerminal returns true if the given file descriptor is a terminal. 16 | func IsTerminal() bool { 17 | fd := syscall.Stdout 18 | var termios Termios 19 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 20 | return err == 0 21 | } 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_openbsd.go: -------------------------------------------------------------------------------- 1 | 2 | package logrus 3 | 4 | import "syscall" 5 | 6 | const ioctlReadTermios = syscall.TIOCGETA 7 | 8 | type Termios syscall.Termios 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_windows.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2011 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // +build windows 7 | 8 | package logrus 9 | 10 | import ( 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 16 | 17 | var ( 18 | procGetConsoleMode = kernel32.NewProc("GetConsoleMode") 19 | ) 20 | 21 | // IsTerminal returns true if the given file descriptor is a terminal. 22 | func IsTerminal() bool { 23 | fd := syscall.Stdout 24 | var st uint32 25 | r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 26 | return r != 0 && e == 0 27 | } 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "regexp" 7 | "sort" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | const ( 13 | nocolor = 0 14 | red = 31 15 | green = 32 16 | yellow = 33 17 | blue = 34 18 | gray = 37 19 | ) 20 | 21 | var ( 22 | baseTimestamp time.Time 23 | isTerminal bool 24 | noQuoteNeeded *regexp.Regexp 25 | ) 26 | 27 | func init() { 28 | baseTimestamp = time.Now() 29 | isTerminal = IsTerminal() 30 | } 31 | 32 | func miniTS() int { 33 | return int(time.Since(baseTimestamp) / time.Second) 34 | } 35 | 36 | type TextFormatter struct { 37 | // Set to true to bypass checking for a TTY before outputting colors. 38 | ForceColors bool 39 | 40 | // Force disabling colors. 41 | DisableColors bool 42 | 43 | // Disable timestamp logging. useful when output is redirected to logging 44 | // system that already adds timestamps. 45 | DisableTimestamp bool 46 | 47 | // Enable logging the full timestamp when a TTY is attached instead of just 48 | // the time passed since beginning of execution. 49 | FullTimestamp bool 50 | 51 | // The fields are sorted by default for a consistent output. For applications 52 | // that log extremely frequently and don't use the JSON formatter this may not 53 | // be desired. 54 | DisableSorting bool 55 | } 56 | 57 | func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { 58 | var keys []string = make([]string, 0, len(entry.Data)) 59 | for k := range entry.Data { 60 | keys = append(keys, k) 61 | } 62 | 63 | if !f.DisableSorting { 64 | sort.Strings(keys) 65 | } 66 | 67 | b := &bytes.Buffer{} 68 | 69 | prefixFieldClashes(entry.Data) 70 | 71 | isColored := (f.ForceColors || isTerminal) && !f.DisableColors 72 | 73 | if isColored { 74 | f.printColored(b, entry, keys) 75 | } else { 76 | if !f.DisableTimestamp { 77 | f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339)) 78 | } 79 | f.appendKeyValue(b, "level", entry.Level.String()) 80 | f.appendKeyValue(b, "msg", entry.Message) 81 | for _, key := range keys { 82 | f.appendKeyValue(b, key, entry.Data[key]) 83 | } 84 | } 85 | 86 | b.WriteByte('\n') 87 | return b.Bytes(), nil 88 | } 89 | 90 | func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string) { 91 | var levelColor int 92 | switch entry.Level { 93 | case DebugLevel: 94 | levelColor = gray 95 | case WarnLevel: 96 | levelColor = yellow 97 | case ErrorLevel, FatalLevel, PanicLevel: 98 | levelColor = red 99 | default: 100 | levelColor = blue 101 | } 102 | 103 | levelText := strings.ToUpper(entry.Level.String())[0:4] 104 | 105 | if !f.FullTimestamp { 106 | fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message) 107 | } else { 108 | fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(time.RFC3339), entry.Message) 109 | } 110 | for _, k := range keys { 111 | v := entry.Data[k] 112 | fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v) 113 | } 114 | } 115 | 116 | func needsQuoting(text string) bool { 117 | for _, ch := range text { 118 | if !((ch >= 'a' && ch <= 'z') || 119 | (ch >= 'A' && ch <= 'Z') || 120 | (ch >= '0' && ch <= '9') || 121 | ch == '-' || ch == '.') { 122 | return false 123 | } 124 | } 125 | return true 126 | } 127 | 128 | func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) { 129 | switch value.(type) { 130 | case string: 131 | if needsQuoting(value.(string)) { 132 | fmt.Fprintf(b, "%v=%s ", key, value) 133 | } else { 134 | fmt.Fprintf(b, "%v=%q ", key, value) 135 | } 136 | case error: 137 | if needsQuoting(value.(error).Error()) { 138 | fmt.Fprintf(b, "%v=%s ", key, value) 139 | } else { 140 | fmt.Fprintf(b, "%v=%q ", key, value) 141 | } 142 | default: 143 | fmt.Fprintf(b, "%v=%v ", key, value) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestQuoting(t *testing.T) { 11 | tf := &TextFormatter{DisableColors: true} 12 | 13 | checkQuoting := func(q bool, value interface{}) { 14 | b, _ := tf.Format(WithField("test", value)) 15 | idx := bytes.Index(b, ([]byte)("test=")) 16 | cont := bytes.Contains(b[idx+5:], []byte{'"'}) 17 | if cont != q { 18 | if q { 19 | t.Errorf("quoting expected for: %#v", value) 20 | } else { 21 | t.Errorf("quoting not expected for: %#v", value) 22 | } 23 | } 24 | } 25 | 26 | checkQuoting(false, "abcd") 27 | checkQuoting(false, "v1.0") 28 | checkQuoting(false, "1234567890") 29 | checkQuoting(true, "/foobar") 30 | checkQuoting(true, "x y") 31 | checkQuoting(true, "x,y") 32 | checkQuoting(false, errors.New("invalid")) 33 | checkQuoting(true, errors.New("invalid argument")) 34 | } 35 | 36 | // TODO add tests for sorting etc., this requires a parser for the text 37 | // formatter output. 38 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/Sirupsen/logrus/writer.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "runtime" 7 | ) 8 | 9 | func (logger *Logger) Writer() (*io.PipeWriter) { 10 | reader, writer := io.Pipe() 11 | 12 | go logger.writerScanner(reader) 13 | runtime.SetFinalizer(writer, writerFinalizer) 14 | 15 | return writer 16 | } 17 | 18 | func (logger *Logger) writerScanner(reader *io.PipeReader) { 19 | scanner := bufio.NewScanner(reader) 20 | for scanner.Scan() { 21 | logger.Print(scanner.Text()) 22 | } 23 | if err := scanner.Err(); err != nil { 24 | logger.Errorf("Error while reading from Writer: %s", err) 25 | } 26 | reader.Close() 27 | } 28 | 29 | func writerFinalizer(writer *io.PipeWriter) { 30 | writer.Close() 31 | } 32 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package agent 6 | 7 | import ( 8 | "bytes" 9 | "crypto/rand" 10 | "errors" 11 | "net" 12 | "os" 13 | "os/exec" 14 | "path/filepath" 15 | "strconv" 16 | "testing" 17 | 18 | "golang.org/x/crypto/ssh" 19 | ) 20 | 21 | // startAgent executes ssh-agent, and returns a Agent interface to it. 22 | func startAgent(t *testing.T) (client Agent, socket string, cleanup func()) { 23 | if testing.Short() { 24 | // ssh-agent is not always available, and the key 25 | // types supported vary by platform. 26 | t.Skip("skipping test due to -short") 27 | } 28 | 29 | bin, err := exec.LookPath("ssh-agent") 30 | if err != nil { 31 | t.Skip("could not find ssh-agent") 32 | } 33 | 34 | cmd := exec.Command(bin, "-s") 35 | out, err := cmd.Output() 36 | if err != nil { 37 | t.Fatalf("cmd.Output: %v", err) 38 | } 39 | 40 | /* Output looks like: 41 | 42 | SSH_AUTH_SOCK=/tmp/ssh-P65gpcqArqvH/agent.15541; export SSH_AUTH_SOCK; 43 | SSH_AGENT_PID=15542; export SSH_AGENT_PID; 44 | echo Agent pid 15542; 45 | */ 46 | fields := bytes.Split(out, []byte(";")) 47 | line := bytes.SplitN(fields[0], []byte("="), 2) 48 | line[0] = bytes.TrimLeft(line[0], "\n") 49 | if string(line[0]) != "SSH_AUTH_SOCK" { 50 | t.Fatalf("could not find key SSH_AUTH_SOCK in %q", fields[0]) 51 | } 52 | socket = string(line[1]) 53 | 54 | line = bytes.SplitN(fields[2], []byte("="), 2) 55 | line[0] = bytes.TrimLeft(line[0], "\n") 56 | if string(line[0]) != "SSH_AGENT_PID" { 57 | t.Fatalf("could not find key SSH_AGENT_PID in %q", fields[2]) 58 | } 59 | pidStr := line[1] 60 | pid, err := strconv.Atoi(string(pidStr)) 61 | if err != nil { 62 | t.Fatalf("Atoi(%q): %v", pidStr, err) 63 | } 64 | 65 | conn, err := net.Dial("unix", string(socket)) 66 | if err != nil { 67 | t.Fatalf("net.Dial: %v", err) 68 | } 69 | 70 | ac := NewClient(conn) 71 | return ac, socket, func() { 72 | proc, _ := os.FindProcess(pid) 73 | if proc != nil { 74 | proc.Kill() 75 | } 76 | conn.Close() 77 | os.RemoveAll(filepath.Dir(socket)) 78 | } 79 | } 80 | 81 | func testAgent(t *testing.T, key interface{}, cert *ssh.Certificate) { 82 | agent, _, cleanup := startAgent(t) 83 | defer cleanup() 84 | 85 | testAgentInterface(t, agent, key, cert) 86 | } 87 | 88 | func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate) { 89 | signer, err := ssh.NewSignerFromKey(key) 90 | if err != nil { 91 | t.Fatalf("NewSignerFromKey(%T): %v", key, err) 92 | } 93 | // The agent should start up empty. 94 | if keys, err := agent.List(); err != nil { 95 | t.Fatalf("RequestIdentities: %v", err) 96 | } else if len(keys) > 0 { 97 | t.Fatalf("got %d keys, want 0: %v", len(keys), keys) 98 | } 99 | 100 | // Attempt to insert the key, with certificate if specified. 101 | var pubKey ssh.PublicKey 102 | if cert != nil { 103 | err = agent.Add(key, cert, "comment") 104 | pubKey = cert 105 | } else { 106 | err = agent.Add(key, nil, "comment") 107 | pubKey = signer.PublicKey() 108 | } 109 | if err != nil { 110 | t.Fatalf("insert(%T): %v", key, err) 111 | } 112 | 113 | // Did the key get inserted successfully? 114 | if keys, err := agent.List(); err != nil { 115 | t.Fatalf("List: %v", err) 116 | } else if len(keys) != 1 { 117 | t.Fatalf("got %v, want 1 key", keys) 118 | } else if keys[0].Comment != "comment" { 119 | t.Fatalf("key comment: got %v, want %v", keys[0].Comment, "comment") 120 | } else if !bytes.Equal(keys[0].Blob, pubKey.Marshal()) { 121 | t.Fatalf("key mismatch") 122 | } 123 | 124 | // Can the agent make a valid signature? 125 | data := []byte("hello") 126 | sig, err := agent.Sign(pubKey, data) 127 | if err != nil { 128 | t.Fatalf("Sign(%s): %v", pubKey.Type(), err) 129 | } 130 | 131 | if err := pubKey.Verify(data, sig); err != nil { 132 | t.Fatalf("Verify(%s): %v", pubKey.Type(), err) 133 | } 134 | } 135 | 136 | func TestAgent(t *testing.T) { 137 | for _, keyType := range []string{"rsa", "dsa", "ecdsa"} { 138 | testAgent(t, testPrivateKeys[keyType], nil) 139 | } 140 | } 141 | 142 | func TestCert(t *testing.T) { 143 | cert := &ssh.Certificate{ 144 | Key: testPublicKeys["rsa"], 145 | ValidBefore: ssh.CertTimeInfinity, 146 | CertType: ssh.UserCert, 147 | } 148 | cert.SignCert(rand.Reader, testSigners["ecdsa"]) 149 | 150 | testAgent(t, testPrivateKeys["rsa"], cert) 151 | } 152 | 153 | // netPipe is analogous to net.Pipe, but it uses a real net.Conn, and 154 | // therefore is buffered (net.Pipe deadlocks if both sides start with 155 | // a write.) 156 | func netPipe() (net.Conn, net.Conn, error) { 157 | listener, err := net.Listen("tcp", "127.0.0.1:0") 158 | if err != nil { 159 | return nil, nil, err 160 | } 161 | defer listener.Close() 162 | c1, err := net.Dial("tcp", listener.Addr().String()) 163 | if err != nil { 164 | return nil, nil, err 165 | } 166 | 167 | c2, err := listener.Accept() 168 | if err != nil { 169 | c1.Close() 170 | return nil, nil, err 171 | } 172 | 173 | return c1, c2, nil 174 | } 175 | 176 | func TestAuth(t *testing.T) { 177 | a, b, err := netPipe() 178 | if err != nil { 179 | t.Fatalf("netPipe: %v", err) 180 | } 181 | 182 | defer a.Close() 183 | defer b.Close() 184 | 185 | agent, _, cleanup := startAgent(t) 186 | defer cleanup() 187 | 188 | if err := agent.Add(testPrivateKeys["rsa"], nil, "comment"); err != nil { 189 | t.Errorf("Add: %v", err) 190 | } 191 | 192 | serverConf := ssh.ServerConfig{} 193 | serverConf.AddHostKey(testSigners["rsa"]) 194 | serverConf.PublicKeyCallback = func(c ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { 195 | if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { 196 | return nil, nil 197 | } 198 | 199 | return nil, errors.New("pubkey rejected") 200 | } 201 | 202 | go func() { 203 | conn, _, _, err := ssh.NewServerConn(a, &serverConf) 204 | if err != nil { 205 | t.Fatalf("Server: %v", err) 206 | } 207 | conn.Close() 208 | }() 209 | 210 | conf := ssh.ClientConfig{} 211 | conf.Auth = append(conf.Auth, ssh.PublicKeysCallback(agent.Signers)) 212 | conn, _, _, err := ssh.NewClientConn(b, "", &conf) 213 | if err != nil { 214 | t.Fatalf("NewClientConn: %v", err) 215 | } 216 | conn.Close() 217 | } 218 | 219 | func TestLockClient(t *testing.T) { 220 | agent, _, cleanup := startAgent(t) 221 | defer cleanup() 222 | testLockAgent(agent, t) 223 | } 224 | 225 | func testLockAgent(agent Agent, t *testing.T) { 226 | if err := agent.Add(testPrivateKeys["rsa"], nil, "comment 1"); err != nil { 227 | t.Errorf("Add: %v", err) 228 | } 229 | if err := agent.Add(testPrivateKeys["dsa"], nil, "comment dsa"); err != nil { 230 | t.Errorf("Add: %v", err) 231 | } 232 | if keys, err := agent.List(); err != nil { 233 | t.Errorf("List: %v", err) 234 | } else if len(keys) != 2 { 235 | t.Errorf("Want 2 keys, got %v", keys) 236 | } 237 | 238 | passphrase := []byte("secret") 239 | if err := agent.Lock(passphrase); err != nil { 240 | t.Errorf("Lock: %v", err) 241 | } 242 | 243 | if keys, err := agent.List(); err != nil { 244 | t.Errorf("List: %v", err) 245 | } else if len(keys) != 0 { 246 | t.Errorf("Want 0 keys, got %v", keys) 247 | } 248 | 249 | signer, _ := ssh.NewSignerFromKey(testPrivateKeys["rsa"]) 250 | if _, err := agent.Sign(signer.PublicKey(), []byte("hello")); err == nil { 251 | t.Fatalf("Sign did not fail") 252 | } 253 | 254 | if err := agent.Remove(signer.PublicKey()); err == nil { 255 | t.Fatalf("Remove did not fail") 256 | } 257 | 258 | if err := agent.RemoveAll(); err == nil { 259 | t.Fatalf("RemoveAll did not fail") 260 | } 261 | 262 | if err := agent.Unlock(nil); err == nil { 263 | t.Errorf("Unlock with wrong passphrase succeeded") 264 | } 265 | if err := agent.Unlock(passphrase); err != nil { 266 | t.Errorf("Unlock: %v", err) 267 | } 268 | 269 | if err := agent.Remove(signer.PublicKey()); err != nil { 270 | t.Fatalf("Remove: %v", err) 271 | } 272 | 273 | if keys, err := agent.List(); err != nil { 274 | t.Errorf("List: %v", err) 275 | } else if len(keys) != 1 { 276 | t.Errorf("Want 1 keys, got %v", keys) 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/forward.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package agent 6 | 7 | import ( 8 | "errors" 9 | "io" 10 | "net" 11 | "sync" 12 | 13 | "golang.org/x/crypto/ssh" 14 | ) 15 | 16 | // RequestAgentForwarding sets up agent forwarding for the session. 17 | // ForwardToAgent or ForwardToRemote should be called to route 18 | // the authentication requests. 19 | func RequestAgentForwarding(session *ssh.Session) error { 20 | ok, err := session.SendRequest("auth-agent-req@openssh.com", true, nil) 21 | if err != nil { 22 | return err 23 | } 24 | if !ok { 25 | return errors.New("forwarding request denied") 26 | } 27 | return nil 28 | } 29 | 30 | // ForwardToAgent routes authentication requests to the given keyring. 31 | func ForwardToAgent(client *ssh.Client, keyring Agent) error { 32 | channels := client.HandleChannelOpen(channelType) 33 | if channels == nil { 34 | return errors.New("agent: already have handler for " + channelType) 35 | } 36 | 37 | go func() { 38 | for ch := range channels { 39 | channel, reqs, err := ch.Accept() 40 | if err != nil { 41 | continue 42 | } 43 | go ssh.DiscardRequests(reqs) 44 | go func() { 45 | ServeAgent(keyring, channel) 46 | channel.Close() 47 | }() 48 | } 49 | }() 50 | return nil 51 | } 52 | 53 | const channelType = "auth-agent@openssh.com" 54 | 55 | // ForwardToRemote routes authentication requests to the ssh-agent 56 | // process serving on the given unix socket. 57 | func ForwardToRemote(client *ssh.Client, addr string) error { 58 | channels := client.HandleChannelOpen(channelType) 59 | if channels == nil { 60 | return errors.New("agent: already have handler for " + channelType) 61 | } 62 | conn, err := net.Dial("unix", addr) 63 | if err != nil { 64 | return err 65 | } 66 | conn.Close() 67 | 68 | go func() { 69 | for ch := range channels { 70 | channel, reqs, err := ch.Accept() 71 | if err != nil { 72 | continue 73 | } 74 | go ssh.DiscardRequests(reqs) 75 | go forwardUnixSocket(channel, addr) 76 | } 77 | }() 78 | return nil 79 | } 80 | 81 | func forwardUnixSocket(channel ssh.Channel, addr string) { 82 | conn, err := net.Dial("unix", addr) 83 | if err != nil { 84 | return 85 | } 86 | 87 | var wg sync.WaitGroup 88 | wg.Add(2) 89 | go func() { 90 | io.Copy(conn, channel) 91 | conn.(*net.UnixConn).CloseWrite() 92 | wg.Done() 93 | }() 94 | go func() { 95 | io.Copy(channel, conn) 96 | channel.CloseWrite() 97 | wg.Done() 98 | }() 99 | 100 | wg.Wait() 101 | conn.Close() 102 | channel.Close() 103 | } 104 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/keyring.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package agent 6 | 7 | import ( 8 | "bytes" 9 | "crypto/rand" 10 | "crypto/subtle" 11 | "errors" 12 | "fmt" 13 | "sync" 14 | 15 | "golang.org/x/crypto/ssh" 16 | ) 17 | 18 | type privKey struct { 19 | signer ssh.Signer 20 | comment string 21 | } 22 | 23 | type keyring struct { 24 | mu sync.Mutex 25 | keys []privKey 26 | 27 | locked bool 28 | passphrase []byte 29 | } 30 | 31 | var errLocked = errors.New("agent: locked") 32 | 33 | // NewKeyring returns an Agent that holds keys in memory. It is safe 34 | // for concurrent use by multiple goroutines. 35 | func NewKeyring() Agent { 36 | return &keyring{} 37 | } 38 | 39 | // RemoveAll removes all identities. 40 | func (r *keyring) RemoveAll() error { 41 | r.mu.Lock() 42 | defer r.mu.Unlock() 43 | if r.locked { 44 | return errLocked 45 | } 46 | 47 | r.keys = nil 48 | return nil 49 | } 50 | 51 | // Remove removes all identities with the given public key. 52 | func (r *keyring) Remove(key ssh.PublicKey) error { 53 | r.mu.Lock() 54 | defer r.mu.Unlock() 55 | if r.locked { 56 | return errLocked 57 | } 58 | 59 | want := key.Marshal() 60 | found := false 61 | for i := 0; i < len(r.keys); { 62 | if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) { 63 | found = true 64 | r.keys[i] = r.keys[len(r.keys)-1] 65 | r.keys = r.keys[len(r.keys)-1:] 66 | continue 67 | } else { 68 | i++ 69 | } 70 | } 71 | 72 | if !found { 73 | return errors.New("agent: key not found") 74 | } 75 | return nil 76 | } 77 | 78 | // Lock locks the agent. Sign and Remove will fail, and List will empty an empty list. 79 | func (r *keyring) Lock(passphrase []byte) error { 80 | r.mu.Lock() 81 | defer r.mu.Unlock() 82 | if r.locked { 83 | return errLocked 84 | } 85 | 86 | r.locked = true 87 | r.passphrase = passphrase 88 | return nil 89 | } 90 | 91 | // Unlock undoes the effect of Lock 92 | func (r *keyring) Unlock(passphrase []byte) error { 93 | r.mu.Lock() 94 | defer r.mu.Unlock() 95 | if !r.locked { 96 | return errors.New("agent: not locked") 97 | } 98 | if len(passphrase) != len(r.passphrase) || 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) { 99 | return fmt.Errorf("agent: incorrect passphrase") 100 | } 101 | 102 | r.locked = false 103 | r.passphrase = nil 104 | return nil 105 | } 106 | 107 | // List returns the identities known to the agent. 108 | func (r *keyring) List() ([]*Key, error) { 109 | r.mu.Lock() 110 | defer r.mu.Unlock() 111 | if r.locked { 112 | // section 2.7: locked agents return empty. 113 | return nil, nil 114 | } 115 | 116 | var ids []*Key 117 | for _, k := range r.keys { 118 | pub := k.signer.PublicKey() 119 | ids = append(ids, &Key{ 120 | Format: pub.Type(), 121 | Blob: pub.Marshal(), 122 | Comment: k.comment}) 123 | } 124 | return ids, nil 125 | } 126 | 127 | // Insert adds a private key to the keyring. If a certificate 128 | // is given, that certificate is added as public key. 129 | func (r *keyring) Add(priv interface{}, cert *ssh.Certificate, comment string) error { 130 | r.mu.Lock() 131 | defer r.mu.Unlock() 132 | if r.locked { 133 | return errLocked 134 | } 135 | signer, err := ssh.NewSignerFromKey(priv) 136 | 137 | if err != nil { 138 | return err 139 | } 140 | 141 | if cert != nil { 142 | signer, err = ssh.NewCertSigner(cert, signer) 143 | if err != nil { 144 | return err 145 | } 146 | } 147 | 148 | r.keys = append(r.keys, privKey{signer, comment}) 149 | 150 | return nil 151 | } 152 | 153 | // Sign returns a signature for the data. 154 | func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { 155 | r.mu.Lock() 156 | defer r.mu.Unlock() 157 | if r.locked { 158 | return nil, errLocked 159 | } 160 | 161 | wanted := key.Marshal() 162 | for _, k := range r.keys { 163 | if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { 164 | return k.signer.Sign(rand.Reader, data) 165 | } 166 | } 167 | return nil, errors.New("not found") 168 | } 169 | 170 | // Signers returns signers for all the known keys. 171 | func (r *keyring) Signers() ([]ssh.Signer, error) { 172 | r.mu.Lock() 173 | defer r.mu.Unlock() 174 | if r.locked { 175 | return nil, errLocked 176 | } 177 | 178 | s := make([]ssh.Signer, 0, len(r.keys)) 179 | for _, k := range r.keys { 180 | s = append(s, k.signer) 181 | } 182 | return s, nil 183 | } 184 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package agent 6 | 7 | import ( 8 | "crypto/rsa" 9 | "encoding/binary" 10 | "fmt" 11 | "io" 12 | "log" 13 | "math/big" 14 | 15 | "golang.org/x/crypto/ssh" 16 | ) 17 | 18 | // Server wraps an Agent and uses it to implement the agent side of 19 | // the SSH-agent, wire protocol. 20 | type server struct { 21 | agent Agent 22 | } 23 | 24 | func (s *server) processRequestBytes(reqData []byte) []byte { 25 | rep, err := s.processRequest(reqData) 26 | if err != nil { 27 | if err != errLocked { 28 | // TODO(hanwen): provide better logging interface? 29 | log.Printf("agent %d: %v", reqData[0], err) 30 | } 31 | return []byte{agentFailure} 32 | } 33 | 34 | if err == nil && rep == nil { 35 | return []byte{agentSuccess} 36 | } 37 | 38 | return ssh.Marshal(rep) 39 | } 40 | 41 | func marshalKey(k *Key) []byte { 42 | var record struct { 43 | Blob []byte 44 | Comment string 45 | } 46 | record.Blob = k.Marshal() 47 | record.Comment = k.Comment 48 | 49 | return ssh.Marshal(&record) 50 | } 51 | 52 | type agentV1IdentityMsg struct { 53 | Numkeys uint32 `sshtype:"2"` 54 | } 55 | 56 | type agentRemoveIdentityMsg struct { 57 | KeyBlob []byte `sshtype:"18"` 58 | } 59 | 60 | type agentLockMsg struct { 61 | Passphrase []byte `sshtype:"22"` 62 | } 63 | 64 | type agentUnlockMsg struct { 65 | Passphrase []byte `sshtype:"23"` 66 | } 67 | 68 | func (s *server) processRequest(data []byte) (interface{}, error) { 69 | switch data[0] { 70 | case agentRequestV1Identities: 71 | return &agentV1IdentityMsg{0}, nil 72 | case agentRemoveIdentity: 73 | var req agentRemoveIdentityMsg 74 | if err := ssh.Unmarshal(data, &req); err != nil { 75 | return nil, err 76 | } 77 | 78 | var wk wireKey 79 | if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { 80 | return nil, err 81 | } 82 | 83 | return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob}) 84 | 85 | case agentRemoveAllIdentities: 86 | return nil, s.agent.RemoveAll() 87 | 88 | case agentLock: 89 | var req agentLockMsg 90 | if err := ssh.Unmarshal(data, &req); err != nil { 91 | return nil, err 92 | } 93 | 94 | return nil, s.agent.Lock(req.Passphrase) 95 | 96 | case agentUnlock: 97 | var req agentLockMsg 98 | if err := ssh.Unmarshal(data, &req); err != nil { 99 | return nil, err 100 | } 101 | return nil, s.agent.Unlock(req.Passphrase) 102 | 103 | case agentSignRequest: 104 | var req signRequestAgentMsg 105 | if err := ssh.Unmarshal(data, &req); err != nil { 106 | return nil, err 107 | } 108 | 109 | var wk wireKey 110 | if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { 111 | return nil, err 112 | } 113 | 114 | k := &Key{ 115 | Format: wk.Format, 116 | Blob: req.KeyBlob, 117 | } 118 | 119 | sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags. 120 | if err != nil { 121 | return nil, err 122 | } 123 | return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil 124 | case agentRequestIdentities: 125 | keys, err := s.agent.List() 126 | if err != nil { 127 | return nil, err 128 | } 129 | 130 | rep := identitiesAnswerAgentMsg{ 131 | NumKeys: uint32(len(keys)), 132 | } 133 | for _, k := range keys { 134 | rep.Keys = append(rep.Keys, marshalKey(k)...) 135 | } 136 | return rep, nil 137 | case agentAddIdentity: 138 | return nil, s.insertIdentity(data) 139 | } 140 | 141 | return nil, fmt.Errorf("unknown opcode %d", data[0]) 142 | } 143 | 144 | func (s *server) insertIdentity(req []byte) error { 145 | var record struct { 146 | Type string `sshtype:"17"` 147 | Rest []byte `ssh:"rest"` 148 | } 149 | if err := ssh.Unmarshal(req, &record); err != nil { 150 | return err 151 | } 152 | 153 | switch record.Type { 154 | case ssh.KeyAlgoRSA: 155 | var k rsaKeyMsg 156 | if err := ssh.Unmarshal(req, &k); err != nil { 157 | return err 158 | } 159 | 160 | priv := rsa.PrivateKey{ 161 | PublicKey: rsa.PublicKey{ 162 | E: int(k.E.Int64()), 163 | N: k.N, 164 | }, 165 | D: k.D, 166 | Primes: []*big.Int{k.P, k.Q}, 167 | } 168 | priv.Precompute() 169 | 170 | return s.agent.Add(&priv, nil, k.Comments) 171 | } 172 | return fmt.Errorf("not implemented: %s", record.Type) 173 | } 174 | 175 | // ServeAgent serves the agent protocol on the given connection. It 176 | // returns when an I/O error occurs. 177 | func ServeAgent(agent Agent, c io.ReadWriter) error { 178 | s := &server{agent} 179 | 180 | var length [4]byte 181 | for { 182 | if _, err := io.ReadFull(c, length[:]); err != nil { 183 | return err 184 | } 185 | l := binary.BigEndian.Uint32(length[:]) 186 | if l > maxAgentResponseBytes { 187 | // We also cap requests. 188 | return fmt.Errorf("agent: request too large: %d", l) 189 | } 190 | 191 | req := make([]byte, l) 192 | if _, err := io.ReadFull(c, req); err != nil { 193 | return err 194 | } 195 | 196 | repData := s.processRequestBytes(req) 197 | if len(repData) > maxAgentResponseBytes { 198 | return fmt.Errorf("agent: reply too large: %d bytes", len(repData)) 199 | } 200 | 201 | binary.BigEndian.PutUint32(length[:], uint32(len(repData))) 202 | if _, err := c.Write(length[:]); err != nil { 203 | return err 204 | } 205 | if _, err := c.Write(repData); err != nil { 206 | return err 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/server_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package agent 6 | 7 | import ( 8 | "testing" 9 | 10 | "golang.org/x/crypto/ssh" 11 | ) 12 | 13 | func TestServer(t *testing.T) { 14 | c1, c2, err := netPipe() 15 | if err != nil { 16 | t.Fatalf("netPipe: %v", err) 17 | } 18 | defer c1.Close() 19 | defer c2.Close() 20 | client := NewClient(c1) 21 | 22 | go ServeAgent(NewKeyring(), c2) 23 | 24 | testAgentInterface(t, client, testPrivateKeys["rsa"], nil) 25 | } 26 | 27 | func TestLockServer(t *testing.T) { 28 | testLockAgent(NewKeyring(), t) 29 | } 30 | 31 | func TestSetupForwardAgent(t *testing.T) { 32 | a, b, err := netPipe() 33 | if err != nil { 34 | t.Fatalf("netPipe: %v", err) 35 | } 36 | 37 | defer a.Close() 38 | defer b.Close() 39 | 40 | _, socket, cleanup := startAgent(t) 41 | defer cleanup() 42 | 43 | serverConf := ssh.ServerConfig{ 44 | NoClientAuth: true, 45 | } 46 | serverConf.AddHostKey(testSigners["rsa"]) 47 | incoming := make(chan *ssh.ServerConn, 1) 48 | go func() { 49 | conn, _, _, err := ssh.NewServerConn(a, &serverConf) 50 | if err != nil { 51 | t.Fatalf("Server: %v", err) 52 | } 53 | incoming <- conn 54 | }() 55 | 56 | conf := ssh.ClientConfig{} 57 | conn, chans, reqs, err := ssh.NewClientConn(b, "", &conf) 58 | if err != nil { 59 | t.Fatalf("NewClientConn: %v", err) 60 | } 61 | client := ssh.NewClient(conn, chans, reqs) 62 | 63 | if err := ForwardToRemote(client, socket); err != nil { 64 | t.Fatalf("SetupForwardAgent: %v", err) 65 | } 66 | 67 | server := <-incoming 68 | ch, reqs, err := server.OpenChannel(channelType, nil) 69 | if err != nil { 70 | t.Fatalf("OpenChannel(%q): %v", channelType, err) 71 | } 72 | go ssh.DiscardRequests(reqs) 73 | 74 | agentClient := NewClient(ch) 75 | testAgentInterface(t, agentClient, testPrivateKeys["rsa"], nil) 76 | conn.Close() 77 | } 78 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/testdata_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places: 6 | // ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three 7 | // instances. 8 | 9 | package agent 10 | 11 | import ( 12 | "crypto/rand" 13 | "fmt" 14 | 15 | "golang.org/x/crypto/ssh" 16 | "golang.org/x/crypto/ssh/testdata" 17 | ) 18 | 19 | var ( 20 | testPrivateKeys map[string]interface{} 21 | testSigners map[string]ssh.Signer 22 | testPublicKeys map[string]ssh.PublicKey 23 | ) 24 | 25 | func init() { 26 | var err error 27 | 28 | n := len(testdata.PEMBytes) 29 | testPrivateKeys = make(map[string]interface{}, n) 30 | testSigners = make(map[string]ssh.Signer, n) 31 | testPublicKeys = make(map[string]ssh.PublicKey, n) 32 | for t, k := range testdata.PEMBytes { 33 | testPrivateKeys[t], err = ssh.ParseRawPrivateKey(k) 34 | if err != nil { 35 | panic(fmt.Sprintf("Unable to parse test key %s: %v", t, err)) 36 | } 37 | testSigners[t], err = ssh.NewSignerFromKey(testPrivateKeys[t]) 38 | if err != nil { 39 | panic(fmt.Sprintf("Unable to create signer for test key %s: %v", t, err)) 40 | } 41 | testPublicKeys[t] = testSigners[t].PublicKey() 42 | } 43 | 44 | // Create a cert and sign it for use in tests. 45 | testCert := &ssh.Certificate{ 46 | Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil 47 | ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage 48 | ValidAfter: 0, // unix epoch 49 | ValidBefore: ssh.CertTimeInfinity, // The end of currently representable time. 50 | Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil 51 | Key: testPublicKeys["ecdsa"], 52 | SignatureKey: testPublicKeys["rsa"], 53 | Permissions: ssh.Permissions{ 54 | CriticalOptions: map[string]string{}, 55 | Extensions: map[string]string{}, 56 | }, 57 | } 58 | testCert.SignCert(rand.Reader, testSigners["rsa"]) 59 | testPrivateKeys["cert"] = testPrivateKeys["ecdsa"] 60 | testSigners["cert"], err = ssh.NewCertSigner(testCert, testSigners["ecdsa"]) 61 | if err != nil { 62 | panic(fmt.Sprintf("Unable to create certificate signer: %v", err)) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/benchmark_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "errors" 9 | "io" 10 | "net" 11 | "testing" 12 | ) 13 | 14 | type server struct { 15 | *ServerConn 16 | chans <-chan NewChannel 17 | } 18 | 19 | func newServer(c net.Conn, conf *ServerConfig) (*server, error) { 20 | sconn, chans, reqs, err := NewServerConn(c, conf) 21 | if err != nil { 22 | return nil, err 23 | } 24 | go DiscardRequests(reqs) 25 | return &server{sconn, chans}, nil 26 | } 27 | 28 | func (s *server) Accept() (NewChannel, error) { 29 | n, ok := <-s.chans 30 | if !ok { 31 | return nil, io.EOF 32 | } 33 | return n, nil 34 | } 35 | 36 | func sshPipe() (Conn, *server, error) { 37 | c1, c2, err := netPipe() 38 | if err != nil { 39 | return nil, nil, err 40 | } 41 | 42 | clientConf := ClientConfig{ 43 | User: "user", 44 | } 45 | serverConf := ServerConfig{ 46 | NoClientAuth: true, 47 | } 48 | serverConf.AddHostKey(testSigners["ecdsa"]) 49 | done := make(chan *server, 1) 50 | go func() { 51 | server, err := newServer(c2, &serverConf) 52 | if err != nil { 53 | done <- nil 54 | } 55 | done <- server 56 | }() 57 | 58 | client, _, reqs, err := NewClientConn(c1, "", &clientConf) 59 | if err != nil { 60 | return nil, nil, err 61 | } 62 | 63 | server := <-done 64 | if server == nil { 65 | return nil, nil, errors.New("server handshake failed.") 66 | } 67 | go DiscardRequests(reqs) 68 | 69 | return client, server, nil 70 | } 71 | 72 | func BenchmarkEndToEnd(b *testing.B) { 73 | b.StopTimer() 74 | 75 | client, server, err := sshPipe() 76 | if err != nil { 77 | b.Fatalf("sshPipe: %v", err) 78 | } 79 | 80 | defer client.Close() 81 | defer server.Close() 82 | 83 | size := (1 << 20) 84 | input := make([]byte, size) 85 | output := make([]byte, size) 86 | b.SetBytes(int64(size)) 87 | done := make(chan int, 1) 88 | 89 | go func() { 90 | newCh, err := server.Accept() 91 | if err != nil { 92 | b.Fatalf("Client: %v", err) 93 | } 94 | ch, incoming, err := newCh.Accept() 95 | go DiscardRequests(incoming) 96 | for i := 0; i < b.N; i++ { 97 | if _, err := io.ReadFull(ch, output); err != nil { 98 | b.Fatalf("ReadFull: %v", err) 99 | } 100 | } 101 | ch.Close() 102 | done <- 1 103 | }() 104 | 105 | ch, in, err := client.OpenChannel("speed", nil) 106 | if err != nil { 107 | b.Fatalf("OpenChannel: %v", err) 108 | } 109 | go DiscardRequests(in) 110 | 111 | b.ResetTimer() 112 | b.StartTimer() 113 | for i := 0; i < b.N; i++ { 114 | if _, err := ch.Write(input); err != nil { 115 | b.Fatalf("WriteFull: %v", err) 116 | } 117 | } 118 | ch.Close() 119 | b.StopTimer() 120 | 121 | <-done 122 | } 123 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/buffer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "io" 9 | "sync" 10 | ) 11 | 12 | // buffer provides a linked list buffer for data exchange 13 | // between producer and consumer. Theoretically the buffer is 14 | // of unlimited capacity as it does no allocation of its own. 15 | type buffer struct { 16 | // protects concurrent access to head, tail and closed 17 | *sync.Cond 18 | 19 | head *element // the buffer that will be read first 20 | tail *element // the buffer that will be read last 21 | 22 | closed bool 23 | } 24 | 25 | // An element represents a single link in a linked list. 26 | type element struct { 27 | buf []byte 28 | next *element 29 | } 30 | 31 | // newBuffer returns an empty buffer that is not closed. 32 | func newBuffer() *buffer { 33 | e := new(element) 34 | b := &buffer{ 35 | Cond: newCond(), 36 | head: e, 37 | tail: e, 38 | } 39 | return b 40 | } 41 | 42 | // write makes buf available for Read to receive. 43 | // buf must not be modified after the call to write. 44 | func (b *buffer) write(buf []byte) { 45 | b.Cond.L.Lock() 46 | e := &element{buf: buf} 47 | b.tail.next = e 48 | b.tail = e 49 | b.Cond.Signal() 50 | b.Cond.L.Unlock() 51 | } 52 | 53 | // eof closes the buffer. Reads from the buffer once all 54 | // the data has been consumed will receive os.EOF. 55 | func (b *buffer) eof() error { 56 | b.Cond.L.Lock() 57 | b.closed = true 58 | b.Cond.Signal() 59 | b.Cond.L.Unlock() 60 | return nil 61 | } 62 | 63 | // Read reads data from the internal buffer in buf. Reads will block 64 | // if no data is available, or until the buffer is closed. 65 | func (b *buffer) Read(buf []byte) (n int, err error) { 66 | b.Cond.L.Lock() 67 | defer b.Cond.L.Unlock() 68 | 69 | for len(buf) > 0 { 70 | // if there is data in b.head, copy it 71 | if len(b.head.buf) > 0 { 72 | r := copy(buf, b.head.buf) 73 | buf, b.head.buf = buf[r:], b.head.buf[r:] 74 | n += r 75 | continue 76 | } 77 | // if there is a next buffer, make it the head 78 | if len(b.head.buf) == 0 && b.head != b.tail { 79 | b.head = b.head.next 80 | continue 81 | } 82 | 83 | // if at least one byte has been copied, return 84 | if n > 0 { 85 | break 86 | } 87 | 88 | // if nothing was read, and there is nothing outstanding 89 | // check to see if the buffer is closed. 90 | if b.closed { 91 | err = io.EOF 92 | break 93 | } 94 | // out of buffers, wait for producer 95 | b.Cond.Wait() 96 | } 97 | return 98 | } 99 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/buffer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "io" 9 | "testing" 10 | ) 11 | 12 | var alphabet = []byte("abcdefghijklmnopqrstuvwxyz") 13 | 14 | func TestBufferReadwrite(t *testing.T) { 15 | b := newBuffer() 16 | b.write(alphabet[:10]) 17 | r, _ := b.Read(make([]byte, 10)) 18 | if r != 10 { 19 | t.Fatalf("Expected written == read == 10, written: 10, read %d", r) 20 | } 21 | 22 | b = newBuffer() 23 | b.write(alphabet[:5]) 24 | r, _ = b.Read(make([]byte, 10)) 25 | if r != 5 { 26 | t.Fatalf("Expected written == read == 5, written: 5, read %d", r) 27 | } 28 | 29 | b = newBuffer() 30 | b.write(alphabet[:10]) 31 | r, _ = b.Read(make([]byte, 5)) 32 | if r != 5 { 33 | t.Fatalf("Expected written == 10, read == 5, written: 10, read %d", r) 34 | } 35 | 36 | b = newBuffer() 37 | b.write(alphabet[:5]) 38 | b.write(alphabet[5:15]) 39 | r, _ = b.Read(make([]byte, 10)) 40 | r2, _ := b.Read(make([]byte, 10)) 41 | if r != 10 || r2 != 5 || 15 != r+r2 { 42 | t.Fatal("Expected written == read == 15") 43 | } 44 | } 45 | 46 | func TestBufferClose(t *testing.T) { 47 | b := newBuffer() 48 | b.write(alphabet[:10]) 49 | b.eof() 50 | _, err := b.Read(make([]byte, 5)) 51 | if err != nil { 52 | t.Fatal("expected read of 5 to not return EOF") 53 | } 54 | b = newBuffer() 55 | b.write(alphabet[:10]) 56 | b.eof() 57 | r, err := b.Read(make([]byte, 5)) 58 | r2, err2 := b.Read(make([]byte, 10)) 59 | if r != 5 || r2 != 5 || err != nil || err2 != nil { 60 | t.Fatal("expected reads of 5 and 5") 61 | } 62 | 63 | b = newBuffer() 64 | b.write(alphabet[:10]) 65 | b.eof() 66 | r, err = b.Read(make([]byte, 5)) 67 | r2, err2 = b.Read(make([]byte, 10)) 68 | r3, err3 := b.Read(make([]byte, 10)) 69 | if r != 5 || r2 != 5 || r3 != 0 || err != nil || err2 != nil || err3 != io.EOF { 70 | t.Fatal("expected reads of 5 and 5 and 0, with EOF") 71 | } 72 | 73 | b = newBuffer() 74 | b.write(make([]byte, 5)) 75 | b.write(make([]byte, 10)) 76 | b.eof() 77 | r, err = b.Read(make([]byte, 9)) 78 | r2, err2 = b.Read(make([]byte, 3)) 79 | r3, err3 = b.Read(make([]byte, 3)) 80 | r4, err4 := b.Read(make([]byte, 10)) 81 | if err != nil || err2 != nil || err3 != nil || err4 != io.EOF { 82 | t.Fatalf("Expected EOF on forth read only, err=%v, err2=%v, err3=%v, err4=%v", err, err2, err3, err4) 83 | } 84 | if r != 9 || r2 != 3 || r3 != 3 || r4 != 0 { 85 | t.Fatal("Expected written == read == 15", r, r2, r3, r4) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/certs_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "bytes" 9 | "crypto/rand" 10 | "testing" 11 | "time" 12 | ) 13 | 14 | // Cert generated by ssh-keygen 6.0p1 Debian-4. 15 | // % ssh-keygen -s ca-key -I test user-key 16 | var exampleSSHCert = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgb1srW/W3ZDjYAO45xLYAwzHBDLsJ4Ux6ICFIkTjb1LEAAAADAQABAAAAYQCkoR51poH0wE8w72cqSB8Sszx+vAhzcMdCO0wqHTj7UNENHWEXGrU0E0UQekD7U+yhkhtoyjbPOVIP7hNa6aRk/ezdh/iUnCIt4Jt1v3Z1h1P+hA4QuYFMHNB+rmjPwAcAAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAHcAAAAHc3NoLXJzYQAAAAMBAAEAAABhANFS2kaktpSGc+CcmEKPyw9mJC4nZKxHKTgLVZeaGbFZOvJTNzBspQHdy7Q1uKSfktxpgjZnksiu/tFF9ngyY2KFoc+U88ya95IZUycBGCUbBQ8+bhDtw/icdDGQD5WnUwAAAG8AAAAHc3NoLXJzYQAAAGC8Y9Z2LQKhIhxf52773XaWrXdxP0t3GBVo4A10vUWiYoAGepr6rQIoGGXFxT4B9Gp+nEBJjOwKDXPrAevow0T9ca8gZN+0ykbhSrXLE5Ao48rqr3zP4O1/9P7e6gp0gw8=` 17 | 18 | func TestParseCert(t *testing.T) { 19 | authKeyBytes := []byte(exampleSSHCert) 20 | 21 | key, _, _, rest, err := ParseAuthorizedKey(authKeyBytes) 22 | if err != nil { 23 | t.Fatalf("ParseAuthorizedKey: %v", err) 24 | } 25 | if len(rest) > 0 { 26 | t.Errorf("rest: got %q, want empty", rest) 27 | } 28 | 29 | if _, ok := key.(*Certificate); !ok { 30 | t.Fatalf("got %#v, want *Certificate", key) 31 | } 32 | 33 | marshaled := MarshalAuthorizedKey(key) 34 | // Before comparison, remove the trailing newline that 35 | // MarshalAuthorizedKey adds. 36 | marshaled = marshaled[:len(marshaled)-1] 37 | if !bytes.Equal(authKeyBytes, marshaled) { 38 | t.Errorf("marshaled certificate does not match original: got %q, want %q", marshaled, authKeyBytes) 39 | } 40 | } 41 | 42 | func TestValidateCert(t *testing.T) { 43 | key, _, _, _, err := ParseAuthorizedKey([]byte(exampleSSHCert)) 44 | if err != nil { 45 | t.Fatalf("ParseAuthorizedKey: %v", err) 46 | } 47 | validCert, ok := key.(*Certificate) 48 | if !ok { 49 | t.Fatalf("got %v (%T), want *Certificate", key, key) 50 | } 51 | checker := CertChecker{} 52 | checker.IsAuthority = func(k PublicKey) bool { 53 | return bytes.Equal(k.Marshal(), validCert.SignatureKey.Marshal()) 54 | } 55 | 56 | if err := checker.CheckCert("user", validCert); err != nil { 57 | t.Errorf("Unable to validate certificate: %v", err) 58 | } 59 | invalidCert := &Certificate{ 60 | Key: testPublicKeys["rsa"], 61 | SignatureKey: testPublicKeys["ecdsa"], 62 | ValidBefore: CertTimeInfinity, 63 | Signature: &Signature{}, 64 | } 65 | if err := checker.CheckCert("user", invalidCert); err == nil { 66 | t.Error("Invalid cert signature passed validation") 67 | } 68 | } 69 | 70 | func TestValidateCertTime(t *testing.T) { 71 | cert := Certificate{ 72 | ValidPrincipals: []string{"user"}, 73 | Key: testPublicKeys["rsa"], 74 | ValidAfter: 50, 75 | ValidBefore: 100, 76 | } 77 | 78 | cert.SignCert(rand.Reader, testSigners["ecdsa"]) 79 | 80 | for ts, ok := range map[int64]bool{ 81 | 25: false, 82 | 50: true, 83 | 99: true, 84 | 100: false, 85 | 125: false, 86 | } { 87 | checker := CertChecker{ 88 | Clock: func() time.Time { return time.Unix(ts, 0) }, 89 | } 90 | checker.IsAuthority = func(k PublicKey) bool { 91 | return bytes.Equal(k.Marshal(), 92 | testPublicKeys["ecdsa"].Marshal()) 93 | } 94 | 95 | if v := checker.CheckCert("user", &cert); (v == nil) != ok { 96 | t.Errorf("Authenticate(%d): %v", ts, v) 97 | } 98 | } 99 | } 100 | 101 | // TODO(hanwen): tests for 102 | // 103 | // host keys: 104 | // * fallbacks 105 | 106 | func TestHostKeyCert(t *testing.T) { 107 | cert := &Certificate{ 108 | ValidPrincipals: []string{"hostname", "hostname.domain"}, 109 | Key: testPublicKeys["rsa"], 110 | ValidBefore: CertTimeInfinity, 111 | CertType: HostCert, 112 | } 113 | cert.SignCert(rand.Reader, testSigners["ecdsa"]) 114 | 115 | checker := &CertChecker{ 116 | IsAuthority: func(p PublicKey) bool { 117 | return bytes.Equal(testPublicKeys["ecdsa"].Marshal(), p.Marshal()) 118 | }, 119 | } 120 | 121 | certSigner, err := NewCertSigner(cert, testSigners["rsa"]) 122 | if err != nil { 123 | t.Errorf("NewCertSigner: %v", err) 124 | } 125 | 126 | for _, name := range []string{"hostname", "otherhost"} { 127 | c1, c2, err := netPipe() 128 | if err != nil { 129 | t.Fatalf("netPipe: %v", err) 130 | } 131 | defer c1.Close() 132 | defer c2.Close() 133 | 134 | go func() { 135 | conf := ServerConfig{ 136 | NoClientAuth: true, 137 | } 138 | conf.AddHostKey(certSigner) 139 | _, _, _, err := NewServerConn(c1, &conf) 140 | if err != nil { 141 | t.Fatalf("NewServerConn: %v", err) 142 | } 143 | }() 144 | 145 | config := &ClientConfig{ 146 | User: "user", 147 | HostKeyCallback: checker.CheckHostKey, 148 | } 149 | _, _, _, err = NewClientConn(c2, name, config) 150 | 151 | succeed := name == "hostname" 152 | if (err == nil) != succeed { 153 | t.Fatalf("NewClientConn(%q): %v", name, err) 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "bytes" 9 | "crypto" 10 | "crypto/rand" 11 | "testing" 12 | ) 13 | 14 | func TestDefaultCiphersExist(t *testing.T) { 15 | for _, cipherAlgo := range supportedCiphers { 16 | if _, ok := cipherModes[cipherAlgo]; !ok { 17 | t.Errorf("default cipher %q is unknown", cipherAlgo) 18 | } 19 | } 20 | } 21 | 22 | func TestPacketCiphers(t *testing.T) { 23 | for cipher := range cipherModes { 24 | kr := &kexResult{Hash: crypto.SHA1} 25 | algs := directionAlgorithms{ 26 | Cipher: cipher, 27 | MAC: "hmac-sha1", 28 | Compression: "none", 29 | } 30 | client, err := newPacketCipher(clientKeys, algs, kr) 31 | if err != nil { 32 | t.Errorf("newPacketCipher(client, %q): %v", cipher, err) 33 | continue 34 | } 35 | server, err := newPacketCipher(clientKeys, algs, kr) 36 | if err != nil { 37 | t.Errorf("newPacketCipher(client, %q): %v", cipher, err) 38 | continue 39 | } 40 | 41 | want := "bla bla" 42 | input := []byte(want) 43 | buf := &bytes.Buffer{} 44 | if err := client.writePacket(0, buf, rand.Reader, input); err != nil { 45 | t.Errorf("writePacket(%q): %v", cipher, err) 46 | continue 47 | } 48 | 49 | packet, err := server.readPacket(0, buf) 50 | if err != nil { 51 | t.Errorf("readPacket(%q): %v", cipher, err) 52 | continue 53 | } 54 | 55 | if string(packet) != want { 56 | t.Errorf("roundtrip(%q): got %q, want %q", cipher, packet, want) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "net" 11 | "sync" 12 | ) 13 | 14 | // Client implements a traditional SSH client that supports shells, 15 | // subprocesses, port forwarding and tunneled dialing. 16 | type Client struct { 17 | Conn 18 | 19 | forwards forwardList // forwarded tcpip connections from the remote side 20 | mu sync.Mutex 21 | channelHandlers map[string]chan NewChannel 22 | } 23 | 24 | // HandleChannelOpen returns a channel on which NewChannel requests 25 | // for the given type are sent. If the type already is being handled, 26 | // nil is returned. The channel is closed when the connection is closed. 27 | func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { 28 | c.mu.Lock() 29 | defer c.mu.Unlock() 30 | if c.channelHandlers == nil { 31 | // The SSH channel has been closed. 32 | c := make(chan NewChannel) 33 | close(c) 34 | return c 35 | } 36 | 37 | ch := c.channelHandlers[channelType] 38 | if ch != nil { 39 | return nil 40 | } 41 | 42 | ch = make(chan NewChannel, 16) 43 | c.channelHandlers[channelType] = ch 44 | return ch 45 | } 46 | 47 | // NewClient creates a Client on top of the given connection. 48 | func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { 49 | conn := &Client{ 50 | Conn: c, 51 | channelHandlers: make(map[string]chan NewChannel, 1), 52 | } 53 | 54 | go conn.handleGlobalRequests(reqs) 55 | go conn.handleChannelOpens(chans) 56 | go func() { 57 | conn.Wait() 58 | conn.forwards.closeAll() 59 | }() 60 | go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip")) 61 | return conn 62 | } 63 | 64 | // NewClientConn establishes an authenticated SSH connection using c 65 | // as the underlying transport. The Request and NewChannel channels 66 | // must be serviced or the connection will hang. 67 | func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) { 68 | fullConf := *config 69 | fullConf.SetDefaults() 70 | conn := &connection{ 71 | sshConn: sshConn{conn: c}, 72 | } 73 | 74 | if err := conn.clientHandshake(addr, &fullConf); err != nil { 75 | c.Close() 76 | return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) 77 | } 78 | conn.mux = newMux(conn.transport) 79 | return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil 80 | } 81 | 82 | // clientHandshake performs the client side key exchange. See RFC 4253 Section 83 | // 7. 84 | func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { 85 | if config.ClientVersion != "" { 86 | c.clientVersion = []byte(config.ClientVersion) 87 | } else { 88 | c.clientVersion = []byte(packageVersion) 89 | } 90 | var err error 91 | c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion) 92 | if err != nil { 93 | return err 94 | } 95 | 96 | c.transport = newClientTransport( 97 | newTransport(c.sshConn.conn, config.Rand, true /* is client */), 98 | c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) 99 | if err := c.transport.requestKeyChange(); err != nil { 100 | return err 101 | } 102 | 103 | if packet, err := c.transport.readPacket(); err != nil { 104 | return err 105 | } else if packet[0] != msgNewKeys { 106 | return unexpectedMessageError(msgNewKeys, packet[0]) 107 | } 108 | 109 | // We just did the key change, so the session ID is established. 110 | c.sessionID = c.transport.getSessionID() 111 | 112 | return c.clientAuthenticate(config) 113 | } 114 | 115 | // verifyHostKeySignature verifies the host key obtained in the key 116 | // exchange. 117 | func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error { 118 | sig, rest, ok := parseSignatureBody(result.Signature) 119 | if len(rest) > 0 || !ok { 120 | return errors.New("ssh: signature parse error") 121 | } 122 | 123 | return hostKey.Verify(result.H, sig) 124 | } 125 | 126 | // NewSession opens a new Session for this client. (A session is a remote 127 | // execution of a program.) 128 | func (c *Client) NewSession() (*Session, error) { 129 | ch, in, err := c.OpenChannel("session", nil) 130 | if err != nil { 131 | return nil, err 132 | } 133 | return newSession(ch, in) 134 | } 135 | 136 | func (c *Client) handleGlobalRequests(incoming <-chan *Request) { 137 | for r := range incoming { 138 | // This handles keepalive messages and matches 139 | // the behaviour of OpenSSH. 140 | r.Reply(false, nil) 141 | } 142 | } 143 | 144 | // handleChannelOpens channel open messages from the remote side. 145 | func (c *Client) handleChannelOpens(in <-chan NewChannel) { 146 | for ch := range in { 147 | c.mu.Lock() 148 | handler := c.channelHandlers[ch.ChannelType()] 149 | c.mu.Unlock() 150 | 151 | if handler != nil { 152 | handler <- ch 153 | } else { 154 | ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType())) 155 | } 156 | } 157 | 158 | c.mu.Lock() 159 | for _, ch := range c.channelHandlers { 160 | close(ch) 161 | } 162 | c.channelHandlers = nil 163 | c.mu.Unlock() 164 | } 165 | 166 | // Dial starts a client connection to the given SSH server. It is a 167 | // convenience function that connects to the given network address, 168 | // initiates the SSH handshake, and then sets up a Client. For access 169 | // to incoming channels and requests, use net.Dial with NewClientConn 170 | // instead. 171 | func Dial(network, addr string, config *ClientConfig) (*Client, error) { 172 | conn, err := net.Dial(network, addr) 173 | if err != nil { 174 | return nil, err 175 | } 176 | c, chans, reqs, err := NewClientConn(conn, addr, config) 177 | if err != nil { 178 | return nil, err 179 | } 180 | return NewClient(c, chans, reqs), nil 181 | } 182 | 183 | // A ClientConfig structure is used to configure a Client. It must not be 184 | // modified after having been passed to an SSH function. 185 | type ClientConfig struct { 186 | // Config contains configuration that is shared between clients and 187 | // servers. 188 | Config 189 | 190 | // User contains the username to authenticate as. 191 | User string 192 | 193 | // Auth contains possible authentication methods to use with the 194 | // server. Only the first instance of a particular RFC 4252 method will 195 | // be used during authentication. 196 | Auth []AuthMethod 197 | 198 | // HostKeyCallback, if not nil, is called during the cryptographic 199 | // handshake to validate the server's host key. A nil HostKeyCallback 200 | // implies that all host keys are accepted. 201 | HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error 202 | 203 | // ClientVersion contains the version identification string that will 204 | // be used for the connection. If empty, a reasonable default is used. 205 | ClientVersion string 206 | } 207 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "net" 9 | "testing" 10 | ) 11 | 12 | func testClientVersion(t *testing.T, config *ClientConfig, expected string) { 13 | clientConn, serverConn := net.Pipe() 14 | defer clientConn.Close() 15 | receivedVersion := make(chan string, 1) 16 | go func() { 17 | version, err := readVersion(serverConn) 18 | if err != nil { 19 | receivedVersion <- "" 20 | } else { 21 | receivedVersion <- string(version) 22 | } 23 | serverConn.Close() 24 | }() 25 | NewClientConn(clientConn, "", config) 26 | actual := <-receivedVersion 27 | if actual != expected { 28 | t.Fatalf("got %s; want %s", actual, expected) 29 | } 30 | } 31 | 32 | func TestCustomClientVersion(t *testing.T) { 33 | version := "Test-Client-Version-0.0" 34 | testClientVersion(t, &ClientConfig{ClientVersion: version}, version) 35 | } 36 | 37 | func TestDefaultClientVersion(t *testing.T) { 38 | testClientVersion(t, &ClientConfig{}, packageVersion) 39 | } 40 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/connection.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "fmt" 9 | "net" 10 | ) 11 | 12 | // OpenChannelError is returned if the other side rejects an 13 | // OpenChannel request. 14 | type OpenChannelError struct { 15 | Reason RejectionReason 16 | Message string 17 | } 18 | 19 | func (e *OpenChannelError) Error() string { 20 | return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) 21 | } 22 | 23 | // ConnMetadata holds metadata for the connection. 24 | type ConnMetadata interface { 25 | // User returns the user ID for this connection. 26 | // It is empty if no authentication is used. 27 | User() string 28 | 29 | // SessionID returns the sesson hash, also denoted by H. 30 | SessionID() []byte 31 | 32 | // ClientVersion returns the client's version string as hashed 33 | // into the session ID. 34 | ClientVersion() []byte 35 | 36 | // ServerVersion returns the client's version string as hashed 37 | // into the session ID. 38 | ServerVersion() []byte 39 | 40 | // RemoteAddr returns the remote address for this connection. 41 | RemoteAddr() net.Addr 42 | 43 | // LocalAddr returns the local address for this connection. 44 | LocalAddr() net.Addr 45 | } 46 | 47 | // Conn represents an SSH connection for both server and client roles. 48 | // Conn is the basis for implementing an application layer, such 49 | // as ClientConn, which implements the traditional shell access for 50 | // clients. 51 | type Conn interface { 52 | ConnMetadata 53 | 54 | // SendRequest sends a global request, and returns the 55 | // reply. If wantReply is true, it returns the response status 56 | // and payload. See also RFC4254, section 4. 57 | SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) 58 | 59 | // OpenChannel tries to open an channel. If the request is 60 | // rejected, it returns *OpenChannelError. On success it returns 61 | // the SSH Channel and a Go channel for incoming, out-of-band 62 | // requests. The Go channel must be serviced, or the 63 | // connection will hang. 64 | OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) 65 | 66 | // Close closes the underlying network connection 67 | Close() error 68 | 69 | // Wait blocks until the connection has shut down, and returns the 70 | // error causing the shutdown. 71 | Wait() error 72 | 73 | // TODO(hanwen): consider exposing: 74 | // RequestKeyChange 75 | // Disconnect 76 | } 77 | 78 | // DiscardRequests consumes and rejects all requests from the 79 | // passed-in channel. 80 | func DiscardRequests(in <-chan *Request) { 81 | for req := range in { 82 | if req.WantReply { 83 | req.Reply(false, nil) 84 | } 85 | } 86 | } 87 | 88 | // A connection represents an incoming connection. 89 | type connection struct { 90 | transport *handshakeTransport 91 | sshConn 92 | 93 | // The connection protocol. 94 | *mux 95 | } 96 | 97 | func (c *connection) Close() error { 98 | return c.sshConn.conn.Close() 99 | } 100 | 101 | // sshconn provides net.Conn metadata, but disallows direct reads and 102 | // writes. 103 | type sshConn struct { 104 | conn net.Conn 105 | 106 | user string 107 | sessionID []byte 108 | clientVersion []byte 109 | serverVersion []byte 110 | } 111 | 112 | func dup(src []byte) []byte { 113 | dst := make([]byte, len(src)) 114 | copy(dst, src) 115 | return dst 116 | } 117 | 118 | func (c *sshConn) User() string { 119 | return c.user 120 | } 121 | 122 | func (c *sshConn) RemoteAddr() net.Addr { 123 | return c.conn.RemoteAddr() 124 | } 125 | 126 | func (c *sshConn) Close() error { 127 | return c.conn.Close() 128 | } 129 | 130 | func (c *sshConn) LocalAddr() net.Addr { 131 | return c.conn.LocalAddr() 132 | } 133 | 134 | func (c *sshConn) SessionID() []byte { 135 | return dup(c.sessionID) 136 | } 137 | 138 | func (c *sshConn) ClientVersion() []byte { 139 | return dup(c.clientVersion) 140 | } 141 | 142 | func (c *sshConn) ServerVersion() []byte { 143 | return dup(c.serverVersion) 144 | } 145 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package ssh implements an SSH client and server. 7 | 8 | SSH is a transport security protocol, an authentication protocol and a 9 | family of application protocols. The most typical application level 10 | protocol is a remote shell and this is specifically implemented. However, 11 | the multiplexed nature of SSH is exposed to users that wish to support 12 | others. 13 | 14 | References: 15 | [PROTOCOL.certkeys]: http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys 16 | [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 17 | */ 18 | package ssh // import "golang.org/x/crypto/ssh" 19 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh_test 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "io/ioutil" 11 | "log" 12 | "net" 13 | "net/http" 14 | 15 | "golang.org/x/crypto/ssh" 16 | "golang.org/x/crypto/ssh/terminal" 17 | ) 18 | 19 | func ExampleNewServerConn() { 20 | // An SSH server is represented by a ServerConfig, which holds 21 | // certificate details and handles authentication of ServerConns. 22 | config := &ssh.ServerConfig{ 23 | PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { 24 | // Should use constant-time compare (or better, salt+hash) in 25 | // a production setting. 26 | if c.User() == "testuser" && string(pass) == "tiger" { 27 | return nil, nil 28 | } 29 | return nil, fmt.Errorf("password rejected for %q", c.User()) 30 | }, 31 | } 32 | 33 | privateBytes, err := ioutil.ReadFile("id_rsa") 34 | if err != nil { 35 | panic("Failed to load private key") 36 | } 37 | 38 | private, err := ssh.ParsePrivateKey(privateBytes) 39 | if err != nil { 40 | panic("Failed to parse private key") 41 | } 42 | 43 | config.AddHostKey(private) 44 | 45 | // Once a ServerConfig has been configured, connections can be 46 | // accepted. 47 | listener, err := net.Listen("tcp", "0.0.0.0:2022") 48 | if err != nil { 49 | panic("failed to listen for connection") 50 | } 51 | nConn, err := listener.Accept() 52 | if err != nil { 53 | panic("failed to accept incoming connection") 54 | } 55 | 56 | // Before use, a handshake must be performed on the incoming 57 | // net.Conn. 58 | _, chans, reqs, err := ssh.NewServerConn(nConn, config) 59 | if err != nil { 60 | panic("failed to handshake") 61 | } 62 | // The incoming Request channel must be serviced. 63 | go ssh.DiscardRequests(reqs) 64 | 65 | // Service the incoming Channel channel. 66 | for newChannel := range chans { 67 | // Channels have a type, depending on the application level 68 | // protocol intended. In the case of a shell, the type is 69 | // "session" and ServerShell may be used to present a simple 70 | // terminal interface. 71 | if newChannel.ChannelType() != "session" { 72 | newChannel.Reject(ssh.UnknownChannelType, "unknown channel type") 73 | continue 74 | } 75 | channel, requests, err := newChannel.Accept() 76 | if err != nil { 77 | panic("could not accept channel.") 78 | } 79 | 80 | // Sessions have out-of-band requests such as "shell", 81 | // "pty-req" and "env". Here we handle only the 82 | // "shell" request. 83 | go func(in <-chan *ssh.Request) { 84 | for req := range in { 85 | ok := false 86 | switch req.Type { 87 | case "shell": 88 | ok = true 89 | if len(req.Payload) > 0 { 90 | // We don't accept any 91 | // commands, only the 92 | // default shell. 93 | ok = false 94 | } 95 | } 96 | req.Reply(ok, nil) 97 | } 98 | }(requests) 99 | 100 | term := terminal.NewTerminal(channel, "> ") 101 | 102 | go func() { 103 | defer channel.Close() 104 | for { 105 | line, err := term.ReadLine() 106 | if err != nil { 107 | break 108 | } 109 | fmt.Println(line) 110 | } 111 | }() 112 | } 113 | } 114 | 115 | func ExampleDial() { 116 | // An SSH client is represented with a ClientConn. Currently only 117 | // the "password" authentication method is supported. 118 | // 119 | // To authenticate with the remote server you must pass at least one 120 | // implementation of AuthMethod via the Auth field in ClientConfig. 121 | config := &ssh.ClientConfig{ 122 | User: "username", 123 | Auth: []ssh.AuthMethod{ 124 | ssh.Password("yourpassword"), 125 | }, 126 | } 127 | client, err := ssh.Dial("tcp", "yourserver.com:22", config) 128 | if err != nil { 129 | panic("Failed to dial: " + err.Error()) 130 | } 131 | 132 | // Each ClientConn can support multiple interactive sessions, 133 | // represented by a Session. 134 | session, err := client.NewSession() 135 | if err != nil { 136 | panic("Failed to create session: " + err.Error()) 137 | } 138 | defer session.Close() 139 | 140 | // Once a Session is created, you can execute a single command on 141 | // the remote side using the Run method. 142 | var b bytes.Buffer 143 | session.Stdout = &b 144 | if err := session.Run("/usr/bin/whoami"); err != nil { 145 | panic("Failed to run: " + err.Error()) 146 | } 147 | fmt.Println(b.String()) 148 | } 149 | 150 | func ExampleClient_Listen() { 151 | config := &ssh.ClientConfig{ 152 | User: "username", 153 | Auth: []ssh.AuthMethod{ 154 | ssh.Password("password"), 155 | }, 156 | } 157 | // Dial your ssh server. 158 | conn, err := ssh.Dial("tcp", "localhost:22", config) 159 | if err != nil { 160 | log.Fatalf("unable to connect: %s", err) 161 | } 162 | defer conn.Close() 163 | 164 | // Request the remote side to open port 8080 on all interfaces. 165 | l, err := conn.Listen("tcp", "0.0.0.0:8080") 166 | if err != nil { 167 | log.Fatalf("unable to register tcp forward: %v", err) 168 | } 169 | defer l.Close() 170 | 171 | // Serve HTTP with your SSH server acting as a reverse proxy. 172 | http.Serve(l, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { 173 | fmt.Fprintf(resp, "Hello world!\n") 174 | })) 175 | } 176 | 177 | func ExampleSession_RequestPty() { 178 | // Create client config 179 | config := &ssh.ClientConfig{ 180 | User: "username", 181 | Auth: []ssh.AuthMethod{ 182 | ssh.Password("password"), 183 | }, 184 | } 185 | // Connect to ssh server 186 | conn, err := ssh.Dial("tcp", "localhost:22", config) 187 | if err != nil { 188 | log.Fatalf("unable to connect: %s", err) 189 | } 190 | defer conn.Close() 191 | // Create a session 192 | session, err := conn.NewSession() 193 | if err != nil { 194 | log.Fatalf("unable to create session: %s", err) 195 | } 196 | defer session.Close() 197 | // Set up terminal modes 198 | modes := ssh.TerminalModes{ 199 | ssh.ECHO: 0, // disable echoing 200 | ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud 201 | ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud 202 | } 203 | // Request pseudo terminal 204 | if err := session.RequestPty("xterm", 80, 40, modes); err != nil { 205 | log.Fatalf("request for pseudo terminal failed: %s", err) 206 | } 207 | // Start remote shell 208 | if err := session.Shell(); err != nil { 209 | log.Fatalf("failed to start shell: %s", err) 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/kex_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | // Key exchange tests. 8 | 9 | import ( 10 | "crypto/rand" 11 | "reflect" 12 | "testing" 13 | ) 14 | 15 | func TestKexes(t *testing.T) { 16 | type kexResultErr struct { 17 | result *kexResult 18 | err error 19 | } 20 | 21 | for name, kex := range kexAlgoMap { 22 | a, b := memPipe() 23 | 24 | s := make(chan kexResultErr, 1) 25 | c := make(chan kexResultErr, 1) 26 | var magics handshakeMagics 27 | go func() { 28 | r, e := kex.Client(a, rand.Reader, &magics) 29 | c <- kexResultErr{r, e} 30 | }() 31 | go func() { 32 | r, e := kex.Server(b, rand.Reader, &magics, testSigners["ecdsa"]) 33 | s <- kexResultErr{r, e} 34 | }() 35 | 36 | clientRes := <-c 37 | serverRes := <-s 38 | if clientRes.err != nil { 39 | t.Errorf("client: %v", clientRes.err) 40 | } 41 | if serverRes.err != nil { 42 | t.Errorf("server: %v", serverRes.err) 43 | } 44 | if !reflect.DeepEqual(clientRes.result, serverRes.result) { 45 | t.Errorf("kex %q: mismatch %#v, %#v", name, clientRes.result, serverRes.result) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/mac.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | // Message authentication support 8 | 9 | import ( 10 | "crypto/hmac" 11 | "crypto/sha1" 12 | "hash" 13 | ) 14 | 15 | type macMode struct { 16 | keySize int 17 | new func(key []byte) hash.Hash 18 | } 19 | 20 | // truncatingMAC wraps around a hash.Hash and truncates the output digest to 21 | // a given size. 22 | type truncatingMAC struct { 23 | length int 24 | hmac hash.Hash 25 | } 26 | 27 | func (t truncatingMAC) Write(data []byte) (int, error) { 28 | return t.hmac.Write(data) 29 | } 30 | 31 | func (t truncatingMAC) Sum(in []byte) []byte { 32 | out := t.hmac.Sum(in) 33 | return out[:len(in)+t.length] 34 | } 35 | 36 | func (t truncatingMAC) Reset() { 37 | t.hmac.Reset() 38 | } 39 | 40 | func (t truncatingMAC) Size() int { 41 | return t.length 42 | } 43 | 44 | func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } 45 | 46 | var macModes = map[string]*macMode{ 47 | "hmac-sha1": {20, func(key []byte) hash.Hash { 48 | return hmac.New(sha1.New, key) 49 | }}, 50 | "hmac-sha1-96": {20, func(key []byte) hash.Hash { 51 | return truncatingMAC{12, hmac.New(sha1.New, key)} 52 | }}, 53 | } 54 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/mempipe_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "io" 9 | "sync" 10 | "testing" 11 | ) 12 | 13 | // An in-memory packetConn. It is safe to call Close and writePacket 14 | // from different goroutines. 15 | type memTransport struct { 16 | eof bool 17 | pending [][]byte 18 | write *memTransport 19 | sync.Mutex 20 | *sync.Cond 21 | } 22 | 23 | func (t *memTransport) readPacket() ([]byte, error) { 24 | t.Lock() 25 | defer t.Unlock() 26 | for { 27 | if len(t.pending) > 0 { 28 | r := t.pending[0] 29 | t.pending = t.pending[1:] 30 | return r, nil 31 | } 32 | if t.eof { 33 | return nil, io.EOF 34 | } 35 | t.Cond.Wait() 36 | } 37 | } 38 | 39 | func (t *memTransport) closeSelf() error { 40 | t.Lock() 41 | defer t.Unlock() 42 | if t.eof { 43 | return io.EOF 44 | } 45 | t.eof = true 46 | t.Cond.Broadcast() 47 | return nil 48 | } 49 | 50 | func (t *memTransport) Close() error { 51 | err := t.write.closeSelf() 52 | t.closeSelf() 53 | return err 54 | } 55 | 56 | func (t *memTransport) writePacket(p []byte) error { 57 | t.write.Lock() 58 | defer t.write.Unlock() 59 | if t.write.eof { 60 | return io.EOF 61 | } 62 | c := make([]byte, len(p)) 63 | copy(c, p) 64 | t.write.pending = append(t.write.pending, c) 65 | t.write.Cond.Signal() 66 | return nil 67 | } 68 | 69 | func memPipe() (a, b packetConn) { 70 | t1 := memTransport{} 71 | t2 := memTransport{} 72 | t1.write = &t2 73 | t2.write = &t1 74 | t1.Cond = sync.NewCond(&t1.Mutex) 75 | t2.Cond = sync.NewCond(&t2.Mutex) 76 | return &t1, &t2 77 | } 78 | 79 | func TestmemPipe(t *testing.T) { 80 | a, b := memPipe() 81 | if err := a.writePacket([]byte{42}); err != nil { 82 | t.Fatalf("writePacket: %v", err) 83 | } 84 | if err := a.Close(); err != nil { 85 | t.Fatal("Close: ", err) 86 | } 87 | p, err := b.readPacket() 88 | if err != nil { 89 | t.Fatal("readPacket: ", err) 90 | } 91 | if len(p) != 1 || p[0] != 42 { 92 | t.Fatalf("got %v, want {42}", p) 93 | } 94 | p, err = b.readPacket() 95 | if err != io.EOF { 96 | t.Fatalf("got %v, %v, want EOF", p, err) 97 | } 98 | } 99 | 100 | func TestDoubleClose(t *testing.T) { 101 | a, _ := memPipe() 102 | err := a.Close() 103 | if err != nil { 104 | t.Errorf("Close: %v", err) 105 | } 106 | err = a.Close() 107 | if err != io.EOF { 108 | t.Errorf("expect EOF on double close.") 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/messages_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "bytes" 9 | "math/big" 10 | "math/rand" 11 | "reflect" 12 | "testing" 13 | "testing/quick" 14 | ) 15 | 16 | var intLengthTests = []struct { 17 | val, length int 18 | }{ 19 | {0, 4 + 0}, 20 | {1, 4 + 1}, 21 | {127, 4 + 1}, 22 | {128, 4 + 2}, 23 | {-1, 4 + 1}, 24 | } 25 | 26 | func TestIntLength(t *testing.T) { 27 | for _, test := range intLengthTests { 28 | v := new(big.Int).SetInt64(int64(test.val)) 29 | length := intLength(v) 30 | if length != test.length { 31 | t.Errorf("For %d, got length %d but expected %d", test.val, length, test.length) 32 | } 33 | } 34 | } 35 | 36 | type msgAllTypes struct { 37 | Bool bool `sshtype:"21"` 38 | Array [16]byte 39 | Uint64 uint64 40 | Uint32 uint32 41 | Uint8 uint8 42 | String string 43 | Strings []string 44 | Bytes []byte 45 | Int *big.Int 46 | Rest []byte `ssh:"rest"` 47 | } 48 | 49 | func (t *msgAllTypes) Generate(rand *rand.Rand, size int) reflect.Value { 50 | m := &msgAllTypes{} 51 | m.Bool = rand.Intn(2) == 1 52 | randomBytes(m.Array[:], rand) 53 | m.Uint64 = uint64(rand.Int63n(1<<63 - 1)) 54 | m.Uint32 = uint32(rand.Intn((1 << 31) - 1)) 55 | m.Uint8 = uint8(rand.Intn(1 << 8)) 56 | m.String = string(m.Array[:]) 57 | m.Strings = randomNameList(rand) 58 | m.Bytes = m.Array[:] 59 | m.Int = randomInt(rand) 60 | m.Rest = m.Array[:] 61 | return reflect.ValueOf(m) 62 | } 63 | 64 | func TestMarshalUnmarshal(t *testing.T) { 65 | rand := rand.New(rand.NewSource(0)) 66 | iface := &msgAllTypes{} 67 | ty := reflect.ValueOf(iface).Type() 68 | 69 | n := 100 70 | if testing.Short() { 71 | n = 5 72 | } 73 | for j := 0; j < n; j++ { 74 | v, ok := quick.Value(ty, rand) 75 | if !ok { 76 | t.Errorf("failed to create value") 77 | break 78 | } 79 | 80 | m1 := v.Elem().Interface() 81 | m2 := iface 82 | 83 | marshaled := Marshal(m1) 84 | if err := Unmarshal(marshaled, m2); err != nil { 85 | t.Errorf("Unmarshal %#v: %s", m1, err) 86 | break 87 | } 88 | 89 | if !reflect.DeepEqual(v.Interface(), m2) { 90 | t.Errorf("got: %#v\nwant:%#v\n%x", m2, m1, marshaled) 91 | break 92 | } 93 | } 94 | } 95 | 96 | func TestUnmarshalEmptyPacket(t *testing.T) { 97 | var b []byte 98 | var m channelRequestSuccessMsg 99 | if err := Unmarshal(b, &m); err == nil { 100 | t.Fatalf("unmarshal of empty slice succeeded") 101 | } 102 | } 103 | 104 | func TestUnmarshalUnexpectedPacket(t *testing.T) { 105 | type S struct { 106 | I uint32 `sshtype:"43"` 107 | S string 108 | B bool 109 | } 110 | 111 | s := S{11, "hello", true} 112 | packet := Marshal(s) 113 | packet[0] = 42 114 | roundtrip := S{} 115 | err := Unmarshal(packet, &roundtrip) 116 | if err == nil { 117 | t.Fatal("expected error, not nil") 118 | } 119 | } 120 | 121 | func TestMarshalPtr(t *testing.T) { 122 | s := struct { 123 | S string 124 | }{"hello"} 125 | 126 | m1 := Marshal(s) 127 | m2 := Marshal(&s) 128 | if !bytes.Equal(m1, m2) { 129 | t.Errorf("got %q, want %q for marshaled pointer", m2, m1) 130 | } 131 | } 132 | 133 | func TestBareMarshalUnmarshal(t *testing.T) { 134 | type S struct { 135 | I uint32 136 | S string 137 | B bool 138 | } 139 | 140 | s := S{42, "hello", true} 141 | packet := Marshal(s) 142 | roundtrip := S{} 143 | Unmarshal(packet, &roundtrip) 144 | 145 | if !reflect.DeepEqual(s, roundtrip) { 146 | t.Errorf("got %#v, want %#v", roundtrip, s) 147 | } 148 | } 149 | 150 | func TestBareMarshal(t *testing.T) { 151 | type S2 struct { 152 | I uint32 153 | } 154 | s := S2{42} 155 | packet := Marshal(s) 156 | i, rest, ok := parseUint32(packet) 157 | if len(rest) > 0 || !ok { 158 | t.Errorf("parseInt(%q): parse error", packet) 159 | } 160 | if i != s.I { 161 | t.Errorf("got %d, want %d", i, s.I) 162 | } 163 | } 164 | 165 | func randomBytes(out []byte, rand *rand.Rand) { 166 | for i := 0; i < len(out); i++ { 167 | out[i] = byte(rand.Int31()) 168 | } 169 | } 170 | 171 | func randomNameList(rand *rand.Rand) []string { 172 | ret := make([]string, rand.Int31()&15) 173 | for i := range ret { 174 | s := make([]byte, 1+(rand.Int31()&15)) 175 | for j := range s { 176 | s[j] = 'a' + uint8(rand.Int31()&15) 177 | } 178 | ret[i] = string(s) 179 | } 180 | return ret 181 | } 182 | 183 | func randomInt(rand *rand.Rand) *big.Int { 184 | return new(big.Int).SetInt64(int64(int32(rand.Uint32()))) 185 | } 186 | 187 | func (*kexInitMsg) Generate(rand *rand.Rand, size int) reflect.Value { 188 | ki := &kexInitMsg{} 189 | randomBytes(ki.Cookie[:], rand) 190 | ki.KexAlgos = randomNameList(rand) 191 | ki.ServerHostKeyAlgos = randomNameList(rand) 192 | ki.CiphersClientServer = randomNameList(rand) 193 | ki.CiphersServerClient = randomNameList(rand) 194 | ki.MACsClientServer = randomNameList(rand) 195 | ki.MACsServerClient = randomNameList(rand) 196 | ki.CompressionClientServer = randomNameList(rand) 197 | ki.CompressionServerClient = randomNameList(rand) 198 | ki.LanguagesClientServer = randomNameList(rand) 199 | ki.LanguagesServerClient = randomNameList(rand) 200 | if rand.Int31()&1 == 1 { 201 | ki.FirstKexFollows = true 202 | } 203 | return reflect.ValueOf(ki) 204 | } 205 | 206 | func (*kexDHInitMsg) Generate(rand *rand.Rand, size int) reflect.Value { 207 | dhi := &kexDHInitMsg{} 208 | dhi.X = randomInt(rand) 209 | return reflect.ValueOf(dhi) 210 | } 211 | 212 | var ( 213 | _kexInitMsg = new(kexInitMsg).Generate(rand.New(rand.NewSource(0)), 10).Elem().Interface() 214 | _kexDHInitMsg = new(kexDHInitMsg).Generate(rand.New(rand.NewSource(0)), 10).Elem().Interface() 215 | 216 | _kexInit = Marshal(_kexInitMsg) 217 | _kexDHInit = Marshal(_kexDHInitMsg) 218 | ) 219 | 220 | func BenchmarkMarshalKexInitMsg(b *testing.B) { 221 | for i := 0; i < b.N; i++ { 222 | Marshal(_kexInitMsg) 223 | } 224 | } 225 | 226 | func BenchmarkUnmarshalKexInitMsg(b *testing.B) { 227 | m := new(kexInitMsg) 228 | for i := 0; i < b.N; i++ { 229 | Unmarshal(_kexInit, m) 230 | } 231 | } 232 | 233 | func BenchmarkMarshalKexDHInitMsg(b *testing.B) { 234 | for i := 0; i < b.N; i++ { 235 | Marshal(_kexDHInitMsg) 236 | } 237 | } 238 | 239 | func BenchmarkUnmarshalKexDHInitMsg(b *testing.B) { 240 | m := new(kexDHInitMsg) 241 | for i := 0; i < b.N; i++ { 242 | Unmarshal(_kexDHInit, m) 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/tcpip_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "testing" 9 | ) 10 | 11 | func TestAutoPortListenBroken(t *testing.T) { 12 | broken := "SSH-2.0-OpenSSH_5.9hh11" 13 | works := "SSH-2.0-OpenSSH_6.1" 14 | if !isBrokenOpenSSHVersion(broken) { 15 | t.Errorf("version %q not marked as broken", broken) 16 | } 17 | if isBrokenOpenSSHVersion(works) { 18 | t.Errorf("version %q marked as broken", works) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/terminal_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package terminal 6 | 7 | import ( 8 | "io" 9 | "testing" 10 | ) 11 | 12 | type MockTerminal struct { 13 | toSend []byte 14 | bytesPerRead int 15 | received []byte 16 | } 17 | 18 | func (c *MockTerminal) Read(data []byte) (n int, err error) { 19 | n = len(data) 20 | if n == 0 { 21 | return 22 | } 23 | if n > len(c.toSend) { 24 | n = len(c.toSend) 25 | } 26 | if n == 0 { 27 | return 0, io.EOF 28 | } 29 | if c.bytesPerRead > 0 && n > c.bytesPerRead { 30 | n = c.bytesPerRead 31 | } 32 | copy(data, c.toSend[:n]) 33 | c.toSend = c.toSend[n:] 34 | return 35 | } 36 | 37 | func (c *MockTerminal) Write(data []byte) (n int, err error) { 38 | c.received = append(c.received, data...) 39 | return len(data), nil 40 | } 41 | 42 | func TestClose(t *testing.T) { 43 | c := &MockTerminal{} 44 | ss := NewTerminal(c, "> ") 45 | line, err := ss.ReadLine() 46 | if line != "" { 47 | t.Errorf("Expected empty line but got: %s", line) 48 | } 49 | if err != io.EOF { 50 | t.Errorf("Error should have been EOF but got: %s", err) 51 | } 52 | } 53 | 54 | var keyPressTests = []struct { 55 | in string 56 | line string 57 | err error 58 | throwAwayLines int 59 | }{ 60 | { 61 | err: io.EOF, 62 | }, 63 | { 64 | in: "\r", 65 | line: "", 66 | }, 67 | { 68 | in: "foo\r", 69 | line: "foo", 70 | }, 71 | { 72 | in: "a\x1b[Cb\r", // right 73 | line: "ab", 74 | }, 75 | { 76 | in: "a\x1b[Db\r", // left 77 | line: "ba", 78 | }, 79 | { 80 | in: "a\177b\r", // backspace 81 | line: "b", 82 | }, 83 | { 84 | in: "\x1b[A\r", // up 85 | }, 86 | { 87 | in: "\x1b[B\r", // down 88 | }, 89 | { 90 | in: "line\x1b[A\x1b[B\r", // up then down 91 | line: "line", 92 | }, 93 | { 94 | in: "line1\rline2\x1b[A\r", // recall previous line. 95 | line: "line1", 96 | throwAwayLines: 1, 97 | }, 98 | { 99 | // recall two previous lines and append. 100 | in: "line1\rline2\rline3\x1b[A\x1b[Axxx\r", 101 | line: "line1xxx", 102 | throwAwayLines: 2, 103 | }, 104 | { 105 | // Ctrl-A to move to beginning of line followed by ^K to kill 106 | // line. 107 | in: "a b \001\013\r", 108 | line: "", 109 | }, 110 | { 111 | // Ctrl-A to move to beginning of line, Ctrl-E to move to end, 112 | // finally ^K to kill nothing. 113 | in: "a b \001\005\013\r", 114 | line: "a b ", 115 | }, 116 | { 117 | in: "\027\r", 118 | line: "", 119 | }, 120 | { 121 | in: "a\027\r", 122 | line: "", 123 | }, 124 | { 125 | in: "a \027\r", 126 | line: "", 127 | }, 128 | { 129 | in: "a b\027\r", 130 | line: "a ", 131 | }, 132 | { 133 | in: "a b \027\r", 134 | line: "a ", 135 | }, 136 | { 137 | in: "one two thr\x1b[D\027\r", 138 | line: "one two r", 139 | }, 140 | { 141 | in: "\013\r", 142 | line: "", 143 | }, 144 | { 145 | in: "a\013\r", 146 | line: "a", 147 | }, 148 | { 149 | in: "ab\x1b[D\013\r", 150 | line: "a", 151 | }, 152 | { 153 | in: "Ξεσκεπάζω\r", 154 | line: "Ξεσκεπάζω", 155 | }, 156 | { 157 | in: "£\r\x1b[A\177\r", // non-ASCII char, enter, up, backspace. 158 | line: "", 159 | throwAwayLines: 1, 160 | }, 161 | { 162 | in: "£\r££\x1b[A\x1b[B\177\r", // non-ASCII char, enter, 2x non-ASCII, up, down, backspace, enter. 163 | line: "£", 164 | throwAwayLines: 1, 165 | }, 166 | { 167 | // Ctrl-D at the end of the line should be ignored. 168 | in: "a\004\r", 169 | line: "a", 170 | }, 171 | { 172 | // a, b, left, Ctrl-D should erase the b. 173 | in: "ab\x1b[D\004\r", 174 | line: "a", 175 | }, 176 | { 177 | // a, b, c, d, left, left, ^U should erase to the beginning of 178 | // the line. 179 | in: "abcd\x1b[D\x1b[D\025\r", 180 | line: "cd", 181 | }, 182 | { 183 | // Bracketed paste mode: control sequences should be returned 184 | // verbatim in paste mode. 185 | in: "abc\x1b[200~de\177f\x1b[201~\177\r", 186 | line: "abcde\177", 187 | }, 188 | { 189 | // Enter in bracketed paste mode should still work. 190 | in: "abc\x1b[200~d\refg\x1b[201~h\r", 191 | line: "efgh", 192 | throwAwayLines: 1, 193 | }, 194 | { 195 | // Lines consisting entirely of pasted data should be indicated as such. 196 | in: "\x1b[200~a\r", 197 | line: "a", 198 | err: ErrPasteIndicator, 199 | }, 200 | } 201 | 202 | func TestKeyPresses(t *testing.T) { 203 | for i, test := range keyPressTests { 204 | for j := 1; j < len(test.in); j++ { 205 | c := &MockTerminal{ 206 | toSend: []byte(test.in), 207 | bytesPerRead: j, 208 | } 209 | ss := NewTerminal(c, "> ") 210 | for k := 0; k < test.throwAwayLines; k++ { 211 | _, err := ss.ReadLine() 212 | if err != nil { 213 | t.Errorf("Throwaway line %d from test %d resulted in error: %s", k, i, err) 214 | } 215 | } 216 | line, err := ss.ReadLine() 217 | if line != test.line { 218 | t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line) 219 | break 220 | } 221 | if err != test.err { 222 | t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err) 223 | break 224 | } 225 | } 226 | } 227 | } 228 | 229 | func TestPasswordNotSaved(t *testing.T) { 230 | c := &MockTerminal{ 231 | toSend: []byte("password\r\x1b[A\r"), 232 | bytesPerRead: 1, 233 | } 234 | ss := NewTerminal(c, "> ") 235 | pw, _ := ss.ReadPassword("> ") 236 | if pw != "password" { 237 | t.Fatalf("failed to read password, got %s", pw) 238 | } 239 | line, _ := ss.ReadLine() 240 | if len(line) > 0 { 241 | t.Fatalf("password was saved in history") 242 | } 243 | } 244 | 245 | var setSizeTests = []struct { 246 | width, height int 247 | }{ 248 | {40, 13}, 249 | {80, 24}, 250 | {132, 43}, 251 | } 252 | 253 | func TestTerminalSetSize(t *testing.T) { 254 | for _, setSize := range setSizeTests { 255 | c := &MockTerminal{ 256 | toSend: []byte("password\r\x1b[A\r"), 257 | bytesPerRead: 1, 258 | } 259 | ss := NewTerminal(c, "> ") 260 | ss.SetSize(setSize.width, setSize.height) 261 | pw, _ := ss.ReadPassword("Password: ") 262 | if pw != "password" { 263 | t.Fatalf("failed to read password, got %s", pw) 264 | } 265 | if string(c.received) != "Password: \r\n" { 266 | t.Errorf("failed to set the temporary prompt expected %q, got %q", "Password: ", c.received) 267 | } 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux,!appengine netbsd openbsd 6 | 7 | // Package terminal provides support functions for dealing with terminals, as 8 | // commonly found on UNIX systems. 9 | // 10 | // Putting a terminal into raw mode is the most common requirement: 11 | // 12 | // oldState, err := terminal.MakeRaw(0) 13 | // if err != nil { 14 | // panic(err) 15 | // } 16 | // defer terminal.Restore(0, oldState) 17 | package terminal // import "golang.org/x/crypto/ssh/terminal" 18 | 19 | import ( 20 | "io" 21 | "syscall" 22 | "unsafe" 23 | ) 24 | 25 | // State contains the state of a terminal. 26 | type State struct { 27 | termios syscall.Termios 28 | } 29 | 30 | // IsTerminal returns true if the given file descriptor is a terminal. 31 | func IsTerminal(fd int) bool { 32 | var termios syscall.Termios 33 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 34 | return err == 0 35 | } 36 | 37 | // MakeRaw put the terminal connected to the given file descriptor into raw 38 | // mode and returns the previous state of the terminal so that it can be 39 | // restored. 40 | func MakeRaw(fd int) (*State, error) { 41 | var oldState State 42 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { 43 | return nil, err 44 | } 45 | 46 | newState := oldState.termios 47 | newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF 48 | newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG 49 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { 50 | return nil, err 51 | } 52 | 53 | return &oldState, nil 54 | } 55 | 56 | // GetState returns the current state of a terminal which may be useful to 57 | // restore the terminal after a signal. 58 | func GetState(fd int) (*State, error) { 59 | var oldState State 60 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { 61 | return nil, err 62 | } 63 | 64 | return &oldState, nil 65 | } 66 | 67 | // Restore restores the terminal connected to the given file descriptor to a 68 | // previous state. 69 | func Restore(fd int, state *State) error { 70 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0) 71 | return err 72 | } 73 | 74 | // GetSize returns the dimensions of the given terminal. 75 | func GetSize(fd int) (width, height int, err error) { 76 | var dimensions [4]uint16 77 | 78 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 { 79 | return -1, -1, err 80 | } 81 | return int(dimensions[1]), int(dimensions[0]), nil 82 | } 83 | 84 | // ReadPassword reads a line of input from a terminal without local echo. This 85 | // is commonly used for inputting passwords and other sensitive data. The slice 86 | // returned does not include the \n. 87 | func ReadPassword(fd int) ([]byte, error) { 88 | var oldState syscall.Termios 89 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 { 90 | return nil, err 91 | } 92 | 93 | newState := oldState 94 | newState.Lflag &^= syscall.ECHO 95 | newState.Lflag |= syscall.ICANON | syscall.ISIG 96 | newState.Iflag |= syscall.ICRNL 97 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { 98 | return nil, err 99 | } 100 | 101 | defer func() { 102 | syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0) 103 | }() 104 | 105 | var buf [16]byte 106 | var ret []byte 107 | for { 108 | n, err := syscall.Read(fd, buf[:]) 109 | if err != nil { 110 | return nil, err 111 | } 112 | if n == 0 { 113 | if len(ret) == 0 { 114 | return nil, io.EOF 115 | } 116 | break 117 | } 118 | if buf[n-1] == '\n' { 119 | n-- 120 | } 121 | ret = append(ret, buf[:n]...) 122 | if n < len(buf) { 123 | break 124 | } 125 | } 126 | 127 | return ret, nil 128 | } 129 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util_bsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd netbsd openbsd 6 | 7 | package terminal 8 | 9 | import "syscall" 10 | 11 | const ioctlReadTermios = syscall.TIOCGETA 12 | const ioctlWriteTermios = syscall.TIOCSETA 13 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package terminal 6 | 7 | // These constants are declared here, rather than importing 8 | // them from the syscall package as some syscall packages, even 9 | // on linux, for example gccgo, do not declare them. 10 | const ioctlReadTermios = 0x5401 // syscall.TCGETS 11 | const ioctlWriteTermios = 0x5402 // syscall.TCSETS 12 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build windows 6 | 7 | // Package terminal provides support functions for dealing with terminals, as 8 | // commonly found on UNIX systems. 9 | // 10 | // Putting a terminal into raw mode is the most common requirement: 11 | // 12 | // oldState, err := terminal.MakeRaw(0) 13 | // if err != nil { 14 | // panic(err) 15 | // } 16 | // defer terminal.Restore(0, oldState) 17 | package terminal 18 | 19 | import ( 20 | "io" 21 | "syscall" 22 | "unsafe" 23 | ) 24 | 25 | const ( 26 | enableLineInput = 2 27 | enableEchoInput = 4 28 | enableProcessedInput = 1 29 | enableWindowInput = 8 30 | enableMouseInput = 16 31 | enableInsertMode = 32 32 | enableQuickEditMode = 64 33 | enableExtendedFlags = 128 34 | enableAutoPosition = 256 35 | enableProcessedOutput = 1 36 | enableWrapAtEolOutput = 2 37 | ) 38 | 39 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 40 | 41 | var ( 42 | procGetConsoleMode = kernel32.NewProc("GetConsoleMode") 43 | procSetConsoleMode = kernel32.NewProc("SetConsoleMode") 44 | procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") 45 | ) 46 | 47 | type ( 48 | short int16 49 | word uint16 50 | 51 | coord struct { 52 | x short 53 | y short 54 | } 55 | smallRect struct { 56 | left short 57 | top short 58 | right short 59 | bottom short 60 | } 61 | consoleScreenBufferInfo struct { 62 | size coord 63 | cursorPosition coord 64 | attributes word 65 | window smallRect 66 | maximumWindowSize coord 67 | } 68 | ) 69 | 70 | type State struct { 71 | mode uint32 72 | } 73 | 74 | // IsTerminal returns true if the given file descriptor is a terminal. 75 | func IsTerminal(fd int) bool { 76 | var st uint32 77 | r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 78 | return r != 0 && e == 0 79 | } 80 | 81 | // MakeRaw put the terminal connected to the given file descriptor into raw 82 | // mode and returns the previous state of the terminal so that it can be 83 | // restored. 84 | func MakeRaw(fd int) (*State, error) { 85 | var st uint32 86 | _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 87 | if e != 0 { 88 | return nil, error(e) 89 | } 90 | st &^= (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput) 91 | _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0) 92 | if e != 0 { 93 | return nil, error(e) 94 | } 95 | return &State{st}, nil 96 | } 97 | 98 | // GetState returns the current state of a terminal which may be useful to 99 | // restore the terminal after a signal. 100 | func GetState(fd int) (*State, error) { 101 | var st uint32 102 | _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 103 | if e != 0 { 104 | return nil, error(e) 105 | } 106 | return &State{st}, nil 107 | } 108 | 109 | // Restore restores the terminal connected to the given file descriptor to a 110 | // previous state. 111 | func Restore(fd int, state *State) error { 112 | _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0) 113 | return err 114 | } 115 | 116 | // GetSize returns the dimensions of the given terminal. 117 | func GetSize(fd int) (width, height int, err error) { 118 | var info consoleScreenBufferInfo 119 | _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0) 120 | if e != 0 { 121 | return 0, 0, error(e) 122 | } 123 | return int(info.size.x), int(info.size.y), nil 124 | } 125 | 126 | // ReadPassword reads a line of input from a terminal without local echo. This 127 | // is commonly used for inputting passwords and other sensitive data. The slice 128 | // returned does not include the \n. 129 | func ReadPassword(fd int) ([]byte, error) { 130 | var st uint32 131 | _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 132 | if e != 0 { 133 | return nil, error(e) 134 | } 135 | old := st 136 | 137 | st &^= (enableEchoInput) 138 | st |= (enableProcessedInput | enableLineInput | enableProcessedOutput) 139 | _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0) 140 | if e != 0 { 141 | return nil, error(e) 142 | } 143 | 144 | defer func() { 145 | syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0) 146 | }() 147 | 148 | var buf [16]byte 149 | var ret []byte 150 | for { 151 | n, err := syscall.Read(syscall.Handle(fd), buf[:]) 152 | if err != nil { 153 | return nil, err 154 | } 155 | if n == 0 { 156 | if len(ret) == 0 { 157 | return nil, io.EOF 158 | } 159 | break 160 | } 161 | if buf[n-1] == '\n' { 162 | n-- 163 | } 164 | if n > 0 && buf[n-1] == '\r' { 165 | n-- 166 | } 167 | ret = append(ret, buf[:n]...) 168 | if n < len(buf) { 169 | break 170 | } 171 | } 172 | 173 | return ret, nil 174 | } 175 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/agent_unix_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux netbsd openbsd 6 | 7 | package test 8 | 9 | import ( 10 | "bytes" 11 | "testing" 12 | 13 | "golang.org/x/crypto/ssh" 14 | "golang.org/x/crypto/ssh/agent" 15 | ) 16 | 17 | func TestAgentForward(t *testing.T) { 18 | server := newServer(t) 19 | defer server.Shutdown() 20 | conn := server.Dial(clientConfig()) 21 | defer conn.Close() 22 | 23 | keyring := agent.NewKeyring() 24 | keyring.Add(testPrivateKeys["dsa"], nil, "") 25 | pub := testPublicKeys["dsa"] 26 | 27 | sess, err := conn.NewSession() 28 | if err != nil { 29 | t.Fatalf("NewSession: %v", err) 30 | } 31 | if err := agent.RequestAgentForwarding(sess); err != nil { 32 | t.Fatalf("RequestAgentForwarding: %v", err) 33 | } 34 | 35 | if err := agent.ForwardToAgent(conn, keyring); err != nil { 36 | t.Fatalf("SetupForwardKeyring: %v", err) 37 | } 38 | out, err := sess.CombinedOutput("ssh-add -L") 39 | if err != nil { 40 | t.Fatalf("running ssh-add: %v, out %s", err, out) 41 | } 42 | key, _, _, _, err := ssh.ParseAuthorizedKey(out) 43 | if err != nil { 44 | t.Fatalf("ParseAuthorizedKey(%q): %v", out, err) 45 | } 46 | 47 | if !bytes.Equal(key.Marshal(), pub.Marshal()) { 48 | t.Fatalf("got key %s, want %s", ssh.MarshalAuthorizedKey(key), ssh.MarshalAuthorizedKey(pub)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/cert_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux netbsd openbsd 6 | 7 | package test 8 | 9 | import ( 10 | "crypto/rand" 11 | "testing" 12 | 13 | "golang.org/x/crypto/ssh" 14 | ) 15 | 16 | func TestCertLogin(t *testing.T) { 17 | s := newServer(t) 18 | defer s.Shutdown() 19 | 20 | // Use a key different from the default. 21 | clientKey := testSigners["dsa"] 22 | caAuthKey := testSigners["ecdsa"] 23 | cert := &ssh.Certificate{ 24 | Key: clientKey.PublicKey(), 25 | ValidPrincipals: []string{username()}, 26 | CertType: ssh.UserCert, 27 | ValidBefore: ssh.CertTimeInfinity, 28 | } 29 | if err := cert.SignCert(rand.Reader, caAuthKey); err != nil { 30 | t.Fatalf("SetSignature: %v", err) 31 | } 32 | 33 | certSigner, err := ssh.NewCertSigner(cert, clientKey) 34 | if err != nil { 35 | t.Fatalf("NewCertSigner: %v", err) 36 | } 37 | 38 | conf := &ssh.ClientConfig{ 39 | User: username(), 40 | } 41 | conf.Auth = append(conf.Auth, ssh.PublicKeys(certSigner)) 42 | client, err := s.TryDial(conf) 43 | if err != nil { 44 | t.Fatalf("TryDial: %v", err) 45 | } 46 | client.Close() 47 | } 48 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This package contains integration tests for the 6 | // code.google.com/p/go.crypto/ssh package. 7 | package test // import "golang.org/x/crypto/ssh/test" 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/forward_unix_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux netbsd openbsd 6 | 7 | package test 8 | 9 | import ( 10 | "bytes" 11 | "io" 12 | "io/ioutil" 13 | "math/rand" 14 | "net" 15 | "testing" 16 | "time" 17 | ) 18 | 19 | func TestPortForward(t *testing.T) { 20 | server := newServer(t) 21 | defer server.Shutdown() 22 | conn := server.Dial(clientConfig()) 23 | defer conn.Close() 24 | 25 | sshListener, err := conn.Listen("tcp", "localhost:0") 26 | if err != nil { 27 | t.Fatal(err) 28 | } 29 | 30 | go func() { 31 | sshConn, err := sshListener.Accept() 32 | if err != nil { 33 | t.Fatalf("listen.Accept failed: %v", err) 34 | } 35 | 36 | _, err = io.Copy(sshConn, sshConn) 37 | if err != nil && err != io.EOF { 38 | t.Fatalf("ssh client copy: %v", err) 39 | } 40 | sshConn.Close() 41 | }() 42 | 43 | forwardedAddr := sshListener.Addr().String() 44 | tcpConn, err := net.Dial("tcp", forwardedAddr) 45 | if err != nil { 46 | t.Fatalf("TCP dial failed: %v", err) 47 | } 48 | 49 | readChan := make(chan []byte) 50 | go func() { 51 | data, _ := ioutil.ReadAll(tcpConn) 52 | readChan <- data 53 | }() 54 | 55 | // Invent some data. 56 | data := make([]byte, 100*1000) 57 | for i := range data { 58 | data[i] = byte(i % 255) 59 | } 60 | 61 | var sent []byte 62 | for len(sent) < 1000*1000 { 63 | // Send random sized chunks 64 | m := rand.Intn(len(data)) 65 | n, err := tcpConn.Write(data[:m]) 66 | if err != nil { 67 | break 68 | } 69 | sent = append(sent, data[:n]...) 70 | } 71 | if err := tcpConn.(*net.TCPConn).CloseWrite(); err != nil { 72 | t.Errorf("tcpConn.CloseWrite: %v", err) 73 | } 74 | 75 | read := <-readChan 76 | 77 | if len(sent) != len(read) { 78 | t.Fatalf("got %d bytes, want %d", len(read), len(sent)) 79 | } 80 | if bytes.Compare(sent, read) != 0 { 81 | t.Fatalf("read back data does not match") 82 | } 83 | 84 | if err := sshListener.Close(); err != nil { 85 | t.Fatalf("sshListener.Close: %v", err) 86 | } 87 | 88 | // Check that the forward disappeared. 89 | tcpConn, err = net.Dial("tcp", forwardedAddr) 90 | if err == nil { 91 | tcpConn.Close() 92 | t.Errorf("still listening to %s after closing", forwardedAddr) 93 | } 94 | } 95 | 96 | func TestAcceptClose(t *testing.T) { 97 | server := newServer(t) 98 | defer server.Shutdown() 99 | conn := server.Dial(clientConfig()) 100 | 101 | sshListener, err := conn.Listen("tcp", "localhost:0") 102 | if err != nil { 103 | t.Fatal(err) 104 | } 105 | 106 | quit := make(chan error, 1) 107 | go func() { 108 | for { 109 | c, err := sshListener.Accept() 110 | if err != nil { 111 | quit <- err 112 | break 113 | } 114 | c.Close() 115 | } 116 | }() 117 | sshListener.Close() 118 | 119 | select { 120 | case <-time.After(1 * time.Second): 121 | t.Errorf("timeout: listener did not close.") 122 | case err := <-quit: 123 | t.Logf("quit as expected (error %v)", err) 124 | } 125 | } 126 | 127 | // Check that listeners exit if the underlying client transport dies. 128 | func TestPortForwardConnectionClose(t *testing.T) { 129 | server := newServer(t) 130 | defer server.Shutdown() 131 | conn := server.Dial(clientConfig()) 132 | 133 | sshListener, err := conn.Listen("tcp", "localhost:0") 134 | if err != nil { 135 | t.Fatal(err) 136 | } 137 | 138 | quit := make(chan error, 1) 139 | go func() { 140 | for { 141 | c, err := sshListener.Accept() 142 | if err != nil { 143 | quit <- err 144 | break 145 | } 146 | c.Close() 147 | } 148 | }() 149 | 150 | // It would be even nicer if we closed the server side, but it 151 | // is more involved as the fd for that side is dup()ed. 152 | server.clientConn.Close() 153 | 154 | select { 155 | case <-time.After(1 * time.Second): 156 | t.Errorf("timeout: listener did not close.") 157 | case err := <-quit: 158 | t.Logf("quit as expected (error %v)", err) 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/session_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !windows 6 | 7 | package test 8 | 9 | // Session functional tests. 10 | 11 | import ( 12 | "bytes" 13 | "errors" 14 | "io" 15 | "strings" 16 | "testing" 17 | 18 | "golang.org/x/crypto/ssh" 19 | ) 20 | 21 | func TestRunCommandSuccess(t *testing.T) { 22 | server := newServer(t) 23 | defer server.Shutdown() 24 | conn := server.Dial(clientConfig()) 25 | defer conn.Close() 26 | 27 | session, err := conn.NewSession() 28 | if err != nil { 29 | t.Fatalf("session failed: %v", err) 30 | } 31 | defer session.Close() 32 | err = session.Run("true") 33 | if err != nil { 34 | t.Fatalf("session failed: %v", err) 35 | } 36 | } 37 | 38 | func TestHostKeyCheck(t *testing.T) { 39 | server := newServer(t) 40 | defer server.Shutdown() 41 | 42 | conf := clientConfig() 43 | hostDB := hostKeyDB() 44 | conf.HostKeyCallback = hostDB.Check 45 | 46 | // change the keys. 47 | hostDB.keys[ssh.KeyAlgoRSA][25]++ 48 | hostDB.keys[ssh.KeyAlgoDSA][25]++ 49 | hostDB.keys[ssh.KeyAlgoECDSA256][25]++ 50 | 51 | conn, err := server.TryDial(conf) 52 | if err == nil { 53 | conn.Close() 54 | t.Fatalf("dial should have failed.") 55 | } else if !strings.Contains(err.Error(), "host key mismatch") { 56 | t.Fatalf("'host key mismatch' not found in %v", err) 57 | } 58 | } 59 | 60 | func TestRunCommandStdin(t *testing.T) { 61 | server := newServer(t) 62 | defer server.Shutdown() 63 | conn := server.Dial(clientConfig()) 64 | defer conn.Close() 65 | 66 | session, err := conn.NewSession() 67 | if err != nil { 68 | t.Fatalf("session failed: %v", err) 69 | } 70 | defer session.Close() 71 | 72 | r, w := io.Pipe() 73 | defer r.Close() 74 | defer w.Close() 75 | session.Stdin = r 76 | 77 | err = session.Run("true") 78 | if err != nil { 79 | t.Fatalf("session failed: %v", err) 80 | } 81 | } 82 | 83 | func TestRunCommandStdinError(t *testing.T) { 84 | server := newServer(t) 85 | defer server.Shutdown() 86 | conn := server.Dial(clientConfig()) 87 | defer conn.Close() 88 | 89 | session, err := conn.NewSession() 90 | if err != nil { 91 | t.Fatalf("session failed: %v", err) 92 | } 93 | defer session.Close() 94 | 95 | r, w := io.Pipe() 96 | defer r.Close() 97 | session.Stdin = r 98 | pipeErr := errors.New("closing write end of pipe") 99 | w.CloseWithError(pipeErr) 100 | 101 | err = session.Run("true") 102 | if err != pipeErr { 103 | t.Fatalf("expected %v, found %v", pipeErr, err) 104 | } 105 | } 106 | 107 | func TestRunCommandFailed(t *testing.T) { 108 | server := newServer(t) 109 | defer server.Shutdown() 110 | conn := server.Dial(clientConfig()) 111 | defer conn.Close() 112 | 113 | session, err := conn.NewSession() 114 | if err != nil { 115 | t.Fatalf("session failed: %v", err) 116 | } 117 | defer session.Close() 118 | err = session.Run(`bash -c "kill -9 $$"`) 119 | if err == nil { 120 | t.Fatalf("session succeeded: %v", err) 121 | } 122 | } 123 | 124 | func TestRunCommandWeClosed(t *testing.T) { 125 | server := newServer(t) 126 | defer server.Shutdown() 127 | conn := server.Dial(clientConfig()) 128 | defer conn.Close() 129 | 130 | session, err := conn.NewSession() 131 | if err != nil { 132 | t.Fatalf("session failed: %v", err) 133 | } 134 | err = session.Shell() 135 | if err != nil { 136 | t.Fatalf("shell failed: %v", err) 137 | } 138 | err = session.Close() 139 | if err != nil { 140 | t.Fatalf("shell failed: %v", err) 141 | } 142 | } 143 | 144 | func TestFuncLargeRead(t *testing.T) { 145 | server := newServer(t) 146 | defer server.Shutdown() 147 | conn := server.Dial(clientConfig()) 148 | defer conn.Close() 149 | 150 | session, err := conn.NewSession() 151 | if err != nil { 152 | t.Fatalf("unable to create new session: %s", err) 153 | } 154 | 155 | stdout, err := session.StdoutPipe() 156 | if err != nil { 157 | t.Fatalf("unable to acquire stdout pipe: %s", err) 158 | } 159 | 160 | err = session.Start("dd if=/dev/urandom bs=2048 count=1024") 161 | if err != nil { 162 | t.Fatalf("unable to execute remote command: %s", err) 163 | } 164 | 165 | buf := new(bytes.Buffer) 166 | n, err := io.Copy(buf, stdout) 167 | if err != nil { 168 | t.Fatalf("error reading from remote stdout: %s", err) 169 | } 170 | 171 | if n != 2048*1024 { 172 | t.Fatalf("Expected %d bytes but read only %d from remote command", 2048, n) 173 | } 174 | } 175 | 176 | func TestKeyChange(t *testing.T) { 177 | server := newServer(t) 178 | defer server.Shutdown() 179 | conf := clientConfig() 180 | hostDB := hostKeyDB() 181 | conf.HostKeyCallback = hostDB.Check 182 | conf.RekeyThreshold = 1024 183 | conn := server.Dial(conf) 184 | defer conn.Close() 185 | 186 | for i := 0; i < 4; i++ { 187 | session, err := conn.NewSession() 188 | if err != nil { 189 | t.Fatalf("unable to create new session: %s", err) 190 | } 191 | 192 | stdout, err := session.StdoutPipe() 193 | if err != nil { 194 | t.Fatalf("unable to acquire stdout pipe: %s", err) 195 | } 196 | 197 | err = session.Start("dd if=/dev/urandom bs=1024 count=1") 198 | if err != nil { 199 | t.Fatalf("unable to execute remote command: %s", err) 200 | } 201 | buf := new(bytes.Buffer) 202 | n, err := io.Copy(buf, stdout) 203 | if err != nil { 204 | t.Fatalf("error reading from remote stdout: %s", err) 205 | } 206 | 207 | want := int64(1024) 208 | if n != want { 209 | t.Fatalf("Expected %d bytes but read only %d from remote command", want, n) 210 | } 211 | } 212 | 213 | if changes := hostDB.checkCount; changes < 4 { 214 | t.Errorf("got %d key changes, want 4", changes) 215 | } 216 | } 217 | 218 | func TestInvalidTerminalMode(t *testing.T) { 219 | server := newServer(t) 220 | defer server.Shutdown() 221 | conn := server.Dial(clientConfig()) 222 | defer conn.Close() 223 | 224 | session, err := conn.NewSession() 225 | if err != nil { 226 | t.Fatalf("session failed: %v", err) 227 | } 228 | defer session.Close() 229 | 230 | if err = session.RequestPty("vt100", 80, 40, ssh.TerminalModes{255: 1984}); err == nil { 231 | t.Fatalf("req-pty failed: successful request with invalid mode") 232 | } 233 | } 234 | 235 | func TestValidTerminalMode(t *testing.T) { 236 | server := newServer(t) 237 | defer server.Shutdown() 238 | conn := server.Dial(clientConfig()) 239 | defer conn.Close() 240 | 241 | session, err := conn.NewSession() 242 | if err != nil { 243 | t.Fatalf("session failed: %v", err) 244 | } 245 | defer session.Close() 246 | 247 | stdout, err := session.StdoutPipe() 248 | if err != nil { 249 | t.Fatalf("unable to acquire stdout pipe: %s", err) 250 | } 251 | 252 | stdin, err := session.StdinPipe() 253 | if err != nil { 254 | t.Fatalf("unable to acquire stdin pipe: %s", err) 255 | } 256 | 257 | tm := ssh.TerminalModes{ssh.ECHO: 0} 258 | if err = session.RequestPty("xterm", 80, 40, tm); err != nil { 259 | t.Fatalf("req-pty failed: %s", err) 260 | } 261 | 262 | err = session.Shell() 263 | if err != nil { 264 | t.Fatalf("session failed: %s", err) 265 | } 266 | 267 | stdin.Write([]byte("stty -a && exit\n")) 268 | 269 | var buf bytes.Buffer 270 | if _, err := io.Copy(&buf, stdout); err != nil { 271 | t.Fatalf("reading failed: %s", err) 272 | } 273 | 274 | if sttyOutput := buf.String(); !strings.Contains(sttyOutput, "-echo ") { 275 | t.Fatalf("terminal mode failure: expected -echo in stty output, got %s", sttyOutput) 276 | } 277 | } 278 | 279 | func TestCiphers(t *testing.T) { 280 | var config ssh.Config 281 | config.SetDefaults() 282 | cipherOrder := config.Ciphers 283 | 284 | for _, ciph := range cipherOrder { 285 | server := newServer(t) 286 | defer server.Shutdown() 287 | conf := clientConfig() 288 | conf.Ciphers = []string{ciph} 289 | // Don't fail if sshd doesnt have the cipher. 290 | conf.Ciphers = append(conf.Ciphers, cipherOrder...) 291 | conn, err := server.TryDial(conf) 292 | if err == nil { 293 | conn.Close() 294 | } else { 295 | t.Fatalf("failed for cipher %q", ciph) 296 | } 297 | } 298 | } 299 | 300 | func TestMACs(t *testing.T) { 301 | var config ssh.Config 302 | config.SetDefaults() 303 | macOrder := config.MACs 304 | 305 | for _, mac := range macOrder { 306 | server := newServer(t) 307 | defer server.Shutdown() 308 | conf := clientConfig() 309 | conf.MACs = []string{mac} 310 | // Don't fail if sshd doesnt have the MAC. 311 | conf.MACs = append(conf.MACs, macOrder...) 312 | if conn, err := server.TryDial(conf); err == nil { 313 | conn.Close() 314 | } else { 315 | t.Fatalf("failed for MAC %q", mac) 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/tcpip_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !windows 6 | 7 | package test 8 | 9 | // direct-tcpip functional tests 10 | 11 | import ( 12 | "io" 13 | "net" 14 | "testing" 15 | ) 16 | 17 | func TestDial(t *testing.T) { 18 | server := newServer(t) 19 | defer server.Shutdown() 20 | sshConn := server.Dial(clientConfig()) 21 | defer sshConn.Close() 22 | 23 | l, err := net.Listen("tcp", "127.0.0.1:0") 24 | if err != nil { 25 | t.Fatalf("Listen: %v", err) 26 | } 27 | defer l.Close() 28 | 29 | go func() { 30 | for { 31 | c, err := l.Accept() 32 | if err != nil { 33 | break 34 | } 35 | 36 | io.WriteString(c, c.RemoteAddr().String()) 37 | c.Close() 38 | } 39 | }() 40 | 41 | conn, err := sshConn.Dial("tcp", l.Addr().String()) 42 | if err != nil { 43 | t.Fatalf("Dial: %v", err) 44 | } 45 | defer conn.Close() 46 | } 47 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/test_unix_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux netbsd openbsd plan9 6 | 7 | package test 8 | 9 | // functional test harness for unix. 10 | 11 | import ( 12 | "bytes" 13 | "fmt" 14 | "io/ioutil" 15 | "log" 16 | "net" 17 | "os" 18 | "os/exec" 19 | "os/user" 20 | "path/filepath" 21 | "testing" 22 | "text/template" 23 | 24 | "golang.org/x/crypto/ssh" 25 | "golang.org/x/crypto/ssh/testdata" 26 | ) 27 | 28 | const sshd_config = ` 29 | Protocol 2 30 | HostKey {{.Dir}}/id_rsa 31 | HostKey {{.Dir}}/id_dsa 32 | HostKey {{.Dir}}/id_ecdsa 33 | Pidfile {{.Dir}}/sshd.pid 34 | #UsePrivilegeSeparation no 35 | KeyRegenerationInterval 3600 36 | ServerKeyBits 768 37 | SyslogFacility AUTH 38 | LogLevel DEBUG2 39 | LoginGraceTime 120 40 | PermitRootLogin no 41 | StrictModes no 42 | RSAAuthentication yes 43 | PubkeyAuthentication yes 44 | AuthorizedKeysFile {{.Dir}}/id_user.pub 45 | TrustedUserCAKeys {{.Dir}}/id_ecdsa.pub 46 | IgnoreRhosts yes 47 | RhostsRSAAuthentication no 48 | HostbasedAuthentication no 49 | ` 50 | 51 | var configTmpl = template.Must(template.New("").Parse(sshd_config)) 52 | 53 | type server struct { 54 | t *testing.T 55 | cleanup func() // executed during Shutdown 56 | configfile string 57 | cmd *exec.Cmd 58 | output bytes.Buffer // holds stderr from sshd process 59 | 60 | // Client half of the network connection. 61 | clientConn net.Conn 62 | } 63 | 64 | func username() string { 65 | var username string 66 | if user, err := user.Current(); err == nil { 67 | username = user.Username 68 | } else { 69 | // user.Current() currently requires cgo. If an error is 70 | // returned attempt to get the username from the environment. 71 | log.Printf("user.Current: %v; falling back on $USER", err) 72 | username = os.Getenv("USER") 73 | } 74 | if username == "" { 75 | panic("Unable to get username") 76 | } 77 | return username 78 | } 79 | 80 | type storedHostKey struct { 81 | // keys map from an algorithm string to binary key data. 82 | keys map[string][]byte 83 | 84 | // checkCount counts the Check calls. Used for testing 85 | // rekeying. 86 | checkCount int 87 | } 88 | 89 | func (k *storedHostKey) Add(key ssh.PublicKey) { 90 | if k.keys == nil { 91 | k.keys = map[string][]byte{} 92 | } 93 | k.keys[key.Type()] = key.Marshal() 94 | } 95 | 96 | func (k *storedHostKey) Check(addr string, remote net.Addr, key ssh.PublicKey) error { 97 | k.checkCount++ 98 | algo := key.Type() 99 | 100 | if k.keys == nil || bytes.Compare(key.Marshal(), k.keys[algo]) != 0 { 101 | return fmt.Errorf("host key mismatch. Got %q, want %q", key, k.keys[algo]) 102 | } 103 | return nil 104 | } 105 | 106 | func hostKeyDB() *storedHostKey { 107 | keyChecker := &storedHostKey{} 108 | keyChecker.Add(testPublicKeys["ecdsa"]) 109 | keyChecker.Add(testPublicKeys["rsa"]) 110 | keyChecker.Add(testPublicKeys["dsa"]) 111 | return keyChecker 112 | } 113 | 114 | func clientConfig() *ssh.ClientConfig { 115 | config := &ssh.ClientConfig{ 116 | User: username(), 117 | Auth: []ssh.AuthMethod{ 118 | ssh.PublicKeys(testSigners["user"]), 119 | }, 120 | HostKeyCallback: hostKeyDB().Check, 121 | } 122 | return config 123 | } 124 | 125 | // unixConnection creates two halves of a connected net.UnixConn. It 126 | // is used for connecting the Go SSH client with sshd without opening 127 | // ports. 128 | func unixConnection() (*net.UnixConn, *net.UnixConn, error) { 129 | dir, err := ioutil.TempDir("", "unixConnection") 130 | if err != nil { 131 | return nil, nil, err 132 | } 133 | defer os.Remove(dir) 134 | 135 | addr := filepath.Join(dir, "ssh") 136 | listener, err := net.Listen("unix", addr) 137 | if err != nil { 138 | return nil, nil, err 139 | } 140 | defer listener.Close() 141 | c1, err := net.Dial("unix", addr) 142 | if err != nil { 143 | return nil, nil, err 144 | } 145 | 146 | c2, err := listener.Accept() 147 | if err != nil { 148 | c1.Close() 149 | return nil, nil, err 150 | } 151 | 152 | return c1.(*net.UnixConn), c2.(*net.UnixConn), nil 153 | } 154 | 155 | func (s *server) TryDial(config *ssh.ClientConfig) (*ssh.Client, error) { 156 | sshd, err := exec.LookPath("sshd") 157 | if err != nil { 158 | s.t.Skipf("skipping test: %v", err) 159 | } 160 | 161 | c1, c2, err := unixConnection() 162 | if err != nil { 163 | s.t.Fatalf("unixConnection: %v", err) 164 | } 165 | 166 | s.cmd = exec.Command(sshd, "-f", s.configfile, "-i", "-e") 167 | f, err := c2.File() 168 | if err != nil { 169 | s.t.Fatalf("UnixConn.File: %v", err) 170 | } 171 | defer f.Close() 172 | s.cmd.Stdin = f 173 | s.cmd.Stdout = f 174 | s.cmd.Stderr = &s.output 175 | if err := s.cmd.Start(); err != nil { 176 | s.t.Fail() 177 | s.Shutdown() 178 | s.t.Fatalf("s.cmd.Start: %v", err) 179 | } 180 | s.clientConn = c1 181 | conn, chans, reqs, err := ssh.NewClientConn(c1, "", config) 182 | if err != nil { 183 | return nil, err 184 | } 185 | return ssh.NewClient(conn, chans, reqs), nil 186 | } 187 | 188 | func (s *server) Dial(config *ssh.ClientConfig) *ssh.Client { 189 | conn, err := s.TryDial(config) 190 | if err != nil { 191 | s.t.Fail() 192 | s.Shutdown() 193 | s.t.Fatalf("ssh.Client: %v", err) 194 | } 195 | return conn 196 | } 197 | 198 | func (s *server) Shutdown() { 199 | if s.cmd != nil && s.cmd.Process != nil { 200 | // Don't check for errors; if it fails it's most 201 | // likely "os: process already finished", and we don't 202 | // care about that. Use os.Interrupt, so child 203 | // processes are killed too. 204 | s.cmd.Process.Signal(os.Interrupt) 205 | s.cmd.Wait() 206 | } 207 | if s.t.Failed() { 208 | // log any output from sshd process 209 | s.t.Logf("sshd: %s", s.output.String()) 210 | } 211 | s.cleanup() 212 | } 213 | 214 | func writeFile(path string, contents []byte) { 215 | f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600) 216 | if err != nil { 217 | panic(err) 218 | } 219 | defer f.Close() 220 | if _, err := f.Write(contents); err != nil { 221 | panic(err) 222 | } 223 | } 224 | 225 | // newServer returns a new mock ssh server. 226 | func newServer(t *testing.T) *server { 227 | if testing.Short() { 228 | t.Skip("skipping test due to -short") 229 | } 230 | dir, err := ioutil.TempDir("", "sshtest") 231 | if err != nil { 232 | t.Fatal(err) 233 | } 234 | f, err := os.Create(filepath.Join(dir, "sshd_config")) 235 | if err != nil { 236 | t.Fatal(err) 237 | } 238 | err = configTmpl.Execute(f, map[string]string{ 239 | "Dir": dir, 240 | }) 241 | if err != nil { 242 | t.Fatal(err) 243 | } 244 | f.Close() 245 | 246 | for k, v := range testdata.PEMBytes { 247 | filename := "id_" + k 248 | writeFile(filepath.Join(dir, filename), v) 249 | writeFile(filepath.Join(dir, filename+".pub"), ssh.MarshalAuthorizedKey(testPublicKeys[k])) 250 | } 251 | 252 | return &server{ 253 | t: t, 254 | configfile: f.Name(), 255 | cleanup: func() { 256 | if err := os.RemoveAll(dir); err != nil { 257 | t.Error(err) 258 | } 259 | }, 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/test/testdata_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places: 6 | // ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three 7 | // instances. 8 | 9 | package test 10 | 11 | import ( 12 | "crypto/rand" 13 | "fmt" 14 | 15 | "golang.org/x/crypto/ssh" 16 | "golang.org/x/crypto/ssh/testdata" 17 | ) 18 | 19 | var ( 20 | testPrivateKeys map[string]interface{} 21 | testSigners map[string]ssh.Signer 22 | testPublicKeys map[string]ssh.PublicKey 23 | ) 24 | 25 | func init() { 26 | var err error 27 | 28 | n := len(testdata.PEMBytes) 29 | testPrivateKeys = make(map[string]interface{}, n) 30 | testSigners = make(map[string]ssh.Signer, n) 31 | testPublicKeys = make(map[string]ssh.PublicKey, n) 32 | for t, k := range testdata.PEMBytes { 33 | testPrivateKeys[t], err = ssh.ParseRawPrivateKey(k) 34 | if err != nil { 35 | panic(fmt.Sprintf("Unable to parse test key %s: %v", t, err)) 36 | } 37 | testSigners[t], err = ssh.NewSignerFromKey(testPrivateKeys[t]) 38 | if err != nil { 39 | panic(fmt.Sprintf("Unable to create signer for test key %s: %v", t, err)) 40 | } 41 | testPublicKeys[t] = testSigners[t].PublicKey() 42 | } 43 | 44 | // Create a cert and sign it for use in tests. 45 | testCert := &ssh.Certificate{ 46 | Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil 47 | ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage 48 | ValidAfter: 0, // unix epoch 49 | ValidBefore: ssh.CertTimeInfinity, // The end of currently representable time. 50 | Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil 51 | Key: testPublicKeys["ecdsa"], 52 | SignatureKey: testPublicKeys["rsa"], 53 | Permissions: ssh.Permissions{ 54 | CriticalOptions: map[string]string{}, 55 | Extensions: map[string]string{}, 56 | }, 57 | } 58 | testCert.SignCert(rand.Reader, testSigners["rsa"]) 59 | testPrivateKeys["cert"] = testPrivateKeys["ecdsa"] 60 | testSigners["cert"], err = ssh.NewCertSigner(testCert, testSigners["ecdsa"]) 61 | if err != nil { 62 | panic(fmt.Sprintf("Unable to create certificate signer: %v", err)) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This package contains test data shared between the various subpackages of 6 | // the code.google.com/p/go.crypto/ssh package. Under no circumstance should 7 | // this data be used for production code. 8 | package testdata // import "golang.org/x/crypto/ssh/testdata" 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/keys.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package testdata 6 | 7 | var PEMBytes = map[string][]byte{ 8 | "dsa": []byte(`-----BEGIN DSA PRIVATE KEY----- 9 | MIIBuwIBAAKBgQD6PDSEyXiI9jfNs97WuM46MSDCYlOqWw80ajN16AohtBncs1YB 10 | lHk//dQOvCYOsYaE+gNix2jtoRjwXhDsc25/IqQbU1ahb7mB8/rsaILRGIbA5WH3 11 | EgFtJmXFovDz3if6F6TzvhFpHgJRmLYVR8cqsezL3hEZOvvs2iH7MorkxwIVAJHD 12 | nD82+lxh2fb4PMsIiaXudAsBAoGAQRf7Q/iaPRn43ZquUhd6WwvirqUj+tkIu6eV 13 | 2nZWYmXLlqFQKEy4Tejl7Wkyzr2OSYvbXLzo7TNxLKoWor6ips0phYPPMyXld14r 14 | juhT24CrhOzuLMhDduMDi032wDIZG4Y+K7ElU8Oufn8Sj5Wge8r6ANmmVgmFfynr 15 | FhdYCngCgYEA3ucGJ93/Mx4q4eKRDxcWD3QzWyqpbRVRRV1Vmih9Ha/qC994nJFz 16 | DQIdjxDIT2Rk2AGzMqFEB68Zc3O+Wcsmz5eWWzEwFxaTwOGWTyDqsDRLm3fD+QYj 17 | nOwuxb0Kce+gWI8voWcqC9cyRm09jGzu2Ab3Bhtpg8JJ8L7gS3MRZK4CFEx4UAfY 18 | Fmsr0W6fHB9nhS4/UXM8 19 | -----END DSA PRIVATE KEY----- 20 | `), 21 | "ecdsa": []byte(`-----BEGIN EC PRIVATE KEY----- 22 | MHcCAQEEINGWx0zo6fhJ/0EAfrPzVFyFC9s18lBt3cRoEDhS3ARooAoGCCqGSM49 23 | AwEHoUQDQgAEi9Hdw6KvZcWxfg2IDhA7UkpDtzzt6ZqJXSsFdLd+Kx4S3Sx4cVO+ 24 | 6/ZOXRnPmNAlLUqjShUsUBBngG0u2fqEqA== 25 | -----END EC PRIVATE KEY----- 26 | `), 27 | "rsa": []byte(`-----BEGIN RSA PRIVATE KEY----- 28 | MIIBOwIBAAJBALdGZxkXDAjsYk10ihwU6Id2KeILz1TAJuoq4tOgDWxEEGeTrcld 29 | r/ZwVaFzjWzxaf6zQIJbfaSEAhqD5yo72+sCAwEAAQJBAK8PEVU23Wj8mV0QjwcJ 30 | tZ4GcTUYQL7cF4+ezTCE9a1NrGnCP2RuQkHEKxuTVrxXt+6OF15/1/fuXnxKjmJC 31 | nxkCIQDaXvPPBi0c7vAxGwNY9726x01/dNbHCE0CBtcotobxpwIhANbbQbh3JHVW 32 | 2haQh4fAG5mhesZKAGcxTyv4mQ7uMSQdAiAj+4dzMpJWdSzQ+qGHlHMIBvVHLkqB 33 | y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr 34 | rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg== 35 | -----END RSA PRIVATE KEY----- 36 | `), 37 | "user": []byte(`-----BEGIN EC PRIVATE KEY----- 38 | MHcCAQEEILYCAeq8f7V4vSSypRw7pxy8yz3V5W4qg8kSC3zJhqpQoAoGCCqGSM49 39 | AwEHoUQDQgAEYcO2xNKiRUYOLEHM7VYAp57HNyKbOdYtHD83Z4hzNPVC4tM5mdGD 40 | PLL8IEwvYu2wq+lpXfGQnNMbzYf9gspG0w== 41 | -----END EC PRIVATE KEY----- 42 | `), 43 | } 44 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places: 6 | // ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three 7 | // instances. 8 | 9 | package ssh 10 | 11 | import ( 12 | "crypto/rand" 13 | "fmt" 14 | 15 | "golang.org/x/crypto/ssh/testdata" 16 | ) 17 | 18 | var ( 19 | testPrivateKeys map[string]interface{} 20 | testSigners map[string]Signer 21 | testPublicKeys map[string]PublicKey 22 | ) 23 | 24 | func init() { 25 | var err error 26 | 27 | n := len(testdata.PEMBytes) 28 | testPrivateKeys = make(map[string]interface{}, n) 29 | testSigners = make(map[string]Signer, n) 30 | testPublicKeys = make(map[string]PublicKey, n) 31 | for t, k := range testdata.PEMBytes { 32 | testPrivateKeys[t], err = ParseRawPrivateKey(k) 33 | if err != nil { 34 | panic(fmt.Sprintf("Unable to parse test key %s: %v", t, err)) 35 | } 36 | testSigners[t], err = NewSignerFromKey(testPrivateKeys[t]) 37 | if err != nil { 38 | panic(fmt.Sprintf("Unable to create signer for test key %s: %v", t, err)) 39 | } 40 | testPublicKeys[t] = testSigners[t].PublicKey() 41 | } 42 | 43 | // Create a cert and sign it for use in tests. 44 | testCert := &Certificate{ 45 | Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil 46 | ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage 47 | ValidAfter: 0, // unix epoch 48 | ValidBefore: CertTimeInfinity, // The end of currently representable time. 49 | Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil 50 | Key: testPublicKeys["ecdsa"], 51 | SignatureKey: testPublicKeys["rsa"], 52 | Permissions: Permissions{ 53 | CriticalOptions: map[string]string{}, 54 | Extensions: map[string]string{}, 55 | }, 56 | } 57 | testCert.SignCert(rand.Reader, testSigners["rsa"]) 58 | testPrivateKeys["cert"] = testPrivateKeys["ecdsa"] 59 | testSigners["cert"], err = NewCertSigner(testCert, testSigners["ecdsa"]) 60 | if err != nil { 61 | panic(fmt.Sprintf("Unable to create certificate signer: %v", err)) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/golang.org/x/crypto/ssh/transport_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "bytes" 9 | "crypto/rand" 10 | "encoding/binary" 11 | "strings" 12 | "testing" 13 | ) 14 | 15 | func TestReadVersion(t *testing.T) { 16 | longversion := strings.Repeat("SSH-2.0-bla", 50)[:253] 17 | cases := map[string]string{ 18 | "SSH-2.0-bla\r\n": "SSH-2.0-bla", 19 | "SSH-2.0-bla\n": "SSH-2.0-bla", 20 | longversion + "\r\n": longversion, 21 | } 22 | 23 | for in, want := range cases { 24 | result, err := readVersion(bytes.NewBufferString(in)) 25 | if err != nil { 26 | t.Errorf("readVersion(%q): %s", in, err) 27 | } 28 | got := string(result) 29 | if got != want { 30 | t.Errorf("got %q, want %q", got, want) 31 | } 32 | } 33 | } 34 | 35 | func TestReadVersionError(t *testing.T) { 36 | longversion := strings.Repeat("SSH-2.0-bla", 50)[:253] 37 | cases := []string{ 38 | longversion + "too-long\r\n", 39 | } 40 | for _, in := range cases { 41 | if _, err := readVersion(bytes.NewBufferString(in)); err == nil { 42 | t.Errorf("readVersion(%q) should have failed", in) 43 | } 44 | } 45 | } 46 | 47 | func TestExchangeVersionsBasic(t *testing.T) { 48 | v := "SSH-2.0-bla" 49 | buf := bytes.NewBufferString(v + "\r\n") 50 | them, err := exchangeVersions(buf, []byte("xyz")) 51 | if err != nil { 52 | t.Errorf("exchangeVersions: %v", err) 53 | } 54 | 55 | if want := "SSH-2.0-bla"; string(them) != want { 56 | t.Errorf("got %q want %q for our version", them, want) 57 | } 58 | } 59 | 60 | func TestExchangeVersions(t *testing.T) { 61 | cases := []string{ 62 | "not\x000allowed", 63 | "not allowed\n", 64 | } 65 | for _, c := range cases { 66 | buf := bytes.NewBufferString("SSH-2.0-bla\r\n") 67 | if _, err := exchangeVersions(buf, []byte(c)); err == nil { 68 | t.Errorf("exchangeVersions(%q): should have failed", c) 69 | } 70 | } 71 | } 72 | 73 | type closerBuffer struct { 74 | bytes.Buffer 75 | } 76 | 77 | func (b *closerBuffer) Close() error { 78 | return nil 79 | } 80 | 81 | func TestTransportMaxPacketWrite(t *testing.T) { 82 | buf := &closerBuffer{} 83 | tr := newTransport(buf, rand.Reader, true) 84 | huge := make([]byte, maxPacket+1) 85 | err := tr.writePacket(huge) 86 | if err == nil { 87 | t.Errorf("transport accepted write for a huge packet.") 88 | } 89 | } 90 | 91 | func TestTransportMaxPacketReader(t *testing.T) { 92 | var header [5]byte 93 | huge := make([]byte, maxPacket+128) 94 | binary.BigEndian.PutUint32(header[0:], uint32(len(huge))) 95 | // padding. 96 | header[4] = 0 97 | 98 | buf := &closerBuffer{} 99 | buf.Write(header[:]) 100 | buf.Write(huge) 101 | 102 | tr := newTransport(buf, rand.Reader, true) 103 | _, err := tr.readPacket() 104 | if err == nil { 105 | t.Errorf("transport succeeded reading huge packet.") 106 | } else if !strings.Contains(err.Error(), "large") { 107 | t.Errorf("got %q, should mention %q", err.Error(), "large") 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Matt Bostock 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SSH key checker 2 | 3 | A small SSH server written in Go that checks any public keys 4 | presented to it for: 5 | 6 | - [known weak keys][] vulnerable to the [Debian PRNG bug][] 7 | - potentially weak key lengths, e.g. 1024-bit RSA keys 8 | - DSA (ssh-dss) keys, which [OpenSSH no longer supports by default][] 9 | 10 | The results are output back to the user over the SSH session. 11 | 12 | ## Example output 13 | 14 | ``` 15 | $ ssh keycheck.mattbostock.com 16 | This server checks your SSH public keys for known or potential 17 | security weaknesses. 18 | 19 | For more information, please see: 20 | https://github.com/mattbostock/sshkeycheck 21 | 22 | The public keys presented by your SSH client are: 23 | 24 | Bits Type Fingerprint Issues 25 | 4096 ssh-rsa ed:9a:d2:5d:7b:c0:e5:cf:b9:bc:5c:6b:ce:3a:db:20 No known issues 26 | 1024 ssh-dss 4a:0d:9b:b7:92:ba:0a:93:2a:2f:27:d7:58:73:74:91 DSA KEY 27 | 384 ecdsa-sha2-nistp384 d8:99:74:7a:0b:d0:e0:be:d0:b1:93:ee:ee:0f:b5:a4 No known issues 28 | 29 | WARNING: You are using DSA (ssh-dss) key(s), which are no longer supported by 30 | default in OpenSSH 7.0 and above. 31 | Consider replacing them with a new RSA or ECDSA key. 32 | 33 | Connection to keycheck.mattbostock.com closed. 34 | ``` 35 | 36 | ## Inspiration 37 | 38 | This toy project is heavily inspired by [Filippo Valsorda][]'s [whosthere][] server, 39 | which infers your name from the SSH public keys associated with your GitHub account. 40 | 41 | I wanted to provide an easy way for anyone to check if the SSH key they are using 42 | is reasonably secure, in so far as we can define 'secure' from the key length 43 | and from lists of known weak keys. 44 | 45 | Kudos to [Ben Cox][] for raising awareness of [weak SSH keys on GitHub][]. 46 | 47 | ## Disclaimer 48 | 49 | I'm not a cryptographer, nor am I an expert in SSH. Use at your own risk and discretion. 50 | 51 | If you spot any problems, please raise an issue. Pull requests are also welcome. 52 | 53 | [known weak keys]: https://github.com/g0tmi1k/debian-ssh 54 | [Debian PRNG bug]: https://www.debian.org/security/2008/dsa-1571 55 | [Filippo Valsorda]: https://twitter.com/FiloSottile 56 | [whosthere]: https://github.com/FiloSottile/whosthere 57 | [Ben Cox]: https://twitter.com/Benjojo12 58 | [weak SSH keys on GitHub]: https://blog.benjojo.co.uk/post/auditing-github-users-keys 59 | [OpenSSH no longer supports by default]: http://www.openssh.com/txt/release-7.0 60 | -------------------------------------------------------------------------------- /blacklist.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "io/ioutil" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | 11 | "golang.org/x/crypto/ssh" 12 | ) 13 | 14 | const blacklistPath = "blacklist" 15 | 16 | var blacklist = make(map[string]bool) 17 | 18 | func loadBlacklistedKeys() { 19 | files, err := ioutil.ReadDir(blacklistPath) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | 24 | for _, f := range files { 25 | if f.IsDir() { 26 | log.Fatalf("Subdirectories not supported in %q directory\n", blacklistPath) 27 | } 28 | 29 | file, err := os.Open(filepath.Join(blacklistPath, f.Name())) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | defer file.Close() 34 | 35 | scanner := bufio.NewScanner(file) 36 | for scanner.Scan() { 37 | key := strings.TrimSpace(scanner.Text()) 38 | blacklist[key] = true 39 | } 40 | 41 | if err := scanner.Err(); err != nil { 42 | log.Fatal(err) 43 | } 44 | } 45 | 46 | return 47 | } 48 | 49 | func markBlacklistedKeys(keys []*publicKey) { 50 | 51 | for _, k := range keys { 52 | key := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(k.key))) 53 | if blacklist[key] { 54 | k.blacklisted = true 55 | } 56 | } 57 | 58 | return 59 | } 60 | -------------------------------------------------------------------------------- /key.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/md5" 7 | "errors" 8 | "fmt" 9 | "math/big" 10 | "strings" 11 | 12 | "golang.org/x/crypto/ssh" 13 | ) 14 | 15 | type publicKey struct { 16 | key ssh.PublicKey 17 | blacklisted bool 18 | } 19 | 20 | func (p *publicKey) BitLen() (int, error) { 21 | var ( 22 | length int 23 | err error 24 | ) 25 | 26 | switch p.key.Type() { 27 | case ssh.KeyAlgoRSA: 28 | length, err = rsaKeyLength(p.key) 29 | case ssh.KeyAlgoDSA: 30 | length, err = dsaKeyLength(p.key) 31 | case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521: 32 | length, err = ecdsaKeyLength(p.key) 33 | default: 34 | err = errors.New("Key type not supported: " + p.key.Type()) 35 | } 36 | 37 | return length, err 38 | } 39 | 40 | func (p *publicKey) Fingerprint() string { 41 | return md5HexString(md5.Sum(p.key.Marshal())) 42 | } 43 | 44 | func rsaKeyLength(key ssh.PublicKey) (int, error) { 45 | var w struct { 46 | Name string 47 | E *big.Int 48 | N *big.Int 49 | Rest []byte `ssh:"rest"` 50 | } 51 | 52 | err := ssh.Unmarshal(key.Marshal(), &w) 53 | if err != nil { 54 | return 0, err 55 | } 56 | 57 | return w.N.BitLen(), nil 58 | } 59 | 60 | func dsaKeyLength(key ssh.PublicKey) (int, error) { 61 | var w struct { 62 | Name string 63 | P, Q, G, Y *big.Int 64 | Rest []byte `ssh:"rest"` 65 | } 66 | err := ssh.Unmarshal(key.Marshal(), &w) 67 | if err != nil { 68 | return 0, err 69 | } 70 | 71 | return w.P.BitLen(), nil 72 | } 73 | 74 | func ecdsaKeyLength(key ssh.PublicKey) (int, error) { 75 | var w struct { 76 | Name string 77 | Curve string 78 | KeyBytes []byte 79 | Rest []byte `ssh:"rest"` 80 | } 81 | 82 | err := ssh.Unmarshal(key.Marshal(), &w) 83 | if err != nil { 84 | return 0, err 85 | } 86 | 87 | k := new(ecdsa.PublicKey) 88 | switch w.Curve { 89 | case "nistp256": 90 | k.Curve = elliptic.P256() 91 | case "nistp384": 92 | k.Curve = elliptic.P384() 93 | case "nistp521": 94 | k.Curve = elliptic.P521() 95 | default: 96 | return 0, fmt.Errorf("ECSDA curve not supported: %q", w.Curve) 97 | } 98 | 99 | k.X, k.Y = elliptic.Unmarshal(k.Curve, w.KeyBytes) 100 | if k.X == nil || k.Y == nil { 101 | return 0, fmt.Errorf("ECDSA X or Y points were nil: %q, %q", k.X, k.Y) 102 | } 103 | 104 | return k.Params().BitSize, nil 105 | } 106 | 107 | // md5HexString returns a formatted string representing the given md5 sum in hex 108 | func md5HexString(md5 [16]byte) (s string) { 109 | s = fmt.Sprintf("% x", md5) 110 | s = strings.Replace(s, " ", ":", -1) 111 | return s 112 | } 113 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net" 5 | "os" 6 | 7 | log "github.com/Sirupsen/logrus" 8 | "golang.org/x/crypto/ssh" 9 | ) 10 | 11 | func main() { 12 | log.SetOutput(os.Stderr) 13 | 14 | config := &ssh.ServerConfig{ 15 | KeyboardInteractiveCallback: keyboardInteractiveCallback, 16 | PublicKeyCallback: publicKeyCallback, 17 | } 18 | 19 | loadBlacklistedKeys() 20 | 21 | private, err := ssh.ParsePrivateKey([]byte(os.Getenv("HOST_PRIVATE_KEY"))) 22 | if err != nil { 23 | log.Fatalln("Failed to parse host private key") 24 | } 25 | config.AddHostKey(private) 26 | 27 | addr := os.Getenv("ADDR") 28 | if addr == "" { 29 | addr = "localhost:2022" 30 | } 31 | 32 | listener, err := net.Listen("tcp", addr) 33 | if err != nil { 34 | log.Fatalf("Failed to listen for connection on %s, perhaps that port is already in use", addr) 35 | } 36 | 37 | log.Infoln("Listening on", addr) 38 | 39 | for { 40 | conn, err := listener.Accept() 41 | if err != nil { 42 | log.Warnln("Accept failed:", err) 43 | continue 44 | } 45 | 46 | go serve(config, conn) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "net" 8 | "strings" 9 | "sync" 10 | "text/tabwriter" 11 | "time" 12 | 13 | log "github.com/Sirupsen/logrus" 14 | 15 | "golang.org/x/crypto/ssh" 16 | ) 17 | 18 | var sessions = struct { 19 | mu sync.RWMutex 20 | keys map[string][]*publicKey 21 | }{ 22 | keys: make(map[string][]*publicKey), 23 | } 24 | 25 | func serve(config *ssh.ServerConfig, nConn net.Conn) { 26 | // Before use, a handshake must be performed on the incoming net.Conn 27 | conn, chans, reqs, err := ssh.NewServerConn(nConn, config) 28 | if err != nil { 29 | log.Warnln("Failed to handshake:", err) 30 | return 31 | } 32 | 33 | defer func() { 34 | sessions.mu.Lock() 35 | delete(sessions.keys, string(conn.SessionID())) 36 | sessions.mu.Unlock() 37 | conn.Close() 38 | }() 39 | 40 | // The incoming Request channel must be serviced 41 | go ssh.DiscardRequests(reqs) 42 | 43 | sessions.mu.RLock() 44 | keys := sessions.keys[string(conn.SessionID())] 45 | sessions.mu.RUnlock() 46 | 47 | // Service the incoming Channel channel 48 | for n := range chans { 49 | // Channels have a type, depending on the application level 50 | // protocol intended. In the case of a shell, the type is 51 | // "session" and ServerShell may be used to present a simple 52 | // terminal interface. 53 | if n.ChannelType() != "session" { 54 | n.Reject(ssh.UnknownChannelType, "unknown channel type") 55 | continue 56 | } 57 | 58 | channel, requests, err := n.Accept() 59 | if err != nil { 60 | log.Warnln("Could not accept channel:", err) 61 | continue 62 | } 63 | 64 | agentFwd, x11 := false, false 65 | reqLock := &sync.Mutex{} 66 | reqLock.Lock() 67 | timeout := time.AfterFunc(30*time.Second, func() { reqLock.Unlock() }) 68 | 69 | go func(in <-chan *ssh.Request) { 70 | for req := range in { 71 | ok := false 72 | switch req.Type { 73 | case "shell": 74 | fallthrough 75 | case "pty-req": 76 | ok = true 77 | 78 | // "auth-agent-req@openssh.com" and "x11-req" always arrive 79 | // before the "pty-req", so we can go ahead now 80 | if timeout.Stop() { 81 | reqLock.Unlock() 82 | } 83 | 84 | case "auth-agent-req@openssh.com": 85 | agentFwd = true 86 | case "x11-req": 87 | x11 = true 88 | } 89 | 90 | if req.WantReply { 91 | req.Reply(ok, nil) 92 | } 93 | } 94 | }(requests) 95 | 96 | markBlacklistedKeys(keys) 97 | 98 | channel.Write([]byte(welcomeMsg)) 99 | 100 | var table bytes.Buffer 101 | tabWriter := new(tabwriter.Writer) 102 | tabWriter.Init(&table, 5, 2, 2, ' ', 0) 103 | // Note that using tabwriter, columns are tab-terminated, 104 | // not tab-delimited 105 | fmt.Fprint(tabWriter, "Bits\tType\tFingerprint\tIssues\n") 106 | 107 | var issues string 108 | var blacklisted, weak, dsa bool 109 | for _, k := range keys { 110 | issues = "No known issues" 111 | length, err := k.BitLen() 112 | 113 | if err != nil { 114 | log.Errorf("Failed to determine key length for %s key: %s", k.key.Type(), err) 115 | } 116 | 117 | if k.key.Type() == ssh.KeyAlgoDSA { 118 | issues = "DSA KEY" 119 | dsa = true 120 | } 121 | 122 | if length < 2048 && k.key.Type() == ssh.KeyAlgoRSA { 123 | issues = "WEAK KEY LENGTH" 124 | weak = true 125 | } 126 | 127 | if k.blacklisted { 128 | // being blacklisted takes priority of any key length weaknesses 129 | issues = "BLACKLISTED" 130 | blacklisted = true 131 | } 132 | 133 | fmt.Fprintf(tabWriter, "%d\t%s\t%s\t%s\t\n", length, k.key.Type(), k.Fingerprint(), issues) 134 | } 135 | 136 | err = tabWriter.Flush() 137 | if err != nil { 138 | log.Errorln("Error when flushing tab writer:", err) 139 | } 140 | channel.Write([]byte( 141 | strings.Replace(table.String(), "\n", "\n\r", -1) + 142 | "\n\r")) 143 | 144 | if blacklisted { 145 | channel.Write([]byte(blacklistMsg)) 146 | } 147 | 148 | if dsa { 149 | channel.Write([]byte(dsaMsg)) 150 | } 151 | 152 | if weak { 153 | channel.Write([]byte(weakMsg)) 154 | } 155 | 156 | reqLock.Lock() 157 | if agentFwd { 158 | channel.Write([]byte(agentMsg)) 159 | } 160 | if x11 { 161 | channel.Write([]byte(x11Msg)) 162 | } 163 | 164 | // Explicitly close the channel to end the session 165 | channel.Close() 166 | } 167 | 168 | } 169 | 170 | func publicKeyCallback(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { 171 | sessions.mu.Lock() 172 | sessionID := string(conn.SessionID()) 173 | sessions.keys[sessionID] = append(sessions.keys[sessionID], &publicKey{key: key}) 174 | sessions.mu.Unlock() 175 | 176 | // Never succeed a key, or we might not see the next. See KeyboardInteractiveCallback. 177 | return nil, errors.New("") 178 | } 179 | 180 | func keyboardInteractiveCallback(ssh.ConnMetadata, ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) { 181 | // keyboard-interactive is tried when all public keys failed, and 182 | // since it's server-driven we can just pass without user 183 | // interaction to let the user in once we got all the public keys 184 | return nil, nil 185 | } 186 | 187 | var ( 188 | agentMsg = strings.Replace(`CRITICAL: SSH agent forwarding is enabled; it is dangerous to enable agent forwarding 189 | for servers you do not trust as it allows them to log in to other servers as you. 190 | 191 | `, "\n", "\n\r", -1) 192 | 193 | blacklistMsg = strings.Replace(`CRITICAL: You are using blacklisted key(s) that are known to be insecure. 194 | You should replace them immediately. 195 | See: https://www.debian.org/security/2008/dsa-1576 196 | 197 | `, "\n", "\n\r", -1) 198 | 199 | dsaMsg = strings.Replace(`WARNING: You are using DSA (ssh-dss) key(s), which are no longer supported by 200 | default in OpenSSH version 7.0 and above. 201 | Consider replacing them with a new RSA or ECDSA key. 202 | 203 | `, "\n", "\n\r", -1) 204 | 205 | weakMsg = strings.Replace(`WARNING: You are using RSA key(s) with a length of less than 2048 bits. 206 | Consider replacing them with a new key of 2048 bits or more. 207 | 208 | `, "\n", "\n\r", -1) 209 | 210 | welcomeMsg = strings.Replace(`This server checks your SSH public keys for known or potential 211 | security weaknesses. 212 | 213 | For more information, please see: 214 | https://github.com/mattbostock/sshkeycheck 215 | 216 | The public keys presented by your SSH client are: 217 | 218 | `, "\n", "\n\r", -1) 219 | 220 | x11Msg = strings.Replace(`CRITICAL: X11 forwarding is enabled; it is dangerous to allow X11 forwarding 221 | for servers you do not trust as it allows them to access your desktop. 222 | 223 | `, "\n", "\n\r", -1) 224 | ) 225 | --------------------------------------------------------------------------------