gnodet-bot commented on code in PR #27778:
URL: https://github.com/apache/camel/pull/27778#discussion_r4271255536


##########
components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramServiceRestBotAPIAdapter.java:
##########
@@ -152,36 +154,52 @@ public UpdateResult getUpdates(Long offset, Integer 
limit, Integer timeoutSecond
     }
 
     <T> T sendSyncRequest(final HttpRequest request, Class<T> resultType) {
+        final String description = describe(request.method(), request.uri());
         try {
             final HttpResponse<String> response = client.send(request, 
HttpResponse.BodyHandlers.ofString());
 
             int code = response.statusCode();
             if (code >= 200 && code < 300) {
                 final String responseBody = response.body();
                 if (LOG.isTraceEnabled()) {
-                    LOG.trace("Received body for {} {}: {}", request.method(), 
request.uri(), responseBody);
+                    LOG.trace("Received body for {}: {}", description, 
responseBody);
                 }
                 return mapper.readValue(responseBody, resultType);
             } else {
                 throw new TelegramException(
-                        "Could not " + request.method() + " " + request.uri() 
+ ": " + response.statusCode() + " "
-                                            + response.body(),
+                        "Could not " + description + ": " + 
response.statusCode() + " " + response.body(),
                         response.statusCode(), response.body());
             }
         } catch (JsonProcessingException e) {
-            throw new RuntimeCamelException(
-                    "Could not parse the response from " + request.method() + 
" " + request.uri(), e);
+            throw new RuntimeCamelException("Could not parse the response from 
" + description, e);
         } catch (IOException e) {
-            throw new RuntimeCamelException("Could not request " + 
request.method() + " " + request.uri(), e);
+            throw new RuntimeCamelException("Could not request " + 
description, e);
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             throw new RuntimeCamelException(e);
         }
     }
 
+    /**
+     * Describes a request to the Bot API in logs and exception messages by 
its HTTP method and the method of the Bot
+     * API, such as {@code GET getUpdates}. The request URI is not used, as it 
contains the authorization token.
+     */
+    static String describe(String httpMethod, URI uri) {
+        String path = uri.getPath();
+        return httpMethod + " " + path.substring(path.lastIndexOf('/') + 1);
+    }
+
     @Override
     public boolean setWebhook(String url) {
-        final String uri = baseUri + "/setWebhook?url=" + url;
+        return setWebhook(url, null);
+    }
+
+    @Override
+    public boolean setWebhook(String url, String secretToken) {
+        String uri = baseUri + "/setWebhook?url=" + url;

Review Comment:
   💡 **Raw URL concatenation:** `url` is appended raw while `secretToken` is 
properly encoded with `URLEncoder.encode()`. Pre-existing behavior, but the 
inconsistency is visible now. Consider: `URLEncoder.encode(url, 
StandardCharsets.UTF_8)` for consistency.



##########
components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramWebhookProcessor.java:
##########
@@ -26,21 +28,51 @@
 import org.apache.camel.component.telegram.model.Update;
 import org.apache.camel.support.AsyncProcessorConverterHelper;
 import org.apache.camel.support.AsyncProcessorSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static 
org.apache.camel.component.telegram.util.TelegramMessageHelper.populateExchange;
 
 public class TelegramWebhookProcessor extends AsyncProcessorSupport {
 
+    /**
+     * The header in which Telegram sends the secret token the webhook was 
registered with.
+     */
+    public static final String SECRET_TOKEN_HEADER = 
"X-Telegram-Bot-Api-Secret-Token";
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(TelegramWebhookProcessor.class);
     private static final ObjectMapper MAPPER = new ObjectMapper();
 
     private AsyncProcessor next;
+    private final byte[] secretToken;
 
-    public TelegramWebhookProcessor(Processor next) {
+    /**
+     * @param next        the processor that receives the updates
+     * @param secretToken the secret token that a webhook request must carry, 
or {@code null} to accept every webhook
+     *                    request without verifying it
+     */
+    public TelegramWebhookProcessor(Processor next, String secretToken) {
         this.next = AsyncProcessorConverterHelper.convert(next);
+        this.secretToken = secretToken != null ? 
secretToken.getBytes(StandardCharsets.UTF_8) : null;
     }
 
     @Override
     public boolean process(Exchange exchange, AsyncCallback callback) {
+        if (secretToken != null) {
+            String token = exchange.getIn().getHeader(SECRET_TOKEN_HEADER, 
String.class);
+            if (token == null || !MessageDigest.isEqual(secretToken, 
token.getBytes(StandardCharsets.UTF_8))) {
+                LOG.warn("Rejecting a Telegram webhook request with a missing 
or invalid {} header."

Review Comment:
   ⚠️ **Log flooding risk:** `LOG.warn` here fires on *every* rejected request. 
The webhook endpoint is publicly exposed with no rate limiting — a flood of 
invalid requests will generate millions of WARN log entries. Prefer `LOG.debug` 
for per-request rejection logging.



##########
components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramEndpoint.java:
##########
@@ -122,16 +130,56 @@ public Consumer createConsumer(Processor processor) 
throws Exception {
 
     @Override
     public Processor createWebhookHandler(Processor next) {
-        return new TelegramWebhookProcessor(next);
+        if (!configuration.isWebhookSecretTokenEnabled()) {
+            LOG.warn("The webhook secret token is disabled 
(webhookSecretTokenEnabled=false): webhook requests to {} are not"

Review Comment:
   💡 **LOG.info vs LOG.warn:** This fires once at startup when 
`webhookSecretTokenEnabled=false`. Disabling the secret token is a deliberate 
operator choice — `LOG.info` better reflects intentional configuration, while 
`LOG.warn` implies an unexpected or error condition.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to