diff --git a/KeyboardsBot/KeyboardsBotLib/build.gradle b/KeyboardsBot/KeyboardsBotLib/build.gradle index bda3692..8abfe8a 100644 --- a/KeyboardsBot/KeyboardsBotLib/build.gradle +++ b/KeyboardsBot/KeyboardsBotLib/build.gradle @@ -9,7 +9,7 @@ buildscript { } plugins { - id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version" + id "org.jetbrains.kotlin.multiplatform" } diff --git a/ResenderBot/ResenderBotLib/build.gradle b/ResenderBot/ResenderBotLib/build.gradle index 21b03ee..1d40c3e 100644 --- a/ResenderBot/ResenderBotLib/build.gradle +++ b/ResenderBot/ResenderBotLib/build.gradle @@ -9,7 +9,7 @@ buildscript { } plugins { - id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version" + id "org.jetbrains.kotlin.multiplatform" } diff --git a/WebApp/build.gradle b/WebApp/build.gradle index 334217c..53e310e 100644 --- a/WebApp/build.gradle +++ b/WebApp/build.gradle @@ -9,7 +9,8 @@ buildscript { } plugins { - id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version" + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" } apply plugin: 'application' @@ -25,6 +26,7 @@ kotlin { commonMain { dependencies { implementation kotlin('stdlib') + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version" } } diff --git a/WebApp/src/commonMain/kotlin/WebAppDataWrapper.kt b/WebApp/src/commonMain/kotlin/WebAppDataWrapper.kt new file mode 100644 index 0000000..b8bede6 --- /dev/null +++ b/WebApp/src/commonMain/kotlin/WebAppDataWrapper.kt @@ -0,0 +1,7 @@ +import kotlinx.serialization.Serializable + +@Serializable +data class WebAppDataWrapper( + val data: String, + val hash: String +) diff --git a/WebApp/src/jsMain/kotlin/main.kt b/WebApp/src/jsMain/kotlin/main.kt index 3691e25..0640c2c 100644 --- a/WebApp/src/jsMain/kotlin/main.kt +++ b/WebApp/src/jsMain/kotlin/main.kt @@ -2,10 +2,8 @@ import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions import dev.inmo.tgbotapi.types.webAppQueryIdField import dev.inmo.tgbotapi.webapps.* import io.ktor.client.HttpClient -import io.ktor.client.call.receive import io.ktor.client.request.* -import io.ktor.client.statement.HttpResponse -import io.ktor.client.statement.readText +import io.ktor.client.statement.bodyAsText import io.ktor.http.* import io.ktor.http.content.TextContent import kotlinx.browser.document @@ -13,6 +11,7 @@ import kotlinx.browser.window import kotlinx.coroutines.* import kotlinx.dom.appendElement import kotlinx.dom.appendText +import kotlinx.serialization.json.Json import org.w3c.dom.HTMLElement fun HTMLElement.log(text: String) { @@ -22,14 +21,38 @@ fun HTMLElement.log(text: String) { fun main() { console.log("Web app started") + val client = HttpClient() + val baseUrl = window.location.origin.removeSuffix("/") + window.onload = { val scope = CoroutineScope(Dispatchers.Default) runCatching { + + scope.launchSafelyWithoutExceptions { + val response = client.post("$baseUrl/check") { + setBody( + Json { }.encodeToString( + WebAppDataWrapper.serializer(), + WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash) + ) + ) + } + val dataIsSafe = response.bodyAsText().toBoolean() + + document.body ?.appendElement("div") { + textContent = if (dataIsSafe) { + "Data is safe" + } else { + "Data is unsafe" + } + } + } + document.body ?.appendElement("button") { addEventListener("click", { scope.launchSafelyWithoutExceptions { handleResult({ "Clicked" }) { - HttpClient().post("${window.location.origin.removeSuffix("/")}/inline") { + client.post("${window.location.origin.removeSuffix("/")}/inline") { parameter(webAppQueryIdField, it) setBody(TextContent("Clicked", ContentType.Text.Plain)) document.body ?.log(url.build().toString()) diff --git a/WebApp/src/jvmMain/kotlin/WebAppServer.kt b/WebApp/src/jvmMain/kotlin/WebAppServer.kt index 5deb2f8..b6766c3 100644 --- a/WebApp/src/jvmMain/kotlin/WebAppServer.kt +++ b/WebApp/src/jvmMain/kotlin/WebAppServer.kt @@ -1,4 +1,5 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.micro_utils.crypto.hmacSha256 import dev.inmo.micro_utils.ktor.server.createKtorServer import dev.inmo.tgbotapi.extensions.api.answers.answer import dev.inmo.tgbotapi.extensions.api.bot.getMe @@ -16,7 +17,8 @@ import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessag import dev.inmo.tgbotapi.types.webAppQueryIdField import dev.inmo.tgbotapi.types.webapps.WebAppInfo import dev.inmo.tgbotapi.utils.PreviewFeature -import io.ktor.http.HttpStatusCode +import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper +import io.ktor.http.* import io.ktor.server.application.call import io.ktor.server.http.content.* import io.ktor.server.request.receiveText @@ -24,7 +26,9 @@ import io.ktor.server.response.respond import io.ktor.server.routing.post import io.ktor.server.routing.routing import kotlinx.coroutines.Dispatchers +import kotlinx.serialization.json.Json import java.io.File +import java.nio.charset.Charset /** * Accepts two parameters: @@ -36,7 +40,11 @@ import java.io.File */ @OptIn(PreviewFeature::class) suspend fun main(vararg args: String) { - val bot = telegramBot(args.first(), testServer = args.any { it == "testServer" }) + val telegramBotAPIUrlsKeeper = TelegramAPIUrlsKeeper( + args.first(), + testServer = args.any { it == "testServer" } + ) + val bot = telegramBot(telegramBotAPIUrlsKeeper) createKtorServer( "0.0.0.0", 8080, @@ -56,6 +64,14 @@ suspend fun main(vararg args: String) { bot.answer(queryId, InlineQueryResultArticle(queryId, "Result", InputTextMessageContent(requestBody))) call.respond(HttpStatusCode.OK) } + post("check") { + val requestBody = call.receiveText() + val webAppCheckData = Json { }.decodeFromString(WebAppDataWrapper.serializer(), requestBody) + + val isSafe = telegramBotAPIUrlsKeeper.checkWebAppLink(webAppCheckData.data, webAppCheckData.hash) + + call.respond(HttpStatusCode.OK, isSafe.toString()) + } } }.start(false) diff --git a/build.gradle b/build.gradle index 56c12ba..05027b6 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,14 @@ +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" + } +} + allprojects { repositories { mavenLocal() diff --git a/gradle.properties b/gradle.properties index a0d143d..99d4793 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,4 +7,5 @@ org.gradle.jvmargs=-Xmx768m kotlin_version=1.6.21 telegram_bot_api_version=1.1.0 micro_utils_version=0.10.4 +serialization_version=1.3.3 ktor_version=2.0.1