diff --git a/.envrc.example b/.env.example similarity index 100% rename from .envrc.example rename to .env.example diff --git a/.envrc.bat b/.envrc.bat deleted file mode 100644 index 9abd936..0000000 --- a/.envrc.bat +++ /dev/null @@ -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 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c9961f7 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Cloudflare Gateway Adblocking +Serverless adblocking via Cloudflare Zero Trust Gateway \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 28c0a9a..a1b7fdd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -135,6 +135,20 @@ 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 = "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" @@ -216,4 +230,4 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "2213d241196503176caefedd103dfc06ddd3a12c386e2948706dc0d732d7ed50" +content-hash = "843328e3217d5ebc1fbb55737ca6edc4d47894e2b1c48e5ab5f3fe0b6a27045c" diff --git a/pyproject.toml b/pyproject.toml index 3e51a94..fb7090f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,15 +2,16 @@ name = "cloudflare-gateway-adblocking" version = "0.1.0" description = "Serverless adblocking via Cloudflare Zero Trust Gateway" -authors = ["slastechno 77907286+slashtechno@users.noreply.github.com"] +authors = ["slastechno <77907286+slashtechno@users.noreply.github.com>"] license = "MIT" readme = "README.md" -packages = [{include = "cloudflare_gateway_adblocking"}] +packages = [{include = "src"}] [tool.poetry.dependencies] python = "^3.10" requests = "^2.31.0" loguru = "^0.7.0" +python-dotenv = "^1.0.0" [tool.poetry.group.dev.dependencies] diff --git a/src/cmd.py b/src/cmd.py index eea55c9..9bc75c3 100644 --- a/src/cmd.py +++ b/src/cmd.py @@ -1,39 +1,121 @@ +from loguru import logger +# Import the utils package import utils + import argparse import os -from loguru import logger +import dotenv +from sys import exit, stderr +from pathlib import Path + +TOKEN = None +ACCOUNT_ID = None def cli(): + # Setup logging + logger.remove() + # ^10 is a formatting directive to center with a padding of 10 + logger_format = "{time:YYYY-MM-DD HH:mm:ss} |{level: ^10}| {message}" # pylint: disable=line-too-long + logger.add(stderr, format=logger_format, colorize=True, level="DEBUG") + + + # Load .env if it exists + # This must precede the argparse setup as os.environ is used in the default arguments + 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() + 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 - argparser.add_argument( + credential_args.add_argument( "--account-id", "-a", help="Cloudflare account ID - environment variable: CLOUDFLARE_ACCOUNT_ID", default=os.environ.get("CLOUDFLARE_ACCOUNT_ID") ) - argparser.add_argument('--token', + credential_args.add_argument('--token', '-t', help='Cloudflare API token - environment variable: CLOUDFLARE_TOKEN', default=os.environ.get("CLOUDFLARE_TOKEN") ) - # Parse arguments + + # 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", + default="blocklists" + ) + upload_parser.add_argument( + "--whitelists", + "-w", + # help="Either a whitelist hosts file or a directory containing whitelist hosts files" + help="Whitelist hosts file or directory", + default="whitelist.txt" # Need to change this so it's optional + ) + # 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() - - - + exit(1) + args.func(args) +def upload_to_cloudflare(args): + logger.info("Uploading to Cloudflare") + blocklists = utils.utils.get_blocklists(args.blocklists) + blocklists = utils.adblock_zerotrust.apply_whitelists(blocklists, args.whitelists) + lists = utils.adblock_zerotrust.split_list(blocklists) + utils.adblock_zerotrust.upload_to_cloudflare(lists, ACCOUNT_ID, TOKEN) + cloud_lists = utils.utils.get_lists(ACCOUNT_ID, TOKEN) + cloud_lists = utils.utils.filter_adblock_lists(cloud_lists) + utils.adblock_zerotrust.create_dns_policy(cloud_lists, ACCOUNT_ID, TOKEN) +def delete_from_cloudflare(args): + logger.info("Deleting from Cloudflare") + rules = utils.utils.get_gateway_rules(ACCOUNT_ID, TOKEN) + utils.delete_adblock_zerotrust.delete_adblock_policy(rules, ACCOUNT_ID, TOKEN) + lists = utils.utils.get_lists(ACCOUNT_ID, TOKEN) + lists = utils.utils.filter_adblock_lists(lists) + utils.delete_adblock_zerotrust.delete_adblock_list(lists, ACCOUNT_ID, TOKEN) if __name__ == "__main__": cli() diff --git a/src/utils/__init.py__ b/src/utils/__init.py__ deleted file mode 100644 index e69de29..0000000 diff --git a/src/utils/__init__.py b/src/utils/__init__.py new file mode 100644 index 0000000..b045e2a --- /dev/null +++ b/src/utils/__init__.py @@ -0,0 +1,3 @@ +from .utils import * +from .adblock_zerotrust import * +from .delete_adblock_zerotrust import * diff --git a/src/utils/adblock_zerotrust.py b/src/utils/adblock_zerotrust.py index 8c2ac3d..6b326f3 100644 --- a/src/utils/adblock_zerotrust.py +++ b/src/utils/adblock_zerotrust.py @@ -3,17 +3,20 @@ import utils import pathlib -def get_blocklists(): +def get_blocklists(path_to_blocklists: str = None): # __file__ is a special variable that is the path to the current file - list_directory = pathlib.Path(__file__).parent.parent.joinpath("blocklists") + # list_directory = pathlib.Path(__file__).parent.parent.joinpath("blocklists") + + list_directory = pathlib.Path(path_to_blocklists) for file in list_directory.iterdir(): blocklists = utils.convert_to_list(file) return blocklists -def apply_whitelists(blocklists): +def apply_whitelists(blocklists, whitelist: str = None): whitelist = utils.convert_to_list( - pathlib.Path(__file__).parent.parent.joinpath("whitelist.txt") + # pathlib.Path(__file__).parent.parent.joinpath("whitelist.txt") + pathlib.Path(whitelist) ) blocklists = [x for x in blocklists if x not in whitelist] return blocklists