urn.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package urn
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strings"
  6. )
  7. const errInvalidURN = "invalid URN: %s"
  8. // URN represents an Uniform Resource Name.
  9. //
  10. // The general form represented is:
  11. //
  12. // urn:<id>:<ss>
  13. //
  14. // Details at https://tools.ietf.org/html/rfc2141.
  15. type URN struct {
  16. prefix string // Static prefix. Equal to "urn" when empty.
  17. ID string // Namespace identifier (NID)
  18. SS string // Namespace specific string (NSS)
  19. norm string // Normalized namespace specific string
  20. kind Kind
  21. scim *SCIM
  22. rComponent string // RFC8141
  23. qComponent string // RFC8141
  24. fComponent string // RFC8141
  25. rStart bool // RFC8141
  26. qStart bool // RFC8141
  27. tolower []int
  28. }
  29. // Normalize turns the receiving URN into its norm version.
  30. //
  31. // Which means: lowercase prefix, lowercase namespace identifier, and immutate namespace specific string chars (except <hex> tokens which are lowercased).
  32. func (u *URN) Normalize() *URN {
  33. return &URN{
  34. prefix: "urn",
  35. ID: strings.ToLower(u.ID),
  36. SS: u.norm,
  37. // rComponent: u.rComponent,
  38. // qComponent: u.qComponent,
  39. // fComponent: u.fComponent,
  40. }
  41. }
  42. // Equal checks the lexical equivalence of the current URN with another one.
  43. func (u *URN) Equal(x *URN) bool {
  44. if x == nil {
  45. return false
  46. }
  47. nu := u.Normalize()
  48. nx := x.Normalize()
  49. return nu.prefix == nx.prefix && nu.ID == nx.ID && nu.SS == nx.SS
  50. }
  51. // String reassembles the URN into a valid URN string.
  52. //
  53. // This requires both ID and SS fields to be non-empty.
  54. // Otherwise it returns an empty string.
  55. //
  56. // Default URN prefix is "urn".
  57. func (u *URN) String() string {
  58. var res string
  59. if u.ID != "" && u.SS != "" {
  60. if u.prefix == "" {
  61. res += "urn"
  62. }
  63. res += u.prefix + ":" + u.ID + ":" + u.SS
  64. if u.rComponent != "" {
  65. res += "?+" + u.rComponent
  66. }
  67. if u.qComponent != "" {
  68. res += "?=" + u.qComponent
  69. }
  70. if u.fComponent != "" {
  71. res += "#" + u.fComponent
  72. }
  73. }
  74. return res
  75. }
  76. // Parse is responsible to create an URN instance from a byte array matching the correct URN syntax (RFC 2141).
  77. func Parse(u []byte, options ...Option) (*URN, bool) {
  78. urn, err := NewMachine(options...).Parse(u)
  79. if err != nil {
  80. return nil, false
  81. }
  82. return urn, true
  83. }
  84. // MarshalJSON marshals the URN to JSON string form (e.g. `"urn:oid:1.2.3.4"`).
  85. func (u URN) MarshalJSON() ([]byte, error) {
  86. return json.Marshal(u.String())
  87. }
  88. // UnmarshalJSON unmarshals a URN from JSON string form (e.g. `"urn:oid:1.2.3.4"`).
  89. func (u *URN) UnmarshalJSON(bytes []byte) error {
  90. var str string
  91. if err := json.Unmarshal(bytes, &str); err != nil {
  92. return err
  93. }
  94. if value, ok := Parse([]byte(str)); !ok {
  95. return fmt.Errorf(errInvalidURN, str)
  96. } else {
  97. *u = *value
  98. }
  99. return nil
  100. }
  101. func (u *URN) IsSCIM() bool {
  102. return u.kind == RFC7643
  103. }
  104. func (u *URN) SCIM() *SCIM {
  105. if u.kind != RFC7643 {
  106. return nil
  107. }
  108. return u.scim
  109. }
  110. func (u *URN) RFC() Kind {
  111. return u.kind
  112. }
  113. func (u *URN) FComponent() string {
  114. return u.fComponent
  115. }
  116. func (u *URN) QComponent() string {
  117. return u.qComponent
  118. }
  119. func (u *URN) RComponent() string {
  120. return u.rComponent
  121. }