pax_global_header 0000666 0000000 0000000 00000000064 14475556377 0014541 g ustar 00root root 0000000 0000000 52 comment=622cf86b4cf815cb716576f117ab5f56b7c77441
pycrowdsec-0.0.5/ 0000775 0000000 0000000 00000000000 14475556377 0013725 5 ustar 00root root 0000000 0000000 pycrowdsec-0.0.5/.github/ 0000775 0000000 0000000 00000000000 14475556377 0015265 5 ustar 00root root 0000000 0000000 pycrowdsec-0.0.5/.github/workflows/ 0000775 0000000 0000000 00000000000 14475556377 0017322 5 ustar 00root root 0000000 0000000 pycrowdsec-0.0.5/.github/workflows/pypi_publish.yml 0000664 0000000 0000000 00000001205 14475556377 0022552 0 ustar 00root root 0000000 0000000 name: Upload Python Package
on:
release:
types: [published, prereleased, released]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
pycrowdsec-0.0.5/.github/workflows/unittests.yml 0000664 0000000 0000000 00000001424 14475556377 0022110 0 ustar 00root root 0000000 0000000 name: Python Unittests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
docker network create net-test
python -m pip install --upgrade pip
python setup.py install
python -m pip install -r requirements-dev.txt
- name: Lint check
run: |
black --check -l 100 ./
- name: Tests
run: |
python -m pytest
pycrowdsec-0.0.5/.gitignore 0000664 0000000 0000000 00000003762 14475556377 0015725 0 ustar 00root root 0000000 0000000 # Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/ pycrowdsec-0.0.5/LICENSE 0000664 0000000 0000000 00000002055 14475556377 0014734 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2020-2021 Crowdsec
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. pycrowdsec-0.0.5/README.md 0000664 0000000 0000000 00000011731 14475556377 0015207 0 ustar 00root root 0000000 0000000
# PyCrowdSec
[CrowdSec](https://github.com/crowdsecurity/crowdsec) is a FOSS tool which parses logs and detects attacks. PyCrowdSec enables integration of CrowdSec with python projects. It is easy to setup and boosts the security by leveraging CrowdSec's attack detection capabilities.
PyCrowdSec contains a python client library for CrowdSec, as well as middlewares for django and flask integrations.
## Installation:
```bash
pip install pycrowdsec
```
You'll also need an instance of CrowdSec running, see installation instructions [here](https://docs.crowdsec.net/Crowdsec/v1/getting_started/installation/)
## Client library:
### StreamClient
This client polls CrowdSec LAPI and keeps track of active decisions.
In the below example assume that there's a ban decisions for IP "77.88.99.66" and captcha decision for country "CN".
**Basic Usage:**
```python
from pycrowdsec.client import StreamClient
client = StreamClient(
api_key=,
)
client.run() # This starts polling the API
assert client.get_current_decisions() == {
"77.88.99.66": "ban"
"CN": "captcha"
}
assert client.get_action_for("77.88.99.66") == "ban"
assert client.get_action_for("CN") == "captcha"
```
The `CROWDSEC_API_KEY` can be obtained by running
```bash
sudo cscli bouncers add python_bouncer
```
The `StreamClient`'s constructor also accepts the following optional parameters for more advanced configurations.
**lapi_url** : str
Base URL of CrowdSec API. Default is http://localhost:8080/ .
**interval** : int
Query the CrowdSec API every "interval" second
**user_agent** : str
User agent to use while calling the API.
**scopes** : List[str]
List of decision scopes which shall be fetched. Default is ["ip", "range"]
### QueryClient
This client will query CrowdSec LAPI to check whether the requested item has any decisions against it.
In the below example assume that there's a ban decisions for IP "77.88.99.66" and captcha decision for country "CN".
**Basic Usage:**
```python
from pycrowdsec.client import StreamClient
client = StreamClient(
api_key=,
)
client.run() # This starts polling the API
assert client.get_action_for("77.88.99.66") == "ban"
assert client.get_action_for("CN") == "captcha"
```
The `QueryClient`'s constructor also accepts the following optional parameters for more advanced configurations.
**lapi_url** : str
Base URL of CrowdSec API. Default is http://localhost:8080/ .
**user_agent** : str
User agent to use while calling the API.
## Flask Integration:
See `./examples/flask` for more detailed example (includes captcha remediation too).
A minimal flask app with PyCrowdSec protection would look like:
```python
from flask import Flask
from pycrowdsec.client import StreamClient
from pycrowdsec.flask import get_crowdsec_middleware
client = StreamClient(api_key=)
app = Flask(__name__)
app.before_request(
get_crowdsec_middleware(actions, c.cache, exclude_views=["ban_page"]
)
actions = {
"ban": lambda: redirect(url_for("ban_page")),
}
@app.route("/ban")
def ban_page():
return abort(403)
@app.route("/")
def index():
return "Hello"
if __name__ = "__main__":
app.run(host="0.0.0.0")
```
## Django Integration:
See `./examples/django` for more detailed example (includes captcha remediation too).
After installing `pycrowdsec`, in your `settings.py` add the following line in the `MIDDLEWARE` list
```python
MIDDLEWARE = [
.........
"pycrowdsec.django.crowdsec_middleware",
.........
]
```
Next add define the following variables required for `pycrowdsec` to function.
```python
PYCROWDSEC_LAPI_KEY =
PYCROWDSEC_ACTIONS = {
"ban": lambda request: redirect(reverse("ban_view")),
}
# IMPORTANT: If any action is doing a redirect to some view, always exclude it for pycrowdsec. Otherwise the middleware will trigger the redirect on the action view too.
PYCROWDSEC_EXCLUDE_VIEWS = {"ban_view"}
```
You'll also need to register a view with name `ban_view`. In this example all the banned IPs would be redirected to the `ban_view`
For more advanced configurations, you can specify the following variables in your `settings.py`
**PYCROWDSEC_POLL_INTERVAL** int : Query the CrowdSec API every `PYCROWDSEC_POLL_INTERVAL` seconds.
**PYCROWDSEC_LAPI_URL** str: Base URL of CrowdSec API.
**PYCROWDSEC_ACTIONS** Dict[str, Callable]: Action to be taken when some request matches CrowdSec's decision.
**PYCROWDSEC_REQUEST_TRANSFORMERS** List[Callable]: Obtains value from Django Request object, this value is used to match the request with CrowdSec's decisions. By default it contains only one transformer which obtains IP from the request.
pycrowdsec-0.0.5/assets/ 0000775 0000000 0000000 00000000000 14475556377 0015227 5 ustar 00root root 0000000 0000000 pycrowdsec-0.0.5/assets/pycrowdsec.jpg 0000664 0000000 0000000 00000240607 14475556377 0020124 0 ustar 00root root 0000000 0000000 JFIF C C qq"
d !1 A"Qa
2q#BR$3b%4CSr(5VtUcu&78DHWsw
L !1A"Qaq2 #BR$3b4CSrDs%TV ? ┥)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR+D.ET5DO1)|)~K(_2ր)G J{)*wjW7JǨ Qk@r)JR)JR)JR)JR)JVMBp3sÚV &=݂nL}6܅LlҶAOvo*N7%Ind|piZҔ)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)Cӭt}G_K0\Qs[VlS -mDW%H!KRR^t!,Eh1O2aKXI܄-šҥhHʖ%)H)D $9=F]!]7.&eF#5
{.<nqyu+Lԝa-a:ځfٝE{ɖķ^/kOX̯aq!ێRcqEq&}ykXk$1yoX[IߵeϘOr*vtϧtKɬ딇Bh+)eqKZ
@ʐ;T' 8̟| \}DUc&IdO\ni؆=tJuٷ'l t*q[g7ǔgluVG"`o}=ɾRX~}e;k4T\-^qj,ԴRҹ,OlJ@JR
TI$)R[JR)JR)JR)JRی,+?j>eS0+NW7ql0,r/9MG*0lJHRrHafS~ ݺΘڣ^͆Q"!Yq;pE%vRzO
N5ǔ)9 ze@cf,9ah͘.l& 57IZ셇TO IGgۜS:舰?Ҿ;K
He/ߙ45T@O-69gpkRTC/8[RѸKd.qݧJy+`Dk.њ.ZG)an$*+J$!$)8Si5G!l V䨀{GνB߯ZН8Lŋbn.Umjԛ5$
CSM2pdGz$HB#
mPr>}W;JRiJR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR({z:?HwtA0N*jwjumOG8'EIʔC6i,:5,j߶??Mo^q=xIi6:qJf7썾;Y"A$!R2nsQ9H ~_u'_@\[3k8O4ۈ \,608+!p{|j-?_p)ST_ l !)|&ѭH@Z$ U'BOz:!}¼ XCWgr&:;iF ; ؏A&O鷧oözo[{ 8=$Jo8 86@?#g #[JUu)JZR`mu'aj=JAm2G9#88n)[JRmW?WL)!t:5#v眾j)t
w9a%eIac(6(f YۢovwPK0n3dp#3TRqӏ^jYE'p\S7ѫZg32mjʃmȉ%6ߞղqNYӋոU-PV́Cb)2I!*,klmFM:6ǿELm MDkp].3[;r}A| :iJUm)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JR)JRqpK(g_dR٬W7j"Nzu"sfke9%MrKM*CJqoYwNunI䔄'FwF/<^DK2%}uVPusC^n@m)m#d)B@ ;oza$EԷ0amC q5gHRsʀFԥ*L.7ï'%ߜu,g]pH2Q&l?[W t "Q |:}?嵧yZM@3-m/5f ruO )$d
P\N(1')
AyGȠHR9%$%\lyz"r)\z#ͼsT~^}9@ة]w#q>,,xš%]r+ŶmB
>*$TBI~%zpl HLD!l21Iܥ@uCo
lV9V6N;9
W(߿v 5&XpF\qpq+c7ӗ9qg d4:SƄaɵ>+Qj
[XNjVky)Qn"uF5w ?
\ڕ=3ʵ,s rr.W.K]S}TJVIe-a4iMOKӬ𧚱E{KL-b2v$-hֵml!j^N s?)ƞ_ptҝ&yH2+Z
RQ헜Z`MQQnBt\Y/:STe
V<k+2r8$uTv546h$a;7)n2