github.com/Jeffail/benthos/v3@v3.65.0/lib/processor/hash.go (about)

     1  package processor
     2  
     3  import (
     4  	"crypto/hmac"
     5  	"crypto/md5"
     6  	"crypto/sha1"
     7  	"crypto/sha256"
     8  	"crypto/sha512"
     9  	"fmt"
    10  	"strconv"
    11  	"time"
    12  
    13  	"github.com/Jeffail/benthos/v3/internal/docs"
    14  	"github.com/Jeffail/benthos/v3/internal/tracing"
    15  	"github.com/Jeffail/benthos/v3/lib/log"
    16  	"github.com/Jeffail/benthos/v3/lib/metrics"
    17  	"github.com/Jeffail/benthos/v3/lib/response"
    18  	"github.com/Jeffail/benthos/v3/lib/types"
    19  	"github.com/OneOfOne/xxhash"
    20  )
    21  
    22  //------------------------------------------------------------------------------
    23  
    24  func init() {
    25  	Constructors[TypeHash] = TypeSpec{
    26  		constructor: NewHash,
    27  		Status:      docs.StatusDeprecated,
    28  		Footnotes: `
    29  ## Alternatives
    30  
    31  All functionality of this processor has been superseded by the
    32  [bloblang](/docs/components/processors/bloblang) processor.`,
    33  		FieldSpecs: docs.FieldSpecs{
    34  			docs.FieldCommon("algorithm", "The hash algorithm to use.").HasOptions("sha256", "sha512", "sha1", "xxhash64", "hmac-sha1", "hmac-sha256", "hmac-sha512", "md5"),
    35  			docs.FieldCommon("key", "key used for HMAC algorithms"),
    36  			PartsFieldSpec,
    37  		},
    38  	}
    39  }
    40  
    41  //------------------------------------------------------------------------------
    42  
    43  // HashConfig contains configuration fields for the Hash processor.
    44  type HashConfig struct {
    45  	Parts     []int  `json:"parts" yaml:"parts"`
    46  	Algorithm string `json:"algorithm" yaml:"algorithm"`
    47  	Key       string `json:"key" yaml:"key"`
    48  }
    49  
    50  // NewHashConfig returns a HashConfig with default values.
    51  func NewHashConfig() HashConfig {
    52  	return HashConfig{
    53  		Parts:     []int{},
    54  		Algorithm: "sha256",
    55  	}
    56  }
    57  
    58  //------------------------------------------------------------------------------
    59  
    60  type hashFunc func(bytes []byte) ([]byte, error)
    61  
    62  func hmacsha1Hash(key string) hashFunc {
    63  	return func(b []byte) ([]byte, error) {
    64  		hasher := hmac.New(sha1.New, []byte(key))
    65  		hasher.Write(b)
    66  		return hasher.Sum(nil), nil
    67  	}
    68  }
    69  
    70  func hmacsha256Hash(key string) hashFunc {
    71  	return func(b []byte) ([]byte, error) {
    72  		hasher := hmac.New(sha256.New, []byte(key))
    73  		hasher.Write(b)
    74  		return hasher.Sum(nil), nil
    75  	}
    76  }
    77  
    78  func hmacsha512Hash(key string) hashFunc {
    79  	return func(b []byte) ([]byte, error) {
    80  		hasher := hmac.New(sha512.New, []byte(key))
    81  		hasher.Write(b)
    82  		return hasher.Sum(nil), nil
    83  	}
    84  }
    85  
    86  func md5Hash(b []byte) ([]byte, error) {
    87  	hasher := md5.New()
    88  	hasher.Write(b)
    89  	return hasher.Sum(nil), nil
    90  }
    91  
    92  func sha1Hash(b []byte) ([]byte, error) {
    93  	hasher := sha1.New()
    94  	hasher.Write(b)
    95  	return hasher.Sum(nil), nil
    96  }
    97  
    98  func sha256Hash(b []byte) ([]byte, error) {
    99  	hasher := sha256.New()
   100  	hasher.Write(b)
   101  	return hasher.Sum(nil), nil
   102  }
   103  
   104  func sha512Hash(b []byte) ([]byte, error) {
   105  	hasher := sha512.New()
   106  	hasher.Write(b)
   107  	return hasher.Sum(nil), nil
   108  }
   109  
   110  func xxhash64Hash(b []byte) ([]byte, error) {
   111  	h := xxhash.New64()
   112  	h.Write(b)
   113  	return []byte(strconv.FormatUint(h.Sum64(), 10)), nil
   114  }
   115  
   116  func strToHashr(conf HashConfig) (hashFunc, error) {
   117  	switch conf.Algorithm {
   118  	case "hmac-sha1":
   119  		return hmacsha1Hash(conf.Key), nil
   120  	case "hmac-sha256":
   121  		return hmacsha256Hash(conf.Key), nil
   122  	case "hmac-sha512":
   123  		return hmacsha512Hash(conf.Key), nil
   124  	case "md5":
   125  		return md5Hash, nil
   126  	case "sha1":
   127  		return sha1Hash, nil
   128  	case "sha256":
   129  		return sha256Hash, nil
   130  	case "sha512":
   131  		return sha512Hash, nil
   132  	case "xxhash64":
   133  		return xxhash64Hash, nil
   134  	}
   135  	return nil, fmt.Errorf("hash algorithm not recognised: %v", conf.Algorithm)
   136  }
   137  
   138  //------------------------------------------------------------------------------
   139  
   140  // Hash is a processor that can selectively hash parts of a message following a
   141  // chosen algorithm.
   142  type Hash struct {
   143  	conf HashConfig
   144  	fn   hashFunc
   145  
   146  	log   log.Modular
   147  	stats metrics.Type
   148  
   149  	mCount     metrics.StatCounter
   150  	mErr       metrics.StatCounter
   151  	mSent      metrics.StatCounter
   152  	mBatchSent metrics.StatCounter
   153  }
   154  
   155  // NewHash returns a Hash processor.
   156  func NewHash(
   157  	conf Config, mgr types.Manager, log log.Modular, stats metrics.Type,
   158  ) (Type, error) {
   159  	cor, err := strToHashr(conf.Hash)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	return &Hash{
   164  		conf:  conf.Hash,
   165  		fn:    cor,
   166  		log:   log,
   167  		stats: stats,
   168  
   169  		mCount:     stats.GetCounter("count"),
   170  		mErr:       stats.GetCounter("error"),
   171  		mSent:      stats.GetCounter("sent"),
   172  		mBatchSent: stats.GetCounter("batch.sent"),
   173  	}, nil
   174  }
   175  
   176  //------------------------------------------------------------------------------
   177  
   178  // ProcessMessage applies the processor to a message, either creating >0
   179  // resulting messages or a response to be sent back to the message source.
   180  func (c *Hash) ProcessMessage(msg types.Message) ([]types.Message, types.Response) {
   181  	c.mCount.Incr(1)
   182  
   183  	newMsg := msg.Copy()
   184  
   185  	proc := func(index int, span *tracing.Span, part types.Part) error {
   186  		newPart, err := c.fn(part.Get())
   187  		if err == nil {
   188  			newMsg.Get(index).Set(newPart)
   189  		} else {
   190  			c.log.Debugf("Failed to hash message part: %v\n", err)
   191  			c.mErr.Incr(1)
   192  		}
   193  		return err
   194  	}
   195  
   196  	if newMsg.Len() == 0 {
   197  		return nil, response.NewAck()
   198  	}
   199  
   200  	IteratePartsWithSpanV2(TypeHash, c.conf.Parts, newMsg, proc)
   201  
   202  	c.mBatchSent.Incr(1)
   203  	c.mSent.Incr(int64(newMsg.Len()))
   204  	msgs := [1]types.Message{newMsg}
   205  	return msgs[:], nil
   206  }
   207  
   208  // CloseAsync shuts down the processor and stops processing requests.
   209  func (c *Hash) CloseAsync() {
   210  }
   211  
   212  // WaitForClose blocks until the processor has closed down.
   213  func (c *Hash) WaitForClose(timeout time.Duration) error {
   214  	return nil
   215  }
   216  
   217  //------------------------------------------------------------------------------