1package awsrulesfn
2
3import (
4 "strings"
5)
6
7// ARN provides AWS ARN components broken out into a data structure.
8type ARN struct {
9 Partition string
10 Service string
11 Region string
12 AccountId string
13 ResourceId OptionalStringSlice
14}
15
16const (
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].
33func 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.
63func 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.
83type OptionalStringSlice []string
84
85// Get returns a string pointer of the string at index i if the index is valid.
86// Otherwise returns nil.
87func (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}