Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions detect_secrets/core/usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,12 @@ class PluginOptions:
help_text='Disables scans for GitHub credentials',
filename='github_token',
),
PluginDescriptor(
classname='TelegramBotTokenDetector',
flag_text='--no-telegram-bot-token-scan',
help_text='Disables scans for Telegram bot tokens',
filename='telegram_token',
),
]
opt_in_plugins = [
PluginDescriptor(
Expand Down
37 changes: 37 additions & 0 deletions detect_secrets/plugins/telegram_token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
This plugin searches for Telegram bot tokens
"""
import re

import requests

from detect_secrets.core.constants import VerifiedResult
from .base import RegexBasedDetector


class TelegramBotTokenDetector(RegexBasedDetector):
"""Scans for Telegram bot tokens."""
secret_type = 'Telegram Bot Token'

denylist = [
# refs https://core.telegram.org/bots/api#authorizing-your-bot
re.compile(r'(?<![:\w])\d{8,10}:[0-9A-Za-z_-]{35}(?![0-9A-Za-z_-])'),
]

def verify(self, token, *args, **kwargs): # pragma: no cover
try:
response = requests.get(
'https://api.telegram.org/bot{}/getMe'.format(
token,
),
timeout=5,
)
except requests.exceptions.RequestException:
return VerifiedResult.UNVERIFIED

if response.status_code == 200:
return VerifiedResult.VERIFIED_TRUE
if response.status_code == 401:
return VerifiedResult.VERIFIED_FALSE

return VerifiedResult.UNVERIFIED
28 changes: 28 additions & 0 deletions tests/plugins/telegram_token_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest

from detect_secrets.plugins.telegram_token import TelegramBotTokenDetector


class TestTelegramTokenDetector:

@pytest.mark.parametrize(
'payload, should_flag',
[
('110201543:AAHdqTcvCH1vGWJxfSe1ofSAs0K5PALDsaw', True),
('7213808860:AAH1bjqpKKW3maRSPAxzIU-0v6xNuq2-NjM', True),
# Embedded in assignments, quotes, JSON
('TELEGRAM_TOKEN=110201543:AAHdqTcvCH1vGWJxfSe1ofSAs0K5PALDsaw', True),
('token = "110201543:AAHdqTcvCH1vGWJxfSe1ofSAs0K5PALDsaw"', True),
('{"bot_token": "110201543:AAHdqTcvCH1vGWJxfSe1ofSAs0K5PALDsaw"}', True),
# Should not match
('bot110201543:AAHdqTcvCH1vGWJxfSe1ofSAs0K5PALDsaw', False),
('foo:AAH1bjqpKKW3maRSPAxzIU-0v6xNuq2-NjM', False),
('foo', False),
('arn:aws:sns:aaa:111122223333:aaaaaaaaaaaaaaaaaaassssssddddddddddddd', False),
],
)
def test_analyze(self, payload, should_flag):
logic = TelegramBotTokenDetector()
output = logic.analyze_line(payload, 1, 'mock_filename')

assert len(output) == int(should_flag)