github.com/craicoverflow/tyk@v2.9.6-rc3+incompatible/storage/storage.go (about)

     1  package storage
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"encoding/base64"
     6  	"encoding/hex"
     7  	"errors"
     8  	"fmt"
     9  	"hash"
    10  	"strings"
    11  
    12  	"github.com/buger/jsonparser"
    13  	uuid "github.com/satori/go.uuid"
    14  
    15  	"github.com/TykTechnologies/murmur3"
    16  	"github.com/TykTechnologies/tyk/config"
    17  	logger "github.com/TykTechnologies/tyk/log"
    18  )
    19  
    20  var log = logger.Get()
    21  
    22  // ErrKeyNotFound is a standard error for when a key is not found in the storage engine
    23  var ErrKeyNotFound = errors.New("key not found")
    24  
    25  // Handler is a standard interface to a storage backend, used by
    26  // AuthorisationManager to read and write key values to the backend
    27  type Handler interface {
    28  	GetKey(string) (string, error) // Returned string is expected to be a JSON object (user.SessionState)
    29  	GetMultiKey([]string) ([]string, error)
    30  	GetRawKey(string) (string, error)
    31  	SetKey(string, string, int64) error // Second input string is expected to be a JSON object (user.SessionState)
    32  	SetRawKey(string, string, int64) error
    33  	SetExp(string, int64) error   // Set key expiration
    34  	GetExp(string) (int64, error) // Returns expiry of a key
    35  	GetKeys(string) []string
    36  	DeleteKey(string) bool
    37  	DeleteAllKeys() bool
    38  	DeleteRawKey(string) bool
    39  	Connect() bool
    40  	GetKeysAndValues() map[string]string
    41  	GetKeysAndValuesWithFilter(string) map[string]string
    42  	DeleteKeys([]string) bool
    43  	Decrement(string)
    44  	IncrememntWithExpire(string, int64) int64
    45  	SetRollingWindow(key string, per int64, val string, pipeline bool) (int, []interface{})
    46  	GetRollingWindow(key string, per int64, pipeline bool) (int, []interface{})
    47  	GetSet(string) (map[string]string, error)
    48  	AddToSet(string, string)
    49  	AppendToSetPipelined(string, []string)
    50  	GetAndDeleteSet(string) []interface{}
    51  	RemoveFromSet(string, string)
    52  	DeleteScanMatch(string) bool
    53  	GetKeyPrefix() string
    54  	AddToSortedSet(string, string, float64)
    55  	GetSortedSetRange(string, string, string) ([]string, []float64, error)
    56  	RemoveSortedSetRange(string, string, string) error
    57  	GetListRange(string, int64, int64) ([]string, error)
    58  	RemoveFromList(string, string) error
    59  	AppendToSet(string, string)
    60  	Exists(string) (bool, error)
    61  }
    62  
    63  const defaultHashAlgorithm = "murmur64"
    64  
    65  // If hashing algorithm is empty, use legacy key generation
    66  func GenerateToken(orgID, keyID, hashAlgorithm string) (string, error) {
    67  	if keyID == "" {
    68  		keyID = strings.Replace(uuid.NewV4().String(), "-", "", -1)
    69  	}
    70  
    71  	if hashAlgorithm != "" {
    72  		_, err := hashFunction(hashAlgorithm)
    73  		if err != nil {
    74  			hashAlgorithm = defaultHashAlgorithm
    75  		}
    76  
    77  		jsonToken := fmt.Sprintf(`{"org":"%s","id":"%s","h":"%s"}`, orgID, keyID, hashAlgorithm)
    78  		return base64.StdEncoding.EncodeToString([]byte(jsonToken)), err
    79  	}
    80  
    81  	// Legacy keys
    82  	return orgID + keyID, nil
    83  }
    84  
    85  // `{"` in base64
    86  const B64JSONPrefix = "ey"
    87  
    88  func TokenHashAlgo(token string) string {
    89  	// Legacy tokens not b64 and not JSON records
    90  	if strings.HasPrefix(token, B64JSONPrefix) {
    91  		if jsonToken, err := base64.StdEncoding.DecodeString(token); err == nil {
    92  			hashAlgo, _ := jsonparser.GetString(jsonToken, "h")
    93  			return hashAlgo
    94  		}
    95  	}
    96  
    97  	return ""
    98  }
    99  
   100  func TokenOrg(token string) string {
   101  	if strings.HasPrefix(token, B64JSONPrefix) {
   102  		if jsonToken, err := base64.StdEncoding.DecodeString(token); err == nil {
   103  			// Checking error in case if it is a legacy tooken which just by accided has the same b64JSON prefix
   104  			if org, err := jsonparser.GetString(jsonToken, "org"); err == nil {
   105  				return org
   106  			}
   107  		}
   108  	}
   109  
   110  	// 24 is mongo bson id length
   111  	if len(token) > 24 {
   112  		return token[:24]
   113  	}
   114  
   115  	return ""
   116  }
   117  
   118  var (
   119  	HashSha256    = "sha256"
   120  	HashMurmur32  = "murmur32"
   121  	HashMurmur64  = "murmur64"
   122  	HashMurmur128 = "murmur128"
   123  )
   124  
   125  func hashFunction(algorithm string) (hash.Hash, error) {
   126  	switch algorithm {
   127  	case HashSha256:
   128  		return sha256.New(), nil
   129  	case HashMurmur64:
   130  		return murmur3.New64(), nil
   131  	case HashMurmur128:
   132  		return murmur3.New128(), nil
   133  	case "", HashMurmur32:
   134  		return murmur3.New32(), nil
   135  	default:
   136  		return murmur3.New32(), fmt.Errorf("Unknown key hash function: %s. Falling back to murmur32.", algorithm)
   137  	}
   138  }
   139  
   140  func HashStr(in string, withAlg ...string) string {
   141  	var algo string
   142  	if len(withAlg) > 0 && withAlg[0] != "" {
   143  		algo = withAlg[0]
   144  	} else {
   145  		algo = TokenHashAlgo(in)
   146  	}
   147  
   148  	h, _ := hashFunction(algo)
   149  	h.Write([]byte(in))
   150  	return hex.EncodeToString(h.Sum(nil))
   151  }
   152  
   153  func HashKey(in string) string {
   154  	if !config.Global().HashKeys {
   155  		// Not hashing? Return the raw key
   156  		return in
   157  	}
   158  	return HashStr(in)
   159  }