summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/couchbase/goutils
diff options
context:
space:
mode:
authortechknowlogick <matti@mdranta.net>2019-02-05 11:52:51 -0500
committerGitHub <noreply@github.com>2019-02-05 11:52:51 -0500
commit9de871a0f8911030f8e06a881803cf722b8798ea (patch)
tree206400f0a5873d7d078fcdd004956036f07a1db5 /vendor/github.com/couchbase/goutils
parentbf4badad1d68c18d7ffb92c69e09e4e8aa252935 (diff)
downloadgitea-9de871a0f8911030f8e06a881803cf722b8798ea.tar.gz
gitea-9de871a0f8911030f8e06a881803cf722b8798ea.zip
add other session providers (#5963)
Diffstat (limited to 'vendor/github.com/couchbase/goutils')
-rw-r--r--vendor/github.com/couchbase/goutils/LICENSE.md47
-rw-r--r--vendor/github.com/couchbase/goutils/logging/logger.go481
-rw-r--r--vendor/github.com/couchbase/goutils/logging/logger_golog.go318
-rw-r--r--vendor/github.com/couchbase/goutils/scramsha/scramsha.go207
-rw-r--r--vendor/github.com/couchbase/goutils/scramsha/scramsha_http.go252
5 files changed, 1305 insertions, 0 deletions
diff --git a/vendor/github.com/couchbase/goutils/LICENSE.md b/vendor/github.com/couchbase/goutils/LICENSE.md
new file mode 100644
index 0000000000..a572e246e6
--- /dev/null
+++ b/vendor/github.com/couchbase/goutils/LICENSE.md
@@ -0,0 +1,47 @@
+COUCHBASE INC. COMMUNITY EDITION LICENSE AGREEMENT
+
+IMPORTANT-READ CAREFULLY: BY CLICKING THE "I ACCEPT" BOX OR INSTALLING,
+DOWNLOADING OR OTHERWISE USING THIS SOFTWARE AND ANY ASSOCIATED
+DOCUMENTATION, YOU, ON BEHALF OF YOURSELF OR AS AN AUTHORIZED
+REPRESENTATIVE ON BEHALF OF AN ENTITY ("LICENSEE") AGREE TO ALL THE
+TERMS OF THIS COMMUNITY EDITION LICENSE AGREEMENT (THE "AGREEMENT")
+REGARDING YOUR USE OF THE SOFTWARE. YOU REPRESENT AND WARRANT THAT YOU
+HAVE FULL LEGAL AUTHORITY TO BIND THE LICENSEE TO THIS AGREEMENT. IF YOU
+DO NOT AGREE WITH ALL OF THESE TERMS, DO NOT SELECT THE "I ACCEPT" BOX
+AND DO NOT INSTALL, DOWNLOAD OR OTHERWISE USE THE SOFTWARE. THE
+EFFECTIVE DATE OF THIS AGREEMENT IS THE DATE ON WHICH YOU CLICK "I
+ACCEPT" OR OTHERWISE INSTALL, DOWNLOAD OR USE THE SOFTWARE.
+
+1. License Grant. Couchbase Inc. hereby grants Licensee, free of charge,
+the non-exclusive right to use, copy, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to
+whom the Software is furnished to do so, subject to Licensee including
+the following copyright notice in all copies or substantial portions of
+the Software:
+
+Couchbase (r) http://www.Couchbase.com Copyright 2016 Couchbase, Inc.
+
+As used in this Agreement, "Software" means the object code version of
+the applicable elastic data management server software provided by
+Couchbase Inc.
+
+2. Restrictions. Licensee will not reverse engineer, disassemble, or
+decompile the Software (except to the extent such restrictions are
+prohibited by law).
+
+3. Support. Couchbase, Inc. will provide Licensee with access to, and
+use of, the Couchbase, Inc. support forum available at the following
+URL: http://www.couchbase.org/forums/. Couchbase, Inc. may, at its
+discretion, modify, suspend or terminate support at any time upon notice
+to Licensee.
+
+4. Warranty Disclaimer and Limitation of Liability. THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+COUCHBASE INC. OR THE AUTHORS OR COPYRIGHT HOLDERS IN THE SOFTWARE BE
+LIABLE FOR ANY CLAIM, DAMAGES (IINCLUDING, WITHOUT LIMITATION, DIRECT,
+INDIRECT OR CONSEQUENTIAL DAMAGES) OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/couchbase/goutils/logging/logger.go b/vendor/github.com/couchbase/goutils/logging/logger.go
new file mode 100644
index 0000000000..b9948f9b2e
--- /dev/null
+++ b/vendor/github.com/couchbase/goutils/logging/logger.go
@@ -0,0 +1,481 @@
+// Copyright (c) 2016 Couchbase, Inc.
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions
+// and limitations under the License.
+
+package logging
+
+import (
+ "os"
+ "runtime"
+ "strings"
+ "sync"
+)
+
+type Level int
+
+const (
+ NONE = Level(iota) // Disable all logging
+ FATAL // System is in severe error state and has to abort
+ SEVERE // System is in severe error state and cannot recover reliably
+ ERROR // System is in error state but can recover and continue reliably
+ WARN // System approaching error state, or is in a correct but undesirable state
+ INFO // System-level events and status, in correct states
+ REQUEST // Request-level events, with request-specific rlevel
+ TRACE // Trace detailed system execution, e.g. function entry / exit
+ DEBUG // Debug
+)
+
+type LogEntryFormatter int
+
+const (
+ TEXTFORMATTER = LogEntryFormatter(iota)
+ JSONFORMATTER
+ KVFORMATTER
+)
+
+func (level Level) String() string {
+ return _LEVEL_NAMES[level]
+}
+
+var _LEVEL_NAMES = []string{
+ DEBUG: "DEBUG",
+ TRACE: "TRACE",
+ REQUEST: "REQUEST",
+ INFO: "INFO",
+ WARN: "WARN",
+ ERROR: "ERROR",
+ SEVERE: "SEVERE",
+ FATAL: "FATAL",
+ NONE: "NONE",
+}
+
+var _LEVEL_MAP = map[string]Level{
+ "debug": DEBUG,
+ "trace": TRACE,
+ "request": REQUEST,
+ "info": INFO,
+ "warn": WARN,
+ "error": ERROR,
+ "severe": SEVERE,
+ "fatal": FATAL,
+ "none": NONE,
+}
+
+func ParseLevel(name string) (level Level, ok bool) {
+ level, ok = _LEVEL_MAP[strings.ToLower(name)]
+ return
+}
+
+/*
+
+Pair supports logging of key-value pairs. Keys beginning with _ are
+reserved for the logger, e.g. _time, _level, _msg, and _rlevel. The
+Pair APIs are designed to avoid heap allocation and garbage
+collection.
+
+*/
+type Pairs []Pair
+type Pair struct {
+ Name string
+ Value interface{}
+}
+
+/*
+
+Map allows key-value pairs to be specified using map literals or data
+structures. For example:
+
+Errorm(msg, Map{...})
+
+Map incurs heap allocation and garbage collection, so the Pair APIs
+should be preferred.
+
+*/
+type Map map[string]interface{}
+
+// Logger provides a common interface for logging libraries
+type Logger interface {
+ /*
+ These APIs write all the given pairs in addition to standard logger keys.
+ */
+ Logp(level Level, msg string, kv ...Pair)
+
+ Debugp(msg string, kv ...Pair)
+
+ Tracep(msg string, kv ...Pair)
+
+ Requestp(rlevel Level, msg string, kv ...Pair)
+
+ Infop(msg string, kv ...Pair)
+
+ Warnp(msg string, kv ...Pair)
+
+ Errorp(msg string, kv ...Pair)
+
+ Severep(msg string, kv ...Pair)
+
+ Fatalp(msg string, kv ...Pair)
+
+ /*
+ These APIs write the fields in the given kv Map in addition to standard logger keys.
+ */
+ Logm(level Level, msg string, kv Map)
+
+ Debugm(msg string, kv Map)
+
+ Tracem(msg string, kv Map)
+
+ Requestm(rlevel Level, msg string, kv Map)
+
+ Infom(msg string, kv Map)
+
+ Warnm(msg string, kv Map)
+
+ Errorm(msg string, kv Map)
+
+ Severem(msg string, kv Map)
+
+ Fatalm(msg string, kv Map)
+
+ /*
+
+ These APIs only write _msg, _time, _level, and other logger keys. If
+ the msg contains other fields, use the Pair or Map APIs instead.
+
+ */
+ Logf(level Level, fmt string, args ...interface{})
+
+ Debugf(fmt string, args ...interface{})
+
+ Tracef(fmt string, args ...interface{})
+
+ Requestf(rlevel Level, fmt string, args ...interface{})
+
+ Infof(fmt string, args ...interface{})
+
+ Warnf(fmt string, args ...interface{})
+
+ Errorf(fmt string, args ...interface{})
+
+ Severef(fmt string, args ...interface{})
+
+ Fatalf(fmt string, args ...interface{})
+
+ /*
+ These APIs control the logging level
+ */
+
+ SetLevel(Level) // Set the logging level
+
+ Level() Level // Get the current logging level
+}
+
+var logger Logger = nil
+var curLevel Level = DEBUG // initially set to never skip
+
+var loggerMutex sync.RWMutex
+
+// All the methods below first acquire the mutex (mostly in exclusive mode)
+// and only then check if logging at the current level is enabled.
+// This introduces a fair bottleneck for those log entries that should be
+// skipped (the majority, at INFO or below levels)
+// We try to predict here if we should lock the mutex at all by caching
+// the current log level: while dynamically changing logger, there might
+// be the odd entry skipped as the new level is cached.
+// Since we seem to never change the logger, this is not an issue.
+func skipLogging(level Level) bool {
+ if logger == nil {
+ return true
+ }
+ return level > curLevel
+}
+
+func SetLogger(newLogger Logger) {
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger = newLogger
+ if logger == nil {
+ curLevel = NONE
+ } else {
+ curLevel = newLogger.Level()
+ }
+}
+
+func Logp(level Level, msg string, kv ...Pair) {
+ if skipLogging(level) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Logp(level, msg, kv...)
+}
+
+func Debugp(msg string, kv ...Pair) {
+ if skipLogging(DEBUG) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Debugp(msg, kv...)
+}
+
+func Tracep(msg string, kv ...Pair) {
+ if skipLogging(TRACE) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Tracep(msg, kv...)
+}
+
+func Requestp(rlevel Level, msg string, kv ...Pair) {
+ if skipLogging(REQUEST) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Requestp(rlevel, msg, kv...)
+}
+
+func Infop(msg string, kv ...Pair) {
+ if skipLogging(INFO) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Infop(msg, kv...)
+}
+
+func Warnp(msg string, kv ...Pair) {
+ if skipLogging(WARN) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Warnp(msg, kv...)
+}
+
+func Errorp(msg string, kv ...Pair) {
+ if skipLogging(ERROR) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Errorp(msg, kv...)
+}
+
+func Severep(msg string, kv ...Pair) {
+ if skipLogging(SEVERE) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Severep(msg, kv...)
+}
+
+func Fatalp(msg string, kv ...Pair) {
+ if skipLogging(FATAL) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Fatalp(msg, kv...)
+}
+
+func Logm(level Level, msg string, kv Map) {
+ if skipLogging(level) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Logm(level, msg, kv)
+}
+
+func Debugm(msg string, kv Map) {
+ if skipLogging(DEBUG) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Debugm(msg, kv)
+}
+
+func Tracem(msg string, kv Map) {
+ if skipLogging(TRACE) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Tracem(msg, kv)
+}
+
+func Requestm(rlevel Level, msg string, kv Map) {
+ if skipLogging(REQUEST) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Requestm(rlevel, msg, kv)
+}
+
+func Infom(msg string, kv Map) {
+ if skipLogging(INFO) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Infom(msg, kv)
+}
+
+func Warnm(msg string, kv Map) {
+ if skipLogging(WARN) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Warnm(msg, kv)
+}
+
+func Errorm(msg string, kv Map) {
+ if skipLogging(ERROR) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Errorm(msg, kv)
+}
+
+func Severem(msg string, kv Map) {
+ if skipLogging(SEVERE) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Severem(msg, kv)
+}
+
+func Fatalm(msg string, kv Map) {
+ if skipLogging(FATAL) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Fatalm(msg, kv)
+}
+
+func Logf(level Level, fmt string, args ...interface{}) {
+ if skipLogging(level) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Logf(level, fmt, args...)
+}
+
+func Debugf(fmt string, args ...interface{}) {
+ if skipLogging(DEBUG) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Debugf(fmt, args...)
+}
+
+func Tracef(fmt string, args ...interface{}) {
+ if skipLogging(TRACE) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Tracef(fmt, args...)
+}
+
+func Requestf(rlevel Level, fmt string, args ...interface{}) {
+ if skipLogging(REQUEST) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Requestf(rlevel, fmt, args...)
+}
+
+func Infof(fmt string, args ...interface{}) {
+ if skipLogging(INFO) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Infof(fmt, args...)
+}
+
+func Warnf(fmt string, args ...interface{}) {
+ if skipLogging(WARN) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Warnf(fmt, args...)
+}
+
+func Errorf(fmt string, args ...interface{}) {
+ if skipLogging(ERROR) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Errorf(fmt, args...)
+}
+
+func Severef(fmt string, args ...interface{}) {
+ if skipLogging(SEVERE) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Severef(fmt, args...)
+}
+
+func Fatalf(fmt string, args ...interface{}) {
+ if skipLogging(FATAL) {
+ return
+ }
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Fatalf(fmt, args...)
+}
+
+func SetLevel(level Level) {
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.SetLevel(level)
+ curLevel = level
+}
+
+func LogLevel() Level {
+ loggerMutex.RLock()
+ defer loggerMutex.RUnlock()
+ return logger.Level()
+}
+
+func Stackf(level Level, fmt string, args ...interface{}) {
+ if skipLogging(level) {
+ return
+ }
+ buf := make([]byte, 1<<16)
+ n := runtime.Stack(buf, false)
+ s := string(buf[0:n])
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+ logger.Logf(level, fmt, args...)
+ logger.Logf(level, s)
+}
+
+func init() {
+ logger = NewLogger(os.Stderr, INFO, TEXTFORMATTER)
+ SetLogger(logger)
+}
diff --git a/vendor/github.com/couchbase/goutils/logging/logger_golog.go b/vendor/github.com/couchbase/goutils/logging/logger_golog.go
new file mode 100644
index 0000000000..eec432a513
--- /dev/null
+++ b/vendor/github.com/couchbase/goutils/logging/logger_golog.go
@@ -0,0 +1,318 @@
+// Copyright (c) 2016 Couchbase, Inc.
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions
+// and limitations under the License.
+
+package logging
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "time"
+)
+
+type goLogger struct {
+ logger *log.Logger
+ level Level
+ entryFormatter formatter
+}
+
+const (
+ _LEVEL = "_level"
+ _MSG = "_msg"
+ _TIME = "_time"
+ _RLEVEL = "_rlevel"
+)
+
+func NewLogger(out io.Writer, lvl Level, fmtLogging LogEntryFormatter) *goLogger {
+ logger := &goLogger{
+ logger: log.New(out, "", 0),
+ level: lvl,
+ }
+ if fmtLogging == JSONFORMATTER {
+ logger.entryFormatter = &jsonFormatter{}
+ } else if fmtLogging == KVFORMATTER {
+ logger.entryFormatter = &keyvalueFormatter{}
+ } else {
+ logger.entryFormatter = &textFormatter{}
+ }
+ return logger
+}
+
+func (gl *goLogger) Logp(level Level, msg string, kv ...Pair) {
+ if gl.logger == nil {
+ return
+ }
+ if level <= gl.level {
+ e := newLogEntry(msg, level)
+ copyPairs(e, kv)
+ gl.log(e)
+ }
+}
+
+func (gl *goLogger) Debugp(msg string, kv ...Pair) {
+ gl.Logp(DEBUG, msg, kv...)
+}
+
+func (gl *goLogger) Tracep(msg string, kv ...Pair) {
+ gl.Logp(TRACE, msg, kv...)
+}
+
+func (gl *goLogger) Requestp(rlevel Level, msg string, kv ...Pair) {
+ if gl.logger == nil {
+ return
+ }
+ if REQUEST <= gl.level {
+ e := newLogEntry(msg, REQUEST)
+ e.Rlevel = rlevel
+ copyPairs(e, kv)
+ gl.log(e)
+ }
+}
+
+func (gl *goLogger) Infop(msg string, kv ...Pair) {
+ gl.Logp(INFO, msg, kv...)
+}
+
+func (gl *goLogger) Warnp(msg string, kv ...Pair) {
+ gl.Logp(WARN, msg, kv...)
+}
+
+func (gl *goLogger) Errorp(msg string, kv ...Pair) {
+ gl.Logp(ERROR, msg, kv...)
+}
+
+func (gl *goLogger) Severep(msg string, kv ...Pair) {
+ gl.Logp(SEVERE, msg, kv...)
+}
+
+func (gl *goLogger) Fatalp(msg string, kv ...Pair) {
+ gl.Logp(FATAL, msg, kv...)
+}
+
+func (gl *goLogger) Logm(level Level, msg string, kv Map) {
+ if gl.logger == nil {
+ return
+ }
+ if level <= gl.level {
+ e := newLogEntry(msg, level)
+ e.Data = kv
+ gl.log(e)
+ }
+}
+
+func (gl *goLogger) Debugm(msg string, kv Map) {
+ gl.Logm(DEBUG, msg, kv)
+}
+
+func (gl *goLogger) Tracem(msg string, kv Map) {
+ gl.Logm(TRACE, msg, kv)
+}
+
+func (gl *goLogger) Requestm(rlevel Level, msg string, kv Map) {
+ if gl.logger == nil {
+ return
+ }
+ if REQUEST <= gl.level {
+ e := newLogEntry(msg, REQUEST)
+ e.Rlevel = rlevel
+ e.Data = kv
+ gl.log(e)
+ }
+}
+
+func (gl *goLogger) Infom(msg string, kv Map) {
+ gl.Logm(INFO, msg, kv)
+}
+
+func (gl *goLogger) Warnm(msg string, kv Map) {
+ gl.Logm(WARN, msg, kv)
+}
+
+func (gl *goLogger) Errorm(msg string, kv Map) {
+ gl.Logm(ERROR, msg, kv)
+}
+
+func (gl *goLogger) Severem(msg string, kv Map) {
+ gl.Logm(SEVERE, msg, kv)
+}
+
+func (gl *goLogger) Fatalm(msg string, kv Map) {
+ gl.Logm(FATAL, msg, kv)
+}
+
+func (gl *goLogger) Logf(level Level, format string, args ...interface{}) {
+ if gl.logger == nil {
+ return
+ }
+ if level <= gl.level {
+ e := newLogEntry(fmt.Sprintf(format, args...), level)
+ gl.log(e)
+ }
+}
+
+func (gl *goLogger) Debugf(format string, args ...interface{}) {
+ gl.Logf(DEBUG, format, args...)
+}
+
+func (gl *goLogger) Tracef(format string, args ...interface{}) {
+ gl.Logf(TRACE, format, args...)
+}
+
+func (gl *goLogger) Requestf(rlevel Level, format string, args ...interface{}) {
+ if gl.logger == nil {
+ return
+ }
+ if REQUEST <= gl.level {
+ e := newLogEntry(fmt.Sprintf(format, args...), REQUEST)
+ e.Rlevel = rlevel
+ gl.log(e)
+ }
+}
+
+func (gl *goLogger) Infof(format string, args ...interface{}) {
+ gl.Logf(INFO, format, args...)
+}
+
+func (gl *goLogger) Warnf(format string, args ...interface{}) {
+ gl.Logf(WARN, format, args...)
+}
+
+func (gl *goLogger) Errorf(format string, args ...interface{}) {
+ gl.Logf(ERROR, format, args...)
+}
+
+func (gl *goLogger) Severef(format string, args ...interface{}) {
+ gl.Logf(SEVERE, format, args...)
+}
+
+func (gl *goLogger) Fatalf(format string, args ...interface{}) {
+ gl.Logf(FATAL, format, args...)
+}
+
+func (gl *goLogger) Level() Level {
+ return gl.level
+}
+
+func (gl *goLogger) SetLevel(level Level) {
+ gl.level = level
+}
+
+func (gl *goLogger) log(newEntry *logEntry) {
+ s := gl.entryFormatter.format(newEntry)
+ gl.logger.Print(s)
+}
+
+type logEntry struct {
+ Time string
+ Level Level
+ Rlevel Level
+ Message string
+ Data Map
+}
+
+func newLogEntry(msg string, level Level) *logEntry {
+ return &logEntry{
+ Time: time.Now().Format("2006-01-02T15:04:05.000-07:00"), // time.RFC3339 with milliseconds
+ Level: level,
+ Rlevel: NONE,
+ Message: msg,
+ }
+}
+
+func copyPairs(newEntry *logEntry, pairs []Pair) {
+ newEntry.Data = make(Map, len(pairs))
+ for _, p := range pairs {
+ newEntry.Data[p.Name] = p.Value
+ }
+}
+
+type formatter interface {
+ format(*logEntry) string
+}
+
+type textFormatter struct {
+}
+
+// ex. 2016-02-10T09:15:25.498-08:00 [INFO] This is a message from test in text format
+
+func (*textFormatter) format(newEntry *logEntry) string {
+ b := &bytes.Buffer{}
+ appendValue(b, newEntry.Time)
+ if newEntry.Rlevel != NONE {
+ fmt.Fprintf(b, "[%s,%s] ", newEntry.Level.String(), newEntry.Rlevel.String())
+ } else {
+ fmt.Fprintf(b, "[%s] ", newEntry.Level.String())
+ }
+ appendValue(b, newEntry.Message)
+ for key, value := range newEntry.Data {
+ appendKeyValue(b, key, value)
+ }
+ b.WriteByte('\n')
+ s := bytes.NewBuffer(b.Bytes())
+ return s.String()
+}
+
+func appendValue(b *bytes.Buffer, value interface{}) {
+ if _, ok := value.(string); ok {
+ fmt.Fprintf(b, "%s ", value)
+ } else {
+ fmt.Fprintf(b, "%v ", value)
+ }
+}
+
+type keyvalueFormatter struct {
+}
+
+// ex. _time=2016-02-10T09:15:25.498-08:00 _level=INFO _msg=This is a message from test in key-value format
+
+func (*keyvalueFormatter) format(newEntry *logEntry) string {
+ b := &bytes.Buffer{}
+ appendKeyValue(b, _TIME, newEntry.Time)
+ appendKeyValue(b, _LEVEL, newEntry.Level.String())
+ if newEntry.Rlevel != NONE {
+ appendKeyValue(b, _RLEVEL, newEntry.Rlevel.String())
+ }
+ appendKeyValue(b, _MSG, newEntry.Message)
+ for key, value := range newEntry.Data {
+ appendKeyValue(b, key, value)
+ }
+ b.WriteByte('\n')
+ s := bytes.NewBuffer(b.Bytes())
+ return s.String()
+}
+
+func appendKeyValue(b *bytes.Buffer, key, value interface{}) {
+ if _, ok := value.(string); ok {
+ fmt.Fprintf(b, "%v=%s ", key, value)
+ } else {
+ fmt.Fprintf(b, "%v=%v ", key, value)
+ }
+}
+
+type jsonFormatter struct {
+}
+
+// ex. {"_level":"INFO","_msg":"This is a message from test in json format","_time":"2016-02-10T09:12:59.518-08:00"}
+
+func (*jsonFormatter) format(newEntry *logEntry) string {
+ if newEntry.Data == nil {
+ newEntry.Data = make(Map, 5)
+ }
+ newEntry.Data[_TIME] = newEntry.Time
+ newEntry.Data[_LEVEL] = newEntry.Level.String()
+ if newEntry.Rlevel != NONE {
+ newEntry.Data[_RLEVEL] = newEntry.Rlevel.String()
+ }
+ newEntry.Data[_MSG] = newEntry.Message
+ serialized, _ := json.Marshal(newEntry.Data)
+ s := bytes.NewBuffer(append(serialized, '\n'))
+ return s.String()
+}
diff --git a/vendor/github.com/couchbase/goutils/scramsha/scramsha.go b/vendor/github.com/couchbase/goutils/scramsha/scramsha.go
new file mode 100644
index 0000000000..b234bfc8a9
--- /dev/null
+++ b/vendor/github.com/couchbase/goutils/scramsha/scramsha.go
@@ -0,0 +1,207 @@
+// @author Couchbase <info@couchbase.com>
+// @copyright 2018 Couchbase, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package scramsha provides implementation of client side SCRAM-SHA
+// according to https://tools.ietf.org/html/rfc5802
+package scramsha
+
+import (
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "encoding/base64"
+ "fmt"
+ "github.com/pkg/errors"
+ "golang.org/x/crypto/pbkdf2"
+ "hash"
+ "strconv"
+ "strings"
+)
+
+func hmacHash(message []byte, secret []byte, hashFunc func() hash.Hash) []byte {
+ h := hmac.New(hashFunc, secret)
+ h.Write(message)
+ return h.Sum(nil)
+}
+
+func shaHash(message []byte, hashFunc func() hash.Hash) []byte {
+ h := hashFunc()
+ h.Write(message)
+ return h.Sum(nil)
+}
+
+func generateClientNonce(size int) (string, error) {
+ randomBytes := make([]byte, size)
+ _, err := rand.Read(randomBytes)
+ if err != nil {
+ return "", errors.Wrap(err, "Unable to generate nonce")
+ }
+ return base64.StdEncoding.EncodeToString(randomBytes), nil
+}
+
+// ScramSha provides context for SCRAM-SHA handling
+type ScramSha struct {
+ hashSize int
+ hashFunc func() hash.Hash
+ clientNonce string
+ serverNonce string
+ salt []byte
+ i int
+ saltedPassword []byte
+ authMessage string
+}
+
+var knownMethods = []string{"SCRAM-SHA512", "SCRAM-SHA256", "SCRAM-SHA1"}
+
+// BestMethod returns SCRAM-SHA method we consider the best out of suggested
+// by server
+func BestMethod(methods string) (string, error) {
+ for _, m := range knownMethods {
+ if strings.Index(methods, m) != -1 {
+ return m, nil
+ }
+ }
+ return "", errors.Errorf(
+ "None of the server suggested methods [%s] are supported",
+ methods)
+}
+
+// NewScramSha creates context for SCRAM-SHA handling
+func NewScramSha(method string) (*ScramSha, error) {
+ s := &ScramSha{}
+
+ if method == knownMethods[0] {
+ s.hashFunc = sha512.New
+ s.hashSize = 64
+ } else if method == knownMethods[1] {
+ s.hashFunc = sha256.New
+ s.hashSize = 32
+ } else if method == knownMethods[2] {
+ s.hashFunc = sha1.New
+ s.hashSize = 20
+ } else {
+ return nil, errors.Errorf("Unsupported method %s", method)
+ }
+ return s, nil
+}
+
+// GetStartRequest builds start SCRAM-SHA request to be sent to server
+func (s *ScramSha) GetStartRequest(user string) (string, error) {
+ var err error
+ s.clientNonce, err = generateClientNonce(24)
+ if err != nil {
+ return "", errors.Wrapf(err, "Unable to generate SCRAM-SHA "+
+ "start request for user %s", user)
+ }
+
+ message := fmt.Sprintf("n,,n=%s,r=%s", user, s.clientNonce)
+ s.authMessage = message[3:]
+ return message, nil
+}
+
+// HandleStartResponse handles server response on start SCRAM-SHA request
+func (s *ScramSha) HandleStartResponse(response string) error {
+ parts := strings.Split(response, ",")
+ if len(parts) != 3 {
+ return errors.Errorf("expected 3 fields in first SCRAM-SHA-1 "+
+ "server message %s", response)
+ }
+ if !strings.HasPrefix(parts[0], "r=") || len(parts[0]) < 3 {
+ return errors.Errorf("Server sent an invalid nonce %s",
+ parts[0])
+ }
+ if !strings.HasPrefix(parts[1], "s=") || len(parts[1]) < 3 {
+ return errors.Errorf("Server sent an invalid salt %s", parts[1])
+ }
+ if !strings.HasPrefix(parts[2], "i=") || len(parts[2]) < 3 {
+ return errors.Errorf("Server sent an invalid iteration count %s",
+ parts[2])
+ }
+
+ s.serverNonce = parts[0][2:]
+ encodedSalt := parts[1][2:]
+ var err error
+ s.i, err = strconv.Atoi(parts[2][2:])
+ if err != nil {
+ return errors.Errorf("Iteration count %s must be integer.",
+ parts[2][2:])
+ }
+
+ if s.i < 1 {
+ return errors.New("Iteration count should be positive")
+ }
+
+ if !strings.HasPrefix(s.serverNonce, s.clientNonce) {
+ return errors.Errorf("Server nonce %s doesn't contain client"+
+ " nonce %s", s.serverNonce, s.clientNonce)
+ }
+
+ s.salt, err = base64.StdEncoding.DecodeString(encodedSalt)
+ if err != nil {
+ return errors.Wrapf(err, "Unable to decode salt %s",
+ encodedSalt)
+ }
+
+ s.authMessage = s.authMessage + "," + response
+ return nil
+}
+
+// GetFinalRequest builds final SCRAM-SHA request to be sent to server
+func (s *ScramSha) GetFinalRequest(pass string) string {
+ clientFinalMessageBare := "c=biws,r=" + s.serverNonce
+ s.authMessage = s.authMessage + "," + clientFinalMessageBare
+
+ s.saltedPassword = pbkdf2.Key([]byte(pass), s.salt, s.i,
+ s.hashSize, s.hashFunc)
+
+ clientKey := hmacHash([]byte("Client Key"), s.saltedPassword, s.hashFunc)
+ storedKey := shaHash(clientKey, s.hashFunc)
+ clientSignature := hmacHash([]byte(s.authMessage), storedKey, s.hashFunc)
+
+ clientProof := make([]byte, len(clientSignature))
+ for i := 0; i < len(clientSignature); i++ {
+ clientProof[i] = clientKey[i] ^ clientSignature[i]
+ }
+
+ return clientFinalMessageBare + ",p=" +
+ base64.StdEncoding.EncodeToString(clientProof)
+}
+
+// HandleFinalResponse handles server's response on final SCRAM-SHA request
+func (s *ScramSha) HandleFinalResponse(response string) error {
+ if strings.Contains(response, ",") ||
+ !strings.HasPrefix(response, "v=") {
+ return errors.Errorf("Server sent an invalid final message %s",
+ response)
+ }
+
+ decodedMessage, err := base64.StdEncoding.DecodeString(response[2:])
+ if err != nil {
+ return errors.Wrapf(err, "Unable to decode server message %s",
+ response[2:])
+ }
+ serverKey := hmacHash([]byte("Server Key"), s.saltedPassword,
+ s.hashFunc)
+ serverSignature := hmacHash([]byte(s.authMessage), serverKey,
+ s.hashFunc)
+ if string(decodedMessage) != string(serverSignature) {
+ return errors.Errorf("Server proof %s doesn't match "+
+ "the expected: %s",
+ string(decodedMessage), string(serverSignature))
+ }
+ return nil
+}
diff --git a/vendor/github.com/couchbase/goutils/scramsha/scramsha_http.go b/vendor/github.com/couchbase/goutils/scramsha/scramsha_http.go
new file mode 100644
index 0000000000..19f32b3134
--- /dev/null
+++ b/vendor/github.com/couchbase/goutils/scramsha/scramsha_http.go
@@ -0,0 +1,252 @@
+// @author Couchbase <info@couchbase.com>
+// @copyright 2018 Couchbase, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package scramsha provides implementation of client side SCRAM-SHA
+// via Http according to https://tools.ietf.org/html/rfc7804
+package scramsha
+
+import (
+ "encoding/base64"
+ "github.com/pkg/errors"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "strings"
+)
+
+// consts used to parse scramsha response from target
+const (
+ WWWAuthenticate = "WWW-Authenticate"
+ AuthenticationInfo = "Authentication-Info"
+ Authorization = "Authorization"
+ DataPrefix = "data="
+ SidPrefix = "sid="
+)
+
+// Request provides implementation of http request that can be retried
+type Request struct {
+ body io.ReadSeeker
+
+ // Embed an HTTP request directly. This makes a *Request act exactly
+ // like an *http.Request so that all meta methods are supported.
+ *http.Request
+}
+
+type lenReader interface {
+ Len() int
+}
+
+// NewRequest creates http request that can be retried
+func NewRequest(method, url string, body io.ReadSeeker) (*Request, error) {
+ // Wrap the body in a noop ReadCloser if non-nil. This prevents the
+ // reader from being closed by the HTTP client.
+ var rcBody io.ReadCloser
+ if body != nil {
+ rcBody = ioutil.NopCloser(body)
+ }
+
+ // Make the request with the noop-closer for the body.
+ httpReq, err := http.NewRequest(method, url, rcBody)
+ if err != nil {
+ return nil, err
+ }
+
+ // Check if we can set the Content-Length automatically.
+ if lr, ok := body.(lenReader); ok {
+ httpReq.ContentLength = int64(lr.Len())
+ }
+
+ return &Request{body, httpReq}, nil
+}
+
+func encode(str string) string {
+ return base64.StdEncoding.EncodeToString([]byte(str))
+}
+
+func decode(str string) (string, error) {
+ bytes, err := base64.StdEncoding.DecodeString(str)
+ if err != nil {
+ return "", errors.Errorf("Cannot base64 decode %s",
+ str)
+ }
+ return string(bytes), err
+}
+
+func trimPrefix(s, prefix string) (string, error) {
+ l := len(s)
+ trimmed := strings.TrimPrefix(s, prefix)
+ if l == len(trimmed) {
+ return trimmed, errors.Errorf("Prefix %s not found in %s",
+ prefix, s)
+ }
+ return trimmed, nil
+}
+
+func drainBody(resp *http.Response) {
+ defer resp.Body.Close()
+ io.Copy(ioutil.Discard, resp.Body)
+}
+
+// DoScramSha performs SCRAM-SHA handshake via Http
+func DoScramSha(req *Request,
+ username string,
+ password string,
+ client *http.Client) (*http.Response, error) {
+
+ method := "SCRAM-SHA-512"
+ s, err := NewScramSha("SCRAM-SHA512")
+ if err != nil {
+ return nil, errors.Wrap(err,
+ "Unable to initialize SCRAM-SHA handler")
+ }
+
+ message, err := s.GetStartRequest(username)
+ if err != nil {
+ return nil, err
+ }
+
+ encodedMessage := method + " " + DataPrefix + encode(message)
+
+ req.Header.Set(Authorization, encodedMessage)
+
+ res, err := client.Do(req.Request)
+ if err != nil {
+ return nil, errors.Wrap(err, "Problem sending SCRAM-SHA start"+
+ "request")
+ }
+
+ if res.StatusCode != http.StatusUnauthorized {
+ return res, nil
+ }
+
+ authHeader := res.Header.Get(WWWAuthenticate)
+ if authHeader == "" {
+ drainBody(res)
+ return nil, errors.Errorf("Header %s is not populated in "+
+ "SCRAM-SHA start response", WWWAuthenticate)
+ }
+
+ authHeader, err = trimPrefix(authHeader, method+" ")
+ if err != nil {
+ if strings.HasPrefix(authHeader, "Basic ") {
+ // user not found
+ return res, nil
+ }
+ drainBody(res)
+ return nil, errors.Wrapf(err, "Error while parsing SCRAM-SHA "+
+ "start response %s", authHeader)
+ }
+
+ drainBody(res)
+
+ sid, response, err := parseSidAndData(authHeader)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error while parsing SCRAM-SHA "+
+ "start response %s", authHeader)
+ }
+
+ err = s.HandleStartResponse(response)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error parsing SCRAM-SHA start "+
+ "response %s", response)
+ }
+
+ message = s.GetFinalRequest(password)
+ encodedMessage = method + " " + SidPrefix + sid + "," + DataPrefix +
+ encode(message)
+
+ req.Header.Set(Authorization, encodedMessage)
+
+ // rewind request body so it can be resent again
+ if req.body != nil {
+ if _, err = req.body.Seek(0, 0); err != nil {
+ return nil, errors.Errorf("Failed to seek body: %v",
+ err)
+ }
+ }
+
+ res, err = client.Do(req.Request)
+ if err != nil {
+ return nil, errors.Wrap(err, "Problem sending SCRAM-SHA final"+
+ "request")
+ }
+
+ if res.StatusCode == http.StatusUnauthorized {
+ // TODO retrieve and return error
+ return res, nil
+ }
+
+ if res.StatusCode >= http.StatusInternalServerError {
+ // in this case we cannot expect server to set headers properly
+ return res, nil
+ }
+
+ authHeader = res.Header.Get(AuthenticationInfo)
+ if authHeader == "" {
+ drainBody(res)
+ return nil, errors.Errorf("Header %s is not populated in "+
+ "SCRAM-SHA final response", AuthenticationInfo)
+ }
+
+ finalSid, response, err := parseSidAndData(authHeader)
+ if err != nil {
+ drainBody(res)
+ return nil, errors.Wrapf(err, "Error while parsing SCRAM-SHA "+
+ "final response %s", authHeader)
+ }
+
+ if finalSid != sid {
+ drainBody(res)
+ return nil, errors.Errorf("Sid %s returned by server "+
+ "doesn't match the original sid %s", finalSid, sid)
+ }
+
+ err = s.HandleFinalResponse(response)
+ if err != nil {
+ drainBody(res)
+ return nil, errors.Wrapf(err,
+ "Error handling SCRAM-SHA final server response %s",
+ response)
+ }
+ return res, nil
+}
+
+func parseSidAndData(authHeader string) (string, string, error) {
+ sidIndex := strings.Index(authHeader, SidPrefix)
+ if sidIndex < 0 {
+ return "", "", errors.Errorf("Cannot find %s in %s",
+ SidPrefix, authHeader)
+ }
+
+ sidEndIndex := strings.Index(authHeader, ",")
+ if sidEndIndex < 0 {
+ return "", "", errors.Errorf("Cannot find ',' in %s",
+ authHeader)
+ }
+
+ sid := authHeader[sidIndex+len(SidPrefix) : sidEndIndex]
+
+ dataIndex := strings.Index(authHeader, DataPrefix)
+ if dataIndex < 0 {
+ return "", "", errors.Errorf("Cannot find %s in %s",
+ DataPrefix, authHeader)
+ }
+
+ data, err := decode(authHeader[dataIndex+len(DataPrefix):])
+ if err != nil {
+ return "", "", err
+ }
+ return sid, data, nil
+}