1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-17 04:20:13 +00:00

Compare commits

..

14 Commits
1.0.0 ... 1.1.1

7 changed files with 90 additions and 49 deletions

View File

@@ -1,5 +1,26 @@
# TelegramBotAPI changelog # TelegramBotAPI changelog
## 1.1.1
* `Versions`:
* `MicroUtils.Crypto` will not be provided with that library anymore. Instead, it is recommended to use `Korlibs.Krypto`. You still can add crypto from microutils using next groovy dependency: `dev.inmo:micro_utils.crypto:$micro_utils_version`
* `Core`:
* Improvements in `TelegramAPIUrlsKeeper#checkWebAppLink`
* New field in `TelegramAPIUrlsKeeper#webAppDataSecretKeyHash`
* `Behaviour Builder`:
* Extension `TelegramBot#buildBehaviour` now returns `BehaviourContext`
## 1.1.0
* `Utils`:
* New parameter `additionalApplicationEngineEnvironmentConfigurator` in `RequestsExecutor#setWebhookInfoAndStartListenWebhooks` and `startListenWebhooks`
## 1.0.1
* `Versions`:
* `Serialization`: `1.3.2` -> `1.3.3`
* `MicroUtils`: `0.10.3` -> `0.10.4`
## 1.0.0 ## 1.0.0
__All the `tgbotapi.extensions.*` packages have been removed__ __All the `tgbotapi.extensions.*` packages have been removed__
@@ -7,7 +28,7 @@ __All the `tgbotapi.extensions.*` packages have been removed__
* `Versions`: * `Versions`:
* `Kotlin`: `1.6.10` -> `1.6.21` * `Kotlin`: `1.6.10` -> `1.6.21`
* `Ktor`: `1.6.8` -> `2.0.1` * `Ktor`: `1.6.8` -> `2.0.1`
* `MicroUtils`: `0.9.24` -> `0.10.2` * `MicroUtils`: `0.9.24` -> `0.10.3`
* `Core`: * `Core`:
* **`Ktor` package renamed. Migration:** `dev.inmo.tgbotapi.bot.Ktor` -> `dev.inmo.tgbotapi.bot.ktor` * **`Ktor` package renamed. Migration:** `dev.inmo.tgbotapi.bot.Ktor` -> `dev.inmo.tgbotapi.bot.ktor`
* **`CallbackQuery` package renamed. Migration:** `dev.inmo.tgbotapi.types.CallbackQuery([\s\\.])` -> `dev.inmo.tgbotapi.types.queries.callback$1` * **`CallbackQuery` package renamed. Migration:** `dev.inmo.tgbotapi.types.CallbackQuery([\s\\.])` -> `dev.inmo.tgbotapi.types.queries.callback$1`

View File

@@ -7,12 +7,12 @@ kotlin.incremental.js=true
kotlin_version=1.6.21 kotlin_version=1.6.21
kotlin_coroutines_version=1.6.1 kotlin_coroutines_version=1.6.1
kotlin_serialisation_runtime_version=1.3.2 kotlin_serialisation_runtime_version=1.3.3
klock_version=2.7.0 korlibs_version=2.7.0
uuid_version=0.4.0 uuid_version=0.4.0
ktor_version=2.0.1 ktor_version=2.0.1
micro_utils_version=0.10.3 micro_utils_version=0.10.4
javax_activation_version=1.1.1 javax_activation_version=1.1.1
@@ -20,6 +20,6 @@ javax_activation_version=1.1.1
dokka_version=1.6.21 dokka_version=1.6.21
library_group=dev.inmo library_group=dev.inmo
library_version=1.0.0 library_version=1.1.1
github_release_plugin_version=2.3.7 github_release_plugin_version=2.3.7

View File

