arn.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package arn
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/aws/aws-sdk-go/aws/arn"
  6. )
  7. var supportedServiceARN = []string{
  8. "s3",
  9. "s3-outposts",
  10. "s3-object-lambda",
  11. }
  12. func isSupportedServiceARN(service string) bool {
  13. for _, name := range supportedServiceARN {
  14. if name == service {
  15. return true
  16. }
  17. }
  18. return false
  19. }
  20. // Resource provides the interfaces abstracting ARNs of specific resource
  21. // types.
  22. type Resource interface {
  23. GetARN() arn.ARN
  24. String() string
  25. }
  26. // ResourceParser provides the function for parsing an ARN's resource
  27. // component into a typed resource.
  28. type ResourceParser func(arn.ARN) (Resource, error)
  29. // ParseResource parses an AWS ARN into a typed resource for the S3 API.
  30. func ParseResource(s string, resParser ResourceParser) (resARN Resource, err error) {
  31. a, err := arn.Parse(s)
  32. if err != nil {
  33. return nil, err
  34. }
  35. if len(a.Partition) == 0 {
  36. return nil, InvalidARNError{ARN: a, Reason: "partition not set"}
  37. }
  38. if !isSupportedServiceARN(a.Service) {
  39. return nil, InvalidARNError{ARN: a, Reason: "service is not supported"}
  40. }
  41. if strings.HasPrefix(a.Region, "fips-") || strings.HasSuffix(a.Region, "-fips") {
  42. return nil, InvalidARNError{ARN: a, Reason: "FIPS region not allowed in ARN"}
  43. }
  44. if len(a.Resource) == 0 {
  45. return nil, InvalidARNError{ARN: a, Reason: "resource not set"}
  46. }
  47. return resParser(a)
  48. }
  49. // SplitResource splits the resource components by the ARN resource delimiters.
  50. func SplitResource(v string) []string {
  51. var parts []string
  52. var offset int
  53. for offset <= len(v) {
  54. idx := strings.IndexAny(v[offset:], "/:")
  55. if idx < 0 {
  56. parts = append(parts, v[offset:])
  57. break
  58. }
  59. parts = append(parts, v[offset:idx+offset])
  60. offset += idx + 1
  61. }
  62. return parts
  63. }
  64. // IsARN returns whether the given string is an ARN
  65. func IsARN(s string) bool {
  66. return arn.IsARN(s)
  67. }
  68. // InvalidARNError provides the error for an invalid ARN error.
  69. type InvalidARNError struct {
  70. ARN arn.ARN
  71. Reason string
  72. }
  73. // Error returns a string denoting the occurred InvalidARNError
  74. func (e InvalidARNError) Error() string {
  75. return fmt.Sprintf("invalid Amazon %s ARN, %s, %s", e.ARN.Service, e.Reason, e.ARN.String())
  76. }