From ec264c2ebc1e7760d660f45b73fbc01141dbe81b Mon Sep 17 00:00:00 2001 From: Kyri Petrou Date: Fri, 28 Jun 2024 22:09:33 +1000 Subject: [PATCH] Optimize APQ hash checking --- .../wrappers/ApolloPersistedQueries.scala | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala/caliban/wrappers/ApolloPersistedQueries.scala b/core/src/main/scala/caliban/wrappers/ApolloPersistedQueries.scala index 31bd691fd..17a23fdf4 100644 --- a/core/src/main/scala/caliban/wrappers/ApolloPersistedQueries.scala +++ b/core/src/main/scala/caliban/wrappers/ApolloPersistedQueries.scala @@ -120,15 +120,26 @@ object ApolloPersistedQueries { case _ => None } - private def hex(bytes: Array[Byte]): String = { - val builder = new mutable.StringBuilder(bytes.length * 2) - bytes.foreach(byte => builder.append(f"$byte%02x".toLowerCase)) - builder.mkString - } + private val HexArray: Array[Char] = "0123456789abcdef".toCharArray private def checkHash(hash: String, query: String): Boolean = { val sha256 = java.security.MessageDigest.getInstance("SHA-256") val digest = sha256.digest(query.getBytes(StandardCharsets.UTF_8)) - hex(digest) == hash + digestMatchesHash(digest, hash) } + + private def digestMatchesHash(digest: Array[Byte], hash: String): Boolean = { + val chars = hash.toCharArray + val size = digest.length + var j = 0 + var res = chars.length == size * 2 + while (j < size && res) { + val v = digest(j) & 0xff + if (chars(j * 2) == HexArray(v >>> 4) && chars(j * 2 + 1) == HexArray(v & 0xf)) () + else res = false + j += 1 + } + res + } + }