zhangzengfei
2024-09-13 dbc038d5318d53ac7c14e26386588c48c621a591
pkg/auth/misc.go
New file
@@ -0,0 +1,146 @@
package auth
import (
   "bytes"
   "crypto/md5"
   "crypto/rand"
   "encoding/base64"
   "fmt"
   "net/http"
   "strings"
)
// RandomKey returns a random 16-byte base64 alphabet string
func RandomKey() string {
   k := make([]byte, 12)
   for bytes := 0; bytes < len(k); {
      n, err := rand.Read(k[bytes:])
      if err != nil {
         panic("rand.Read() failed")
      }
      bytes += n
   }
   return base64.StdEncoding.EncodeToString(k)
}
// H function for MD5 algorithm (returns a lower-case hex MD5 digest)
func H(data string) string {
   digest := md5.New()
   digest.Write([]byte(data))
   return fmt.Sprintf("%x", digest.Sum(nil))
}
// ParseList parses a comma-separated list of values as described by
// RFC 2068 and returns list elements.
//
// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
// which was ported from urllib2.parse_http_list, from the Python
// standard library.
func ParseList(value string) []string {
   var list []string
   var escape, quote bool
   b := new(bytes.Buffer)
   for _, r := range value {
      switch {
      case escape:
         b.WriteRune(r)
         escape = false
      case quote:
         if r == '\\' {
            escape = true
         } else {
            if r == '"' {
               quote = false
            }
            b.WriteRune(r)
         }
      case r == ',':
         list = append(list, strings.TrimSpace(b.String()))
         b.Reset()
      case r == '"':
         quote = true
         b.WriteRune(r)
      default:
         b.WriteRune(r)
      }
   }
   // Append last part.
   if s := b.String(); s != "" {
      list = append(list, strings.TrimSpace(s))
   }
   return list
}
// ParsePairs extracts key/value pairs from a comma-separated list of
// values as described by RFC 2068 and returns a map[key]value. The
// resulting values are unquoted. If a list element doesn't contain a
// "=", the key is the element itself and the value is an empty
// string.
//
// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
func ParsePairs(value string) map[string]string {
   m := make(map[string]string)
   for _, pair := range ParseList(strings.TrimSpace(value)) {
      switch i := strings.Index(pair, "="); {
      case i < 0:
         // No '=' in pair, treat whole string as a 'key'.
         m[pair] = ""
      case i == len(pair)-1:
         // Malformed pair ('key=' with no value), keep key with empty value.
         m[pair[:i]] = ""
      default:
         v := pair[i+1:]
         if v[0] == '"' && v[len(v)-1] == '"' {
            // Unquote it.
            v = v[1 : len(v)-1]
         }
         m[pair[:i]] = v
      }
   }
   return m
}
// Headers contains header and error codes used by authenticator.
type Headers struct {
   Authenticate      string // WWW-Authenticate
   Authorization     string // Authorization
   AuthInfo          string // Authentication-Info
   UnauthCode        int    // 401
   UnauthContentType string // text/plain
   UnauthResponse    string // Unauthorized.
}
// V returns NormalHeaders when h is nil, or h otherwise. Allows to
// use uninitialized *Headers values in structs.
func (h *Headers) V() *Headers {
   if h == nil {
      return NormalHeaders
   }
   return h
}
var (
   // NormalHeaders are the regular Headers used by an HTTP Server for
   // request authentication.
   NormalHeaders = &Headers{
      Authenticate:      "WWW-Authenticate",
      Authorization:     "Authorization",
      AuthInfo:          "Authentication-Info",
      UnauthCode:        http.StatusUnauthorized,
      UnauthContentType: "text/plain",
      UnauthResponse:    fmt.Sprintf("%d %s\n", http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized)),
   }
   // ProxyHeaders are Headers used by an HTTP Proxy server for proxy
   // access authentication.
   ProxyHeaders = &Headers{
      Authenticate:      "Proxy-Authenticate",
      Authorization:     "Proxy-Authorization",
      AuthInfo:          "Proxy-Authentication-Info",
      UnauthCode:        http.StatusProxyAuthRequired,
      UnauthContentType: "text/plain",
      UnauthResponse:    fmt.Sprintf("%d %s\n", http.StatusProxyAuthRequired, http.StatusText(http.StatusProxyAuthRequired)),
   }
)
const contentType = "Content-Type"