From 3e9a1a28b1283e40bc7edb94e2370c74e7fd68e0 Mon Sep 17 00:00:00 2001
From: zhangzengfei <zhangzengfei@smartai.com>
Date: 星期五, 17 五月 2024 15:54:29 +0800
Subject: [PATCH] 添加订阅查询接口

---
 pkg/auth/basic.go |  161 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 161 insertions(+), 0 deletions(-)

diff --git a/pkg/auth/basic.go b/pkg/auth/basic.go
new file mode 100644
index 0000000..f328a32
--- /dev/null
+++ b/pkg/auth/basic.go
@@ -0,0 +1,161 @@
+package auth
+
+import (
+	"bytes"
+	"context"
+	"crypto/sha1"
+	"crypto/subtle"
+	"encoding/base64"
+	"errors"
+	"net/http"
+	"strings"
+
+	"golang.org/x/crypto/bcrypt"
+)
+
+type compareFunc func(hashedPassword, password []byte) error
+
+var (
+	errMismatchedHashAndPassword = errors.New("mismatched hash and password")
+
+	compareFuncs = []struct {
+		prefix  string
+		compare compareFunc
+	}{
+		{"", compareMD5HashAndPassword}, // default compareFunc
+		{"{SHA}", compareShaHashAndPassword},
+		// Bcrypt is complicated. According to crypt(3) from
+		// crypt_blowfish version 1.3 (fetched from
+		// http://www.openwall.com/crypt/crypt_blowfish-1.3.tar.gz), there
+		// are three different has prefixes: "$2a$", used by versions up
+		// to 1.0.4, and "$2x$" and "$2y$", used in all later
+		// versions. "$2a$" has a known bug, "$2x$" was added as a
+		// migration path for systems with "$2a$" prefix and still has a
+		// bug, and only "$2y$" should be used by modern systems. The bug
+		// has something to do with handling of 8-bit characters. Since
+		// both "$2a$" and "$2x$" are deprecated, we are handling them the
+		// same way as "$2y$", which will yield correct results for 7-bit
+		// character passwords, but is wrong for 8-bit character
+		// passwords. You have to upgrade to "$2y$" if you want sant 8-bit
+		// character password support with bcrypt. To add to the mess,
+		// OpenBSD 5.5. introduced "$2b$" prefix, which behaves exactly
+		// like "$2y$" according to the same source.
+		{"$2a$", bcrypt.CompareHashAndPassword},
+		{"$2b$", bcrypt.CompareHashAndPassword},
+		{"$2x$", bcrypt.CompareHashAndPassword},
+		{"$2y$", bcrypt.CompareHashAndPassword},
+	}
+)
+
+// BasicAuth is an authenticator implementation for 'Basic' HTTP
+// Authentication scheme (RFC 7617).
+type BasicAuth struct {
+	Realm   string
+	Secrets SecretProvider
+	// Headers used by authenticator. Set to ProxyHeaders to use with
+	// proxy server. When nil, NormalHeaders are used.
+	Headers *Headers
+}
+
+// check that BasicAuth implements AuthenticatorInterface
+var _ = (AuthenticatorInterface)((*BasicAuth)(nil))
+
+// CheckAuth checks the username/password combination from the
+// request. Returns either an empty string (authentication failed) or
+// the name of the authenticated user.
+func (a *BasicAuth) CheckAuth(r *http.Request) string {
+	user, password, ok := r.BasicAuth()
+	if !ok {
+		return ""
+	}
+
+	secret := a.Secrets(user, a.Realm)
+	if secret == "" {
+		return ""
+	}
+
+	if !CheckSecret(password, secret) {
+		return ""
+	}
+
+	return user
+}
+
+// CheckSecret returns true if the password matches the encrypted
+// secret.
+func CheckSecret(password, secret string) bool {
+	compare := compareFuncs[0].compare
+	for _, cmp := range compareFuncs[1:] {
+		if strings.HasPrefix(secret, cmp.prefix) {
+			compare = cmp.compare
+			break
+		}
+	}
+	return compare([]byte(secret), []byte(password)) == nil
+}
+
+func compareShaHashAndPassword(hashedPassword, password []byte) error {
+	d := sha1.New()
+	d.Write(password)
+	if subtle.ConstantTimeCompare(hashedPassword[5:], []byte(base64.StdEncoding.EncodeToString(d.Sum(nil)))) != 1 {
+		return errMismatchedHashAndPassword
+	}
+	return nil
+}
+
+func compareMD5HashAndPassword(hashedPassword, password []byte) error {
+	parts := bytes.SplitN(hashedPassword, []byte("$"), 4)
+	if len(parts) != 4 {
+		return errMismatchedHashAndPassword
+	}
+	magic := []byte("$" + string(parts[1]) + "$")
+	salt := parts[2]
+	if subtle.ConstantTimeCompare(hashedPassword, MD5Crypt(password, salt, magic)) != 1 {
+		return errMismatchedHashAndPassword
+	}
+	return nil
+}
+
+// RequireAuth is an http.HandlerFunc for BasicAuth which initiates
+// the authentication process (or requires reauthentication).
+func (a *BasicAuth) RequireAuth(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set(contentType, a.Headers.V().UnauthContentType)
+	w.Header().Set(a.Headers.V().Authenticate, `Basic realm="`+a.Realm+`"`)
+	w.WriteHeader(a.Headers.V().UnauthCode)
+	w.Write([]byte(a.Headers.V().UnauthResponse))
+}
+
+// Wrap returns an http.HandlerFunc, which wraps
+// AuthenticatedHandlerFunc with this BasicAuth authenticator's
+// authentication checks. Once the request contains valid credentials,
+// it calls wrapped AuthenticatedHandlerFunc.
+//
+// Deprecated: new code should use NewContext instead.
+func (a *BasicAuth) Wrap(wrapped AuthenticatedHandlerFunc) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		if username := a.CheckAuth(r); username == "" {
+			a.RequireAuth(w, r)
+		} else {
+			ar := &AuthenticatedRequest{Request: *r, Username: username}
+			wrapped(w, ar)
+		}
+	}
+}
+
+// NewContext returns a context carrying authentication information for the request.
+func (a *BasicAuth) NewContext(ctx context.Context, r *http.Request) context.Context {
+	info := &Info{Username: a.CheckAuth(r), ResponseHeaders: make(http.Header)}
+	info.Authenticated = (info.Username != "")
+	if !info.Authenticated {
+		info.ResponseHeaders.Set(a.Headers.V().Authenticate, `Basic realm="`+a.Realm+`"`)
+	}
+	return context.WithValue(ctx, infoKey, info)
+}
+
+// NewBasicAuthenticator returns a BasicAuth initialized with provided
+// realm and secrets.
+//
+// Deprecated: new code should construct BasicAuth values directly.
+func NewBasicAuthenticator(realm string, secrets SecretProvider) *BasicAuth {
+	return &BasicAuth{Realm: realm, Secrets: secrets}
+}

--
Gitblit v1.8.0