From a84cc877002c2d68a119c8515ef6a3bdc9ec5551 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Fri, 29 Mar 2019 14:39:08 +0100 Subject: [PATCH 01/11] Refactor changing project and text equals "pyGoDaddyAUpdater" --- LICENSE | 4 ++-- README.md | 10 +++++----- .../__init__.py | 2 +- .../__main__.py | 2 +- .../logging_utils/__init__.py | 2 +- .../logging_utils/utils.py | 2 +- .../network/__init__.py | 2 +- .../network/network_utils.py | 2 +- .../preferences/__init__.py | 2 +- .../preferences/user_preferences.py | 2 +- .../values/__init__.py | 2 +- .../values/constants.py | 4 ++-- setup.py | 18 +++++++++--------- 13 files changed, 27 insertions(+), 27 deletions(-) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/__init__.py (93%) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/__main__.py (99%) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/logging_utils/__init__.py (94%) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/logging_utils/utils.py (98%) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/network/__init__.py (94%) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/network/network_utils.py (97%) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/preferences/__init__.py (94%) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/preferences/user_preferences.py (99%) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/values/__init__.py (94%) rename {pyGoDaddyUpdater => pyCloudFlareUpdater}/values/constants.py (90%) diff --git a/LICENSE b/LICENSE index d2daa6e..c9bd668 100644 --- a/LICENSE +++ b/LICENSE @@ -631,7 +631,7 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - pyGoDaddyAUpdater + pyCloudFlareUpdater Copyright (C) 2019 Javinator9889 This program is free software: you can redistribute it and/or modify @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - pyGoDaddyAUpdater Copyright (C) 2019 Javinator9889 + pyCloudFlareUpdater Copyright (C) 2019 Javinator9889 This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/README.md b/README.md index 946b1fb..f80298d 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ *DDNS Service for updating dynamically your GoDaddy 'A' Records when your public IP changes* [![PyPi](https://img.shields.io/badge/v1.1%20-PyPi-green.svg)](https://pypi.org/project/pyGoDaddyUpdater/) -[![ZIP](https://img.shields.io/badge/Package%20-Zip-green.svg)](https://gitlab.javinator9889.com/Javinator9889/pyGoDaddyAUpdater/repository/master/archive.zip) -[![GIT](https://img.shields.io/badge/Package%20-Git-green.svg)](https://gitlab.javinator9889.com/Javinator9889/pyGoDaddyAUpdater.git) +[![ZIP](https://img.shields.io/badge/Package%20-Zip-green.svg)](https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater/repository/master/archive.zip) +[![GIT](https://img.shields.io/badge/Package%20-Git-green.svg)](https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater.git) [![Downloads](https://pepy.tech/badge/pygodaddyupdater)](https://pepy.tech/project/pygodaddyupdater) ## Index @@ -39,7 +39,7 @@ There are two possibilities for installing this script: Start by *cloning* this repository. For that, you will need to have [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) installed. Then, run on Git Bash: ```text - git clone https://gitlab.javinator9889.com/Javinator9889/pyGoDaddyAUpdater.git + git clone https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater.git ``` There is another possibility so you can *directly download* a compressed file with all the necessary data. Just unzip @@ -48,7 +48,7 @@ There are two possibilities for installing this script: For installing, you will need **administrator** permissions, as the script is creating a new command so you can run it from everywhere: ```text - cd pyGoDaddyAUpdater + cd pyCloudFlareUpdater sudo python3 setup.py install ``` @@ -120,7 +120,7 @@ to include the options mentioned above. ### License ```text - pyGoDaddyAUpdater + pyCloudFlareUpdater Copyright (C) 2019 - Javinator9889 This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/__init__.py b/pyCloudFlareUpdater/__init__.py similarity index 93% rename from pyGoDaddyUpdater/__init__.py rename to pyCloudFlareUpdater/__init__.py index 7d930dc..f0a363b 100644 --- a/pyGoDaddyUpdater/__init__.py +++ b/pyCloudFlareUpdater/__init__.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/__main__.py b/pyCloudFlareUpdater/__main__.py similarity index 99% rename from pyGoDaddyUpdater/__main__.py rename to pyCloudFlareUpdater/__main__.py index a8256b7..63830ba 100644 --- a/pyGoDaddyUpdater/__main__.py +++ b/pyCloudFlareUpdater/__main__.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/logging_utils/__init__.py b/pyCloudFlareUpdater/logging_utils/__init__.py similarity index 94% rename from pyGoDaddyUpdater/logging_utils/__init__.py rename to pyCloudFlareUpdater/logging_utils/__init__.py index ae521d9..37f933f 100644 --- a/pyGoDaddyUpdater/logging_utils/__init__.py +++ b/pyCloudFlareUpdater/logging_utils/__init__.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/logging_utils/utils.py b/pyCloudFlareUpdater/logging_utils/utils.py similarity index 98% rename from pyGoDaddyUpdater/logging_utils/utils.py rename to pyCloudFlareUpdater/logging_utils/utils.py index c5f19b6..4e8c948 100644 --- a/pyGoDaddyUpdater/logging_utils/utils.py +++ b/pyCloudFlareUpdater/logging_utils/utils.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/network/__init__.py b/pyCloudFlareUpdater/network/__init__.py similarity index 94% rename from pyGoDaddyUpdater/network/__init__.py rename to pyCloudFlareUpdater/network/__init__.py index e087320..e23c0ab 100644 --- a/pyGoDaddyUpdater/network/__init__.py +++ b/pyCloudFlareUpdater/network/__init__.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/network/network_utils.py b/pyCloudFlareUpdater/network/network_utils.py similarity index 97% rename from pyGoDaddyUpdater/network/network_utils.py rename to pyCloudFlareUpdater/network/network_utils.py index 0460a58..99a9b89 100644 --- a/pyGoDaddyUpdater/network/network_utils.py +++ b/pyCloudFlareUpdater/network/network_utils.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/preferences/__init__.py b/pyCloudFlareUpdater/preferences/__init__.py similarity index 94% rename from pyGoDaddyUpdater/preferences/__init__.py rename to pyCloudFlareUpdater/preferences/__init__.py index ca3ebbf..5f26955 100644 --- a/pyGoDaddyUpdater/preferences/__init__.py +++ b/pyCloudFlareUpdater/preferences/__init__.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/preferences/user_preferences.py b/pyCloudFlareUpdater/preferences/user_preferences.py similarity index 99% rename from pyGoDaddyUpdater/preferences/user_preferences.py rename to pyCloudFlareUpdater/preferences/user_preferences.py index ae617c8..b026da8 100644 --- a/pyGoDaddyUpdater/preferences/user_preferences.py +++ b/pyCloudFlareUpdater/preferences/user_preferences.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/values/__init__.py b/pyCloudFlareUpdater/values/__init__.py similarity index 94% rename from pyGoDaddyUpdater/values/__init__.py rename to pyCloudFlareUpdater/values/__init__.py index b2b0354..9519628 100644 --- a/pyGoDaddyUpdater/values/__init__.py +++ b/pyCloudFlareUpdater/values/__init__.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify diff --git a/pyGoDaddyUpdater/values/constants.py b/pyCloudFlareUpdater/values/constants.py similarity index 90% rename from pyGoDaddyUpdater/values/constants.py rename to pyCloudFlareUpdater/values/constants.py index 6850b0f..60e708a 100644 --- a/pyGoDaddyUpdater/values/constants.py +++ b/pyCloudFlareUpdater/values/constants.py @@ -1,4 +1,4 @@ -# pyGoDaddyAUpdater +# pyCloudFlareUpdater # Copyright (C) 2019 - Javinator9889 # # This program is free software: you can redistribute it and/or modify @@ -13,6 +13,6 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -description = """pyGoDaddyUpdater\n\n +description = """pyCloudFlareUpdater\n\n The first time this application is executed, all params must be included in order to save the user preferences and do this process automatically.""" diff --git a/setup.py b/setup.py index 36a7323..a074bdf 100644 --- a/setup.py +++ b/setup.py @@ -11,14 +11,14 @@ long_description = f.read() setup( - name='pyGoDaddyUpdater', + name='pyCloudFlareUpdater', version='1.1', - packages=['pyGoDaddyUpdater', - 'pyGoDaddyUpdater.values', - 'pyGoDaddyUpdater.network', - 'pyGoDaddyUpdater.preferences', - 'pyGoDaddyUpdater.logging_utils'], - url='https://gitlab.javinator9889.com/Javinator9889/pyGoDaddyAUpdater', + packages=['pyCloudFlareUpdater', + 'pyCloudFlareUpdater.values', + 'pyCloudFlareUpdater.network', + 'pyCloudFlareUpdater.preferences', + 'pyCloudFlareUpdater.logging_utils'], + url='https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater', license='GPL-3.0', author='Javinator9889', author_email='javialonso007@hotmail.es', @@ -27,9 +27,9 @@ long_description_content_type='text/markdown', include_package_data=False, zip_safe=True, - download_url="https://gitlab.javinator9889.com/Javinator9889/pyGoDaddyAUpdater/repository/master/archive.zip", + download_url="https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater/repository/master/archive.zip", entry_points={ - 'console_scripts': ['godaddy_ddns=pyGoDaddyUpdater.__main__:parser'] + 'console_scripts': ['godaddy_ddns=pyCloudFlareUpdater.__main__:parser'] }, install_requires=['daemonize'], classifiers=[ From d2b62bd648e799f2491f8e3402fa55cf5e6be286 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 18:55:32 +0200 Subject: [PATCH 02/11] Updated network method for working with CloudFlare (instead of GoDaddy) --- .idea/dictionaries/Javinator9889.xml | 1 + pyCloudFlareUpdater/__main__.py | 8 +-- pyCloudFlareUpdater/network/__init__.py | 2 +- pyCloudFlareUpdater/network/network_utils.py | 71 ++++++++++++++++---- pyCloudFlareUpdater/values/__init__.py | 1 + pyCloudFlareUpdater/values/constants.py | 1 + 6 files changed, 65 insertions(+), 19 deletions(-) diff --git a/.idea/dictionaries/Javinator9889.xml b/.idea/dictionaries/Javinator9889.xml index 45a46dd..e7a307b 100644 --- a/.idea/dictionaries/Javinator9889.xml +++ b/.idea/dictionaries/Javinator9889.xml @@ -2,6 +2,7 @@ asctime + cloudflare daemonize fpreferences javinator diff --git a/pyCloudFlareUpdater/__main__.py b/pyCloudFlareUpdater/__main__.py index 63830ba..05360ac 100644 --- a/pyCloudFlareUpdater/__main__.py +++ b/pyCloudFlareUpdater/__main__.py @@ -24,7 +24,7 @@ from .logging_utils import LoggingHandler from .logging_utils import setup_logging -from .network import GoDaddy +from .network import CloudFlare from .network import get_machine_public_ip from .preferences import UserPreferences from .values import description @@ -35,19 +35,19 @@ def main(): loop_continuation = True log = LoggingHandler(logs=[getLogger("appLogger")]) - net = GoDaddy(preferences.get_domain(), preferences.get_name(), preferences.get_key(), preferences.get_secret()) + net = CloudFlare(preferences.get_domain(), preferences.get_name(), preferences.get_key(), preferences.get_secret()) try: while loop_continuation: current_ip = get_machine_public_ip() log.info("Current machine IP: \"{0}\"".format(current_ip)) if preferences.get_latest_ip() == "0.0.0.0": - preferences.set_latest_ip(net.get_godaddy_latest_ip()) + preferences.set_latest_ip(net.get_cloudflare_latest_ip()) log.warning("User saved latest IP is not up to date - downloading GoDaddy A Record value: \"{0}\"" .format(preferences.get_latest_ip())) if preferences.get_latest_ip() != current_ip: log.info("IP needs an upgrade - OLD IP: {0} | NEW IP: {1}" .format(preferences.get_latest_ip(), current_ip)) - result = net.set_goddady_ip(current_ip) + result = net.set_cloudflare_ip(current_ip) log.info("IP updated correctly! - Operation return code: {0}".format(result)) log.debug("Updating saved IP...") preferences.set_latest_ip(current_ip) diff --git a/pyCloudFlareUpdater/network/__init__.py b/pyCloudFlareUpdater/network/__init__.py index e23c0ab..e9c73f9 100644 --- a/pyCloudFlareUpdater/network/__init__.py +++ b/pyCloudFlareUpdater/network/__init__.py @@ -13,5 +13,5 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from ..network.network_utils import GoDaddy +from ..network.network_utils import CloudFlare from ..network.network_utils import get_machine_public_ip diff --git a/pyCloudFlareUpdater/network/network_utils.py b/pyCloudFlareUpdater/network/network_utils.py index 99a9b89..7fabc43 100644 --- a/pyCloudFlareUpdater/network/network_utils.py +++ b/pyCloudFlareUpdater/network/network_utils.py @@ -21,33 +21,76 @@ def get_machine_public_ip(): return urllib.request.urlopen('https://ident.me').read().decode('utf8') -class GoDaddy(object): - def __init__(self, domain, name, key, secret): +class CloudFlare(object): + def __init__(self, domain, name, key, mail): self.__domain = domain self.__name = name - self.__headers = "sso-key {0}:{1}".format(key, secret) + self.__zone = self._get_zone() + self.__headers = {"X-Auth-Email": mail, + "X-Auth-Key": key, + "Content-Type": "application/json"} + self.__id = self._get_identifier() - def get_godaddy_latest_ip(self): + def _get_zone(self): + try: + import ujson as json + except ImportError: + import json + from urllib.request import Request, urlopen + + from ..values import cloudflare_base_url + + url_extra_attrs = "zones?name={0}&status=active&page=1&per_page=1&match=all".format(self.__name) + request = Request(cloudflare_base_url.format(url_extra_attrs), headers=self.__headers) + result = json.loads(urlopen(request).read().decode("utf8")) + if not result["success"]: + raise ValueError("CloudFlare returned error code with the request data - more info: " + result["errors"][0]) + + return result["result"][0]["id"] + + def _get_identifier(self): + try: + import ujson as json + except ImportError: + import json from urllib.request import Request, urlopen - from re import search - request = Request("https://api.godaddy.com/v1/domains/{0}/records/A/{1}".format(self.__domain, self.__name)) - request.add_header("Authorization", self.__headers) - result = urlopen(request).read().decode('utf8') + from ..values import cloudflare_base_url + + url_extra_attrs = "zones/{0}/dns_records?type=A&name={1}&page=1&per_page=1".format(self.__zone, self.__name) + request = Request(cloudflare_base_url.format(url_extra_attrs), headers=self.__headers) + result = json.loads(urlopen(request).read().decode("utf8")) + if not result["success"]: + raise ValueError("CloudFlare returned error code with the request data - more info: " + result["errors"][0]) - ip = search("([0-9]{1,3}\.){3}[0-9]{1,3}", result) - return ip.group(0) if ip else "0.0.0.0" + return result["result"][0]["id"] - def set_goddady_ip(self, ip): + def get_cloudflare_latest_ip(self): + try: + import ujson as json + except ImportError: + import json from urllib.request import Request, urlopen + from ..values import cloudflare_base_url + + url_extra_attrs = "zones/{0}/dns_records/{1}".format(self.__zone, self.__id) + request = Request(cloudflare_base_url.format(url_extra_attrs), headers=self.__headers) + result = json.loads(urlopen(request).read().decode("utf8")) + + return result["result"]["content"] + + def set_cloudflare_ip(self, ip): try: from ujson import dumps except ImportError: from json import dumps + from urllib.request import Request, urlopen + from ..values import cloudflare_base_url - data = dumps([{"data": ip, "ttl": 600, "name": self.__name, "type": "A"}]) - request = Request(url="https://api.godaddy.com/v1/domains/{0}/records/A/{1}".format(self.__domain, self.__name), + data = dumps({"type": "A", "name": self.__name, "content": ip, "ttl": 600, "proxied": False}) + url_extra_attrs = "zones/{0}/dns_records/{1}".format(self.__zone, self.__id) + request = Request(url=cloudflare_base_url.format(url_extra_attrs), data=data.encode("utf-8"), - headers={"Authorization": self.__headers, "Content-Type": "application/json"}, + headers=self.__headers, method="PUT") return urlopen(request).getcode() diff --git a/pyCloudFlareUpdater/values/__init__.py b/pyCloudFlareUpdater/values/__init__.py index 9519628..eba6f5f 100644 --- a/pyCloudFlareUpdater/values/__init__.py +++ b/pyCloudFlareUpdater/values/__init__.py @@ -13,4 +13,5 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from ..values.constants import cloudflare_base_url from ..values.constants import description diff --git a/pyCloudFlareUpdater/values/constants.py b/pyCloudFlareUpdater/values/constants.py index 60e708a..bf8215c 100644 --- a/pyCloudFlareUpdater/values/constants.py +++ b/pyCloudFlareUpdater/values/constants.py @@ -16,3 +16,4 @@ description = """pyCloudFlareUpdater\n\n The first time this application is executed, all params must be included in order to save the user preferences and do this process automatically.""" +cloudflare_base_url = """"https://api.cloudflare.com/client/v4/{0}""" From 28eba11f3d74aa9a59360cbd7c8b357416294743 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 19:13:00 +0200 Subject: [PATCH 03/11] Updated preferences and main method --- pyCloudFlareUpdater/__main__.py | 38 +++++++++++-------- pyCloudFlareUpdater/network/network_utils.py | 2 +- .../preferences/user_preferences.py | 23 ++++++----- 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/pyCloudFlareUpdater/__main__.py b/pyCloudFlareUpdater/__main__.py index 05360ac..4dc0bca 100644 --- a/pyCloudFlareUpdater/__main__.py +++ b/pyCloudFlareUpdater/__main__.py @@ -33,16 +33,19 @@ def main(): - loop_continuation = True log = LoggingHandler(logs=[getLogger("appLogger")]) - net = CloudFlare(preferences.get_domain(), preferences.get_name(), preferences.get_key(), preferences.get_secret()) + loop_continuation = True try: + net = CloudFlare(domain=preferences.get_domain(), + name=preferences.get_name(), + key=preferences.get_key(), + mail=preferences.get_mail()) while loop_continuation: current_ip = get_machine_public_ip() log.info("Current machine IP: \"{0}\"".format(current_ip)) if preferences.get_latest_ip() == "0.0.0.0": preferences.set_latest_ip(net.get_cloudflare_latest_ip()) - log.warning("User saved latest IP is not up to date - downloading GoDaddy A Record value: \"{0}\"" + log.warning("User saved latest IP is not up to date - downloading CloudFlare A Record value: \"{0}\"" .format(preferences.get_latest_ip())) if preferences.get_latest_ip() != current_ip: log.info("IP needs an upgrade - OLD IP: {0} | NEW IP: {1}" @@ -63,8 +66,11 @@ def main(): sleep(preferences.get_time()) except KeyboardInterrupt: log.warning("Received SIGINT - exiting...") + except Exception as e: + log.exception("Daemon raised an exception! - " + str(e), exc_info=True) + finally: preferences.save_preferences() - exit(1) + exit(0) def parser(): @@ -74,11 +80,11 @@ def parser(): args.add_argument("--domain", type=str, required=is_first_execution, - help="GoDaddy domain to be updated.") + help="CloudFlare domain to be updated.") args.add_argument("--name", type=str, required=is_first_execution, - help="GoDaddy 'A' Record name.") + help="CloudFlare 'A' Record name.") args.add_argument("--time", type=int, default=SUPPRESS, @@ -87,11 +93,11 @@ def parser(): args.add_argument("--key", type=str, required=is_first_execution, - help="GoDaddy developer key.") - args.add_argument("--secret", + help="CloudFlare API key.") + args.add_argument("--mail", type=str, required=is_first_execution, - help="GoDaddy developer secret.") + help="CloudFlare sign-in mail.") args.add_argument("--no_daemonize", action="store_true", required=False, @@ -112,7 +118,7 @@ def parser(): help="Specifies a custom LOG file for storing current daemon logs.") args.add_argument("--preferences", type=str, - default="user.preferences", + default="cloudflare.user.preferences", required=False, metavar="PREFERENCES FILE", help="Provide a custom preferences file - useful for multiple running daemon for different 'A'" @@ -146,8 +152,8 @@ def parser(): if p_args.key: preferences.set_key(p_args.key) should_save_preferences = True - if p_args.secret: - preferences.set_secret(p_args.secret) + if p_args.mail: + preferences.set_mail(p_args.mail) should_save_preferences = True if p_args.no_daemonize: preferences.run_as_daemon(not p_args.no_daemonize) @@ -156,18 +162,18 @@ def parser(): should_save_preferences = True else: if preferences.get_pid_file() is None: - preferences.set_pid_file("/var/run/pygoddady.pid") + preferences.set_pid_file("/var/run/cloudflare.pid") if "log" in p_args: preferences.set_log_file(p_args.log) should_save_preferences = True else: if preferences.get_log_file() is None: - preferences.set_log_file("/var/log/pygoddady.log") + preferences.set_log_file("/var/log/cloudflare.log") user = p_args.user group = p_args.group if preferences: - if not (p_args.domain and p_args.name and p_args.key and p_args.secret): + if not (p_args.domain and p_args.name and p_args.key and p_args.mail): print("You must provide the required params for a new preferences file") if should_save_preferences: preferences.save_preferences(p_args.preferences) @@ -179,7 +185,7 @@ def parser(): if not path.exists(pid_dir): makedirs(path=pid_dir, exist_ok=True) - daemon = Daemonize(app="pyGoDaddyDaemon", + daemon = Daemonize(app="pyCloudFlareDaemon", pid=preferences.get_pid_file(), action=main, keep_fds=fds, diff --git a/pyCloudFlareUpdater/network/network_utils.py b/pyCloudFlareUpdater/network/network_utils.py index 7fabc43..f6013f0 100644 --- a/pyCloudFlareUpdater/network/network_utils.py +++ b/pyCloudFlareUpdater/network/network_utils.py @@ -25,10 +25,10 @@ class CloudFlare(object): def __init__(self, domain, name, key, mail): self.__domain = domain self.__name = name - self.__zone = self._get_zone() self.__headers = {"X-Auth-Email": mail, "X-Auth-Key": key, "Content-Type": "application/json"} + self.__zone = self._get_zone() self.__id = self._get_identifier() def _get_zone(self): diff --git a/pyCloudFlareUpdater/preferences/user_preferences.py b/pyCloudFlareUpdater/preferences/user_preferences.py index b026da8..e47e0f9 100644 --- a/pyCloudFlareUpdater/preferences/user_preferences.py +++ b/pyCloudFlareUpdater/preferences/user_preferences.py @@ -23,7 +23,7 @@ def __init__(self, **kwargs): self.__name = kwargs["name"] self.__time = kwargs["time"] self.__key = kwargs["key"] - self.__secret = kwargs["secret"] + self.__mail = kwargs["mail"] self.__pid = kwargs["pid"] self.__log = kwargs["log"] except KeyError: @@ -32,14 +32,13 @@ def __init__(self, **kwargs): " - Domain\n" " - Name (of A Record)\n" " - Time (update time)\n" - " - Key\n" - " - Secret\n") + " - Key\n") else: self.__domain = None self.__name = None self.__time = None self.__key = None - self.__secret = None + self.__mail = None self.__pid = None self.__log = None self.__latest_ip = "0.0.0.0" @@ -49,7 +48,7 @@ def __init__(self, **kwargs): def get_preferences_file(): import os - return os.path.dirname(os.path.abspath(__file__)) + "/user.preferences" + return os.path.dirname(os.path.abspath(__file__)) + "/cloudflare.user.preferences" def load_preferences(self): import pickle @@ -61,9 +60,9 @@ def load_preferences(self): with open("user.preferences", "rb") as fpreferences: preferences = pickle.load(fpreferences) self.__domain = preferences["domain"] - self.__secret = b64decode(preferences["secret"]).decode("utf-8") self.__time = preferences["time"] self.__key = b64decode(preferences["key"]).decode("utf-8") + self.__mail = b64decode(preferences["mail"]).decode("utf-8") self.__name = preferences["name"] self.__latest_ip = preferences["latest_ip"] self.__pid = preferences["pid"] @@ -82,7 +81,7 @@ def save_preferences(self, filename="user.preferences"): "name": self.__name, "time": self.__time, "key": b64encode(bytes(self.__key, "utf-8")), - "secret": b64encode(bytes(self.__secret, "utf-8")), + "mail": b64encode(bytes(self.__mail, "utf-8")), "latest_ip": self.__latest_ip, "pid": self.__pid, "log": self.__log} @@ -104,8 +103,8 @@ def get_time(self): def get_key(self): return self.__key - def get_secret(self): - return self.__secret + def get_mail(self): + return self.__mail def get_latest_ip(self): return self.__latest_ip @@ -131,8 +130,8 @@ def set_time(self, time): def set_key(self, key): self.__key = key - def set_secret(self, secret): - self.__secret = secret + def set_mail(self, mail): + self.__mail = mail def set_latest_ip(self, ip): self.__latest_ip = ip @@ -150,4 +149,4 @@ def run_as_daemon(self, daemonize: bool): def are_preferences_stored(): import os - return os.path.exists("user.preferences") + return os.path.exists("cloudflare.user.preferences") From 7d6d292416cf8d56a38e42ad2ee7487dfa9764bb Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 19:22:28 +0200 Subject: [PATCH 04/11] Updated preferences and main method --- pyCloudFlareUpdater/preferences/user_preferences.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyCloudFlareUpdater/preferences/user_preferences.py b/pyCloudFlareUpdater/preferences/user_preferences.py index e47e0f9..be9d684 100644 --- a/pyCloudFlareUpdater/preferences/user_preferences.py +++ b/pyCloudFlareUpdater/preferences/user_preferences.py @@ -56,8 +56,8 @@ def load_preferences(self): from base64 import b64decode - if os.path.exists("user.preferences"): - with open("user.preferences", "rb") as fpreferences: + if os.path.exists("cloudflare.user.preferences"): + with open("cloudflare.user.preferences", "rb") as fpreferences: preferences = pickle.load(fpreferences) self.__domain = preferences["domain"] self.__time = preferences["time"] @@ -70,7 +70,7 @@ def load_preferences(self): else: raise FileNotFoundError("There are no saved user preferences. Call \"save_preferences\" the first time") - def save_preferences(self, filename="user.preferences"): + def save_preferences(self, filename="cloudflare.user.preferences"): import pickle from base64 import b64encode From b1d5f0b2a8b1be4932e1d9e05bd537cb872c3c5d Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 19:25:30 +0200 Subject: [PATCH 05/11] Updated preferences and main method --- pyCloudFlareUpdater/__main__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pyCloudFlareUpdater/__main__.py b/pyCloudFlareUpdater/__main__.py index 4dc0bca..1ba3653 100644 --- a/pyCloudFlareUpdater/__main__.py +++ b/pyCloudFlareUpdater/__main__.py @@ -33,7 +33,7 @@ def main(): - log = LoggingHandler(logs=[getLogger("appLogger")]) + log = LoggingHandler(logs=[getLogger("cloudflareLogger")]) loop_continuation = True try: net = CloudFlare(domain=preferences.get_domain(), @@ -67,6 +67,7 @@ def main(): except KeyboardInterrupt: log.warning("Received SIGINT - exiting...") except Exception as e: + log.error("Exception registered! - " + str(e)) log.exception("Daemon raised an exception! - " + str(e), exc_info=True) finally: preferences.save_preferences() @@ -179,7 +180,7 @@ def parser(): preferences.save_preferences(p_args.preferences) if not is_first_execution: preferences.load_preferences() - file_handler = setup_logging("appLogger", preferences.get_log_file()) + file_handler = setup_logging("cloudflareLogger", preferences.get_log_file()) fds = [file_handler.stream.fileno()] pid_dir = path.dirname(path.abspath(preferences.get_pid_file())) if not path.exists(pid_dir): @@ -191,7 +192,7 @@ def parser(): keep_fds=fds, user=user, group=group, - logger=getLogger("appLogger")) + logger=getLogger("cloudflareLogger")) daemon.start() From 7c2ac9807f63e44283ac08167e93f3bc99796d5b Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 19:28:48 +0200 Subject: [PATCH 06/11] Traceback for exceptions --- pyCloudFlareUpdater/__main__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyCloudFlareUpdater/__main__.py b/pyCloudFlareUpdater/__main__.py index 1ba3653..470e1de 100644 --- a/pyCloudFlareUpdater/__main__.py +++ b/pyCloudFlareUpdater/__main__.py @@ -13,6 +13,7 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import traceback from argparse import ArgumentParser from argparse import SUPPRESS from logging import getLogger @@ -68,7 +69,7 @@ def main(): log.warning("Received SIGINT - exiting...") except Exception as e: log.error("Exception registered! - " + str(e)) - log.exception("Daemon raised an exception! - " + str(e), exc_info=True) + log.exception("Stacktrace: " + traceback.format_exc()) finally: preferences.save_preferences() exit(0) From cd7de044c9dfc3a9d040e6f7c8e6e5e80ddd0952 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 19:32:07 +0200 Subject: [PATCH 07/11] URL correction --- pyCloudFlareUpdater/__main__.py | 2 +- pyCloudFlareUpdater/values/constants.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyCloudFlareUpdater/__main__.py b/pyCloudFlareUpdater/__main__.py index 470e1de..4f10a0a 100644 --- a/pyCloudFlareUpdater/__main__.py +++ b/pyCloudFlareUpdater/__main__.py @@ -69,7 +69,7 @@ def main(): log.warning("Received SIGINT - exiting...") except Exception as e: log.error("Exception registered! - " + str(e)) - log.exception("Stacktrace: " + traceback.format_exc()) + log.error("Stacktrace: " + traceback.format_exc()) finally: preferences.save_preferences() exit(0) diff --git a/pyCloudFlareUpdater/values/constants.py b/pyCloudFlareUpdater/values/constants.py index bf8215c..2788b73 100644 --- a/pyCloudFlareUpdater/values/constants.py +++ b/pyCloudFlareUpdater/values/constants.py @@ -16,4 +16,4 @@ description = """pyCloudFlareUpdater\n\n The first time this application is executed, all params must be included in order to save the user preferences and do this process automatically.""" -cloudflare_base_url = """"https://api.cloudflare.com/client/v4/{0}""" +cloudflare_base_url = "https://api.cloudflare.com/client/v4/{0}" From dc1d4cba8b797d8ead9c19a1d736dfb3ebc93c71 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 19:45:21 +0200 Subject: [PATCH 08/11] Included option for customizing whether the 'A' record is behind (or not) CloudFlare proxy --- .idea/dictionaries/Javinator9889.xml | 1 + pyCloudFlareUpdater/__main__.py | 14 ++++++++++++-- pyCloudFlareUpdater/network/network_utils.py | 5 +++-- .../preferences/user_preferences.py | 10 ++++++++++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/.idea/dictionaries/Javinator9889.xml b/.idea/dictionaries/Javinator9889.xml index e7a307b..66b09e2 100644 --- a/.idea/dictionaries/Javinator9889.xml +++ b/.idea/dictionaries/Javinator9889.xml @@ -7,6 +7,7 @@ fpreferences javinator levelname + proxied \ No newline at end of file diff --git a/pyCloudFlareUpdater/__main__.py b/pyCloudFlareUpdater/__main__.py index 4f10a0a..d82e0c3 100644 --- a/pyCloudFlareUpdater/__main__.py +++ b/pyCloudFlareUpdater/__main__.py @@ -40,7 +40,8 @@ def main(): net = CloudFlare(domain=preferences.get_domain(), name=preferences.get_name(), key=preferences.get_key(), - mail=preferences.get_mail()) + mail=preferences.get_mail(), + proxied=preferences.is_record_behind_proxy()) while loop_continuation: current_ip = get_machine_public_ip() log.info("Current machine IP: \"{0}\"".format(current_ip)) @@ -100,6 +101,12 @@ def parser(): type=str, required=is_first_execution, help="CloudFlare sign-in mail.") + args.add_argument("--proxied", + action="store_true", + required=is_first_execution, + default=False, + help="Set this value if you want your 'A' Record to be behind the Cloudflare proxy " + "(disabled by default).") args.add_argument("--no_daemonize", action="store_true", required=False, @@ -174,13 +181,16 @@ def parser(): user = p_args.user group = p_args.group - if preferences: + if p_args.preferences: if not (p_args.domain and p_args.name and p_args.key and p_args.mail): print("You must provide the required params for a new preferences file") if should_save_preferences: preferences.save_preferences(p_args.preferences) if not is_first_execution: preferences.load_preferences() + if preferences.is_record_behind_proxy() != p_args.proxied: + preferences.record_behind_proxy(p_args.proxied) + preferences.save_preferences() file_handler = setup_logging("cloudflareLogger", preferences.get_log_file()) fds = [file_handler.stream.fileno()] pid_dir = path.dirname(path.abspath(preferences.get_pid_file())) diff --git a/pyCloudFlareUpdater/network/network_utils.py b/pyCloudFlareUpdater/network/network_utils.py index f6013f0..b997aa2 100644 --- a/pyCloudFlareUpdater/network/network_utils.py +++ b/pyCloudFlareUpdater/network/network_utils.py @@ -22,12 +22,13 @@ def get_machine_public_ip(): class CloudFlare(object): - def __init__(self, domain, name, key, mail): + def __init__(self, domain, name, key, mail, proxied): self.__domain = domain self.__name = name self.__headers = {"X-Auth-Email": mail, "X-Auth-Key": key, "Content-Type": "application/json"} + self.__proxied = proxied self.__zone = self._get_zone() self.__id = self._get_identifier() @@ -87,7 +88,7 @@ def set_cloudflare_ip(self, ip): from urllib.request import Request, urlopen from ..values import cloudflare_base_url - data = dumps({"type": "A", "name": self.__name, "content": ip, "ttl": 600, "proxied": False}) + data = dumps({"type": "A", "name": self.__name, "content": ip, "ttl": 600, "proxied": self.__proxied}) url_extra_attrs = "zones/{0}/dns_records/{1}".format(self.__zone, self.__id) request = Request(url=cloudflare_base_url.format(url_extra_attrs), data=data.encode("utf-8"), diff --git a/pyCloudFlareUpdater/preferences/user_preferences.py b/pyCloudFlareUpdater/preferences/user_preferences.py index be9d684..9854883 100644 --- a/pyCloudFlareUpdater/preferences/user_preferences.py +++ b/pyCloudFlareUpdater/preferences/user_preferences.py @@ -24,6 +24,7 @@ def __init__(self, **kwargs): self.__time = kwargs["time"] self.__key = kwargs["key"] self.__mail = kwargs["mail"] + self.__proxy = kwargs["proxy"] self.__pid = kwargs["pid"] self.__log = kwargs["log"] except KeyError: @@ -42,6 +43,7 @@ def __init__(self, **kwargs): self.__pid = None self.__log = None self.__latest_ip = "0.0.0.0" + self.__proxy = True self.__daemonize = True @staticmethod @@ -64,6 +66,7 @@ def load_preferences(self): self.__key = b64decode(preferences["key"]).decode("utf-8") self.__mail = b64decode(preferences["mail"]).decode("utf-8") self.__name = preferences["name"] + self.__proxy = preferences["proxy"] self.__latest_ip = preferences["latest_ip"] self.__pid = preferences["pid"] self.__log = preferences["log"] @@ -82,6 +85,7 @@ def save_preferences(self, filename="cloudflare.user.preferences"): "time": self.__time, "key": b64encode(bytes(self.__key, "utf-8")), "mail": b64encode(bytes(self.__mail, "utf-8")), + "proxy": self.__proxy, "latest_ip": self.__latest_ip, "pid": self.__pid, "log": self.__log} @@ -106,6 +110,9 @@ def get_key(self): def get_mail(self): return self.__mail + def is_record_behind_proxy(self): + return self.__proxy + def get_latest_ip(self): return self.__latest_ip @@ -142,6 +149,9 @@ def set_pid_file(self, pid): def set_log_file(self, log): self.__log = log + def record_behind_proxy(self, behind_proxy: bool): + self.__proxy = behind_proxy + def run_as_daemon(self, daemonize: bool): self.__daemonize = daemonize From e3bed2af482991971b434cb08bb744181fe527de Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 20:10:48 +0200 Subject: [PATCH 09/11] Updated README and setup files --- README.md | 45 +++++++++++++++++++------------- api_keys.png | Bin 0 -> 8434 bytes cloud.png | Bin 0 -> 567 bytes pyCloudFlareUpdater/__main__.py | 2 +- setup.py | 12 ++++----- 5 files changed, 34 insertions(+), 25 deletions(-) create mode 100644 api_keys.png create mode 100644 cloud.png diff --git a/README.md b/README.md index f80298d..599e379 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # GoDaddy 'A' Record Updater -*DDNS Service for updating dynamically your GoDaddy 'A' Records when your public IP changes* +*DDNS Service for updating dynamically your CloudFlare 'A' Records when your public IP changes* -[![PyPi](https://img.shields.io/badge/v1.1%20-PyPi-green.svg)](https://pypi.org/project/pyGoDaddyUpdater/) -[![ZIP](https://img.shields.io/badge/Package%20-Zip-green.svg)](https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater/repository/master/archive.zip) -[![GIT](https://img.shields.io/badge/Package%20-Git-green.svg)](https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater.git) +[![PyPi](https://img.shields.io/badge/v1.0%20-PyPi-green.svg)](https://pypi.org/project/pyGoDaddyUpdater/) +[![ZIP](https://img.shields.io/badge/Package%20-Zip-green.svg)](https://gitlab.javinator9889.com/ddns-clients/pyCloudFlareUpdater/repository/master/archive.zip) +[![GIT](https://img.shields.io/badge/Package%20-Git-green.svg)](https://gitlab.javinator9889.com/ddns-clients/pyCloudFlareUpdater.git) [![Downloads](https://pepy.tech/badge/pygodaddyupdater)](https://pepy.tech/project/pygodaddyupdater) ## Index @@ -18,7 +18,11 @@ ### Purpose -If you are a *GoDaddy* user (you have your own domain, CNAMES, etc.) maybe you have noticed that there is no **Dynamic +As a continuation of the [recently created pyGoDaddyUpdater](https://gitlab.javinator9889.com/ddns-clients/pyGoDaddyAUpdater), +here you have *CloudFlare Updater*. This group aims to create *DDNS* OpenSource clients that are available for every +user/sysadmin with the most common DNS providers. + +If you are a *CloudFlare* user (you have your own domain, CNAMES, etc.) maybe you have noticed that there is no **Dynamic DNS** (*DDNS*) update service, so you have to manually put your **public IP** at your domain 'A' Record whenever it changes. @@ -39,7 +43,7 @@ There are two possibilities for installing this script: Start by *cloning* this repository. For that, you will need to have [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) installed. Then, run on Git Bash: ```text - git clone https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater.git + git clone https://gitlab.javinator9889.com/ddns-clients/pyCloudFlareUpdater.git ``` There is another possibility so you can *directly download* a compressed file with all the necessary data. Just unzip @@ -56,25 +60,26 @@ There are two possibilities for installing this script: I assume you have [**pip** installed](https://www.makeuseof.com/tag/install-pip-for-python/), so for using this package: ```text - sudo pip install pyGoDaddyUpdater + sudo pip install pyCloudFlareUpdater # If you have any error saying that at least Python 3 is needed # try with the following one: - sudo pip3 install pyGoDaddyUpdater + sudo pip3 install pyCloudFlareUpdater ``` ### Usage -First of all, you need to create a [**GoDaddy Developer Account**](https://developer.godaddy.com/getstarted), -and obtaining your *key* and *secret*. The pair you need to create are the **Production** ones, which are hosted at -https://api.godaddy.com (https://api.ote-godaddy.com is not supported). +First of all, go to your *Cloudflare user account* options, and find the section (usually at the bottom of the page) +that says **API Keys**. + +Obtain the *Global API Key* and save it on a safe location, we will use it later. -You can obtain the necessary data here: https://developer.godaddy.com/keys (use the name you want). +![API Keys](api_keys.png) --------- Once you have installed the script, the execution is simple (from your command line): ```text -$ godaddy_ddns [OPTIONS] +$ cloudflare_ddns [OPTIONS] ``` The available options are: @@ -87,17 +92,20 @@ The available options are: + `--time TIME`: change the *update check interval* time (in minutes). By default, it is 5 minutes. - + `--key KEY`: the *GoDaddy Developer key* you obtained as explained before. + + `--key KEY`: the *Cloudflare key* you obtained as explained before. + + + `--mail MAIL`: the *Cloudflare mail* you use to login into your account. - + `--secret SECRET`: the *GoDaddy Developer secret* you obtained as explained before. + + `--proxied`: use this option for making all the requests to your website **access first** Cloudflare servers (the + same as enabling this option ![Cloudflare proxy](cloud.png)). + `--no_daemonize`: include this option for running this script **only once**. + `--pid PID FILE`: define your own PID file, in which the running daemon PID will be saved. By default, it is: - `/var/run/pygoddady.pid`. + `/var/run/cloudflare.pid`. + `--log LOG FILE`: define your own LOG file, in which the running daemon logs will be saved. By default, it is: - `/var/log/pygoddady.log`. + `/var/log/cloudflare.log`. + `--preferences PREFERENCES FILE`: if you are planning to dynamically update **more than one** domain at the same time, you can define a custom preferences file (if not, each time you run the daemon it will be overwritten). @@ -112,7 +120,8 @@ The first time you execute this script (or for defining a new preferences file), + Domain. + Name. + Key. - + Secret. + + Mail. + + Proxied. Then, each time you execute the script with no *extra arguments* or *providing the preferences file* you will not need to include the options mentioned above. diff --git a/api_keys.png b/api_keys.png new file mode 100644 index 0000000000000000000000000000000000000000..6a138bac538e40b361296cee950c3295f6c3a464 GIT binary patch literal 8434 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 literal 0 HcmV?d00001 diff --git a/pyCloudFlareUpdater/__main__.py b/pyCloudFlareUpdater/__main__.py index d82e0c3..6597f1b 100644 --- a/pyCloudFlareUpdater/__main__.py +++ b/pyCloudFlareUpdater/__main__.py @@ -91,7 +91,7 @@ def parser(): args.add_argument("--time", type=int, default=SUPPRESS, - required=is_first_execution, + required=False, help="Time (in minutes) to check for updated IP (defaults: 5 min.) - must be higher than 0.") args.add_argument("--key", type=str, diff --git a/setup.py b/setup.py index a074bdf..9fd726a 100644 --- a/setup.py +++ b/setup.py @@ -12,24 +12,24 @@ setup( name='pyCloudFlareUpdater', - version='1.1', + version='1.0', packages=['pyCloudFlareUpdater', 'pyCloudFlareUpdater.values', 'pyCloudFlareUpdater.network', 'pyCloudFlareUpdater.preferences', 'pyCloudFlareUpdater.logging_utils'], - url='https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater', - license='GPL-3.0', + url='https://gitlab.javinator9889.com/ddns-clients/pyCloudFlareUpdater', + license='GPLv3', author='Javinator9889', author_email='javialonso007@hotmail.es', - description='DDNS service for dynamically update GoDaddy A Records', + description='DDNS service for dynamically update CloudFlare \'A\' Records', long_description=long_description, long_description_content_type='text/markdown', include_package_data=False, zip_safe=True, - download_url="https://gitlab.javinator9889.com/Javinator9889/pyCloudFlareUpdater/repository/master/archive.zip", + download_url="https://gitlab.javinator9889.com/ddns-clients/pyCloudFlareUpdater/repository/master/archive.zip", entry_points={ - 'console_scripts': ['godaddy_ddns=pyCloudFlareUpdater.__main__:parser'] + 'console_scripts': ['cloudflare_ddns=pyCloudFlareUpdater.__main__:parser'] }, install_requires=['daemonize'], classifiers=[ From b78f0ce09a3a2857b1c13f9179d148512b5314c5 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 20:12:05 +0200 Subject: [PATCH 10/11] README correction --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 599e379..123aede 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# GoDaddy 'A' Record Updater +# CloudFlare 'A' Record Updater *DDNS Service for updating dynamically your CloudFlare 'A' Records when your public IP changes* From 94121f1410408ba5edc7c7c01df57fda980a6423 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Sun, 31 Mar 2019 20:13:52 +0200 Subject: [PATCH 11/11] README correction --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 123aede..8e98af7 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ *DDNS Service for updating dynamically your CloudFlare 'A' Records when your public IP changes* -[![PyPi](https://img.shields.io/badge/v1.0%20-PyPi-green.svg)](https://pypi.org/project/pyGoDaddyUpdater/) +[![PyPi](https://img.shields.io/badge/v1.0%20-PyPi-green.svg)](https://pypi.org/project/pyCloudFlareUpdater/) [![ZIP](https://img.shields.io/badge/Package%20-Zip-green.svg)](https://gitlab.javinator9889.com/ddns-clients/pyCloudFlareUpdater/repository/master/archive.zip) [![GIT](https://img.shields.io/badge/Package%20-Git-green.svg)](https://gitlab.javinator9889.com/ddns-clients/pyCloudFlareUpdater.git) -[![Downloads](https://pepy.tech/badge/pygodaddyupdater)](https://pepy.tech/project/pygodaddyupdater) +[![Downloads](https://pepy.tech/badge/pycloudflareupdater)](https://pepy.tech/project/pycloudflareupdater) ## Index @@ -87,8 +87,7 @@ The available options are: + `--domain DOMAIN`: specifies **which domain** will be updated. That is, if your site is hosted at www.example.com, then your domain is *example.com*. - + `--name NAME`: here the 'A' Record name must be included. In most cases, this name usually is `@` (the name pointing to - the host). + + `--name NAME`: here the 'A' Record name must be included. In most cases, this name usually matches the domain. + `--time TIME`: change the *update check interval* time (in minutes). By default, it is 5 minutes.