cf_rules module

class cf_rules.Cloudflare(folder: str | None = None)[source]
__init__(folder: str | None = None)[source]

Initialize Cloudflare class

Specify a folder argument where expressions will be saved

>>> cf = Cloudflare("my_expressions")
auth_key(email: str, key: str) dict[source]

Get your global API Key through cloudflare profile (API Keys section)

Raises:

Error – Email or key is not provided

Warning

This will grant all domains access to this API library, prefer using auth_token()

https://dash.cloudflare.com/profile/api-tokens

  • email -> Email account

  • key -> Global API Key

>>> cf.auth_key("cloudflare@example.com", "your-global-api-key")
>>> {"success": True, "result": {"id": "a1b2c3", "email": "cloudflare@example.com", ...}}
# OR
>>> {"success": False, "errors": [{"code": 6003, "message": "Invalid request headers", ...}]}
auth_token(bearer_token: str) dict[source]

Generate a specific token through cloudflare profile (API Tokens section)

Raises:

Error – Bearer token is not provided

Note

This will grant only specific domains/permissions related access to this API library

https://dash.cloudflare.com/profile/api-tokens

  • bearer_token -> API Token

>>> cf.auth_token("your-specific-bearer-token")
>>> {"success": True, "result": {"id": "a1b2c3", "status": "active"}, ...}
# OR
>>> {"success": False, "errors": [{"code": 1000, "message": "Invalid API token"}], ...}
get_domains() dict[source]

Get all domains

Raises:

Error – If not authenticated (use auth_key(email, key) or auth_token(bearer_token))

>>> cf.get_domains()
>>> {"count": 2, "domains": ["example.com", "example.fr"], "result": [{"id": "a1b2c3", "name": "example.com", ...}, ...]}
property domains: list[DomainObject]

Get all domains as a list of DomainObject

Access any value of the object with the dot operator

Better handling compared to get_domains(), return directly the result key of the function

>>> cf.domains
>>> [{"id": "a1b2c3", "name": "example.com", ...}, {"id": "d4e5f6", "name": "example.fr", ...}]
get_domain(domain_name: str) DomainObject[source]

Get a specific domain as DomainObject

Raises:

Important

This function is the “core” for all other functions, it is needed for every other function to work

>>> cf.get_domain("example.com")
>>> {"id": "a1b2c3", "name": "example.com", ...}
>>> domain = cf.get_domain("example.fr")
>>> domain.name # OR domain["name"]
>>> "example.fr"
set_plan(domain_name: str)[source]

Save current website plan

Note

Will define the current plan of the website in the instance of the class

>>> cf.set_plan("example.com")
# Now the maximum available rules for this domain depends on the current plan
get_rulesets(domain_name: str) dict[source]

Get all rulesets from a specific domain

>>> cf.get_rulesets("example.com")
>>> {"count": 4, "rulesets": ["default", "Cloudflare Normalization Ruleset", ...], "result": [{"id": "a1b2c3", "name": "default", ...}]}
rulesets(domain_name: str) list[RulesetObject][source]

Get all rulesets as a list of RulesetObject

Access any value of the object with the dot operator

Better handling compared to get_rulesets(), return directly the result key of the function

>>> cf.rulesets
>>> [{"id": "a1b2c3", "name": "default", ...}, {"id": "d4e5f6", "name": "Cloudflare Normalization Ruleset", ...}]
get_custom_ruleset(domain_name: str) RulesetObject[source]

Get the custom ruleset from a specific domain as RulesetObject

It should be the only ruleset with the source “firewall_custom” as per Cloudflare’s documentation. This is the ruleset where all custom rules are stored.

Raises:

Error – If no custom ruleset is found

>>> cf.get_custom_ruleset("example.com")
>>> {"id": "a1b2c3", "name": "default", "source": "firewall_custom", ...}
get_rules(domain_name: str) dict[source]

Get all rules from a specific domain

Raises:

Error – If no rules are found

>>> cf.get_rules("example.com")
>>> {"count": 3, "rules": ["Bad Bots", "Bad IP", "Bad AS"], "result": [{"id": "a1b2c3", "description": "Bad Bots", ...}, ...]}
rules(domain_name: str) list[RuleObject][source]

Get all rules as a list of RuleObject

Access any value of the object with the dot operator

Better handling compared to get_rules(), return directly the result key of the function

>>> cf.rules
>>> [{"id": "a1b2c3", "description": "Bad Bots", ...}, {"id": "d4e5f6", "description": "Bad IP", ...}, ...]
get_rule(domain_name: str, *, rule_name: str | None = None, rule_id: str | None = None) RuleObject[source]

Get a specific rule by name or ID from a specific domain as RuleObject

Raises:
  • Error – Rule name or rule ID is not provided

  • Error – If no rule is found with the specified name

>>> cf.get_rule("example.com", rule_name="Bad Bots")
>>> {"id": "a1b2c3", "enabled": True, "action": "block", "description": "Bad Bots", "expression": "(http.user_agent contains "DotBot")", ...}
export_rules(domain_name: str) True[source]

Export all expressions from a specific domain

Note

Will save all expressions into multiple files in the folder specified in Cloudflare’s constructor

>>> cf.export_rules("example.com")
# "Bad Bots.txt", "Bad IP.txt", "Bad AS.txt" files created in "my_expressions" folder
export_rule(domain_name: str, *, rule_name: str | None = None, rule_id: str | None = None) True[source]

Export the expression of a rule in a txt file

Raises:

Error – Rule name or rule ID is not provided

Note

