nonnative.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package nonnative
  2. import (
  3. "encoding/base64"
  4. "encoding/json"
  5. "net/url"
  6. "regexp"
  7. "strings"
  8. )
  9. //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
  10. func ExtractAllValuesFromBytes(bytes []byte) AbstractNonNativeLink {
  11. link := AbstractNonNativeLink{}
  12. link.fromBytes(bytes)
  13. return link
  14. }
  15. type jsonDocument map[string]json.RawMessage
  16. type AbstractNonNativeLink struct {
  17. Values map[string]string
  18. }
  19. func (a *AbstractNonNativeLink) fromBytes(bytes []byte) {
  20. a.Values = make(map[string]string)
  21. content := string(bytes)
  22. content = strings.Trim(content, " \n\t\r")
  23. a.extractValue(content, "root")
  24. }
  25. func (a *AbstractNonNativeLink) extractValue(content, prefix string) {
  26. if content == "" {
  27. return
  28. }
  29. {
  30. // check if the content is a link
  31. match, err := regexp.Match("[a-zA-Z0-9]+:((\\/\\/)|\\?)", []byte(content))
  32. if err != nil {
  33. panic(err)
  34. }
  35. if match {
  36. // if so, parse as link
  37. parsedURL, err := url.Parse(content)
  38. // if process is successful, then continue to parse every element of the link
  39. if err == nil {
  40. a.Values[prefix+"_!kind"] = "link"
  41. a.extractLink(parsedURL, prefix)
  42. return
  43. }
  44. }
  45. }
  46. {
  47. // check if it is base64
  48. content = strings.Trim(content, "=")
  49. decoded, err := base64.RawStdEncoding.DecodeString(content)
  50. if err == nil {
  51. a.Values[prefix+"_!kind"] = "base64"
  52. a.Values[prefix+"_!rawContent"] = string(decoded)
  53. a.extractValue(string(decoded), prefix+"_!base64")
  54. return
  55. }
  56. }
  57. {
  58. // check if it is base64url
  59. content = strings.Trim(content, "=")
  60. decoded, err := base64.RawURLEncoding.DecodeString(content)
  61. if err == nil {
  62. a.Values[prefix+"_!kind"] = "base64url"
  63. a.Values[prefix+"_!rawContent"] = string(decoded)
  64. a.extractValue(string(decoded), prefix+"_!base64")
  65. return
  66. }
  67. }
  68. {
  69. // check if it is json
  70. var doc jsonDocument
  71. if err := json.Unmarshal([]byte(content), &doc); err == nil {
  72. a.Values[prefix+"_!kind"] = "json"
  73. a.extractJSON(&doc, prefix)
  74. return
  75. }
  76. }
  77. }
  78. func (a *AbstractNonNativeLink) extractLink(content *url.URL, prefix string) {
  79. a.Values[prefix+"_!link"] = content.String()
  80. a.Values[prefix+"_!link_protocol"] = content.Scheme
  81. a.Values[prefix+"_!link_host"] = content.Host
  82. a.extractValue(content.Host, prefix+"_!link_host")
  83. a.Values[prefix+"_!link_path"] = content.Path
  84. a.Values[prefix+"_!link_query"] = content.RawQuery
  85. a.Values[prefix+"_!link_fragment"] = content.Fragment
  86. a.Values[prefix+"_!link_userinfo"] = content.User.String()
  87. a.extractValue(content.User.String(), prefix+"_!link_userinfo_!value")
  88. a.Values[prefix+"_!link_opaque"] = content.Opaque
  89. }
  90. func (a *AbstractNonNativeLink) extractJSON(content *jsonDocument, prefix string) {
  91. for key, value := range *content {
  92. switch value[0] {
  93. case '{':
  94. a.extractValue(string(value), prefix+"_!json_"+key)
  95. case '"':
  96. var unquoted string
  97. if err := json.Unmarshal(value, &unquoted); err == nil {
  98. a.Values[prefix+"_!json_"+key+"_!unquoted"] = unquoted
  99. }
  100. fallthrough
  101. default:
  102. a.Values[prefix+"_!json_"+key] = string(value)
  103. }
  104. }
  105. }