From 4799617cedff0ddbfc0bfaf12b91fe592e815245 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 29 Apr 2022 19:11:38 +0600 Subject: [PATCH] "TelegramAPIUrlsKeeper" now have two new things: properties "webAppDataSecretKey" and fun "checkWebAppLink" --- CHANGELOG.md | 3 ++ .../kotlin/dev/inmo/tgbotapi/utils/Crypto.kt | 7 +++++ .../tgbotapi/utils/TelegramAPIUrlsKeeper.kt | 10 +++++++ .../dev/inmo/tgbotapi/utils/CryptoActual.kt | 8 +++++ .../dev/inmo/tgbotapi/utils/CryptoActual.kt | 29 +++++++++++++++++++ tgbotapi.webapps/build.gradle | 7 +++++ .../inmo/tgbotapi/webapps/CheckWebAppData.kt | 9 ++++++ .../dev/inmo/tgbotapi/webapps/WebApp.kt | 8 +++-- 8 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/Crypto.kt create mode 100644 tgbotapi.core/src/jsMain/kotlin/dev/inmo/tgbotapi/utils/CryptoActual.kt create mode 100644 tgbotapi.core/src/jvmMain/kotlin/dev/inmo/tgbotapi/utils/CryptoActual.kt create mode 100644 tgbotapi.webapps/src/commonMain/kotlin/dev/inmo/tgbotapi/webapps/CheckWebAppData.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index a057605c48..73e15253e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 0.38.16 +* `Core`: + * `TelegramAPIUrlsKeeper` now have two new things: properties `webAppDataSecretKey` and fun `checkWebAppLink` + ## 0.38.15 * `Common`: diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/Crypto.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/Crypto.kt new file mode 100644 index 0000000000..163dffea01 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/Crypto.kt @@ -0,0 +1,7 @@ +package dev.inmo.tgbotapi.utils + +import dev.inmo.micro_utils.crypto.SourceString + +internal expect fun SourceString.hmacSha256(key: String): String + +internal expect fun SourceString.hex(): String diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/TelegramAPIUrlsKeeper.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/TelegramAPIUrlsKeeper.kt index 422634479e..649a8ccc2b 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/TelegramAPIUrlsKeeper.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/TelegramAPIUrlsKeeper.kt @@ -18,6 +18,10 @@ class TelegramAPIUrlsKeeper( token: String, hostUrl: String = telegramBotAPIDefaultUrl ) { + val webAppDataSecretKey by lazy { + token.hmacSha256("WebAppData") + } + val commonAPIUrl: String val fileBaseUrl: String @@ -28,4 +32,10 @@ class TelegramAPIUrlsKeeper( } fun createFileLinkUrl(filePath: String) = "${fileBaseUrl}/$filePath" + + /** + * @param rawData Data from [dev.inmo.tgbotapi.webapps.WebApp.initData] + * @param hash Data from [dev.inmo.tgbotapi.webapps.WebApp.initDataUnsafe] from the field [dev.inmo.tgbotapi.webapps.WebAppInitData.hash] + */ + fun checkWebAppLink(rawData: String, hash: String) = rawData.hmacSha256(webAppDataSecretKey).hex() == hash } diff --git a/tgbotapi.core/src/jsMain/kotlin/dev/inmo/tgbotapi/utils/CryptoActual.kt b/tgbotapi.core/src/jsMain/kotlin/dev/inmo/tgbotapi/utils/CryptoActual.kt new file mode 100644 index 0000000000..821bdea167 --- /dev/null +++ b/tgbotapi.core/src/jsMain/kotlin/dev/inmo/tgbotapi/utils/CryptoActual.kt @@ -0,0 +1,8 @@ +package dev.inmo.tgbotapi.utils + +import dev.inmo.micro_utils.crypto.CryptoJS +import dev.inmo.micro_utils.crypto.SourceString + +actual fun SourceString.hmacSha256(key: String) = CryptoJS.asDynamic().HmacSHA256(this, key).unsafeCast() + +actual fun SourceString.hex() = CryptoJS.asDynamic().format.Hex(this).unsafeCast() diff --git a/tgbotapi.core/src/jvmMain/kotlin/dev/inmo/tgbotapi/utils/CryptoActual.kt b/tgbotapi.core/src/jvmMain/kotlin/dev/inmo/tgbotapi/utils/CryptoActual.kt new file mode 100644 index 0000000000..7a63c5f7e6 --- /dev/null +++ b/tgbotapi.core/src/jvmMain/kotlin/dev/inmo/tgbotapi/utils/CryptoActual.kt @@ -0,0 +1,29 @@ +package dev.inmo.tgbotapi.utils + +import dev.inmo.micro_utils.crypto.SourceBytes +import dev.inmo.micro_utils.crypto.SourceString +import javax.crypto.Mac +import javax.crypto.spec.SecretKeySpec + +val HEX_ARRAY = "0123456789ABCDEF".toCharArray() + +private fun SourceBytes.hex(): String { + val hexChars = CharArray(size * 2) + for (j in indices) { + val v: Int = this[j].toInt() and 0xFF + hexChars[j * 2] = HEX_ARRAY[v ushr 4] + hexChars[j * 2 + 1] = HEX_ARRAY[v and 0x0F] + } + return String(hexChars) +} + +actual fun SourceString.hmacSha256(key: String): String { + val mac = Mac.getInstance("HmacSHA256") + + val secretKey = SecretKeySpec(key.toByteArray(), "HmacSHA256") + mac.init(secretKey) + + return mac.doFinal(toByteArray()).hex() +} + +actual fun SourceString.hex(): String = toByteArray().hex() diff --git a/tgbotapi.webapps/build.gradle b/tgbotapi.webapps/build.gradle index 257fcf8f02..951c331574 100644 --- a/tgbotapi.webapps/build.gradle +++ b/tgbotapi.webapps/build.gradle @@ -27,6 +27,13 @@ repositories { } kotlin { + jvm { + compilations.main { + kotlinOptions { + jvmTarget = "1.8" + } + } + } js(IR) { browser() nodejs() diff --git a/tgbotapi.webapps/src/commonMain/kotlin/dev/inmo/tgbotapi/webapps/CheckWebAppData.kt b/tgbotapi.webapps/src/commonMain/kotlin/dev/inmo/tgbotapi/webapps/CheckWebAppData.kt new file mode 100644 index 0000000000..19f09d7a0f --- /dev/null +++ b/tgbotapi.webapps/src/commonMain/kotlin/dev/inmo/tgbotapi/webapps/CheckWebAppData.kt @@ -0,0 +1,9 @@ +package dev.inmo.tgbotapi.webapps + +import dev.inmo.tgbotapi.utils.* + +/** + * @param rawData Data from [dev.inmo.tgbotapi.webapps.WebApp.initData] + * @param hash Data from [dev.inmo.tgbotapi.webapps.WebApp.initDataUnsafe] from the field [dev.inmo.tgbotapi.webapps.WebAppInitData.hash] + */ +fun TelegramAPIUrlsKeeper.checkWebAppLink(rawData: String, hash: String) = rawData.hmacSha256(webAppDataSecretKey).hex() == hash diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebApp.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebApp.kt index 5422c340c2..dd1d788940 100644 --- a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebApp.kt +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebApp.kt @@ -1,6 +1,7 @@ package dev.inmo.tgbotapi.webapps import dev.inmo.micro_utils.crypto.CryptoJS +import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper external class WebApp { val initData: String @@ -76,6 +77,7 @@ fun WebApp.onMainButtonClicked(eventHandler: EventHandler) = onEvent(EventType.M */ fun WebApp.onViewportChanged(eventHandler: ViewportChangedEventHandler) = onEvent(EventType.ViewportChanged, eventHandler) -fun WebApp.isInitDataSafe(botToken: String) = CryptoJS.hex( - CryptoJS.HmacSHA256(botToken, "WebAppData") -) == initDataUnsafe.hash +fun WebApp.isInitDataSafe(botToken: String) = TelegramAPIUrlsKeeper(botToken).checkWebAppLink( + initData, + initDataUnsafe.hash +)