From c7f6f20c9d4ae05a5ce366d8f3f62cd3eb1b1710 Mon Sep 17 00:00:00 2001 From: Scruel Tao Date: Thu, 20 Jul 2023 02:48:29 +0800 Subject: [PATCH 1/5] Add SYNO_USE_TEMP_ADMIN variable & Fix broken logic 1. Fix the broken logic in (Sorry for including fix commit in same PR, I'm feeling quite tired and would like to go to sleep right away...) 2. Provides new method to obtain credential info for authentication, it will create a temp admin user if SYNO_USE_TEMP_ADMIN is set, instead of requiring the user's own credentials which will be saved in disk. I do really don't like to have plaintext credentials be saved in disk, and I noticed that you've spent a lot of time fighting with 2FA related stuffs, so why not just get rid of the whole old way. :) --- deploy/synology_dsm.sh | 89 +++++++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/deploy/synology_dsm.sh b/deploy/synology_dsm.sh index 7398b350..d7dd1890 100644 --- a/deploy/synology_dsm.sh +++ b/deploy/synology_dsm.sh @@ -9,8 +9,11 @@ # Issues: https://github.com/acmesh-official/acme.sh/issues/2727 ################################################################################ # Usage: -# 1. export SYNO_Username="adminUser" -# 2. export SYNO_Password="adminPassword" +# - Create temp admin user automatically: +# export SYNO_USE_TEMP_ADMIN=1 +# - Or provide your own admin user credential: +# 1. export SYNO_Username="adminUser" +# 2. export SYNO_Password="adminPassword" # Optional exports (shown values are the defaults): # - export SYNO_Certificate="" to replace a specific certificate via description # - export SYNO_Scheme="http" @@ -22,6 +25,7 @@ ################################################################################ # Dependencies: # - jq & curl +# - synouser & synogroup (When available and SYNO_USE_TEMP_ADMIN is set) ################################################################################ # Return value: # 0 means success, otherwise error. @@ -38,6 +42,7 @@ synology_dsm_deploy() { _debug _cdomain "$_cdomain" # Get username & password, but don't save until we authenticated successfully + _getdeployconf SYNO_USE_TEMP_ADMIN _getdeployconf SYNO_Username _getdeployconf SYNO_Password _getdeployconf SYNO_Create @@ -45,12 +50,25 @@ synology_dsm_deploy() { _getdeployconf SYNO_TOTP_SECRET _getdeployconf SYNO_Device_Name _getdeployconf SYNO_Device_ID - if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then - _err "SYNO_Username & SYNO_Password must be set" - return 1 + + # Prepare temp admin user info if SYNO_USE_TEMP_ADMIN is set + if [ -n "${SYNO_USE_TEMP_ADMIN:-}" ]; then + if ! _exists synouser; then + if ! _exists synogroup; then + _err "Tools are missing for creating temp admin user, please set SYNO_Username & SYNO_Password instead." + return 1 + fi + fi + _debug "Setting temp admin user credential..." + SYNO_Username=sc-acmesh-tmp + SYNO_Password=`openssl rand -base64 16` + # Ignore 2FA-OTP settings which won't be needed. + SYNO_Device_Name= + SYNO_Device_ID= fi - if [ -n "${SYNO_Device_Name:-}" ] && [ -z "${SYNO_Device_ID:-}" ]; then - _err "SYNO_Device_Name set, but SYNO_Device_ID is empty" + + if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then + _err "You must set either SYNO_USE_TEMP_ADMIN, or set both SYNO_Username and SYNO_Password." return 1 fi _debug2 SYNO_Username "$SYNO_Username" @@ -69,6 +87,7 @@ synology_dsm_deploy() { [ -n "${SYNO_Scheme}" ] || SYNO_Scheme="http" [ -n "${SYNO_Hostname}" ] || SYNO_Hostname="localhost" [ -n "${SYNO_Port}" ] || SYNO_Port="5000" + _savedeployconf SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN" _savedeployconf SYNO_Scheme "$SYNO_Scheme" _savedeployconf SYNO_Hostname "$SYNO_Hostname" _savedeployconf SYNO_Port "$SYNO_Port" @@ -106,13 +125,11 @@ synology_dsm_deploy() { _info "WARNING: Usage of SYNO_TOTP_SECRET is deprecated!" _info " See synology_dsm.sh script or ACME.sh Wiki page for details:" _info " https://github.com/acmesh-official/acme.sh/wiki/Synology-NAS-Guide" - DEPRECATED_otp_code="" - if _exists oathtool; then - DEPRECATED_otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)" - else + if ! _exists oathtool; then _err "oathtool could not be found, install oathtool to use SYNO_TOTP_SECRET" return 1 fi + DEPRECATED_otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)" if [ -n "$SYNO_DID" ]; then _H1="Cookie: did=$SYNO_DID" @@ -123,21 +140,30 @@ synology_dsm_deploy() { response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$DEPRECATED_otp_code&device_name=certrenewal&device_id=$SYNO_DID" "$_base_url/webapi/auth.cgi?enable_syno_token=yes") _debug3 response "$response" # END - DEPRECATED, only kept for legacy compatibility reasons + # If SYNO_DeviceDevice_ID & SYNO_Device_Name both empty, just log in normally + elif [ -z "${SYNO_Device_ID:-}" ] && [ -z "${SYNO_Device_Name:-}" ]; then + if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then + _debug "Creating temp admin user in Synology DSM" + synouser --del "$SYNO_Username" >/dev/null 2>/dev/null + synouser --add "$SYNO_Username" "$SYNO_Password" "" 0 "" 0 >/dev/null + synogroup --memberadd administrators "$SYNO_Username" >/dev/null + fi + response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes") + _debug3 response "$response" # Get device ID if still empty first, otherwise log in right away - elif [ -z "${SYNO_Device_ID:-}" ]; then + elif [ -n "${SYNO_Device_Name:-}" ] && [ -z "${SYNO_Device_ID:-}" ]; then printf "Enter OTP code for user '%s': " "$SYNO_Username" read -r otp_code - if [ -z "${SYNO_Device_Name:-}" ]; then - printf "Enter device name or leave empty for default (CertRenewal): " - read -r SYNO_Device_Name - [ -n "${SYNO_Device_Name}" ] || SYNO_Device_Name="CertRenewal" - fi - response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&otp_code=$otp_code&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_Device_Name") _debug3 response "$response" SYNO_Device_ID=$(echo "$response" | grep "device_id" | sed -n 's/.*"device_id" *: *"\([^"]*\).*/\1/p') _secure_debug2 SYNO_Device_ID "$SYNO_Device_ID" else + if [ -z "${SYNO_Device_Name:-}" ]; then + printf "Enter device name or leave empty for default (CertRenewal): " + read -r SYNO_Device_Name + [ -n "${SYNO_Device_Name}" ] || SYNO_Device_Name="CertRenewal" + fi response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_Device_Name&device_id=$SYNO_Device_ID") _debug3 response "$response" fi @@ -146,9 +172,12 @@ synology_dsm_deploy() { token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p') _debug "Session ID" "$sid" _debug SynoToken "$token" - if [ -z "$SYNO_DID" ] && [ -z "$SYNO_Device_ID" ] || [ -z "$sid" ] || [ -z "$token" ]; then + if [ -z "$sid" ] || [ -z "$token" ]; then _err "Unable to authenticate to $_base_url - check your username & password." - _err "If two-factor authentication is enabled for the user, set SYNO_Device_ID." + _err "If two-factor authentication is enabled for the user:" + _err "- set SYNO_Device_Name then input *correct* OTP-code manually" + _err "- get & set SYNO_Device_ID via your browser cookies" + _remove_temp_admin "$SYNO_USE_TEMP_ADMIN" "$SYNO_Username" return 1 fi @@ -159,8 +188,10 @@ synology_dsm_deploy() { # Now that we know the username & password are good, save them _savedeployconf SYNO_Username "$SYNO_Username" _savedeployconf SYNO_Password "$SYNO_Password" - _savedeployconf SYNO_Device_Name "$SYNO_Device_Name" - _savedeployconf SYNO_Device_ID "$SYNO_Device_ID" + if [ -z "${SYNO_USE_TEMP_ADMIN:-}" ]; then + _savedeployconf SYNO_Device_Name "$SYNO_Device_Name" + _savedeployconf SYNO_Device_ID "$SYNO_Device_ID" + fi _info "Getting certificates in Synology DSM" response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid=$sid" "$_base_url/webapi/entry.cgi") @@ -172,6 +203,7 @@ synology_dsm_deploy() { if [ -z "$id" ] && [ -z "${SYNO_Create:-}" ]; then _err "Unable to find certificate: $SYNO_Certificate & \$SYNO_Create is not set" + _remove_temp_admin "$SYNO_USE_TEMP_ADMIN" "$SYNO_Username" return 1 fi @@ -206,10 +238,11 @@ synology_dsm_deploy() { else _info "Restarting HTTP services failed" fi - + _remove_temp_admin "$SYNO_USE_TEMP_ADMIN" "$SYNO_Username" _logout return 0 else + _remove_temp_admin "$SYNO_USE_TEMP_ADMIN" "$SYNO_Username" _err "Unable to update certificate, error code $response" _logout return 1 @@ -222,3 +255,13 @@ _logout() { response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=logout") _debug3 response "$response" } + +_remove_temp_admin() { + flag=$1 + username=$2 + + if [ -n "${flag}" ]; then + _debug "Removing temp admin user in Synology DSM" + synouser --del "$username" >/dev/null + fi +} From 9e958f4e32794db65fa7fd938df2bcc27f7faaff Mon Sep 17 00:00:00 2001 From: Scruel Tao Date: Thu, 20 Jul 2023 13:09:21 +0800 Subject: [PATCH 2/5] Fix shellcheck --- deploy/synology_dsm.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/synology_dsm.sh b/deploy/synology_dsm.sh index d7dd1890..22e485ce 100644 --- a/deploy/synology_dsm.sh +++ b/deploy/synology_dsm.sh @@ -61,7 +61,7 @@ synology_dsm_deploy() { fi _debug "Setting temp admin user credential..." SYNO_Username=sc-acmesh-tmp - SYNO_Password=`openssl rand -base64 16` + SYNO_Password=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16) # Ignore 2FA-OTP settings which won't be needed. SYNO_Device_Name= SYNO_Device_ID= From cf86d57a9f61e9e2d759c8a44811c3ea6cb612c6 Mon Sep 17 00:00:00 2001 From: Scruel Tao Date: Thu, 20 Jul 2023 13:34:57 +0800 Subject: [PATCH 3/5] Fix for shfmt check --- deploy/synology_dsm.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/deploy/synology_dsm.sh b/deploy/synology_dsm.sh index 22e485ce..b69916c7 100644 --- a/deploy/synology_dsm.sh +++ b/deploy/synology_dsm.sh @@ -66,7 +66,7 @@ synology_dsm_deploy() { SYNO_Device_Name= SYNO_Device_ID= fi - + if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then _err "You must set either SYNO_USE_TEMP_ADMIN, or set both SYNO_Username and SYNO_Password." return 1 @@ -104,8 +104,7 @@ synology_dsm_deploy() { _err "Do not use a backslash (\) in your certificate description" return 1 fi - - _base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port" + _base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port" _debug _base_url "$_base_url" _debug "Getting API version" @@ -259,7 +258,7 @@ _logout() { _remove_temp_admin() { flag=$1 username=$2 - + if [ -n "${flag}" ]; then _debug "Removing temp admin user in Synology DSM" synouser --del "$username" >/dev/null From ba468bb5e4156c6b914b8653abb2af9d4b2006b4 Mon Sep 17 00:00:00 2001 From: Scruel Tao Date: Thu, 20 Jul 2023 13:38:36 +0800 Subject: [PATCH 4/5] Fix for shfmt check --- deploy/synology_dsm.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deploy/synology_dsm.sh b/deploy/synology_dsm.sh index b69916c7..8dc99a85 100644 --- a/deploy/synology_dsm.sh +++ b/deploy/synology_dsm.sh @@ -104,7 +104,8 @@ synology_dsm_deploy() { _err "Do not use a backslash (\) in your certificate description" return 1 fi - _base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port" + + _base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port" _debug _base_url "$_base_url" _debug "Getting API version" From 29b2960805ac850a564e5ec6521720a3511a1771 Mon Sep 17 00:00:00 2001 From: Scruel Tao Date: Thu, 7 Sep 2023 15:01:37 +0800 Subject: [PATCH 5/5] Optimze comment & remove tail space --- deploy/synology_dsm.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/synology_dsm.sh b/deploy/synology_dsm.sh index 15f961e2..455d9de4 100644 --- a/deploy/synology_dsm.sh +++ b/deploy/synology_dsm.sh @@ -19,7 +19,7 @@ # - export SYNO_Scheme="http" # - export SYNO_Hostname="localhost" # - export SYNO_Port="5000" -# - export SYNO_Create=1 to allow creating the certificate if it doesn't exist +# - export SYNO_Create=1 - to allow creating the certificate if it doesn't exist # - export SYNO_Device_Name="CertRenewal" - required if 2FA-OTP enabled # - export SYNO_Device_ID="" - required for skipping 2FA-OTP # 3. acme.sh --deploy --deploy-hook synology_dsm -d example.com @@ -191,7 +191,7 @@ synology_dsm_deploy() { _H1="X-SYNO-TOKEN: $token" export _H1 - _debug2 H1 "${_H1}" + _debug2 H1 "${_H1}" # Now that we know the username & password are good, save them _savedeployconf SYNO_Username "$SYNO_Username"