Closed huangzulin closed 1 year ago
Please use Builder with custom api url
TelegramBot bot = new TelegramBot.Builder("BOT_TOKEN").apiUrl("local-api-url").build();
Hi! I'm trying to run bot with webhooks on local api server, but getting 401 Unauthorized. Here is code listing.
interface TelegramBotService {
fun handleUpdate(update: Update?, token: String): Boolean
}
@ConfigurationProperties(prefix = "com.test.telegrambot", ignoreUnknownFields = false)
data class TelegramBotProperties(
val token: String,
val url: String?,
val telegramApi: TelegramApiProperties = TelegramApiProperties(),
val debug: Boolean = false,
) {
data class TelegramApiProperties(
val telegramApiUrl: String = "https://api.telegram.org/",
val useTestServer: Boolean = false,
)
}
@Configuration
@EnableConfigurationProperties(TelegramBotProperties::class)
class TelegramBotConfig(
private val telegramBotProperties: TelegramBotProperties
) {
private val log: Logger = LoggerFactory.getLogger(this.javaClass)
@Bean
@Order(0)
fun telegramBot(): TelegramBot {
return TelegramBot.Builder(telegramBotProperties.token)
.apiUrl(telegramBotProperties.telegramApi.telegramApiUrl)
.useTestServer(telegramBotProperties.telegramApi.useTestServer)
.let {
if (telegramBotProperties.debug)
return@let it.debug()
else return@let it
}
.build()
}
@Bean
@Order(10)
fun deleteWebhook(telegramBot: TelegramBot): TelegramBot {
val deleteWebhook: DeleteWebhook = DeleteWebhook()
val deleteWebhookResponse: BaseResponse = telegramBot.execute(deleteWebhook)
if (!deleteWebhookResponse.isOk)
throw Error("Error during webhook deletion! ${deleteWebhookResponse.errorCode()} ${deleteWebhookResponse.description()}")
return telegramBot
}
@Bean
@Order(20)
fun configureTelegramBotWebhook(telegramBot: TelegramBot): TelegramBot {
if (telegramBotProperties.url != null) {
deleteWebhook(telegramBot)
log.debug("Configuring webhook for URL: ${telegramBotProperties.url}")
val request = SetWebhook().url(telegramBotProperties.url + "/api/telegram/webhook")
val response: BaseResponse = telegramBot.execute(request)
if (!response.isOk)
throw Error("Error during webhook configuration! ${response.errorCode()}\n${response.description()}")
} else {
log.warn("No webhook url was configured. Continuing with long polling. Use this only in development")
}
return telegramBot
}
}
@Configuration
class SecurityConfig {
@Bean
fun configureTelegramWebhookEndpoint(http: HttpSecurity): SecurityFilterChain {
return http
.csrf { obj: CsrfConfigurer<HttpSecurity> -> obj.disable() }
.cors { cors: CorsConfigurer<HttpSecurity?> ->
cors.configurationSource { request: HttpServletRequest? ->
val corsConfiguration = CorsConfiguration()
corsConfiguration.setAllowedOriginPatterns(listOf("*"))
corsConfiguration.allowedMethods = listOf("POST")
corsConfiguration.allowedHeaders = listOf("*")
corsConfiguration.allowCredentials = true
corsConfiguration.maxAge = 1800L
corsConfiguration
}
}
.securityMatcher("/api/telegram/webhook")
.authorizeHttpRequests { it.anyRequest().permitAll() }
.build()
}
}
@Component
class TelegramBotServiceImpl(
private val telegramBot: TelegramBot
) : TelegramBotService{
private val log: Logger = LoggerFactory.getLogger(this.javaClass)
override fun handleUpdate(update: Update?, token: String): Boolean {
log.trace("Received new update: $update")
log.debug("Token: $token")
if (update!!.message() == null) {
log.trace("No message in update. Skipping.")
return false
}
val message: Message = update.message()
if (message.entities().isEmpty()) {
if (message.text().startsWith("/start")) {
log.trace("This is a \"/start\" command. Sending response")
telegramBot.execute(SendMessage(message.from().id(), "Hello!"))
}
}
return true
}
}
@RestController
@RequestMapping("/api")
class TelegramBotWebhookController(
private val telegramBotService: TelegramBotService
) {
private val log: Logger = LoggerFactory.getLogger(this.javaClass)
@PostMapping("/telegram/webhook")
fun telegramWebhook(@RequestHeader("X-Telegram-Bot-Api-Secret-Token") token: String, @RequestBody update: Update?): Boolean {
log.trace("Received update with webhook: $update")
return telegramBotService.handleUpdate(update, token)
}
}
Looks like, local server requires name to authorize.
DURATION inf 5sec 1min 1hour
uptime 4864.064249
bot_count 2
active_bot_count 2
rss 38984KB
vm 47276KB
rss_peak 38984KB
vm_peak 47500KB
total_cpu 0.805375% 0.505051% 0.637172% 0.805375%
user_cpu 0.352065% 0.202020% 0.300553% 0.352065%
system_cpu 0.453310% 0.303030% 0.336619% 0.453310%
buffer_memory 79360B
active_webhook_connections 0
active_requests 0
active_network_queries 0
request_count 0.031038 0.000000 0.242055 0.031044
request_bytes 7.992706 0.000000 60.513746 7.994349
request_file_count 0.000000 0.000000 0.000000 0.000000
request_files_bytes 0.000000 0.000000 0.000000 0.000000
request_max_bytes 0 0 0 0
response_count 0.031038 0.000000 0.242055 0.031044
response_count_ok 0.000411 0.000000 0.000000 0.000411
response_count_error 0.030627 0.000000 0.242055 0.030633
response_bytes 1.795044 0.000000 14.039189 1.795413
update_count 0.001028 0.000000 0.000000 0.001028
id 6844726460
uptime 287.254129
token ****************
username <failed to authorize>
head_update_id 0
request_count/sec 0.447522 0.000000 0.242055 0.447522
update_count/sec 0.000000 0.000000 0.000000 0.000000
id 6844726460
uptime 2433.012044
token ****************
username test_bot
head_update_id 944369801
tail_update_id 944369806
pending_update_count 5
request_count/sec 0.000822 0.000000 0.000000 0.000822
update_count/sec 0.002054 0.000000 0.000000 0.002054
I've found out, that "useTestServer" option adds "/test" to the end of base url, that's why i was getting 401. After removing this option - everything started working as intended
ref: https://core.telegram.org/bots/api#using-a-local-bot-api-server