github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/security_policies.go (about)

     1  package internal
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  )
     8  
     9  // Security policies documentation:
    10  // https://source.datanerd.us/agents/agent-specs/blob/master/Language-Agent-Security-Policies.md
    11  
    12  // SecurityPolicies contains the security policies.
    13  type SecurityPolicies struct {
    14  	RecordSQL                 securityPolicy `json:"record_sql"`
    15  	AttributesInclude         securityPolicy `json:"attributes_include"`
    16  	AllowRawExceptionMessages securityPolicy `json:"allow_raw_exception_messages"`
    17  	CustomEvents              securityPolicy `json:"custom_events"`
    18  	CustomParameters          securityPolicy `json:"custom_parameters"`
    19  }
    20  
    21  // PointerIfPopulated returns a reference to the security policies if they have
    22  // been populated from JSON.
    23  func (sp *SecurityPolicies) PointerIfPopulated() *SecurityPolicies {
    24  	emptyPolicies := SecurityPolicies{}
    25  	if nil != sp && *sp != emptyPolicies {
    26  		return sp
    27  	}
    28  	return nil
    29  }
    30  
    31  type securityPolicy struct {
    32  	EnabledVal *bool `json:"enabled"`
    33  }
    34  
    35  func (p *securityPolicy) Enabled() bool           { return nil == p.EnabledVal || *p.EnabledVal }
    36  func (p *securityPolicy) SetEnabled(enabled bool) { p.EnabledVal = &enabled }
    37  func (p *securityPolicy) IsSet() bool             { return nil != p.EnabledVal }
    38  
    39  type policyer interface {
    40  	SetEnabled(bool)
    41  	IsSet() bool
    42  }
    43  
    44  // UnmarshalJSON decodes security policies sent from the preconnect endpoint.
    45  func (sp *SecurityPolicies) UnmarshalJSON(data []byte) (er error) {
    46  	defer func() {
    47  		// Zero out all fields if there is an error to ensure that the
    48  		// populated check works.
    49  		if er != nil {
    50  			*sp = SecurityPolicies{}
    51  		}
    52  	}()
    53  
    54  	var raw map[string]struct {
    55  		Enabled  bool `json:"enabled"`
    56  		Required bool `json:"required"`
    57  	}
    58  	err := json.Unmarshal(data, &raw)
    59  	if err != nil {
    60  		return fmt.Errorf("unable to unmarshal security policies: %v", err)
    61  	}
    62  
    63  	knownPolicies := make(map[string]policyer)
    64  
    65  	spv := reflect.ValueOf(sp).Elem()
    66  	for i := 0; i < spv.NumField(); i++ {
    67  		fieldAddress := spv.Field(i).Addr()
    68  		field := fieldAddress.Interface().(policyer)
    69  		name := spv.Type().Field(i).Tag.Get("json")
    70  		knownPolicies[name] = field
    71  	}
    72  
    73  	for name, policy := range raw {
    74  		p, ok := knownPolicies[name]
    75  		if !ok {
    76  			if policy.Required {
    77  				return errUnknownRequiredPolicy{name: name}
    78  			}
    79  		} else {
    80  			p.SetEnabled(policy.Enabled)
    81  		}
    82  	}
    83  	for name, policy := range knownPolicies {
    84  		if !policy.IsSet() {
    85  			return errUnsetPolicy{name: name}
    86  		}
    87  	}
    88  	return nil
    89  }
    90  
    91  type errUnknownRequiredPolicy struct{ name string }
    92  
    93  func (err errUnknownRequiredPolicy) Error() string {
    94  	return fmt.Sprintf("policy '%s' is unrecognized, please check for a newer agent version or contact support", err.name)
    95  }
    96  
    97  type errUnsetPolicy struct{ name string }
    98  
    99  func (err errUnsetPolicy) Error() string {
   100  	return fmt.Sprintf("policy '%s' not received, please contact support", err.name)
   101  }