diff --git a/AppImage/ProxMenux-1.2.2.3-beta.AppImage b/AppImage/ProxMenux-1.2.2.3-beta.AppImage index fcd8c730..5c65e76d 100755 Binary files a/AppImage/ProxMenux-1.2.2.3-beta.AppImage and b/AppImage/ProxMenux-1.2.2.3-beta.AppImage differ diff --git a/AppImage/ProxMenux-Monitor.AppImage.sha256 b/AppImage/ProxMenux-Monitor.AppImage.sha256 index 5f95262d..51d03748 100644 --- a/AppImage/ProxMenux-Monitor.AppImage.sha256 +++ b/AppImage/ProxMenux-Monitor.AppImage.sha256 @@ -1 +1 @@ -df4fe78ec4e77e333adf069528d9df274db16810bbcb110bfc86a5b8a0dc5a42 ProxMenux-1.2.2.3-beta.AppImage +7b7cb13e8f2d4044626663d8187018908705e480e81f510ee46f6df7918fef84 ProxMenux-1.2.2.3-beta.AppImage diff --git a/AppImage/scripts/flask_server.py b/AppImage/scripts/flask_server.py index 357a26a9..23c8ce51 100644 --- a/AppImage/scripts/flask_server.py +++ b/AppImage/scripts/flask_server.py @@ -15419,25 +15419,42 @@ def api_host_backups_job_update(job_id): import socket pbs_backup_id = f'hostcfg-{socket.gethostname()}' pbs_fingerprint = (payload.get('pbs_fingerprint') or existing.get('PBS_FINGERPRINT') or '').strip() - # Encryption: payload `pbs_encrypt` is the new state. When the - # operator toggles it ON we persist the keyfile path; OFF - # simply omits PBS_KEYFILE from the rewritten .env. We never - # delete the host-wide keyfile here — other jobs may depend on - # it. The `pbs_encrypt` key is required to be passed - # explicitly on edit so an absent field is treated as "keep - # the current state". - if 'pbs_encrypt' in payload: - pbs_encrypt = bool(payload.get('pbs_encrypt')) - else: - pbs_encrypt = bool(existing.get('PBS_KEYFILE')) + # Encryption: matches job-create + manual-run. The Web sends + # `pbs_encrypt_mode` ("none" / "new" / "existing"); older + # clients may still send the legacy `pbs_encrypt` bool. + # Absent field on edit means "keep the current state" — so + # a partial payload doesn't accidentally turn encryption off. + # Before this fix the endpoint only looked at `pbs_encrypt` + # and defaulted to `bool(existing PBS_KEYFILE)` when absent, + # which meant unchecking the box in the Edit dialog was a + # no-op because the new UI sends `pbs_encrypt_mode` instead. + pbs_encrypt_mode = (payload.get('pbs_encrypt_mode') or '').strip().lower() + if not pbs_encrypt_mode: + if 'pbs_encrypt' in payload: + pbs_encrypt_mode = 'new' if bool(payload.get('pbs_encrypt')) else 'none' + else: + pbs_encrypt_mode = 'existing' if existing.get('PBS_KEYFILE') else 'none' + if pbs_encrypt_mode not in ('none', 'new', 'existing'): + return jsonify({'error': "pbs_encrypt_mode must be 'none', 'new' or 'existing'"}), 400 lines.append(f'PBS_REPOSITORY={pbs_repo}') lines.append(f'PBS_PASSWORD={pbs_pass}') lines.append(f'PBS_BACKUP_ID={pbs_backup_id}') - if pbs_encrypt: + if pbs_encrypt_mode == 'new': kf = _pbs_keyfile_get_or_create(True) if not kf: return jsonify({'error': 'failed to create PBS encryption keyfile'}), 500 lines.append(f'PBS_KEYFILE={kf}') + elif pbs_encrypt_mode == 'existing': + if not os.path.isfile(_PBS_KEYFILE_PATH): + return jsonify({ + 'error': ( + "pbs_encrypt_mode='existing' but no keyfile is installed at " + f"{_PBS_KEYFILE_PATH} — import one first with " + "POST /api/host-backups/pbs-encryption/import" + ), + }), 400 + lines.append(f'PBS_KEYFILE={_PBS_KEYFILE_PATH}') + # else 'none' → no PBS_KEYFILE line written → job runs unencrypted if pbs_fingerprint: lines.append(f'PBS_FINGERPRINT={pbs_fingerprint}') elif backend == 'local': diff --git a/scripts/backup_restore/backup_scheduler.sh b/scripts/backup_restore/backup_scheduler.sh index f7abb946..dd458795 100755 --- a/scripts/backup_restore/backup_scheduler.sh +++ b/scripts/backup_restore/backup_scheduler.sh @@ -422,11 +422,22 @@ _create_job() { --inputbox "$(translate "Backup ID for this job:")" \ "$HB_UI_INPUT_H" "$HB_UI_INPUT_W" "$bid" 3>&1 1>&2 2>&3) || return 1 bid=$(echo "$bid" | tr -cs '[:alnum:]_-' '-' | sed 's/-*$//') + # PBS_KEYFILE: `hb_ask_pbs_encryption` sets HB_PBS_KEYFILE_OPT + # to the FULL CLI flag string ("--keyfile /path") when + # encryption is accepted, and leaves it empty otherwise. The + # previous read of `HB_PBS_KEYFILE` was picking up an unset + # variable and always wrote an empty PBS_KEYFILE — so the + # Monitor Web (which detects encryption from a non-empty + # PBS_KEYFILE line) surfaced every CLI-created encrypted job + # as unencrypted. Derive the canonical path from + # HB_PBS_KEYFILE_OPT presence instead. + local pbs_kf_val="" + [[ -n "${HB_PBS_KEYFILE_OPT:-}" ]] && pbs_kf_val="$HB_STATE_DIR/pbs-key.conf" lines+=( "PBS_REPOSITORY=${HB_PBS_REPOSITORY}" "PBS_PASSWORD=${HB_PBS_SECRET}" "PBS_BACKUP_ID=${bid}" - "PBS_KEYFILE=${HB_PBS_KEYFILE:-}" + "PBS_KEYFILE=${pbs_kf_val}" "PBS_ENCRYPTION_PASSWORD=${HB_PBS_ENC_PASS:-}" ) ;;