Will save the expression into a file in the folder specified in Cloudflare’s constructor

>>> cf.export_rule("example.com", "Bad Bots")
# "Bad Bots.txt" file created in "my_expressions" folder
create_rule(domain_name: str, rule_file: str, rule_name: str | None = None, action: str | None = None) bool[source]

Create a rule with a specific expression

Available actions as string: managed_challenge, js_challenge, challenge, block, skip, log

Action is read from the header of the file by default, but you can specify it manually. Else it will be “managed_challenge”

Raises:
  • Error – Rule file is not found

  • Error – Rule already exists in remote WAF

  • Error – Cannot create more rules (5 used / 5 available depending on the current plan)

>>> cf.create_rule("example.com", "Bad URL.txt", action="managed_challenge")
# Create a rule with the expression in "Bad URL.txt" and override the action to "managed_challenge"
>>> cf.create_rule("example.com", "Bad IP.txt", "Not allowed IP")
# Create a rule named "Not allowed IP" with the expression in "Bad IP.txt" with the action in the header of the file
update_rule(domain_name: str, rule_file: str, rule_name: str | None = None, action: str | None = None) bool[source]

Update a rule with a specific expression

Raises:

Error – Rule file is not found

Todo

First modify “Bad Bots.txt” by changing the expression or adding a new rule

>>> cf.update_rule("example.com", "Bad Bots.txt")
# Will update the remote rule "Bad Bots" with the expression in "Bad Bots.txt"
>>> cf.update_rule("example.com", "Bad IP.txt", "Not allowed IP", "block")
# Will update the remote rule "Not allowed IP" with the expression in "Bad IP.txt" and override the action to "block"
delete_rule(domain_name: str, rule_name: str) bool[source]

Delete a rule from a specific domain

>>> cf.delete_rule("example.com", "Bad AS")
# Will delete the rule "Bad AS" remotely from the domain "example.com"
purge_rules(domain_name: str) bool[source]

Purge all rules from a specific domain

>>> cf.purge_rules("example.com")
# Will delete all rules remotely from the domain "example.com"
import_rules(domain_name: str, actions_all: str | None = None) bool[source]

Import all expressions from all txt file

Available actions as string: managed_challenge, js_challenge, challenge, block, skip, log

Raises:

Error – Cannot create more rules (5 used / 5 available depending on the current plan)

Note

If you have a better plan, please register your plan using the method set_plan(domain_name)

>>> cf.import_rules("example.com")
# Will use the action in the header specific for every file
>>> cf.import_rules("example.com", "block")
# Will import all rules and use the "block" action
import_rule(domain_name: str, rule_file: str, rule_name: str | None = None, action: str | None = None) bool

Import a rule with a specific expression

Alias for create_rule()

>>> cf.import_rule("example.com", "Bad URL.txt", action="managed_challenge")
# Import a rule with the expression in "Bad URL.txt", will use the action in the header if specified or force it using the action argument
class cf_rules.Utils(directory: str = None)[source]
__init__(directory: str = None) None[source]

Utils class to manage Cloudflare data

>>> utils = Utils("my_expressions")
change_directory(directory: str) None[source]

Change the directory where the expressions are stored

>>> utils.change_directory("my_expressions2")
static escape(string) str[source]

Escape a string

Simply replace slashes with underscores for the file name

>>> utils.escape("Test/1")
>>> "Test_1"
static unescape(string: str) str[source]

Unescape a string

Simply replace underscores with slashes for the rule name

>>> utils.unescape("Test_1")
>>> "Test/1"
static beautify(expression: str) str[source]

Beautify a Cloudflare expression

>>> utils.beautify("(cf.client.bot) or (cf.threat_score ge 1)")
# (cf.client.bot) or
# (cf.threat_score ge 1)
write_expression(rule_file: str, rule_expression: str, header: dict | None = None) None[source]

Write an expression to a readable text file

>>> utils.write_expression("IsBot", "(cf.client.bot)")
>>> utils.write_expression("IsBot", "(cf.client.bot)", header={"action": "managed_challenge", "enabled": "True"})
read_expression(rule_file: str) tuple[str, str][source]

Read an expression from a file

>>> utils.read_expression("IsBot")
>>> "(cf.client.bot)"
process_header(header_line: str) dict | None[source]

Process the header of an expression file if it exists It retrieves all header data and returns a dictionary

>>> utils.process_header("#! action:block enabled:True !#")
>>> {"action": "block", "enabled": "True"}
static get_json_key(json: dict, keys: list[str | int]) object[source]

Get an element from a json using a list of keys

>>> utils.get_json_key({"a": {"b": {"c": "d"}}}, ["a", "b", "c"])
>>> "d"
>>> utils.get_json_key({"a": ["b", "c"]}, ["a", 1])
>>> "c"
exception cf_rules.Error(message: str | None = None)[source]
__init__(message: str | None = None) Error[source]

Error class to handle Cloudflare errors

>>> error = Error()
# OR
>>> error = Error("This is an error message")
handle(request_json: dict, keys: list[str | int]) any[source]

Handle errors from a request response

Raises:

Error – If auth error

>>> error.handle({"success": True, "result": {"a": "b"}}, ["success"])
>>> True
>>> error.handle({"success": False, "errors": [{"code": "invalid_parameter", "message": "Invalid parameter"}]}, ["success"])
>>> False
>>> error.handle({"success": False, "errors": [{"code": 9109, "message": "Invalid access token"}], "messages": [], "result": None}, ["errors"][0]["message"])
>>> "Invalid access token"