Skip to content
This repository was archived by the owner on May 25, 2022. It is now read-only.

Commit 7963b98

Browse files
committed
Increase PEP8 compliance; Add input validation
1 parent 04225fe commit 7963b98

File tree

4 files changed

+213
-32
lines changed

4 files changed

+213
-32
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Project
2+
proxies.csv
3+
4+
# Byte-compiled / optimized / DLL files
5+
__pycache__/
6+
*.py[cod]
7+
*$py.class
8+
9+
# C extensions
10+
*.so
11+
12+
# Distribution / packaging
13+
.Python
14+
build/
15+
develop-eggs/
16+
dist/
17+
downloads/
18+
eggs/
19+
.eggs/
20+
lib/
21+
lib64/
22+
parts/
23+
sdist/
24+
var/
25+
wheels/
26+
share/python-wheels/
27+
*.egg-info/
28+
.installed.cfg
29+
*.egg
30+
MANIFEST
31+
32+
# PyInstaller
33+
# Usually these files are written by a python script from a template
34+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
35+
*.manifest
36+
*.spec
37+
38+
# Installer logs
39+
pip-log.txt
40+
pip-delete-this-directory.txt
41+
42+
# Unit test / coverage reports
43+
htmlcov/
44+
.tox/
45+
.nox/
46+
.coverage
47+
.coverage.*
48+
.cache
49+
nosetests.xml
50+
coverage.xml
51+
*.cover
52+
*.py,cover
53+
.hypothesis/
54+
.pytest_cache/
55+
cover/
56+
57+
# Translations
58+
*.mo
59+
*.pot
60+
61+
# Django stuff:
62+
*.log
63+
local_settings.py
64+
db.sqlite3
65+
db.sqlite3-journal
66+
67+
# Flask stuff:
68+
instance/
69+
.webassets-cache
70+
71+
# Scrapy stuff:
72+
.scrapy
73+
74+
# Sphinx documentation
75+
docs/_build/
76+
77+
# PyBuilder
78+
.pybuilder/
79+
target/
80+
81+
# Jupyter Notebook
82+
.ipynb_checkpoints
83+
84+
# IPython
85+
profile_default/
86+
ipython_config.py
87+
88+
# pyenv
89+
# For a library or package, you might want to ignore these files since the code is
90+
# intended to run in multiple environments; otherwise, check them in:
91+
# .python-version
92+
93+
# pipenv
94+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
95+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
96+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
97+
# install all needed dependencies.
98+
#Pipfile.lock
99+
100+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
101+
__pypackages__/
102+
103+
# Celery stuff
104+
celerybeat-schedule
105+
celerybeat.pid
106+
107+
# SageMath parsed files
108+
*.sage.py
109+
110+
# Environments
111+
.env
112+
.venv
113+
env/
114+
venv/
115+
ENV/
116+
env.bak/
117+
venv.bak/
118+
119+
# Spyder project settings
120+
.spyderproject
121+
.spyproject
122+
123+
# Rope project settings
124+
.ropeproject
125+
126+
# mkdocs documentation
127+
/site
128+
129+
# mypy
130+
.mypy_cache/
131+
.dmypy.json
132+
dmypy.json
133+
134+
# Pyre type checker
135+
.pyre/
136+
137+
# pytype static type analyzer
138+
.pytype/
139+
140+
# Cython debug symbols
141+
cython_debug/

projects/cli_proxy_tester/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ This script tests proxies by querying (GET request) a testing website that retur
1313

1414
`python cli.py single http://1.1.1.1`
1515

