arn.go raw

   1  package awsrulesfn
   2  
   3  import (
   4  	"strings"
   5  )
   6  
   7  // ARN provides AWS ARN components broken out into a data structure.
   8  type ARN struct {
   9  	Partition  string
  10  	Service    string
  11  	Region     string
  12  	AccountId  string
  13  	ResourceId OptionalStringSlice
  14  }
  15  
  16  const (
  17  	arnDelimiters      = ":"
  18  	resourceDelimiters = "/:"
  19  	arnSections        = 6
  20  	arnPrefix          = "arn:"
  21  
  22  	// zero-indexed
  23  	sectionPartition = 1
  24  	sectionService   = 2
  25  	sectionRegion    = 3
  26  	sectionAccountID = 4
  27  	sectionResource  = 5
  28  )
  29  
  30  // ParseARN returns an [ARN] value parsed from the input string provided. If
  31  // the ARN cannot be parsed nil will be returned, and error added to
  32  // [ErrorCollector].
  33  func ParseARN(input string) *ARN {
  34  	if !strings.HasPrefix(input, arnPrefix) {
  35  		return nil
  36  	}
  37  
  38  	sections := strings.SplitN(input, arnDelimiters, arnSections)
  39  	if numSections := len(sections); numSections != arnSections {
  40  		return nil
  41  	}
  42  
  43  	if sections[sectionPartition] == "" {
  44  		return nil
  45  	}
  46  	if sections[sectionService] == "" {
  47  		return nil
  48  	}
  49  	if sections[sectionResource] == "" {
  50  		return nil
  51  	}
  52  
  53  	return &ARN{
  54  		Partition:  sections[sectionPartition],
  55  		Service:    sections[sectionService],
  56  		Region:     sections[sectionRegion],
  57  		AccountId:  sections[sectionAccountID],
  58  		ResourceId: splitResource(sections[sectionResource]),
  59  	}
  60  }
  61  
  62  // splitResource splits the resource components by the ARN resource delimiters.
  63  func splitResource(v string) []string {
  64  	var parts []string
  65  	var offset int
  66  
  67  	for offset <= len(v) {
  68  		idx := strings.IndexAny(v[offset:], "/:")
  69  		if idx < 0 {
  70  			parts = append(parts, v[offset:])
  71  			break
  72  		}
  73  		parts = append(parts, v[offset:idx+offset])
  74  		offset += idx + 1
  75  	}
  76  
  77  	return parts
  78  }
  79  
  80  // OptionalStringSlice provides a helper to safely get the index of a string
  81  // slice that may be out of bounds. Returns pointer to string if index is
  82  // valid. Otherwise returns nil.
  83  type OptionalStringSlice []string
  84  
  85  // Get returns a string pointer of the string at index i if the index is valid.
  86  // Otherwise returns nil.
  87  func (s OptionalStringSlice) Get(i int) *string {
  88  	if i < 0 || i >= len(s) {
  89  		return nil
  90  	}
  91  
  92  	v := s[i]
  93  	return &v
  94  }
  95