parsers.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package apksigner
  2. import (
  3. "regexp"
  4. "strconv"
  5. "strings"
  6. "text/scanner"
  7. "notabug.org/Umnik/GoAndroidSDK/v2/components/misc"
  8. )
  9. var (
  10. signerNum = regexp.MustCompile(`^Signer #(\d+)`)
  11. minSdkVersion = regexp.MustCompile(`^.+minSdkVersion=(\d+)`)
  12. maxSdkVersion = regexp.MustCompile(`^.+maxSdkVersion=(\d+)`)
  13. )
  14. // ParseDumpSignatureInfoFromBytes returns VerifyInfo from bytes
  15. func ParseDumpSignatureInfoFromBytes(rawData []byte) VerifyInfo {
  16. return ParseDumpSignatureInfoFromString(string(rawData))
  17. }
  18. // boolExtractor extracts bool value from "arg:value" line
  19. func boolExtractor(val string) bool {
  20. res, err := strconv.ParseBool(val)
  21. if err != nil {
  22. return false
  23. }
  24. return res
  25. }
  26. func getDN(line string) map[string]string {
  27. if strings.Contains(line, "\"") { // for example line contains `O="Ubiquiti Networks, Inc."`
  28. return getDNExtended(line)
  29. }
  30. value := strings.Split(line, ", ")
  31. res := make(map[string]string, len(value))
  32. for _, i := range value {
  33. parts := strings.SplitN(i, "=", 2)
  34. res[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
  35. }
  36. return res
  37. }
  38. func getDNExtended(line string) map[string]string {
  39. var scnr scanner.Scanner
  40. scnr.Init(strings.NewReader(line))
  41. result := map[string]string{}
  42. key := ""
  43. value := ""
  44. valueTrigger := false
  45. for token := scnr.Scan(); token != scanner.EOF; token = scnr.Scan() {
  46. switch token {
  47. case ',':
  48. valueTrigger = false
  49. key = ""
  50. value = ""
  51. case '=':
  52. valueTrigger = true
  53. default:
  54. if !valueTrigger {
  55. key += scnr.TokenText()
  56. } else {
  57. value += scnr.TokenText()
  58. if scnr.Peek() == ',' || scnr.Peek() == scanner.EOF {
  59. result[key] = value
  60. }
  61. }
  62. }
  63. }
  64. return result
  65. }
  66. func getNotProtectedFile(line string) string {
  67. return strings.TrimSpace(strings.SplitN(misc.TwoSpotValue(line), " ", 2)[0])
  68. }
  69. func getSingerNumber(line string) int {
  70. out := signerNum.FindStringSubmatch(line)
  71. return misc.IntExtractor(misc.RexSubStrSingleVal(out))
  72. }
  73. func getMinSdk(line string) int {
  74. out := minSdkVersion.FindStringSubmatch(line)
  75. return misc.IntExtractor(misc.RexSubStrSingleVal(out))
  76. }
  77. func getMaxSdk(line string) int {
  78. out := maxSdkVersion.FindStringSubmatch(line)
  79. return misc.IntExtractor(misc.RexSubStrSingleVal(out))
  80. }
  81. // ParseDumpSignatureInfoFromString returns VerifyInfo from string ers
  82. func ParseDumpSignatureInfoFromString(rawData string) VerifyInfo {
  83. infoRes := VerifyInfo{SignInfo: []SignatureInfo{}}
  84. index := -1 //uses for v3.1 only
  85. for _, rawLine := range strings.Split(rawData, "\n") {
  86. rawLine = strings.TrimSpace(rawLine)
  87. switch {
  88. case strings.Contains(rawLine, "using v1 scheme"):
  89. infoRes.V1 = boolExtractor(misc.TwoSpotRexValue(rawLine))
  90. case strings.Contains(rawLine, "using v2 scheme"):
  91. infoRes.V2 = boolExtractor(misc.TwoSpotRexValue(rawLine))
  92. case strings.Contains(rawLine, "using v3 scheme"):
  93. infoRes.V3 = boolExtractor(misc.TwoSpotRexValue(rawLine))
  94. case strings.Contains(rawLine, "using v3.1 scheme"):
  95. infoRes.V3_1 = boolExtractor(misc.TwoSpotRexValue(rawLine))
  96. case strings.Contains(rawLine, "using v4 scheme"):
  97. infoRes.V4 = boolExtractor(misc.TwoSpotRexValue(rawLine))
  98. case strings.HasPrefix(rawLine, "Signer #") && strings.Contains(rawLine, "certificate DN"):
  99. // This is first line and we can use append
  100. infoRes.SignInfo = append(infoRes.SignInfo, SignatureInfo{CertDN: getDN(misc.TwoSpotRexValue(rawLine))})
  101. case strings.HasPrefix(rawLine, "Signer #") && strings.Contains(rawLine, "certificate SHA-256 digest"):
  102. infoRes.SignInfo[getSingerNumber(rawLine)-1].CertSHA256 = misc.TwoSpotRexValue(rawLine)
  103. case strings.HasPrefix(rawLine, "Signer #") && strings.Contains(rawLine, "certificate SHA-1 digest"):
  104. infoRes.SignInfo[getSingerNumber(rawLine)-1].CertSHA1 = misc.TwoSpotRexValue(rawLine)
  105. case strings.HasPrefix(rawLine, "Signer #") && strings.Contains(rawLine, "certificate MD5 digest"):
  106. infoRes.SignInfo[getSingerNumber(rawLine)-1].CertMD5 = misc.TwoSpotRexValue(rawLine)
  107. case strings.HasPrefix(rawLine, "Signer #") && strings.Contains(rawLine, "key algorithm"):
  108. infoRes.SignInfo[getSingerNumber(rawLine)-1].KeyAlgorithm = misc.TwoSpotRexValue(rawLine)
  109. case strings.HasPrefix(rawLine, "Signer #") && strings.Contains(rawLine, "key size (bits)"):
  110. infoRes.SignInfo[getSingerNumber(rawLine)-1].KeySize = misc.IntExtractor(misc.TwoSpotRexValue(rawLine))
  111. case strings.HasPrefix(rawLine, "Signer #") && strings.Contains(rawLine, "public key SHA-256 digest"):
  112. infoRes.SignInfo[getSingerNumber(rawLine)-1].PubKeySHA256 = misc.TwoSpotRexValue(rawLine)
  113. case strings.HasPrefix(rawLine, "Signer #") && strings.Contains(rawLine, "public key SHA-1 digest"):
  114. infoRes.SignInfo[getSingerNumber(rawLine)-1].PubKeySHA1 = misc.TwoSpotRexValue(rawLine)
  115. case strings.HasPrefix(rawLine, "Signer #") && strings.Contains(rawLine, "public key MD5 digest"):
  116. infoRes.SignInfo[getSingerNumber(rawLine)-1].PubKeyMD5 = misc.TwoSpotRexValue(rawLine)
  117. case strings.Contains(rawLine, "not protected by signature"):
  118. infoRes.NotProtected = append(infoRes.NotProtected, getNotProtectedFile(rawLine))
  119. // for v3.1 only
  120. case strings.HasPrefix(rawLine, "Signer (minSdkVersion=") && strings.Contains(rawLine, "certificate DN"):
  121. index += 1
  122. // This is first line and we can use append
  123. infoRes.SignInfo = append(infoRes.SignInfo, SignatureInfo{CertDN: getDN(misc.TwoSpotRexValue(rawLine))})
  124. infoRes.SignInfo[index].MinSdk = getMinSdk(rawLine)
  125. infoRes.SignInfo[index].MaxSdk = getMaxSdk(rawLine)
  126. case strings.HasPrefix(rawLine, "Signer (minSdkVersion=") && strings.Contains(rawLine, "certificate SHA-256 digest"):
  127. infoRes.SignInfo[index].CertSHA256 = misc.TwoSpotRexValue(rawLine)
  128. case strings.HasPrefix(rawLine, "Signer (minSdkVersion=") && strings.Contains(rawLine, "certificate SHA-1 digest"):
  129. infoRes.SignInfo[index].CertSHA1 = misc.TwoSpotRexValue(rawLine)
  130. case strings.HasPrefix(rawLine, "Signer (minSdkVersion=") && strings.Contains(rawLine, "certificate MD5 digest"):
  131. infoRes.SignInfo[index].CertMD5 = misc.TwoSpotRexValue(rawLine)
  132. case strings.HasPrefix(rawLine, "Signer (minSdkVersion=") && strings.Contains(rawLine, "key algorithm"):
  133. infoRes.SignInfo[index].KeyAlgorithm = misc.TwoSpotRexValue(rawLine)
  134. case strings.HasPrefix(rawLine, "Signer (minSdkVersion=") && strings.Contains(rawLine, "key size (bits)"):
  135. infoRes.SignInfo[index].KeySize = misc.IntExtractor(misc.TwoSpotRexValue(rawLine))
  136. case strings.HasPrefix(rawLine, "Signer (minSdkVersion=") && strings.Contains(rawLine, "public key SHA-256 digest"):
  137. infoRes.SignInfo[index].PubKeySHA256 = misc.TwoSpotRexValue(rawLine)
  138. case strings.HasPrefix(rawLine, "Signer (minSdkVersion=") && strings.Contains(rawLine, "public key SHA-1 digest"):
  139. infoRes.SignInfo[index].PubKeySHA1 = misc.TwoSpotRexValue(rawLine)
  140. case strings.HasPrefix(rawLine, "Signer (minSdkVersion=") && strings.Contains(rawLine, "public key MD5 digest"):
  141. infoRes.SignInfo[index].PubKeyMD5 = misc.TwoSpotRexValue(rawLine)
  142. }
  143. }
  144. return infoRes
  145. }