Merge pull request #1 from slashtechno/restructure-project
Restructure project
This commit is contained in:
commit
36f2b87823
|
@ -0,0 +1,2 @@
|
|||
CLOUDFLARE_ACCOUNT_ID=
|
||||
CLOUDFLARE_TOKEN=
|
|
@ -1,4 +0,0 @@
|
|||
@REM This script is used to load environment variables from .envrc file
|
||||
@echo off
|
||||
for /f "delims=" %%a in ('type .envrc') do set %%a
|
||||
echo %ENV_VAR
|
|
@ -1,2 +0,0 @@
|
|||
export CLOUDFLARE_ACCOUNT_ID=
|
||||
export CLOUDFLARE_TOKEN=
|
|
@ -2,3 +2,10 @@
|
|||
__pycache__/
|
||||
tmp.txt
|
||||
.env
|
||||
blocklists/*
|
||||
!blocklists/.gitkeep
|
||||
tmp.py
|
||||
.venv
|
||||
dist/
|
||||
.ruff_cache/
|
||||
hosts.txt
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"charliermarsh.ruff"
|
||||
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"python.languageServer": "Pylance", // Ruff is used for linting but Pylance still is useful for intellisense
|
||||
"python.analysis.ignore": [
|
||||
"*"
|
||||
],
|
||||
"python.analysis.exclude": [
|
||||
"."
|
||||
],
|
||||
"python.linting.enabled": false // https://github.com/microsoft/vscode-python/wiki/Migration-to-Python-Tools-Extensions
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
# Cloudflare Gateway Adblocking
|
||||
Serverless adblocking via Cloudflare Zero Trust Gateway
|
||||
|
||||
### What is this?
|
||||
This is a serverless adblocking solution that uses Cloudflare's Zero Trust Gateway to block ads by parsing a hosts file and creating a firewall rule to block the domains. It can be used as an alternative to Pi-Hole or other adblocking solutions.
|
||||
This project was heavily inspired by [this blog post](https://blog.marcolancini.it/2022/blog-serverless-ad-blocking-with-cloudflare-gateway/)
|
||||
|
||||
|
||||
### Pre-requisites
|
||||
* Python > 3.10
|
||||
* A Cloudflare account with Zero Trust enabled
|
||||
* A Cloudflare API tolken with the following permissions:
|
||||
* Zero Trust: Edit
|
||||
* Account Firewall Access Rules: Edit
|
||||
* Access: Apps and Policies: Edit
|
||||
* A device with the WARP client installed and configured to use a Zero Trust account
|
||||
|
||||
<!--
|
||||
### Installation
|
||||
#### From PyPi
|
||||
`pip install cloudflare-gateway-adblocking`
|
||||
-->
|
||||
|
||||
### Usage
|
||||
#### Setting Cloudflare credentials
|
||||
##### Environment variables
|
||||
The following environment variables can be used to set the Cloudflare credentials:
|
||||
* `CLOUDFLARE_ACCOUNT_ID`
|
||||
* `CLOUDFLARE_TOKEN`
|
||||
These can either be set in the environment or in a `.env` file in the current working directory.
|
||||
#### Command line flags
|
||||
The following command line flags can be used to set the Cloudflare credentials:
|
||||
* Cloudflare Account ID: `--account-id` / `-a`
|
||||
* Cloudflare Token: `--token` / `-t`
|
||||
#### Passing blocklists
|
||||
Blocklists can be passed to the program via the command line flag `--blocklist` / `-b`. This flag can either point to a hosts file or a directory containing hosts files. If this flag is not passed, the program will look for a file or directory named `blocklists` in the current working directory.
|
||||
# Passing whitelists
|
||||
Whitelists can be passed to the program via the command line flag `--whitelist` / `-w`. This flag can either point to a hosts file or a directory containing hosts files. If this flag is not passed, then if a file or directory named `whitelists` exists in the current working directory, it will be used. Domains in this whitelist will be excluded from the blocklists.
|
||||
#### Uploading blocklists and creating a firewall policy
|
||||
To upload the blocklists to Cloudflare and create a firewall policy, use the `upload` subcommand.
|
||||
For example:
|
||||
`cloudflare-gateway-adblocking upload`
|
||||
#### Deleting blocklists and firewall policy
|
||||
To delete the blocklists from Cloudflare and delete the firewall policy, use the `delete` subcommand.
|
||||
For example:
|
||||
`cloudflare-gateway-adblocking delete`
|
11782
blocklists/hosts.txt
11782
blocklists/hosts.txt
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,351 @@
|
|||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "23.7.0"
|
||||
description = "The uncompromising code formatter."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"},
|
||||
{file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"},
|
||||
{file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"},
|
||||
{file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"},
|
||||
{file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"},
|
||||
{file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"},
|
||||
{file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"},
|
||||
{file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"},
|
||||
{file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"},
|
||||
{file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"},
|
||||
{file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"},
|
||||
{file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"},
|
||||
{file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"},
|
||||
{file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"},
|
||||
{file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"},
|
||||
{file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"},
|
||||
{file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"},
|
||||
{file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"},
|
||||
{file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"},
|
||||
{file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"},
|
||||
{file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"},
|
||||
{file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=8.0.0"
|
||||
mypy-extensions = ">=0.4.3"
|
||||
packaging = ">=22.0"
|
||||
pathspec = ">=0.9.0"
|
||||
platformdirs = ">=2"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
d = ["aiohttp (>=3.7.4)"]
|
||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||
uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2023.7.22"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"},
|
||||
{file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "3.2.0"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
|
||||
{file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.6"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"},
|
||||
{file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"},
|
||||
]
|
||||
|
||||
[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 = "idna"
|
||||
version = "3.4"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
|
||||
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "loguru"
|
||||
version = "0.7.0"
|
||||
description = "Python logging made (stupidly) simple"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "loguru-0.7.0-py3-none-any.whl", hash = "sha256:b93aa30099fa6860d4727f1b81f8718e965bb96253fa190fab2077aaad6d15d3"},
|
||||
{file = "loguru-0.7.0.tar.gz", hash = "sha256:1612053ced6ae84d7959dd7d5e431a0532642237ec21f7fd83ac73fe539e03e1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""}
|
||||
win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
|
||||
|
||||
[package.extras]
|
||||
dev = ["Sphinx (==5.3.0)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v0.990)", "pre-commit (==3.2.1)", "pytest (==6.1.2)", "pytest (==7.2.1)", "pytest-cov (==2.12.1)", "pytest-cov (==4.0.0)", "pytest-mypy-plugins (==1.10.1)", "pytest-mypy-plugins (==1.9.3)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.2.0)", "tox (==3.27.1)", "tox (==4.4.6)"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
description = "Type system extensions for programs checked with the mypy type checker."
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
|
||||
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.1"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
|
||||
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.11.2"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
|
||||
{file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "3.10.0"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"},
|
||||
{file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.0.0"
|
||||
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.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"},
|
||||
{file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
cli = ["click (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.31.0"
|
||||
description = "Python HTTP for Humans."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = ">=2,<4"
|
||||
idna = ">=2.5,<4"
|
||||
urllib3 = ">=1.21.1,<3"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.281"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.0.281-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:418fbddfd3dba4d7b11e4e016eacc40d321ff0b7d3637c7ba9ad3ee0474c9a35"},
|
||||
{file = "ruff-0.0.281-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:c086bf3968d5cb2b4f31a586fc73bc42cb688c32f4c992ff161d4ce19f551cf2"},
|
||||
{file = "ruff-0.0.281-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0162b149a94f6007768820bcdf4ccb7e90a21655aac829ace49f4682d0565fdb"},
|
||||
{file = "ruff-0.0.281-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3495175e6d85a01d3da409a079461a5a3c15b70237cc82550ad8c1f091002c8"},
|
||||
{file = "ruff-0.0.281-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae0b836c03a7010527bb56384a4e3718e0958e32bea64459879aacdcb65c4945"},
|
||||
{file = "ruff-0.0.281-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6d34cae6ef6c6b6fd6d4f09271fbf635db49e6b788da1b2e1dea11a29f1c2a11"},
|
||||
{file = "ruff-0.0.281-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd3c94260a148e955fb46f41d4bcecd857c75794e9f06ebfa7f9be65cfed9621"},
|
||||
{file = "ruff-0.0.281-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ccb875a4000bcba6cc61cb9d3cd5969d6b0921b5234f0ef99ad75f74e8935ef"},
|
||||
{file = "ruff-0.0.281-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f5b8ccaabad61e2d50494df820b7bafd94eac13f10d2d8b831994c1618801a9"},
|
||||
{file = "ruff-0.0.281-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:cbf279fd9c2ca674896656df2d82831010afd336a6703a060fe08d6f2358e47b"},
|
||||
{file = "ruff-0.0.281-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:24d0defeb2c6a1b16a4230840d1138e08bc4ef2318496fa6ff7ddbf3a443626f"},
|
||||
{file = "ruff-0.0.281-py3-none-musllinux_1_2_i686.whl", hash = "sha256:54bab7128167057ee5987bbd9f925fbf105071068de9d8474ca7c38f684b8463"},
|
||||
{file = "ruff-0.0.281-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:29a22b7a6433ce0b4e601897e8a5dd58a75c75c01afee9b8922ebbdd1fe51e51"},
|
||||
{file = "ruff-0.0.281-py3-none-win32.whl", hash = "sha256:7b781f6a7ed35196e6565ed32f57d07b852b0dcd7158c6c7669c8b5d0f8cf97a"},
|
||||
{file = "ruff-0.0.281-py3-none-win_amd64.whl", hash = "sha256:70f921438bf09f04c0547cf64c137c87ef33cbec2b64be12b8caa87df261a016"},
|
||||
{file = "ruff-0.0.281-py3-none-win_arm64.whl", hash = "sha256:42a92a62fc841f7444821444553fd6e1e700bb55348f24e8ec39afdd4e3d0312"},
|
||||
{file = "ruff-0.0.281.tar.gz", hash = "sha256:bab2cdfa78754315cccc2b4d46ad6181aabb29e89747a3b135a4b85e11baa025"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.0.4"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"},
|
||||
{file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"]
|
||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
zstd = ["zstandard (>=0.18.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "win32-setctime"
|
||||
version = "1.1.0"
|
||||
description = "A small Python utility to set file creation time on Windows"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"},
|
||||
{file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "d1e33ec5def7b19f6fd09ac80725a9a9f24da3274b075ee37eb53fe2b2f54219"
|
|
@ -0,0 +1,29 @@
|
|||
[tool.poetry]
|
||||
name = "cloudflare-gateway-adblocking"
|
||||
version = "0.1.0"
|
||||
description = "Serverless adblocking via Cloudflare Zero Trust Gateway"
|
||||
authors = ["slastechno <77907286+slashtechno@users.noreply.github.com>"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/slashtechno/cloudflare-gateway-adblocking"
|
||||
keywords = ["cloudflare", "dns", "adblocking", "serverless"]
|
||||
|
||||
packages = [{include = "src"}]
|
||||
|
||||
[tool.poetry.scripts]
|
||||
cloudflare-gateway-adblocking = "src.__main__:main"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
requests = "^2.31.0"
|
||||
loguru = "^0.7.0"
|
||||
python-dotenv = "^1.0.0"
|
||||
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
ruff = "^0.0.281"
|
||||
black = "^23.7.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
|
@ -0,0 +1,133 @@
|
|||
# To run from the root project directory, run the following command:
|
||||
# python -m src.__main__
|
||||
# python -m src # also works because __main__ is the default module
|
||||
import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
from sys import exit, stderr
|
||||
|
||||
import dotenv
|
||||
from loguru import logger
|
||||
|
||||
from .utils import delete, upload, utils
|
||||
|
||||
TOKEN = None
|
||||
ACCOUNT_ID = None
|
||||
|
||||
|
||||
def main():
|
||||
# Setup logging
|
||||
logger.remove()
|
||||
# ^10 is a formatting directive to center with a padding of 10
|
||||
logger_format = "<green>{time:YYYY-MM-DD HH:mm:ss}</green> |<level>{level: ^10}</level>| <level>{message}</level>" # noqa E501
|
||||
logger.add(stderr, format=logger_format, colorize=True, level="DEBUG")
|
||||
|
||||
# Load .env if it exists
|
||||
# This must precede the argparse setup as env variables are used as default values
|
||||
if Path(".env").is_file():
|
||||
dotenv.load_dotenv()
|
||||
logger.info("Loaded .env file")
|
||||
else:
|
||||
logger.info("No .env file found")
|
||||
|
||||
# Parse arguments
|
||||
|
||||
# Set up argparse
|
||||
argparser = argparse.ArgumentParser(
|
||||
prog="Cloudflare Gateway Adblocking",
|
||||
description="Serverless adblocking via Cloudflare Zero Trust Gateway",
|
||||
epilog=":)",
|
||||
)
|
||||
|
||||
# Add argument groups
|
||||
credential_args = argparser.add_argument_group("Cloudflare Credentials")
|
||||
|
||||
# Add arguments
|
||||
credential_args.add_argument(
|
||||
"--account-id",
|
||||
"-a",
|
||||
help="Cloudflare account ID - environment variable: CLOUDFLARE_ACCOUNT_ID",
|
||||
default=os.environ.get("CLOUDFLARE_ACCOUNT_ID"),
|
||||
)
|
||||
credential_args.add_argument(
|
||||
"--token",
|
||||
"-t",
|
||||
help="Cloudflare API token - environment variable: CLOUDFLARE_TOKEN",
|
||||
default=os.environ.get("CLOUDFLARE_TOKEN"),
|
||||
)
|
||||
|
||||
# Add subcommands
|
||||
subparsers = argparser.add_subparsers(
|
||||
title="subcommands",
|
||||
description="",
|
||||
help="Subcommands to preform operations",
|
||||
dest="subcommand",
|
||||
)
|
||||
# Add subcommand: upload
|
||||
upload_parser = subparsers.add_parser(
|
||||
"upload", help="Upload adblock lists to Cloudflare"
|
||||
)
|
||||
upload_parser.set_defaults(func=upload_to_cloudflare)
|
||||
upload_parser.add_argument(
|
||||
"--blocklists",
|
||||
"-b",
|
||||
help="Either a blocklist hosts file or a directory containing blocklist hosts files", # noqa E501
|
||||
default="blocklists", # Not really needed because the get_blocklists function will default to this # noqa: E501
|
||||
)
|
||||
upload_parser.add_argument(
|
||||
"--whitelists",
|
||||
"-w",
|
||||
help="Either a whitelist hosts file or a directory containing whitelist hosts files", # noqa E501
|
||||
default="whitelist.txt", # Not really needed because the apply_whitelists function will default to this # noqa: E501
|
||||
)
|
||||
# Add subcommand: delete
|
||||
delete_parser = subparsers.add_parser(
|
||||
"delete", help="Delete adblock lists from Cloudflare"
|
||||
)
|
||||
delete_parser.set_defaults(func=delete_from_cloudflare)
|
||||
|
||||
args = argparser.parse_args()
|
||||
|
||||
logger.debug(args)
|
||||
|
||||
# Load variables
|
||||
global TOKEN
|
||||
global ACCOUNT_ID
|
||||
TOKEN = args.token
|
||||
ACCOUNT_ID = args.account_id
|
||||
# Check if variables are set
|
||||
if TOKEN is None or ACCOUNT_ID is None:
|
||||
logger.error(
|
||||
"No environment variables found. Please create a .env file or .envrc file"
|
||||
) # noqa E501
|
||||
exit(1)
|
||||
try:
|
||||
args.func(args)
|
||||
except AttributeError as e:
|
||||
logger.error("No subcommand specified")
|
||||
argparser.print_help()
|
||||
exit(1)
|
||||
|
||||
|
||||
def upload_to_cloudflare(args):
|
||||
logger.info("Uploading to Cloudflare")
|
||||
blocklists = upload.get_blocklists(args.blocklists)
|
||||
blocklists = upload.apply_whitelists(blocklists, args.whitelists)
|
||||
lists = upload.split_list(blocklists)
|
||||
upload.upload_to_cloudflare(lists, ACCOUNT_ID, TOKEN)
|
||||
cloud_lists = utils.get_lists(ACCOUNT_ID, TOKEN)
|
||||
cloud_lists = utils.filter_adblock_lists(cloud_lists)
|
||||
upload.create_dns_policy(cloud_lists, ACCOUNT_ID, TOKEN)
|
||||
|
||||
|
||||
def delete_from_cloudflare(args):
|
||||
logger.info("Deleting from Cloudflare")
|
||||
rules = utils.get_gateway_rules(ACCOUNT_ID, TOKEN)
|
||||
delete.delete_adblock_policy(rules, ACCOUNT_ID, TOKEN)
|
||||
lists = utils.get_lists(ACCOUNT_ID, TOKEN)
|
||||
lists = utils.filter_adblock_lists(lists)
|
||||
delete.delete_adblock_list(lists, ACCOUNT_ID, TOKEN)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,58 @@
|
|||
# This is a scriprt to undo the changes made by adblock-zerotrust.py
|
||||
|
||||
import requests
|
||||
|
||||
from . import utils
|
||||
|
||||
|
||||
def delete_adblock_list(lists: dict, account_id: str, token: str):
|
||||
try:
|
||||
for lst in lists:
|
||||
url = f'https://api.cloudflare.com/client/v4/accounts/{account_id}/gateway/lists/{lst["id"]}'
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.delete(url, headers=headers, timeout=10)
|
||||
if response.status_code != 200:
|
||||
print(f"Error deleting list: {response.text}")
|
||||
else:
|
||||
print(f'Deleted list {lst["name"]}')
|
||||
except TypeError as e:
|
||||
if str(e) == "'NoneType' object is not iterable":
|
||||
print("No lists found")
|
||||
else:
|
||||
raise e
|
||||
|
||||
|
||||
def delete_adblock_policy(policies: dict, account_id: str, token: str):
|
||||
for policy in policies:
|
||||
if policy["name"] == "Block Ads":
|
||||
url = f'https://api.cloudflare.com/client/v4/accounts/{account_id}/gateway/rules/{policy["id"]}'
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.delete(url, headers=headers, timeout=10)
|
||||
if response.status_code != 200:
|
||||
print(f"Error deleting policy: {response.text}")
|
||||
else:
|
||||
print(f'Deleted policy {policy["name"]}')
|
||||
break
|
||||
else:
|
||||
print("No policy found")
|
||||
|
||||
|
||||
def main():
|
||||
account_id = input("Enter your Cloudflare account ID: ")
|
||||
token = input("Enter your Cloudflare API token: ")
|
||||
|
||||
rules = utils.get_gateway_rules(account_id, token)
|
||||
delete_adblock_policy(rules, account_id, token)
|
||||
lists = utils.get_lists(account_id, token)
|
||||
lists = utils.filter_adblock_lists(lists)
|
||||
delete_adblock_list(lists, account_id, token)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,26 +1,36 @@
|
|||
import os
|
||||
import pathlib
|
||||
|
||||
import requests
|
||||
import utils
|
||||
|
||||
# Load environment variables
|
||||
TOKEN = utils.load_env()["CLOUDFLARE_TOKEN"]
|
||||
ACCOUNT_ID = utils.load_env()["CLOUDFLARE_ACCOUNT_ID"]
|
||||
from . import utils
|
||||
|
||||
|
||||
def get_blocklists():
|
||||
# __file__ is a special variable that is the path to the current file
|
||||
list_directory = pathlib.Path(__file__).parent.parent.joinpath("blocklists")
|
||||
for file in list_directory.iterdir():
|
||||
blocklists = utils.convert_to_list(file)
|
||||
def get_blocklists(hosts_path: str = "blocklists"):
|
||||
blocklists = []
|
||||
hosts_path = pathlib.Path(hosts_path)
|
||||
if hosts_path.is_file():
|
||||
blocklists = utils.convert_to_list(hosts_path)
|
||||
elif hosts_path.is_dir():
|
||||
for file in hosts_path.iterdir():
|
||||
blocklists.extend(utils.convert_to_list(file))
|
||||
else:
|
||||
raise ValueError("Invalid hosts file or directory")
|
||||
return blocklists
|
||||
|
||||
|
||||
def apply_whitelists(blocklists):
|
||||
whitelist = utils.convert_to_list(
|
||||
pathlib.Path(__file__).parent.parent.joinpath("whitelist.txt")
|
||||
)
|
||||
def apply_whitelists(blocklists, whitelist: str = "whitelists"):
|
||||
# If whitelist is a file, convert it to a list.
|
||||
# If whitelist is a directory, convert all files in it to a list and combine them.
|
||||
# If it does not exist, return the original blocklists
|
||||
whitelist_path = pathlib.Path(whitelist)
|
||||
if whitelist_path.is_file():
|
||||
whitelist = utils.convert_to_list(whitelist_path)
|
||||
elif whitelist_path.is_dir():
|
||||
whitelist = []
|
||||
for file in whitelist_path.iterdir():
|
||||
whitelist.extend(utils.convert_to_list(file))
|
||||
else:
|
||||
return blocklists
|
||||
blocklists = [x for x in blocklists if x not in whitelist]
|
||||
return blocklists
|
||||
|
||||
|
@ -31,20 +41,19 @@ def split_list(blocklists):
|
|||
[blocklists[i : i + 1000] for i in range(0, len(blocklists), 1000)]
|
||||
) # This is the same as the for loop below
|
||||
# for i in range(0, len(blocklists), 1000):
|
||||
# # This is appending a list of 1000 domains to the lists list. It is doing this by slicing the blocklists list to get the first 1000 domains, then the next 1000 domains, etc.
|
||||
# This continues to append lists of 1000 items to the lists list via slicing
|
||||
# lists.append(blocklists[i:i + 1000])
|
||||
return lists
|
||||
|
||||
|
||||
def upload_to_cloudflare(lists):
|
||||
# A: It's iterating over the lists and uploading them to Cloudflare, the enumerate function is used to get the index of the list since lists is a list of lists
|
||||
def upload_to_cloudflare(lists, account_id: str, token: str) -> None:
|
||||
for i, lst in enumerate(lists):
|
||||
list_name = f"adblock-list-{i + 1}"
|
||||
url = (
|
||||
f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/gateway/lists"
|
||||
f"https://api.cloudflare.com/client/v4/accounts/{account_id}/gateway/lists"
|
||||
)
|
||||
headers = {
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
|
@ -66,10 +75,10 @@ def upload_to_cloudflare(lists):
|
|||
print(f"Error uploading {list_name}: {response.text}")
|
||||
|
||||
|
||||
def create_dns_policy(lists):
|
||||
url = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/gateway/rules"
|
||||
def create_dns_policy(lists, account_id: str, token: str) -> None:
|
||||
url = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/gateway/rules"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
# Construct the traffic string
|
||||
|
@ -93,13 +102,16 @@ def create_dns_policy(lists):
|
|||
|
||||
|
||||
def main():
|
||||
account_id = input("Enter your Cloudflare account ID: ")
|
||||
token = input("Enter your Cloudflare API token: ")
|
||||
|
||||
blocklists = get_blocklists()
|
||||
blocklists = apply_whitelists(blocklists)
|
||||
lists = split_list(blocklists)
|
||||
upload_to_cloudflare(lists)
|
||||
cloud_lists = utils.get_lists()
|
||||
upload_to_cloudflare(lists, account_id, token)
|
||||
cloud_lists = utils.get_lists(account_id, token)
|
||||
cloud_lists = utils.filter_adblock_lists(cloud_lists)
|
||||
create_dns_policy(cloud_lists)
|
||||
create_dns_policy(cloud_lists, account_id, token)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
|
@ -0,0 +1,126 @@
|
|||
import pathlib
|
||||
import re
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
class Config:
|
||||
def __init__(self, token, account_id):
|
||||
# Set token using setter
|
||||
self.token = token
|
||||
if account_id is None:
|
||||
raise ValueError("No account ID provided")
|
||||
|
||||
@property
|
||||
def token(self):
|
||||
return self._token
|
||||
|
||||
@token.setter
|
||||
def token(self, token):
|
||||
if token is None:
|
||||
raise ValueError("No token provided")
|
||||
else:
|
||||
url = "https://api.cloudflare.com/client/v4/user/tokens/verify"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
if response.json()["success"] is False:
|
||||
raise ValueError("Invalid token")
|
||||
else:
|
||||
# Token needs the following scopes:
|
||||
# Zero Trust: Read/Edit
|
||||
# Account Firewall Access Rules: Read/Edit
|
||||
# Access Apps and Policies: Read/Edit
|
||||
self._token = token
|
||||
|
||||
@property
|
||||
def account_id(self):
|
||||
return self._account_id
|
||||
|
||||
@account_id.setter
|
||||
def account_id(self, account_id):
|
||||
if account_id is None:
|
||||
raise ValueError("No account ID provided")
|
||||
else:
|
||||
# Possibly make a request to lists to check if the account ID exists
|
||||
self._account_id = account_id
|
||||
|
||||
|
||||
# List Utils
|
||||
|
||||
|
||||
# Convert a hosts file to a simple hostname list
|
||||
def convert_to_list(file: pathlib.Path) -> list:
|
||||
with open(file, "r") as f:
|
||||
# Loop through the file and using regex, only get the domain names
|
||||
# Remove the prefixed loopback domain and suffixed comments
|
||||
# Remove any empty strings
|
||||
loopback = [
|
||||
"localhost",
|
||||
"::1",
|
||||
"localhost.localdomain",
|
||||
"broadcasthost",
|
||||
"local",
|
||||
"ip6-localhost",
|
||||
"ip6-loopback",
|
||||
"ip6-localnet",
|
||||
"ip6-mcastprefix",
|
||||
"ip6-allnodes",
|
||||
"ip6-allrouters",
|
||||
"ip6-allhosts",
|
||||
"0.0.0.0",
|
||||
]
|
||||
matches = [
|
||||
re.search(r"^(?:127\.0\.0\.1|0\.0\.0\.0|::1)\s+(.+?)(?:\s+#.+)?$", line)
|
||||
for line in f
|
||||
]
|
||||
hosts = [
|
||||
match.group(1)
|
||||
for match in matches
|
||||
if match and match.group(1) not in loopback
|
||||
]
|
||||
print(f"First 5 hosts: {hosts[:5]}")
|
||||
return hosts
|
||||
|
||||
|
||||
# General Utils
|
||||
|
||||
|
||||
def get_lists(account_id, token) -> dict:
|
||||
url = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/gateway/lists"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
if response.status_code != 200:
|
||||
print(f"Error getting lists: {response.text}")
|
||||
return response.json()["result"]
|
||||
|
||||
|
||||
def filter_adblock_lists(lists: dict) -> dict:
|
||||
adblock_lists = []
|
||||
try:
|
||||
for lst in lists:
|
||||
if lst["name"].startswith("adblock-list") and lst["type"] == "DOMAIN":
|
||||
adblock_lists.append(lst)
|
||||
except TypeError as e:
|
||||
if str(e) == "'NoneType' object is not iterable":
|
||||
print("No lists found")
|
||||
else:
|
||||
raise e
|
||||
return adblock_lists
|
||||
|
||||
|
||||
def get_gateway_rules(account_id, token) -> dict:
|
||||
url = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/gateway/rules"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
if response.status_code != 200:
|
||||
print(f"Error getting lists: {response.text}")
|
||||
return response.json()["result"]
|
|
@ -1,52 +0,0 @@
|
|||
# This is a scriprt to undo the changes made by adblock-zerotrust.py
|
||||
|
||||
import requests
|
||||
import utils
|
||||
|
||||
# Load environment variables
|
||||
TOKEN = utils.load_env()["CLOUDFLARE_TOKEN"]
|
||||
ACCOUNT_ID = utils.load_env()["CLOUDFLARE_ACCOUNT_ID"]
|
||||
|
||||
|
||||
def delete_adblock_list(lists: dict):
|
||||
for lst in lists:
|
||||
url = f'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/gateway/lists/{lst["id"]}'
|
||||
headers = {
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.delete(url, headers=headers, timeout=10)
|
||||
if response.status_code != 200:
|
||||
print(f"Error deleting list: {response.text}")
|
||||
else:
|
||||
print(f'Deleted list {lst["name"]}')
|
||||
|
||||
|
||||
def delete_adblock_policy(policies: dict):
|
||||
for policy in policies:
|
||||
if policy["name"] == "Block Ads":
|
||||
url = f'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/gateway/rules/{policy["id"]}'
|
||||
headers = {
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.delete(url, headers=headers, timeout=10)
|
||||
if response.status_code != 200:
|
||||
print(f"Error deleting policy: {response.text}")
|
||||
else:
|
||||
print(f'Deleted policy {policy["name"]}')
|
||||
break
|
||||
else:
|
||||
print("No policy found")
|
||||
|
||||
|
||||
def main():
|
||||
rules = utils.get_gateway_rules()
|
||||
delete_adblock_policy(rules)
|
||||
lists = utils.get_lists()
|
||||
lists = utils.filter_adblock_lists(lists)
|
||||
delete_adblock_list(lists)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,85 +0,0 @@
|
|||
import os
|
||||
import pathlib
|
||||
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# List Utils
|
||||
|
||||
|
||||
# Convert a hosts file to a simple hostname list
|
||||
def convert_to_list(file: pathlib.Path) -> list:
|
||||
with open(file, "r") as f:
|
||||
# Don't read commented lines; strip whitespace; remove 127.0.0.1 from beginning of line; ignore lines with "localhost"; ignore lines with "::1"; ignore newlines blocklists.extend([i[10:].strip() for i in f.readlines() if not i.startswith('#') and 'localhost' not in i and '::1' not in i])
|
||||
hosts = [
|
||||
i[10:].strip()
|
||||
for i in f.readlines()
|
||||
if not i.startswith("#") and "localhost" not in i and "::1" not in i
|
||||
]
|
||||
# Equivalent to:
|
||||
# for x in f.readlines():
|
||||
# if not x.startswith('#') and 'localhost' not in x and '::1' not in x:
|
||||
# hosts.append(x[10:].strip())
|
||||
# If there are any empty strings in the list, remove them since for some reason, whitespace is stil in the list
|
||||
hosts = [i for i in hosts if i != ""]
|
||||
return hosts
|
||||
|
||||
|
||||
# General Utils
|
||||
|
||||
|
||||
# Load environment variables
|
||||
def load_env() -> dict:
|
||||
load_dotenv(".env")
|
||||
if not os.environ.get("CLOUDFLARE_TOKEN") and not os.environ.get(
|
||||
"CLOUDFLARE_ACCOUNT_ID"
|
||||
):
|
||||
load_dotenv(".envrc")
|
||||
if not os.environ.get("CLOUDFLARE_TOKEN") or not os.environ.get(
|
||||
"CLOUDFLARE_ACCOUNT_ID"
|
||||
):
|
||||
print(
|
||||
"No environment variables found. Please create a .env file or .envrc file"
|
||||
)
|
||||
exit()
|
||||
else:
|
||||
return {
|
||||
"CLOUDFLARE_TOKEN": os.environ.get("CLOUDFLARE_TOKEN"),
|
||||
"CLOUDFLARE_ACCOUNT_ID": os.environ.get("CLOUDFLARE_ACCOUNT_ID"),
|
||||
}
|
||||
|
||||
|
||||
def get_lists() -> dict:
|
||||
url = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/gateway/lists"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
if response.status_code != 200:
|
||||
print(f"Error getting lists: {response.text}")
|
||||
return response.json()["result"]
|
||||
|
||||
|
||||
def filter_adblock_lists(lists: dict) -> dict:
|
||||
adblock_lists = []
|
||||
for lst in lists:
|
||||
if lst["name"].startswith("adblock-list") and lst["type"] == "DOMAIN":
|
||||
adblock_lists.append(lst)
|
||||
return adblock_lists
|
||||
|
||||
|
||||
def get_gateway_rules() -> dict:
|
||||
url = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/gateway/rules"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
if response.status_code != 200:
|
||||
print(f"Error getting lists: {response.text}")
|
||||
return response.json()["result"]
|
||||
|
||||
|
||||
TOKEN = load_env()["CLOUDFLARE_TOKEN"]
|
||||
ACCOUNT_ID = load_env()["CLOUDFLARE_ACCOUNT_ID"]
|
Loading…
Reference in New Issue