<commit_before>package network

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"
	"time"

	"collectd.org/api"
	"collectd.org/cdtime"
)

// Common error conditions.
var (
	ErrorInvalid     = errors.New("Invalid packet")
	ErrorUnsupported = errors.New("Unsupported packet")
)

// Parse parses the binary network format and returns a slice of ValueLists. If
// a parse error is encountered, all ValueLists parsed to this point are
// returned as well as the error. Unknown "parts" are silently ignored.
func Parse(b []byte) ([]api.ValueList, error) {
	var valueLists []api.ValueList

	var state api.ValueList
	buf := bytes.NewBuffer(b)

	// FIXME
	userToPassword := make(map[string]string)

	for buf.Len() > 0 {
		partType := binary.BigEndian.Uint16(buf.Next(2))
		partLength := int(binary.BigEndian.Uint16(buf.Next(2)))

		if partLength < 5 || partLength-4 > buf.Len() {
			return valueLists, fmt.Errorf("invalid length %d", partLength)
		}

		// First 4 bytes were already read
		partLength -= 4

		payload := buf.Next(partLength)
		if len(payload) != partLength {
			return valueLists, fmt.Errorf("invalid length: want %d, got %d", partLength, len(payload))
		}

		switch partType {
		case typeHost, typePlugin, typePluginInstance, typeType, typeTypeInstance:
			str, err := parseString(payload)
			if err != nil {
				return valueLists, err
			}
			switch partType {
			case typeHost:
				state.Identifier.Host = str
			case typePlugin:
				state.Identifier.Plugin = str
			case typePluginInstance:
				state.Identifier.PluginInstance = str
			case typeType:
				state.Identifier.Type = str
			case typeTypeInstance:
				state.Identifier.TypeInstance = str
			}
		case typeInterval, typeIntervalHR, typeTime, typeTimeHR:
			i, err := parseInt(payload)
			if err != nil {
				return valueLists, err
			}
			switch partType {
			case typeInterval:
				state.Interval = time.Duration(i) * time.Second
			case typeIntervalHR:
				state.Interval = cdtime.Time(i).Duration()
			case typeTime:
				state.Time = time.Unix(int64(i), 0)
			case typeTimeHR:
				state.Time = cdtime.Time(i).Time()
			}
		case typeValues:
			vl := state
			var err error
			if vl.Values, err = parseValues(payload); err != nil {
				return valueLists, err
			}

			valueLists = append(valueLists, vl)

		case typeSignSHA256:
			ok, err := verifySHA256(payload, buf.Bytes(), userToPassword)
			if err != nil {
				return valueLists, err
			} else if !ok {
				return valueLists, errors.New("SHA256 signature failed verification")
			}

		default:
			log.Printf("ignoring field of type %#x", partType)
		}
	}

	return valueLists, nil
}

func parseValues(b []byte) ([]api.Value, error) {
	buffer := bytes.NewBuffer(b)

	var n uint16
	if err := binary.Read(buffer, binary.BigEndian, &n); err != nil {
		return nil, err
	}

	if int(n*9) != buffer.Len() {
		return nil, fmt.Errorf("parseValues: length mismatch: %d vs %d", n*9, buffer.Len())
	}

	types := make([]byte, n)
	values := make([]api.Value, n)

	if _, err := buffer.Read(types); err != nil {
		return nil, err
	}

	for i, typ := range types {
		switch typ {
		case dsTypeGauge:
			var v float64<commit_msg>network: Hook decryptAES256() up to Parse().<commit_after>package network

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"
	"time"

	"collectd.org/api"
	"collectd.org/cdtime"
)

// Common error conditions.
var (
	ErrorInvalid     = errors.New("Invalid packet")
	ErrorUnsupported = errors.New("Unsupported packet")
)

// Parse parses the binary network format and returns a slice of ValueLists. If
// a parse error is encountered, all ValueLists parsed to this point are
// returned as well as the error. Unknown "parts" are silently ignored.
func Parse(b []byte) ([]api.ValueList, error) {
	var valueLists []api.ValueList

	var state api.ValueList
	buf := bytes.NewBuffer(b)

	// FIXME
	userToPassword := make(map[string]string)

	for buf.Len() > 0 {
		partType := binary.BigEndian.Uint16(buf.Next(2))
		partLength := int(binary.BigEndian.Uint16(buf.Next(2)))

		if partLength < 5 || partLength-4 > buf.Len() {
			return valueLists, fmt.Errorf("invalid length %d", partLength)
		}

		// First 4 bytes were already read
		partLength -= 4

		payload := buf.Next(partLength)
		if len(payload) != partLength {
			return valueLists, fmt.Errorf("invalid length: want %d, got %d", partLength, len(payload))
		}

		switch partType {
		case typeHost, typePlugin, typePluginInstance, typeType, typeTypeInstance:
			str, err := parseString(payload)
			if err != nil {
				return valueLists, err
			}
			switch partType {
			case typeHost:
				state.Identifier.Host = str
			case typePlugin:
				state.Identifier.Plugin = str
			case typePluginInstance:
				state.Identifier.PluginInstance = str
			case typeType:
				state.Identifier.Type = str
			case typeTypeInstance:
				state.Identifier.TypeInstance = str
			}
		case typeInterval, typeIntervalHR, typeTime, typeTimeHR:
			i, err := parseInt(payload)
			if err != nil {
				return valueLists, err
			}
			switch partType {
			case typeInterval:
				state.Interval = time.Duration(i) * time.Second
			case typeIntervalHR:
				state.Interval = cdtime.Time(i).Duration()
			case typeTime:
				state.Time = time.Unix(int64(i), 0)
			case typeTimeHR:
				state.Time = cdtime.Time(i).Time()
			}
		case typeValues:
			vl := state
			var err error
			if vl.Values, err = parseValues(payload); err != nil {
				return valueLists, err
			}

			valueLists = append(valueLists, vl)

		case typeSignSHA256:
			ok, err := verifySHA256(payload, buf.Bytes(), userToPassword)
			if err != nil {
				return valueLists, err
			} else if !ok {
				return valueLists, errors.New("SHA256 signature failed verification")
			}

		case typeEncryptAES256:
			plaintext, err := decryptAES256(payload, userToPassword)
			if err != nil {
				log.Printf("failed to decrypt encrypted data: %v", err)
				continue
			}
			vls, err := Parse(plaintext)
			if vls != nil {
				valueLists = append(valueLists, vls...)
			}
			if err != nil {
				return valueLists, err
			}

		default:
			log.Printf("ignoring field of type %#x", partType)
		}
	}

	return valueLists, nil
}

func parseValues(b []byte) ([]api.Value, error) {
	buffer := bytes.NewBuffer(b)

	var n uint16
	if err := binary.Read(buffer, binary.BigEndian, &n); err != nil {
		return nil, err
	}

	if int(n*9) != buffer.Len() {
		return nil, fmt.Errorf("parseValues: length mismatch: %d vs %d", n*9, buffer.Len())
	}

	types := make([]byte, n)
	values := make([]api.Value, n)

	if _, err := buffer.Read(types); err != nil {
		return nil, err
	}

	for i, typ := range types {
		switch typ {
		case dsTypeGauge:
			var v float64
{'fraction_non_alphanumeric': 0.12413585813044785, 'fraction_numerical': 0.010069131349564171, 'mean_word_length': 3.4189907038512617, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3988583', 'n_tokens_mistral': 2562, 'n_tokens_neox': 2183, 'n_words': 630}