16-
This will test the HTTP proxy 1.1.1.1 against the default testing website [iptest.ingokleiber.de](http://iptest.ingokleiber.de). You can run your own testing service using the PHP script in `/ipinfo`.
16+
This will test the HTTP proxy 1.1.1.1 against the default testing website [iptest.ingokleiber.de](http://iptest.ingokleiber.de).
17+
You can run your own testing service using the PHP script in `/ipinfo`. This service should be offered both via HTTP and HTTPs.
1718

1819
`python cli.py single http://1.1.1.1 --iptest iptest.yourdomain.com`
1920

projects/cli_proxy_tester/cli.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,51 @@
1-
import logging
1+
import re
2+
23
import click
34

4-
from proxytest import test_single_proxy, test_file, add_from_text_file
5+
from proxytest import add_from_text_file
6+
from proxytest import test_csv_file
7+
from proxytest import test_single_proxy
8+
9+
10+
def validate_proxy(ctx, param, value):
11+
'''Validate proxy input. The RegEx crudely matches both IPv4 and URLs.'''
12+
validator = re.compile(r'(https|http|socks4|socks5):\/\/'
13+
r'((?:[0-9]{1,3}\.){3}[0-9]{1,3}(:[0-9]{2,5})?'
14+
r'|([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?)')
15+
16+
if not validator.match(value):
17+
raise click.BadParameter('Please provide a proxy in the format'
18+
'type://address (e.g., https://42.42.42.42)')
19+
else:
20+
return value
21+
522

623
@click.group()
724
def cli():
825
pass
926

27+
1028
@cli.command()
11-
@click.argument('proxy')
12-
@click.option('--iptest', default='http://iptest.ingokleiber.de', help='iptest address')
29+
@click.argument('proxy', callback=validate_proxy)
30+
@click.option('--iptest', default='iptest.ingokleiber.de',
31+
help='iptest address')
1332
@click.option('--csv', default='proxies.csv', help='CSV path')
1433
def single(proxy, iptest, csv):
1534
test_single_proxy(proxy, iptest, csv)
1635

36+
1737
@cli.command()
1838
@click.argument('csv')
19-
@click.option('--iptest', default='http://iptest.ingokleiber.de', help='iptest address')
39+
@click.option('--iptest', default='iptest.ingokleiber.de',
40+
help='iptest address')
2041
def csv_file(iptest, csv):
2142
test_csv_file(iptest, csv)
2243

44+
2345
@cli.command()
2446
@click.argument('txt')
25-
@click.option('--iptest', default='http://iptest.ingokleiber.de', help='iptest address')
47+
@click.option('--iptest', default='iptest.ingokleiber.de',
48+
help='iptest address')
2649
@click.option('--csv', default='proxies.csv', help='CSV path')
2750
def add_from_txt_file(iptest, txt, csv):
2851
add_from_text_file(iptest, txt, csv)
Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from pathlib import Path
21
import logging
2+
from json.decoder import JSONDecodeError
3+
from pathlib import Path
4+
5+
import pandas as pd
36
import requests
47
from requests.exceptions import ProxyError
5-
import pandas as pd
6-
from json.decoder import JSONDecodeError
78

89
logging.basicConfig(level=logging.INFO)
910

@@ -12,55 +13,66 @@ def add_proxies_to_file(csv_path: str, proxies: list):
1213
'''This function will add one or multiple proxies to the CSV file.'''
1314

1415
if not csv_path.exists():
15-
proxies_file: pd.DataFrame = pd.DataFrame(columns=['proxy_type', 'proxy_address', 'proxy_status'])
16+
pr_file: pd.DataFrame = pd.DataFrame(
17+
columns=['proxy_type', 'proxy_address', 'proxy_status'])
1618
logging.info('New CSV file will be created')
1719
else:
18-
proxies_file: pd.DataFrame = pd.read_csv(csv_path)
20+
pr_file: pd.DataFrame = pd.read_csv(csv_path)
1921
logging.info('Existing CSV file has been loaded')
2022

2123
for proxy in proxies:
22-
if len(proxies_file) == 0:
24+
if len(pr_file) == 0:
2325
# First proxy in the file
24-
proxies_file = proxies_file.append(proxy, ignore_index=True)
26+
pr_file = pr_file.append(proxy, ignore_index=True)
2527
else:
26-
if len(proxies_file.loc[ (proxies_file['proxy_type'] == proxy['proxy_type']) & (proxies_file['proxy_address'] == proxy['proxy_address'])]) > 0:
28+
if len(pr_file.loc[(pr_file['proxy_type'] == proxy['proxy_type']) &
29+
(pr_file['proxy_address'] == proxy['proxy_address'])]) > 0:
2730
# Proxy is already in the file
28-
proxies_file.loc[ (proxies_file['proxy_type'] == proxy['proxy_type']) & (proxies_file['proxy_address'] == proxy['proxy_address']) , ['proxy_status']] = proxy['proxy_status']
31+
pr_file.loc[(pr_file['proxy_type'] == proxy['proxy_type']) &
32+
(pr_file['proxy_address'] == proxy['proxy_address']),
33+
['proxy_status']] = proxy['proxy_status']
2934
else:
3035
# Proxy is not yet in the file
31-
proxies_file = proxies_file.append(proxy, ignore_index=True)
36+
pr_file = pr_file.append(proxy, ignore_index=True)
3237

33-
34-
proxies_file = proxies_file.drop_duplicates()
35-
proxies_file.to_csv(csv_path, index=False)
38+
pr_file = pr_file.drop_duplicates()
39+
pr_file.to_csv(csv_path, index=False)
3640
logging.info('CSV file has been written')
3741

3842

3943
def test_proxy(proxy_type: str, proxy_address: str, iptest: str):
40-
'''This function takes a proxy (type, address) and tests it against a given iptest adress.'''
44+
'''This function takes a proxy (type, address)
45+
and tests it against a given iptest adress.'''
4146

4247
logging.info(f'Testing proxy: {proxy_address}')
4348

4449
try:
4550
proxies = {proxy_type: proxy_address}
4651
proxy_status: str = ''
47-
r = requests.get('http://iptest.ingokleiber.de', proxies=proxies)
52+
53+
if proxy_type == 'https':
54+
r = requests.get(f'https://{iptest}', proxies=proxies)
55+
else:
56+
r = requests.get(f'http://{iptest}', proxies=proxies)
4857

4958
try:
5059
json_response: dict = r.json()
51-
52-
if json_response["ip"] == proxy_address:
60+
61+
if json_response["ip"] in proxy_address:
5362
proxy_status = 'Proxy functional'
5463
else:
55-
logging.warning(f'Proxy "{proxy_address}" returned {json_response}')
64+
logging.warning(f'Proxy "{proxy_address}"'
65+
f'returned {json_response}')
5666
proxy_status = 'Proxy not functional'
5767
except JSONDecodeError:
5868
proxy_status = 'Invalid response'
5969
except ProxyError:
6070
proxy_status = 'Proxy error'
6171

6272
logging.info(f'Proxy {proxy_address}: {proxy_status}')
63-
return {'proxy_type': proxy_type, 'proxy_address': proxy_address, 'proxy_status': proxy_status}
73+
return {'proxy_type': proxy_type,
74+
'proxy_address': proxy_address,
75+
'proxy_status': proxy_status}
6476

6577

6678
def test_single_proxy(proxy: str, iptest: str, csv_path: str):
@@ -71,33 +83,37 @@ def test_single_proxy(proxy: str, iptest: str, csv_path: str):
7183
add_proxies_to_file(Path(csv_path), [result])
7284

7385

74-
def test_file(iptest: str, csv_path: str):
86+
def test_csv_file(iptest: str, csv_path: str):
7587
'''This function (re)tests every proxy in a given CSV file.'''
7688

7789
csv_path: Path = Path(csv_path)
7890

7991
if csv_path.exists():
80-
proxies_file: pd.DataFrame = pd.read_csv(csv_path)
92+
pr_file: pd.DataFrame = pd.read_csv(csv_path)
8193
else:
8294
raise FileNotFoundError
8395

8496
proxies: list = []
8597

86-
for index, proxy in proxies_file.iterrows():
87-
proxies.append(test_proxy(proxy['proxy_type'], proxy['proxy_address'], iptest))
98+
for index, proxy in pr_file.iterrows():
99+
proxies.append(test_proxy(proxy['proxy_type'],
100+
proxy['proxy_address'],
101+
iptest))
88102

89103
add_proxies_to_file(csv_path, proxies)
90104

91105

92106
def add_from_text_file(iptest: str, text_path: str, csv_path: str):
93-
''' This function adds a list of proxies from a text file (line by line).'''
107+
''' This function adds a list of proxies
108+
from a text file (line by line).'''
94109
text_path: Path = Path(text_path)
95110

96111
if text_path.exists():
97112
proxies: list = text_path.read_text().splitlines()
98113

99114
for proxy in proxies:
100-
# We will treat each proxy as a single proxy and leverage the existing function
115+
'''We will treat each proxy as a single proxy
116+
and leverage the existing function'''
101117
test_single_proxy(proxy, iptest, csv_path)
102118
else:
103119
raise FileNotFoundError

0 commit comments

Comments
 (0)