• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hyperledger / identus-cloud-agent / 11056733508

26 Sep 2024 04:52PM UTC coverage: 48.532% (-0.03%) from 48.558%
11056733508

Pull #1366

CryptoKnightIOG
ATL-7775: Fix integration test

Signed-off-by: Bassam Riman <bassam.riman@iohk.io>
Pull Request #1366: feat: Default Backend API to Array Of Credential Schema

41 of 54 new or added lines in 8 files covered. (75.93%)

187 existing lines in 61 files now uncovered.

7622 of 15705 relevant lines covered (48.53%)

0.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.58
/castor/src/main/scala/org/hyperledger/identus/castor/core/util/UriUtils.scala
1
package org.hyperledger.identus.castor.core.util
2

3
import io.lemonlabs.uri.{QueryString, Uri, Url, Urn}
4
import io.lemonlabs.uri.config.UriConfig
5
import io.lemonlabs.uri.decoding.UriDecodeException
6
import io.lemonlabs.uri.encoding.PercentEncoder
7

8
// TODO: unify with the logic used in Node
9
// https://github.com/input-output-hk/atala-prism/blob/ba7b3e3ef307f6bd06734af2bf8fed9b119ee98e/prism-backend/common/src/main/scala/io/iohk/atala/prism/utils/UriUtils.scala
10
object UriUtils {
11

12
  /** Normalized URI according to <a
13
    * href="https://www.rfc-editor.org/rfc/rfc3986#section-6">RFC&nbsp;3986,&nbsp;section-6</a>
14
    *
15
    * @param uri
16
    * @return
17
    *   [[Some]](uri) - normalized uri, if it is a valid uri string, or [[None]]
18
    */
19
  def normalizeUri(uriStr: String): Option[String] = {
1✔
20

21
    /*
22
     * List of normalizations performed:
23
     *   percent encoding normalization
24
     *     decode unreserved characters
25
     *   case normalization
26
     *     scheme and host to lowercase
27
     *     all percent encoded triplets use uppercase hexadecimal chars
28
     *   path segment normalization
29
     *     remove "." and ".." segments from path
30
     *     remove duplicate forward slashes (//) from path
31
     *   scheme specific normalization (http, https) since it is likely to be often used type of URL
32
     *     remove default port
33
     *     sort query parameters by key alphabetically
34
     *     remove duplicates (by name/key)
35
     *     encode special characters that are disallowed in path and query
36
     *     decode the ones that are allowed if encoded
37
     *
38
     * for URN:
39
     *   convert to lowercase
40
     *   decode all percent encoded triplets (including unreserved)
41
     *   encode any that need to be encodedparsingutils
42
     *
43
     * URL without a scheme is treated as invalid
44
     */
45
    implicit val config: UriConfig = UriConfig.default.copy(queryEncoder = PercentEncoder())
1✔
46

47
    try {
1✔
48
      // parsing decodes the percent encoded triplets, including unreserved chars
49
      val parsed = Uri.parse(uriStr)
1✔
50
      parsed match {
51
        case url: Url =>
UNCOV
52
          if (url.schemeOption.isEmpty) throw new UriDecodeException("Scheme is empty")
×
53
          // lowercase schema
54
          val schemeNormalized = url.schemeOption.map(_.toLowerCase())
1✔
55

56
          // lowercase host if not IP
57
          val hostNormalized = url.hostOption.map(_.normalize)
1✔
58

59
          // removes dot segments and extra //
60
          val pathNormalized = url.path.normalize(removeEmptyParts = true)
1✔
61

62
          // remove unneeded ports
63
          val portNormalized = url.port.flatMap { (port: Int) =>
1✔
64
            schemeNormalized match {
65
              case Some(scheme) =>
1✔
66
                scheme match {
UNCOV
67
                  case "http"       => if (port == 80) None else Some(port)
×
68
                  case "https"      => if (port == 443) None else Some(port)
×
69
                  case "ftp"        => if (port == 21) None else Some(port)
1✔
70
                  case "ws" | "wss" => if (port == 80) None else Some(port)
1✔
71
                  case _            => Some(port)
1✔
72
                }
73
              case None => Some(port)
×
74
            }
75
          }
76

77
          val queryNormalized = {
78
            // filter duplicate keys (last one stays) and sort alphabetically (by key)
79
            val filtered = url.query.params.toMap.toVector.sortBy(_._1)
1✔
80
            QueryString(filtered)
81
          }
82

83
          // construction of the instance encodes all special characters that are disallowed in path and query
84
          val urlNormalized = Url(
1✔
85
            scheme = schemeNormalized.orNull,
1✔
86
            user = url.user.orNull,
1✔
87
            password = url.password.orNull,
1✔
88
            host = hostNormalized.map(_.toString).orNull,
1✔
89
            port = portNormalized.getOrElse(-1),
1✔
90
            path = pathNormalized.toString,
1✔
91
            query = queryNormalized,
92
            fragment = url.fragment.orNull
1✔
93
          )
94

95
          Some(urlNormalized.toString)
1✔
96

97
        case urn: Urn =>
1✔
98
          Some(urn.toString.toLowerCase)
1✔
99
      }
100
    } catch {
101
      case _: Exception => None
×
102
    }
103
  }
104

105
  def isValidUriString(str: String): Boolean = {
1✔
106
    try {
1✔
107
      Uri.parse(str) match {
1✔
108
        case url: Url => url.schemeOption.nonEmpty
1✔
109
        case Urn(_)   => true
×
110
      }
111
    } catch {
112
      case _: Exception => false
×
113
    }
114
  }
115

116
  /** Checks if a string is a valid URI fragment according to <a
117
    * href="https://www.rfc-editor.org/rfc/rfc3986#section-3.5">RFC&nbsp;3986&nbsp;section-3.5</a>
118
    *
119
    * @param str
120
    * @return
121
    *   true if str is a valid URI fragment, otherwise false
122
    */
123
  def isValidUriFragment(str: String): Boolean = {
1✔
124

125
    /*
126
     * Alphanumeric characters (A-Z, a-z, 0-9)
127
     * Some special characters: -._~!$&'()*+,;=:@
128
     * Percent-encoded characters, which are represented by the pattern %[0-9A-Fa-f]{2}
129
     */
130
    val uriFragmentRegex = "^([A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*$".r
1✔
131

132
    // In general, empty URI fragment is a valid fragment, but for our use-case it would be pointless
133
    str.nonEmpty && uriFragmentRegex.matches(str)
1✔
134
  }
135
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc