dyndns: be able to unsubscribe using the key + domain and i18n string consistency

This commit is contained in:
Alexandre Aubin 2023-04-11 19:40:30 +02:00
parent e2da51b9a3
commit cbef40798c
3 changed files with 47 additions and 32 deletions

View file

@ -91,7 +91,8 @@
"ask_new_path": "New path", "ask_new_path": "New path",
"ask_password": "Password", "ask_password": "Password",
"ask_dyndns_recovery_password_explain": "Please pick a recovery password for your DynDNS domain, in case you need to reset it later.", "ask_dyndns_recovery_password_explain": "Please pick a recovery password for your DynDNS domain, in case you need to reset it later.",
"ask_dyndns_recovery_password": "DynDNS recovey passwory", "ask_dyndns_recovery_password": "DynDNS recovery password",
"ask_dyndns_recovery_password_explain_during_unsubscribe": "Please enter the recovery password for this DynDNS domain.",
"ask_user_domain": "Domain to use for the user's email address and XMPP account", "ask_user_domain": "Domain to use for the user's email address and XMPP account",
"backup_abstract_method": "This backup method has yet to be implemented", "backup_abstract_method": "This backup method has yet to be implemented",
"backup_actually_backuping": "Creating a backup archive from the collected files...", "backup_actually_backuping": "Creating a backup archive from the collected files...",
@ -404,12 +405,12 @@
"dyndns_no_recovery_password": "No recovery password specified! In case you loose control of this domain, you will need to contact an administrator in the YunoHost team!", "dyndns_no_recovery_password": "No recovery password specified! In case you loose control of this domain, you will need to contact an administrator in the YunoHost team!",
"dyndns_added_password": "Remember your recovery password, you can use it to delete this domain record.", "dyndns_added_password": "Remember your recovery password, you can use it to delete this domain record.",
"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_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_subscribed": "DynDNS domain subscribed",
"dyndns_registration_failed": "Could not register DynDNS domain: {error}", "dyndns_subscribe_failed": "Could not subscribe DynDNS domain: {error}",
"dyndns_unregistration_failed": "Could not unregister DynDNS domain: {error}", "dyndns_unsubscribe_failed": "Could not unsubscribe DynDNS domain: {error}",
"dyndns_unregistered": "DynDNS domain successfully unregistered", "dyndns_unsubscribed": "DynDNS domain unsubscribed",
"dyndns_unsubscribe_wrong_password": "Invalid password", "dyndns_unsubscribe_denied": "Failed to unsubscribe domain: invalid credentials",
"dyndns_unsubscribe_wrong_domain": "Domain is not registered", "dyndns_unsubscribe_already_unsubscribed": "Domain is already unsubscribed",
"dyndns_unavailable": "The domain '{domain}' is unavailable.", "dyndns_unavailable": "The domain '{domain}' is unavailable.",
"extracting": "Extracting...", "extracting": "Extracting...",
"field_invalid": "Invalid field '{}'", "field_invalid": "Invalid field '{}'",

View file

@ -663,9 +663,8 @@ domain:
subscribe: subscribe:
action_help: Subscribe to a DynDNS service action_help: Subscribe to a DynDNS service
arguments: arguments:
-d: domain:
full: --domain help: Domain to subscribe to the DynDNS service
help: Full domain to subscribe with
extra: extra:
pattern: *pattern_domain pattern: *pattern_domain
-p: -p:
@ -681,9 +680,8 @@ domain:
unsubscribe: unsubscribe:
action_help: Unsubscribe from a DynDNS service action_help: Unsubscribe from a DynDNS service
arguments: arguments:
-d: domain:
full: --domain help: Domain to unsubscribe from the DynDNS service
help: Full domain to unsubscribe with
extra: extra:
pattern: *pattern_domain pattern: *pattern_domain
required: True required: True

View file

