mirror of
https://github.com/bellingcat/telegram-phone-number-checker.git
synced 2026-06-07 19:08:31 +03:00
Merge pull request #12 from bellingcat/package-it
refactoring and moving to poetry
This commit is contained in:
18
.github/workflows/pypi-publish.yaml
vendored
Normal file
18
.github/workflows/pypi-publish.yaml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Upload Python Package
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [checks]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build and publish to pypi
|
||||
uses: JRubics/poetry-publish@v1.17
|
||||
with:
|
||||
pypi_token: ${{ secrets.PYPI_TOKEN }}
|
||||
python_version: 3.9
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
.env
|
||||
*.session
|
||||
*.json
|
||||
dist/
|
||||
13
Pipfile
13
Pipfile
@@ -1,13 +0,0 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
telethon = "*"
|
||||
python-dotenv = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
69
Pipfile.lock
generated
69
Pipfile.lock
generated
@@ -1,69 +0,0 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "0c8df074fc457e527734bfb860a87923e5f8f806319557e83d22cbfb7ceea9c4"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.9"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"pyaes": {
|
||||
"hashes": [
|
||||
"sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f"
|
||||
],
|
||||
"version": "==1.6.1"
|
||||
},
|
||||
"pyasn1": {
|
||||
"hashes": [
|
||||
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
|
||||
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
|
||||
"sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
|
||||
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
|
||||
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
|
||||
"sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
|
||||
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
|
||||
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
|
||||
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
|
||||
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
|
||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
|
||||
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2",
|
||||
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"
|
||||
],
|
||||
"version": "==0.4.8"
|
||||
},
|
||||
"python-dotenv": {
|
||||
"hashes": [
|
||||
"sha256:00aa34e92d992e9f8383730816359647f358f4a3be1ba45e5a5cefd27ee91544",
|
||||
"sha256:b1ae5e9643d5ed987fc57cc2583021e38db531946518130777734f9589b3141f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.17.1"
|
||||
},
|
||||
"rsa": {
|
||||
"hashes": [
|
||||
"sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2",
|
||||
"sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"
|
||||
],
|
||||
"markers": "python_version >= '3.5' and python_version < '4'",
|
||||
"version": "==4.7.2"
|
||||
},
|
||||
"telethon": {
|
||||
"hashes": [
|
||||
"sha256:993c837ef745addf972a27d7bfba0ce518a2863d1a50e0737255b764d23e0ef2",
|
||||
"sha256:df643fc988708ad16d16de834ffa12ad4bfa3f956473d835c8158e2283b885ea"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.21.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
||||
92
README.md
92
README.md
@@ -1,33 +1,93 @@
|
||||
# telegram-phone-number-checker
|
||||
|
||||
This script lets you check whether a specific phone number is connected to a Telegram account.
|
||||
Python tool/script toc heck if phone numbers are connected to Telegram accounts.
|
||||
|
||||
## Installation
|
||||
|
||||
[](https://pypi.org/project/telegram-phone-number-checker/)
|
||||
|
||||
You can install this tool directly from the [official pypi release](https://pypi.org/project/telegram-phone-number-checker/).
|
||||
|
||||
```bash
|
||||
pip install telegram-phone-number-checker
|
||||
```
|
||||
|
||||
You can also install it and run it directly from github as a script.
|
||||
```bash
|
||||
git clone https://github.com/bellingcat/telegram-phone-number-checker
|
||||
cd telegram-phone-number-checker
|
||||
pip install -r requirements.txt
|
||||
python telegram-phone-number-checker/main.py
|
||||
```
|
||||
|
||||
## Requirements
|
||||
To run it, you need:
|
||||
|
||||
1. A Telegram account with an active phone number;
|
||||
2. Telegram 'API_ID' and 'API_HASH', which you can get by creating a developers account using this link: https://my.telegram.org/. Place these values in a .env file, along with the phone number of your Telegram account:
|
||||
2. Telegram `API_ID` and `API_HASH`, which you can get by creating a developers account at https://my.telegram.org/. Place these values in a `.env` file, along with the phone number of your Telegram account:
|
||||
|
||||
```
|
||||
API_ID=
|
||||
API_HASH=
|
||||
PHONE_NUMBER=
|
||||
```
|
||||
|
||||
## Installing Dependencies
|
||||
|
||||
This project uses [pipenv](https://pipenv.pypa.io/en/latest/#install-pipenv-today) to manage dependencies. Install pipenv on your machine, and then this project's dependencies can be installed like so:
|
||||
|
||||
```sh
|
||||
pipenv install
|
||||
```
|
||||
If you don't create this file, you can also provide these 3 values when calling the tool, or even be prompted for them interactively.
|
||||
|
||||
## Usage
|
||||
```sh
|
||||
pipenv run python telegram-phone-validation.py
|
||||
The tool accepts a comma-separated list of phone numbers to check, you can pass this when you call the tool, or interactively.
|
||||
|
||||
See the examples below:
|
||||
|
||||
```bash
|
||||
# single phone number
|
||||
telegram-phone-number-checker --phone-numbers +1234567890
|
||||
|
||||
# multiple phone numbers
|
||||
telegram-phone-number-checker --phone-numbers +1234567890,+9876543210,+111111111
|
||||
|
||||
# interactive version, you will be prompted for the phone-numbers
|
||||
telegram-phone-number-checker
|
||||
|
||||
# overwrite the telegram API keys in .env (or if no .env is found)
|
||||
telegram-phone-number-checker --api-id YOUR_API_KEY --api-hash YOUR_API_HASH --api-phone-number YOUR_PHONE_NUMBER --phone-numbers +1234567890
|
||||
```
|
||||
|
||||
You can expect the following possible responses:
|
||||
The result will be written to the console but also written as JSON to a `results.json` file, you can write it to another file by adding `--output your_filename.json` to the command.
|
||||
|
||||
1. If available, you will receive the Telegram Username that is connected with this number.
|
||||
2. 'Response detected, but no user name returned by the API for the number: {phone_number}'. This means that it looks like the number was used to create a Telegram account but the user did not choose a Telegram Username. It is optional to create a Username on Telegram.
|
||||
3. 'ERROR: there was no response for the phone number: {phone_number}': There can be several reasons for this response. Either the phone number has not been used to create a Telegram account. Or: The phone number is connected to a Telegram account but the user has restricted the option to find him/her via the phone number. Or: another error occurred.
|
||||
For each phone number, you can expect the following possible responses:
|
||||
|
||||
1. If available, you will receive the Telegram Username,Name, and ID that are connected with this number.
|
||||
2. 'no username detected'. This means that it looks like the number was used to create a Telegram account but the user did not choose a Telegram Username. It is optional to create a Username on Telegram.
|
||||
3. 'ERROR: no response, the user does not exist or has blocked contact adding.': There can be several reasons for this response. Either the phone number has not been used to create a Telegram account. Or: The phone number is connected to a Telegram account but the user has restricted the option to find him/her via the phone number.
|
||||
4. Or: another error occurred.
|
||||
|
||||
|
||||
## Development
|
||||
This section describes how to install the project in order to run it locally, for example if you want to build new features.
|
||||
|
||||
```bash
|
||||
# clone the code
|
||||
git clone https://github.com/bellingcat/telegram-phone-number-checker
|
||||
|
||||
# move into the project's folder
|
||||
cd telegram-phone-number-checker
|
||||
```
|
||||
|
||||
This project uses [poetry](https://python-poetry.org/) to manage dependencies. You can install dependencies via poetry, or use the up-to-date [requirements.txt](requirements.txt) file.
|
||||
|
||||
```bash
|
||||
# with poetry
|
||||
poetry install
|
||||
|
||||
# with pip
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
You can then run it with any of these:
|
||||
```bash
|
||||
# with poetry
|
||||
poetry run python3 telegram_phone_number_checker/main.py
|
||||
|
||||
# with pip installation
|
||||
python3 telegram_phone_number_checker/main.py
|
||||
```
|
||||
166
poetry.lock
generated
Normal file
166
poetry.lock
generated
Normal file
@@ -0,0 +1,166 @@
|
||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.2.0"
|
||||
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"},
|
||||
{file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""}
|
||||
idna = ">=2.8"
|
||||
sniffio = ">=1.1"
|
||||
typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
|
||||
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
|
||||
trio = ["trio (>=0.23)"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.7"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.0"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"},
|
||||
{file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.6"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"},
|
||||
{file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyaes"
|
||||
version = "1.6.1"
|
||||
description = "Pure-Python Implementation of the AES block-cipher and common modes of operation"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyasn1"
|
||||
version = "0.5.1"
|
||||
description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
||||
files = [
|
||||
{file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"},
|
||||
{file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.0.1"
|
||||
description = "Read key-value pairs from a .env file and set them as environment variables"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
|
||||
{file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
cli = ["click (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "4.9"
|
||||
description = "Pure-Python RSA implementation"
|
||||
optional = false
|
||||
python-versions = ">=3.6,<4"
|
||||
files = [
|
||||
{file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"},
|
||||
{file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyasn1 = ">=0.1.3"
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.0"
|
||||
description = "Sniff out which async library your code is running under"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"},
|
||||
{file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "telethon"
|
||||
version = "1.33.1"
|
||||
description = "Full-featured Telegram client library for Python 3"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "Telethon-1.33.1.tar.gz", hash = "sha256:377107d77fd95f8c2bd7fce77f9d78da84c1ff58023f59e8d06035a4548bd36b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyaes = "*"
|
||||
rsa = "*"
|
||||
|
||||
[package.extras]
|
||||
cryptg = ["cryptg"]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.9.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"},
|
||||
{file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"},
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "1cf8b9ab78b1cf2860f38fc9e50e373b857e6d10ed6a397cb4f29cc556e14c95"
|
||||
29
pyproject.toml
Normal file
29
pyproject.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
[tool.poetry]
|
||||
name = "telegram-phone-number-checker"
|
||||
version = "1.0.0"
|
||||
description = "Check if phone numbers are connected to Telegram accounts."
|
||||
authors = ["Bellingcat"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
telegram-phone-number-checker = "telegram_phone_number_checker.main:main_entrypoint"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
anyio = "4.2.0"
|
||||
click = "8.1.7"
|
||||
exceptiongroup = "1.2.0"
|
||||
idna = "3.6"
|
||||
pyaes = "1.6.1"
|
||||
pyasn1 = "0.5.1"
|
||||
python-dotenv = "1.0.1"
|
||||
rsa = "4.9"
|
||||
sniffio = "1.3.0"
|
||||
telethon = "1.33.1"
|
||||
typing-extensions = "4.9.0"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
11
requirements.txt
Normal file
11
requirements.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
anyio==4.2.0
|
||||
click==8.1.7
|
||||
exceptiongroup==1.2.0
|
||||
idna==3.6
|
||||
pyaes==1.6.1
|
||||
pyasn1==0.5.1
|
||||
python-dotenv==1.0.1
|
||||
rsa==4.9
|
||||
sniffio==1.3.0
|
||||
Telethon==1.33.1
|
||||
typing_extensions==4.9.0
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/usr/local/bin/python3
|
||||
from telethon import TelegramClient, errors, events, sync
|
||||
from telethon.tl.types import InputPhoneContact
|
||||
from telethon import functions, types
|
||||
from dotenv import load_dotenv
|
||||
import argparse
|
||||
import os
|
||||
from getpass import getpass
|
||||
|
||||
load_dotenv()
|
||||
|
||||
result = {}
|
||||
|
||||
API_ID = os.getenv('API_ID')
|
||||
API_HASH = os.getenv('API_HASH')
|
||||
PHONE_NUMBER = os.getenv('PHONE_NUMBER')
|
||||
|
||||
def get_names(phone_number):
|
||||
try:
|
||||
contact = InputPhoneContact(client_id = 0, phone = phone_number, first_name="", last_name="")
|
||||
contacts = client(functions.contacts.ImportContactsRequest([contact]))
|
||||
username = contacts.to_dict()['users'][0]['username']
|
||||
if not username:
|
||||
print("*"*5 + f' Response detected, but no user name returned by the API for the number: {phone_number} ' + "*"*5)
|
||||
del_usr = client(functions.contacts.DeleteContactsRequest(id=[username]))
|
||||
return
|
||||
else:
|
||||
del_usr = client(functions.contacts.DeleteContactsRequest(id=[username]))
|
||||
return username
|
||||
except IndexError as e:
|
||||
return f'ERROR: there was no response for the phone number: {phone_number}'
|
||||
except TypeError as e:
|
||||
return f"TypeError: {e}. --> The error might have occured due to the inability to delete the {phone_number} from the contact list."
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
def user_validator():
|
||||
'''
|
||||
The function uses the get_api_response function to first check if the user exists and if it does, then it returns the first user name and the last user name.
|
||||
'''
|
||||
input_phones = input("Phone numbers: ")
|
||||
phones = input_phones.split()
|
||||
try:
|
||||
for phone in phones:
|
||||
api_res = get_names(phone)
|
||||
result[phone] = api_res
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Check to see if a phone number is a valid Telegram account')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
client = TelegramClient(PHONE_NUMBER, API_ID, API_HASH)
|
||||
client.connect()
|
||||
if not client.is_user_authorized():
|
||||
client.send_code_request(PHONE_NUMBER)
|
||||
try:
|
||||
client.sign_in(PHONE_NUMBER, input('Enter the code (sent on telegram): '))
|
||||
except errors.SessionPasswordNeededError:
|
||||
pw = getpass('Two-Step Verification enabled. Please enter your account password: ')
|
||||
client.sign_in(password=pw)
|
||||
user_validator()
|
||||
print(result)
|
||||
100
telegram_phone_number_checker/main.py
Normal file
100
telegram_phone_number_checker/main.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import os, json
|
||||
from telethon.sync import TelegramClient, errors
|
||||
from telethon.tl.types import InputPhoneContact
|
||||
from telethon import functions
|
||||
from dotenv import load_dotenv
|
||||
from getpass import getpass
|
||||
import click
|
||||
|
||||
load_dotenv()
|
||||
|
||||
def get_names(client, phone_number):
|
||||
"""
|
||||
This function takes in a phone number and returns the username first name and the last name of the user if the user exists. It does so by first adding the user's phones to the contact list, retrieving the information, and then deleting the user from the contact list.
|
||||
"""
|
||||
result = {}
|
||||
print(f'Checking: {phone_number=} ...', end="", flush=True)
|
||||
try:
|
||||
contact = InputPhoneContact(client_id = 0, phone = phone_number, first_name="", last_name="")
|
||||
contacts = client(functions.contacts.ImportContactsRequest([contact]))
|
||||
username = contacts.to_dict()['users'][0]['username']
|
||||
if not username:
|
||||
result.update({"error": f'ERROR: no username detected'})
|
||||
del_usr = client(functions.contacts.DeleteContactsRequest(id=[username]))
|
||||
else:
|
||||
result.update({"username": username})
|
||||
del_usr = client(functions.contacts.DeleteContactsRequest(id=[username]))
|
||||
# getting more information about the user
|
||||
id = del_usr.to_dict()['users'][0]['id']
|
||||
first_name = del_usr.to_dict()['users'][0]['first_name']
|
||||
last_name = del_usr.to_dict()['users'][0]['last_name']
|
||||
result.update({"first_name": first_name, "last_name": last_name, "id": id})
|
||||
|
||||
except IndexError as e:
|
||||
result.update({"error": f'ERROR: no response, the user does not exist or has blocked contact adding.'})
|
||||
except TypeError as e:
|
||||
result.update({"error": f"TypeError: {e}. --> The error might have occurred due to the inability to delete the {phone_number=} from the contact list."})
|
||||
except Exception as e:
|
||||
result.update({"error": f"Unexpected error: {e}."})
|
||||
raise
|
||||
print("Done.")
|
||||
return result
|
||||
|
||||
|
||||
def validate_users(client, phone_numbers):
|
||||
'''
|
||||
The function uses the get_api_response function to first check if the user exists and if it does, then it returns the first user name and the last user name.
|
||||
'''
|
||||
if not phone_numbers or not len(phone_numbers):
|
||||
phone_numbers = click.prompt('Enter the phone numbers to check, separated by commas')
|
||||
result = {}
|
||||
phones = [p.strip() for p in phone_numbers.split(",")]
|
||||
try:
|
||||
for phone in phones:
|
||||
if phone not in result:
|
||||
result[phone] = get_names(client, phone)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
raise
|
||||
return result
|
||||
|
||||
|
||||
def login(api_id, api_hash, phone_number):
|
||||
"""Create a telethon session or reuse existing one"""
|
||||
print('Logging in...', end="", flush=True)
|
||||
API_ID = api_id or os.getenv('API_ID') or click.prompt('Enter your API ID')
|
||||
API_HASH = api_hash or os.getenv('API_HASH') or click.prompt('Enter your API HASH')
|
||||
PHONE_NUMBER = phone_number or os.getenv('PHONE_NUMBER') or click.prompt('Enter your phone number')
|
||||
client = TelegramClient(PHONE_NUMBER, API_ID, API_HASH)
|
||||
client.connect()
|
||||
if not client.is_user_authorized():
|
||||
client.send_code_request(PHONE_NUMBER)
|
||||
try:
|
||||
client.sign_in(PHONE_NUMBER, input('Enter the code (sent on telegram): '))
|
||||
except errors.SessionPasswordNeededError:
|
||||
pw = getpass('Two-Step Verification enabled. Please enter your account password: ')
|
||||
client.sign_in(password=pw)
|
||||
print("Done.")
|
||||
return client
|
||||
|
||||
def show_results(output, res):
|
||||
print(json.dumps(res, indent=4))
|
||||
with open(output, 'w') as f:
|
||||
json.dump(res, f, indent=4)
|
||||
print(f"Results saved to {output}")
|
||||
|
||||
@click.command()
|
||||
@click.option('--phone-numbers', '-p', help='List of phone numbers to check, separated by commas', type=str)
|
||||
@click.option('--api-id', help='Your API_ID', type=str)
|
||||
@click.option('--api-hash', help='Your API_HASH', type=str)
|
||||
@click.option('--api-phone-number', help='Your phone_number', type=str)
|
||||
@click.option('--output', help='results filename, default to results.json', default="results.json", type=str)
|
||||
def main_entrypoint(phone_numbers, api_id, api_hash, api_phone_number, output):
|
||||
"""Check to see if one or more phone numbers belong to a valid Telegram account"""
|
||||
client = login(api_id, api_hash, api_phone_number)
|
||||
res = validate_users(client, phone_numbers)
|
||||
show_results(output, res)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main_entrypoint()
|
||||
Reference in New Issue
Block a user