From 4a9080bdfd5057085dc962f733cd6b27c98bdef0 Mon Sep 17 00:00:00 2001 From: "theo@manjaro" Date: Thu, 30 Jun 2022 12:23:51 +0200 Subject: [PATCH] Added a new command to delete dyndns records --- locales/en.json | 5 +++++ share/actionsmap.yml | 17 +++++++++++++++ src/dyndns.py | 50 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/locales/en.json b/locales/en.json index d7179cd7e..0bbd41387 100644 --- a/locales/en.json +++ b/locales/en.json @@ -361,6 +361,10 @@ "dyndns_provider_unreachable": "Unable to reach DynDNS provider {provider}: either your YunoHost is not correctly connected to the internet or the dynette server is down.", "dyndns_registered": "DynDNS domain registered", "dyndns_registration_failed": "Could not register DynDNS domain: {error}", + "dyndns_unregistration_failed": "Could not unregister DynDNS domain: {error}", + "dyndns_unregistered": "Domain successfully deleted!", + "dyndns_unsubscribe_wrong_password": "Invalid password", + "dyndns_unsubscribe_wrong_domain": "Domain is not registered", "dyndns_unavailable": "The domain '{domain}' is unavailable.", "experimental_feature": "Warning: This feature is experimental and not considered stable, you should not use it unless you know what you are doing.", "extracting": "Extracting...", @@ -451,6 +455,7 @@ "log_domain_main_domain": "Make '{}' the main domain", "log_domain_remove": "Remove '{}' domain from system configuration", "log_dyndns_subscribe": "Subscribe to a YunoHost subdomain '{}'", + "log_dyndns_unsubscribe": "Unsubscribe to a YunoHost subdomain '{}'", "log_dyndns_update": "Update the IP associated with your YunoHost subdomain '{}'", "log_help_to_get_failed_log": "The operation '{desc}' could not be completed. Please share the full log of this operation using the command 'yunohost log share {name}' to get help", "log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log show {name}'", diff --git a/share/actionsmap.yml b/share/actionsmap.yml index bf2f53371..f8d082a70 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -1412,6 +1412,23 @@ dyndns: extra: pattern: *pattern_password comment: dyndns_added_password + + ### dyndns_unsubscribe() + unsubscribe: + action_help: Unsubscribe to a DynDNS service + arguments: + -d: + full: --domain + help: Full domain to subscribe with + extra: + pattern: *pattern_domain + required: True + -p: + full: --password + help: Password used to delete the domain + extra: + required: True + pattern: *pattern_password ### dyndns_update() update: diff --git a/src/dyndns.py b/src/dyndns.py index 39e8a7213..67a8b293d 100644 --- a/src/dyndns.py +++ b/src/dyndns.py @@ -178,6 +178,56 @@ def dyndns_subscribe(operation_logger, domain=None, key=None, password=None): logger.success(m18n.n("dyndns_registered")) +@is_unit_operation() +def dyndns_unsubscribe(operation_logger, domain, password): + """ + Unsubscribe from a DynDNS service + + Keyword argument: + domain -- Full domain to unsubscribe with + password -- Password that is used to delete the domain ( defined when subscribing ) + """ + + operation_logger.start() + + # '165' is the convention identifier for hmac-sha512 algorithm + # '1234' is idk? doesnt matter, but the old format contained a number here... + key_file = f"/etc/yunohost/dyndns/K{domain}.+165+1234.key" + + import requests # lazy loading this module for performance reasons + + # Send delete request + try: + r = requests.delete( + f"https://{DYNDNS_PROVIDER}/domains/{domain}", + data={"recovery_password":hashlib.sha256((str(domain)+":"+str(password).strip()).encode('utf-8')).hexdigest()}, + timeout=30, + ) + except Exception as e: + raise YunohostError("dyndns_unregistration_failed", error=str(e)) + + if r.status_code == 200: # Deletion was successful + rm(key_file, force=True) + # Yunohost regen conf will add the dyndns cron job if a key exists + # in /etc/yunohost/dyndns + regen_conf(["yunohost"]) + + # Add some dyndns update in 2 and 4 minutes from now such that user should + # not have to wait 10ish minutes for the conf to propagate + cmd = ( + "at -M now + {t} >/dev/null 2>&1 <<< \"/bin/bash -c 'yunohost dyndns update'\"" + ) + # For some reason subprocess doesn't like the redirections so we have to use bash -c explicity... + subprocess.check_call(["bash", "-c", cmd.format(t="2 min")]) + subprocess.check_call(["bash", "-c", cmd.format(t="4 min")]) + + logger.success(m18n.n("dyndns_unregistered")) + elif r.status_code == 403: # Wrong password + raise YunohostError("dyndns_unsubscribe_wrong_password") + elif r.status_code == 404: # Invalid domain + raise YunohostError("dyndns_unsubscribe_wrong_domain") + + @is_unit_operation() def dyndns_update( operation_logger,