@ -165,14 +165,14 @@ def dyndns_subscribe(operation_logger, domain=None, recovery_password=None):
) )
except Exception as e: except Exception as e:
rm(key_file, force=True) rm(key_file, force=True)
raise YunohostError("dyndns_registration_failed", error=str(e)) raise YunohostError("dyndns_subscribe_failed", error=str(e))
if r.status_code != 201: if r.status_code != 201:
rm(key_file, force=True) rm(key_file, force=True)
try: try:
error = json.loads(r.text)["error"] error = json.loads(r.text)["error"]
except Exception: except Exception:
error = f'Server error, code: {r.status_code}. (Message: "{r.text}")' error = f'Server error, code: {r.status_code}. (Message: "{r.text}")'
raise YunohostError("dyndns_registration_failed", error=error) raise YunohostError("dyndns_subscribe_failed", error=error)
# Yunohost regen conf will add the dyndns cron job if a key exists # Yunohost regen conf will add the dyndns cron job if a key exists
# in /etc/yunohost/dyndns # in /etc/yunohost/dyndns
@ -187,7 +187,7 @@ def dyndns_subscribe(operation_logger, domain=None, recovery_password=None):
subprocess.check_call(["bash", "-c", cmd.format(t="2 min")]) subprocess.check_call(["bash", "-c", cmd.format(t="2 min")])
subprocess.check_call(["bash", "-c", cmd.format(t="4 min")]) subprocess.check_call(["bash", "-c", cmd.format(t="4 min")])
logger.success(m18n.n("dyndns_registered")) logger.success(m18n.n("dyndns_subscribed"))
@is_unit_operation(exclude=["recovery_password"]) @is_unit_operation(exclude=["recovery_password"])
@ -202,23 +202,37 @@ def dyndns_unsubscribe(operation_logger, domain, recovery_password=None):
import requests # lazy loading this module for performance reasons import requests # lazy loading this module for performance reasons
# FIXME : it should be possible to unsubscribe the domain just using the key file ... # Unsubscribe the domain using the key if available
keys = glob.glob(f"/etc/yunohost/dyndns/K{domain}.+*.key")
if keys:
key = keys[0]
with open(key) as f:
key = f.readline().strip().split(" ", 6)[-1]
base64key = base64.b64encode(key.encode()).decode()
credential = {"key": base64key}
else:
# Ensure sufficiently complex password # Ensure sufficiently complex password
if Moulinette.interface.type == "cli" and not recovery_password: if Moulinette.interface.type == "cli" and not recovery_password:
logger.warning(m18n.n("ask_dyndns_recovery_password_explain_during_unsubscribe"))
recovery_password = Moulinette.prompt( recovery_password = Moulinette.prompt(
m18n.n("ask_dyndns_recovery_password"), m18n.n("ask_dyndns_recovery_password"),
is_password=True is_password=True
) )
if not recovery_password:
logger.error(f"Cannot unsubscribe the domain {domain}: no credential provided")
return
secret = str(domain) + ":" + str(recovery_password).strip()
credential = {"recovery_password": hashlib.sha256(secret.encode('utf-8')).hexdigest()}
operation_logger.start() operation_logger.start()
# Send delete request # Send delete request
try: try:
secret = str(domain) + ":" + str(recovery_password).strip()
r = requests.delete( r = requests.delete(
f"https://{DYNDNS_PROVIDER}/domains/{domain}", f"https://{DYNDNS_PROVIDER}/domains/{domain}",
data={"recovery_password": hashlib.sha256(secret.encode('utf-8')).hexdigest()}, data=credential,
timeout=30, timeout=30,
) )
except Exception as e: except Exception as e:
@ -230,12 +244,14 @@ def dyndns_unsubscribe(operation_logger, domain, recovery_password=None):
# Yunohost regen conf will add the dyndns cron job if a key exists # Yunohost regen conf will add the dyndns cron job if a key exists
# in /etc/yunohost/dyndns # in /etc/yunohost/dyndns
regen_conf(["yunohost"]) regen_conf(["yunohost"])
elif r.status_code == 403: # Wrong password elif r.status_code == 403:
raise YunohostError("dyndns_unsubscribe_wrong_password") raise YunohostError("dyndns_unsubscribe_denied")
elif r.status_code == 404: # Invalid domain elif r.status_code == 409:
raise YunohostError("dyndns_unsubscribe_wrong_domain") raise YunohostError("dyndns_unsubscribe_already_unsubscribed")
else:
raise YunohostError("dyndns_unsubscribe_failed", error=f"The server returned code {r.status_code}")
logger.success(m18n.n("dyndns_unregistered")) logger.success(m18n.n("dyndns_unsubscribed"))
def dyndns_list(): def dyndns_list():