@@ -7,8 +7,7 @@ import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
import dev.inmo.tgbotapi.utils.PreviewFeature import dev.inmo.tgbotapi.utils.PreviewFeature
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.plus
/** /**
* This function is used in [buildBehaviour] extensions to provide default [CoroutineScope] and allow to avoid all * This function is used in [buildBehaviour] extensions to provide default [CoroutineScope] and allow to avoid all
@@ -30,18 +29,18 @@ suspend fun TelegramBot.buildBehaviour(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
block: BehaviourContextReceiver<Unit> block: BehaviourContextReceiver<Unit>
) { ): BehaviourContext = BehaviourContext(
BehaviourContext( this,
this, scope.let {
scope.let { if (defaultExceptionsHandler == null) {
if (defaultExceptionsHandler == null) { it
it } else {
} else { it + ContextSafelyExceptionHandler(defaultExceptionsHandler)
it + ContextSafelyExceptionHandler(defaultExceptionsHandler) }
} },
}, flowUpdatesFilter
flowUpdatesFilter ).apply {
).block() block()
} }
/** /**
@@ -56,15 +55,14 @@ suspend fun TelegramBot.buildBehaviourWithLongPolling(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
block: BehaviourContextReceiver<Unit> block: BehaviourContextReceiver<Unit>
) = FlowsUpdatesFilter().let { ): Job {
buildBehaviour( val behaviourContext = buildBehaviour(
it, scope = scope,
scope, defaultExceptionsHandler = defaultExceptionsHandler,
defaultExceptionsHandler, block = block
block
) )
longPolling( return longPolling(
it, behaviourContext,
scope = scope scope = behaviourContext
) )
} }

View File

@@ -47,10 +47,10 @@ kotlin {
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_runtime_version" api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_runtime_version"
api "org.jetbrains.kotlinx:kotlinx-serialization-properties:$kotlin_serialisation_runtime_version" api "org.jetbrains.kotlinx:kotlinx-serialization-properties:$kotlin_serialisation_runtime_version"
api "com.soywiz.korlibs.klock:klock:$klock_version" api "com.soywiz.korlibs.klock:klock:$korlibs_version"
api "com.soywiz.korlibs.krypto:krypto:$korlibs_version"
api "com.benasher44:uuid:$uuid_version" api "com.benasher44:uuid:$uuid_version"
api "dev.inmo:micro_utils.crypto:$micro_utils_version"
api "dev.inmo:micro_utils.coroutines:$micro_utils_version" api "dev.inmo:micro_utils.coroutines:$micro_utils_version"
api "dev.inmo:micro_utils.serialization.base64:$micro_utils_version" api "dev.inmo:micro_utils.serialization.base64:$micro_utils_version"
api "dev.inmo:micro_utils.serialization.encapsulator:$micro_utils_version" api "dev.inmo:micro_utils.serialization.encapsulator:$micro_utils_version"

View File

@@ -1,7 +1,8 @@
package dev.inmo.tgbotapi.utils package dev.inmo.tgbotapi.utils
import dev.inmo.micro_utils.crypto.hex import com.soywiz.krypto.*
import dev.inmo.micro_utils.crypto.hmacSha256 import io.ktor.http.decodeURLQueryComponent
import io.ktor.utils.io.core.toByteArray
const val telegramBotAPIDefaultUrl = "https://api.telegram.org" const val telegramBotAPIDefaultUrl = "https://api.telegram.org"
@@ -22,9 +23,11 @@ class TelegramAPIUrlsKeeper(
hostUrl: String = telegramBotAPIDefaultUrl, hostUrl: String = telegramBotAPIDefaultUrl,
urlsSuffixes: String = "" urlsSuffixes: String = ""
) { ) {
val webAppDataSecretKey by lazy { val webAppDataSecretKeyHash by lazy {
token.hmacSha256("WebAppData") HMAC.hmacSHA256("WebAppData".toByteArray(), token.toByteArray())
} }
val webAppDataSecretKey
get() = webAppDataSecretKeyHash.hexLower
val commonAPIUrl: String val commonAPIUrl: String
val fileBaseUrl: String val fileBaseUrl: String
@@ -47,5 +50,14 @@ class TelegramAPIUrlsKeeper(
* @param rawData Data from [dev.inmo.tgbotapi.webapps.WebApp.initData] * @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] * @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 fun checkWebAppLink(rawData: String, hash: String): Boolean {
val preparedData = rawData
.decodeURLQueryComponent()
.split("&")
.filterNot { it.startsWith("hash=") }
.sorted()
.joinToString("\n")
return HMAC.hmacSHA256(webAppDataSecretKeyHash.bytes, preparedData.toByteArray()).hexLower == hash.lowercase()
}
} }

View File

@@ -1,7 +1,6 @@
package dev.inmo.tgbotapi.extensions.utils.updates.retrieving package dev.inmo.tgbotapi.extensions.utils.updates.retrieving
import dev.inmo.micro_utils.coroutines.ExceptionHandler import dev.inmo.micro_utils.coroutines.*
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.RequestsExecutor import dev.inmo.tgbotapi.bot.RequestsExecutor
import dev.inmo.tgbotapi.extensions.utils.nonstrictJsonFormat import dev.inmo.tgbotapi.extensions.utils.nonstrictJsonFormat
import dev.inmo.tgbotapi.extensions.utils.updates.flowsUpdatesFilter import dev.inmo.tgbotapi.extensions.utils.updates.flowsUpdatesFilter
@@ -10,6 +9,7 @@ import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.types.update.abstracts.UpdateDeserializationStrategy import dev.inmo.tgbotapi.types.update.abstracts.UpdateDeserializationStrategy
import dev.inmo.tgbotapi.updateshandlers.* import dev.inmo.tgbotapi.updateshandlers.*
import dev.inmo.tgbotapi.updateshandlers.webhook.WebhookPrivateKeyConfig import dev.inmo.tgbotapi.updateshandlers.webhook.WebhookPrivateKeyConfig
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call import io.ktor.server.application.call
import io.ktor.server.engine.* import io.ktor.server.engine.*
import io.ktor.server.request.receiveText import io.ktor.server.request.receiveText
@@ -39,18 +39,22 @@ fun Route.includeWebhookHandlingInRoute(
) { ) {
val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block, mediaGroupsDebounceTimeMillis) val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block, mediaGroupsDebounceTimeMillis)
post { post {
safely( try {
exceptionsHandler ?: {} runCatchingSafely {
) { val asJson = nonstrictJsonFormat.parseToJsonElement(call.receiveText())
val asJson = val update = nonstrictJsonFormat.decodeFromJsonElement(
nonstrictJsonFormat.parseToJsonElement(call.receiveText()) UpdateDeserializationStrategy,
val update = nonstrictJsonFormat.decodeFromJsonElement( asJson
UpdateDeserializationStrategy, )
asJson transformer(update)
) }.onSuccess {
transformer(update) call.respond(HttpStatusCode.OK)
}.onFailure {
call.respond(HttpStatusCode.InternalServerError)
}.getOrThrow()
} catch (e: Throwable) {
exceptionsHandler ?.invoke(e)
} }
call.respond("Ok")
} }
} }
@@ -87,6 +91,7 @@ fun startListenWebhooks(
privateKeyConfig: WebhookPrivateKeyConfig? = null, privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()), scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
mediaGroupsDebounceTimeMillis: Long = 1000L, mediaGroupsDebounceTimeMillis: Long = 1000L,
additionalApplicationEngineEnvironmentConfigurator: ApplicationEngineEnvironmentBuilder.() -> Unit = {},
block: UpdateReceiver<Update> block: UpdateReceiver<Update>
): ApplicationEngine { ): ApplicationEngine {
val env = applicationEngineEnvironment { val env = applicationEngineEnvironment {
@@ -98,6 +103,7 @@ fun startListenWebhooks(
} ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block) } ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block)
} }
} }
privateKeyConfig ?.let { privateKeyConfig ?.let {
sslConnector( sslConnector(
privateKeyConfig.keyStore, privateKeyConfig.keyStore,
@@ -113,6 +119,7 @@ fun startListenWebhooks(
port = listenPort port = listenPort
} }
additionalApplicationEngineEnvironmentConfigurator()
} }
return embeddedServer(engineFactory, env).also { return embeddedServer(engineFactory, env).also {
@@ -142,10 +149,11 @@ suspend fun RequestsExecutor.setWebhookInfoAndStartListenWebhooks(
privateKeyConfig: WebhookPrivateKeyConfig? = null, privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()), scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
mediaGroupsDebounceTimeMillis: Long = 1000L, mediaGroupsDebounceTimeMillis: Long = 1000L,
additionalApplicationEngineEnvironmentConfigurator: ApplicationEngineEnvironmentBuilder.() -> Unit = {},
block: UpdateReceiver<Update> block: UpdateReceiver<Update>
): ApplicationEngine = try { ): ApplicationEngine = try {
execute(setWebhookRequest) execute(setWebhookRequest)
startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, mediaGroupsDebounceTimeMillis, block) startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, mediaGroupsDebounceTimeMillis, additionalApplicationEngineEnvironmentConfigurator, block)
} catch (e: Exception) { } catch (e: Exception) {
throw e throw e
} }

View File

@@ -2,6 +2,8 @@ package dev.inmo.tgbotapi.webapps
import dev.inmo.micro_utils.crypto.CryptoJs import dev.inmo.micro_utils.crypto.CryptoJs
@Deprecated("Useless")
fun CryptoJs.HmacSHA256(text: String, key: String) = this.asDynamic().HmacSHA256(text, key).unsafeCast<String>() fun CryptoJs.HmacSHA256(text: String, key: String) = this.asDynamic().HmacSHA256(text, key).unsafeCast<String>()
@Deprecated("Useless")
fun CryptoJs.hex(text: String) = this.asDynamic().format.Hex(text).unsafeCast<String>() fun CryptoJs.hex(text: String) = this.asDynamic().format.Hex(text).unsafeCast<String>()