@ -8,24 +8,37 @@
# Updated: 2023-07-03
# Updated: 2023-07-03
# Issues: https://github.com/acmesh-official/acme.sh/issues/2727
# Issues: https://github.com/acmesh-official/acme.sh/issues/2727
################################################################################
################################################################################
# Usage:
# - Create temp admin user automatically:
# Usage (shown values are the examples):
# 1. Set required environment variables:
# - use automatically created temp admin user to authenticate
# export SYNO_USE_TEMP_ADMIN=1
# 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"
# - export SYNO_Hostname="localhost"
# - export SYNO_Port="5000"
# - 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
# - or provide your own admin user credential to authenticate
# 1. export SYNO_USERNAME="adminUser"
# 2. export SYNO_PASSWORD="adminPassword"
# 2. Set optional environment variables
# - common optional variables
# - export SYNO_SCHEME="http" - defaults to "http"
# - export SYNO_HOSTNAME="localhost" - defaults to "localhost"
# - export SYNO_PORT="5000" - defaults to "5000"
# - export SYNO_CREATE=1 - to allow creating the cert if it doesn't exist
# - export SYNO_CERTIFICATE="" - to replace a specific cert by its
# description
# - temp admin optional variables
# - export SYNO_LOCAL_HOSTNAME=1 - if set to 1, force to treat hostname is
# targeting current local machine (since
# this method only locally supported)
# - exsiting admin 2FA-OTP optional variables
# - export SYNO_OTP_CODE="XXXXXX" - if set, script won't require to
# interactive input the OTP code
# - export SYNO_DEVICE_NAME="CertRenewal" - if set, script won't require to
# interactive input the device name
# - export SYNO_DEVICE_ID="" - (deprecated, auth with OTP code instead)
# required for omitting 2FA-OTP
# 3. Run command:
# acme.sh --deploy --deploy-hook synology_dsm -d example.com
################################################################################
################################################################################
# Dependencies:
# Dependencies:
# - jq & curl
# - curl
# - synouser & synogroup (When available and SYNO_USE_TEMP_ADMIN is set)
# - synouser & synogroup (When available and SYNO_USE_TEMP_ADMIN is set)
################################################################################
################################################################################
# Return value:
# Return value:
@ -42,74 +55,85 @@ synology_dsm_deploy() {
_debug _cdomain " $_cdomain "
_debug _cdomain " $_cdomain "
# Get username & password, but don't save until we authenticated successfully
# Get username and password, but don't save until we authenticated successfully
_migratedeployconf SYNO_Username SYNO_USERNAME
_migratedeployconf SYNO_Password SYNO_PASSWORD
_migratedeployconf SYNO_Device_ID SYNO_DEVICE_ID
_migratedeployconf SYNO_Device_Name SYNO_DEVICE_NAME
_getdeployconf SYNO_USERNAME
_getdeployconf SYNO_PASSWORD
_getdeployconf SYNO_DEVICE_ID
_getdeployconf SYNO_DEVICE_NAME
# Prepare to use temp admin if SYNO_USE_TEMP_ADMIN is set
_debug2 SYNO_USE_TEMP_ADMIN " $SYNO_USE_TEMP_ADMIN "
_getdeployconf SYNO_USE_TEMP_ADMIN
_getdeployconf SYNO_USE_TEMP_ADMIN
_getdeployconf SYNO_Username
_getdeployconf SYNO_Password
_getdeployconf SYNO_Create
_getdeployconf SYNO_DID
_getdeployconf SYNO_TOTP_SECRET
_getdeployconf SYNO_Device_Name
_getdeployconf SYNO_Device_ID
# 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."
_check2cleardeployconfexp SYNO_USE_TEMP_ADMIN
_debug2 SYNO_USE_TEMP_ADMIN " $SYNO_USE_TEMP_ADMIN "
if [ -n " $SYNO_USE_TEMP_ADMIN " ] ; then
if ! _exists synouser || ! _exists synogroup; then
_err "Tools are missing for creating temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
return 1
return 1
fi
fi
fi
[ -n " $SYNO_USERNAME " ] || _savedeployconf SYNO_USERNAME ""
[ -n " $SYNO_PASSWORD " ] || _savedeployconf SYNO_PASSWORD ""
_debug "Setting temp admin user credential..."
_debug "Setting temp admin user credential..."
SYNO_Username = sc-acmesh-tmp
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 =
SYNO_USERNAME = sc-acmesh-tmp
SYNO_PASSWORD = $( head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16)
# Set 2FA-OTP settings to empty consider they won't be needed.
SYNO_DEVICE_ID =
SYNO_DEVICE_NAME =
SYNO_OTP_CODE =
else
_debug2 SYNO_USERNAME " $SYNO_USERNAME "
_secure_debug2 SYNO_PASSWORD " $SYNO_PASSWORD "
_debug2 SYNO_DEVICE_NAME " $SYNO_DEVICE_NAME "
_secure_debug2 SYNO_DEVICE_ID " $SYNO_DEVICE_ID "
fi
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."
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
return 1
fi
fi
_debug2 SYNO_Username " $SYNO_Username "
_secure_debug2 SYNO_Password " $SYNO_Password "
_debug2 SYNO_Create " $SYNO_Create "
_debug2 SYNO_Device_Name " $SYNO_Device_Name "
_secure_debug2 SYNO_Device_ID " $SYNO_Device_ID "
# Optional scheme, hostname & port for Synology DSM
_getdeployconf SYNO_Scheme
_getdeployconf SYNO_Hostname
_getdeployconf SYNO_Port
# Default values for scheme, hostname & port
# Defaulting to localhost & http, because it's localhost…
[ -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 "
_debug2 SYNO_Scheme " $SYNO_Scheme "
_debug2 SYNO_Hostname " $SYNO_Hostname "
_debug2 SYNO_Port " $SYNO_Port "
# Optional scheme, hostname and port for Synology DSM
_migratedeployconf SYNO_Scheme SYNO_SCHEME
_migratedeployconf SYNO_Hostname SYNO_HOSTNAME
_migratedeployconf SYNO_Port SYNO_PORT
_getdeployconf SYNO_SCHEME
_getdeployconf SYNO_HOSTNAME
_getdeployconf SYNO_PORT
# Default values for scheme, hostname and port
# Defaulting to localhost and http, because it's localhost…
[ -n " $SYNO_SCHEME " ] || SYNO_SCHEME = "http"
[ -n " $SYNO_HOSTNAME " ] || SYNO_HOSTNAME = "localhost"
[ -n " $SYNO_PORT " ] || SYNO_PORT = "5000"
_savedeployconf SYNO_SCHEME " $SYNO_SCHEME "
_savedeployconf SYNO_HOSTNAME " $SYNO_HOSTNAME "
_savedeployconf SYNO_PORT " $SYNO_PORT "
_debug2 SYNO_SCHEME " $SYNO_SCHEME "
_debug2 SYNO_HOSTNAME " $SYNO_HOSTNAME "
_debug2 SYNO_PORT " $SYNO_PORT "
# Get the certificate description, but don't save it until we verify it's real
# Get the certificate description, but don't save it until we verify it's real
_getdeployconf SYNO_Certificate
_debug SYNO_Certificate " ${ SYNO_Certificate :- } "
_migratedeployconf SYNO_Certificate SYNO_CERTIFICATE "base64"
_getdeployconf SYNO_CERTIFICATE
_check2cleardeployconfexp SYNO_CERTIFICATE
_debug SYNO_CERTIFICATE " ${ SYNO_CERTIFICATE :- } "
# shellcheck disable=SC1003 # We are not trying to escape a single quote
# shellcheck disable=SC1003 # We are not trying to escape a single quote
if printf "%s" " $SYNO_Certificate " | grep '\\' ; then
if printf "%s" " $SYNO_CERTIFICATE " | grep '\\' ; then
_err "Do not use a backslash (\) in your certificate description"
_err "Do not use a backslash (\) in your certificate description"
return 1
return 1
fi
fi
_base_url = " $SYNO_Scheme :// $SYNO_Hostname : $SYNO_Port "
_debug "Getting API version..."
_base_url = " $SYNO_SCHEME :// $SYNO_HOSTNAME : $SYNO_PORT "
_debug _base_url " $_base_url "
_debug _base_url " $_base_url "
_debug "Getting API version"
response = $( _get " $_base_url /webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth " )
response = $( _get " $_base_url /webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth " )
api_path = $( echo " $response " | grep "SYNO.API.Auth" | sed -n 's/.*"path" *: *"\([^"]*\)".*/\1/p' )
api_path = $( echo " $response " | grep "SYNO.API.Auth" | sed -n 's/.*"path" *: *"\([^"]*\)".*/\1/p' )
api_version = $( echo " $response " | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p' )
api_version = $( echo " $response " | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p' )
@ -117,13 +141,14 @@ synology_dsm_deploy() {
_debug3 api_path " $api_path "
_debug3 api_path " $api_path "
_debug3 api_version " $api_version "
_debug3 api_version " $api_version "
# Login, get the session ID & SynoToken from JSON
_info " Logging into $SYNO_Hostname : $SYNO_Port "
encoded_username = " $( printf "%s" " $SYNO_Username " | _url_encode) "
encoded_password = " $( printf "%s" " $SYNO_Password " | _url_encode) "
# Login, get the session ID and SynoToken from JSON
_info " Logging into $SYNO_HOSTNAME : $SYNO_PORT ... "
encoded_username = " $( printf "%s" " $SYNO_USERNAME " | _url_encode) "
encoded_password = " $( printf "%s" " $SYNO_PASSWORD " | _url_encode) "
# ## START ## - DEPRECATED, for backward compatibility
_getdeployconf SYNO_TOTP_SECRET
otp_code = ""
# START - DEPRECATED, only kept for legacy compatibility reasons
if [ -n " $SYNO_TOTP_SECRET " ] ; then
if [ -n " $SYNO_TOTP_SECRET " ] ; then
_info "WARNING: Usage of SYNO_TOTP_SECRET is deprecated!"
_info "WARNING: Usage of SYNO_TOTP_SECRET is deprecated!"
_info " See synology_dsm.sh script or ACME.sh Wiki page for details:"
_info " See synology_dsm.sh script or ACME.sh Wiki page for details:"
@ -132,48 +157,132 @@ synology_dsm_deploy() {
_err "oathtool could not be found, install oathtool to use SYNO_TOTP_SECRET"
_err "oathtool could not be found, install oathtool to use SYNO_TOTP_SECRET"
return 1
return 1
fi
fi
DEPRECATED_otp_code = " $( oathtool --base32 --totp " ${ SYNO_TOTP_SECRET } " 2>/dev/null) "
DEPRECATED_otp_code = " $( oathtool --base32 --totp " $ SYNO_TOTP_SECRET" 2>/dev/null) "
if [ -n " $SYNO_DID " ] ; then
_H1 = " Cookie: did= $SYNO_DID "
if [ -z " $SYNO_DEVICE_ID " ] ; then
_getdeployconf SYNO_DID
[ -n " $SYNO_DID " ] || SYNO_DEVICE_ID = " $SYNO_DID "
fi
if [ -n " $SYNO_DEVICE_ID " ] ; then
_H1 = " Cookie: did= $SYNO_DEVICE_ID "
export _H1
export _H1
_debug3 H1 " ${ _H1 } "
_debug3 H1 " ${ _H1 } "
fi
fi
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 " )
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_DEVICE_ ID " " $_base_url /webapi/auth.cgi?enable_syno_token=yes " )
_debug3 response " $response "
_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
# ## END ## - DEPRECATED, for backward compatibility
# If SYNO_DEVICE_ID or SYNO_OTP_CODE is set, we treat current account enabled 2FA-OTP.
# Notice that if SYNO_USE_TEMP_ADMIN=1, both variables will be unset
else
if [ -n " $SYNO_DEVICE_ID " ] || [ -n " $SYNO_OTP_CODE " ] ; then
response = '{"error":{"code":403}}'
# Assume the current account disabled 2FA-OTP, try to log in right away.
else
if [ -n " $SYNO_USE_TEMP_ADMIN " ] ; 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
_getdeployconf SYNO_LOCAL_HOSTNAME
_debug SYNO_LOCAL_HOSTNAME " ${ SYNO_LOCAL_HOSTNAME :- } "
if [ " $SYNO_LOCAL_HOSTNAME " != "1" ] && [ " $SYNO_LOCAL_HOSTNAME " = = " $SYNO_HOSTNAME " ] ; then
if [ " $SYNO_HOSTNAME " != "localhost" ] && [ " $SYNO_HOSTNAME " != "127.0.0.1" ] ; then
_err " SYNO_USE_TEMP_ADMIN=1 Only support locally deployment, if you are sure that hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun. "
return 1
fi
fi
_debug "Creating temp admin user in Synology DSM..."
if synogroup --help | grep -q '\-\-memberadd ' ; then
_temp_admin_create " $SYNO_USERNAME " " $SYNO_PASSWORD "
synogroup --memberadd administrators " $SYNO_USERNAME " >/dev/null
elif synogroup --help | grep -q '\-\-member ' ; then
# For supporting DSM 6.x which only has `--member` parameter.
cur_admins = $( synogroup --get administrators | awk -F '[][]' '/Group Members/,0{if(NF>1)printf "%s ", $2}' )
if [ -n " $cur_admins " ] ; then
_temp_admin_create " $SYNO_USERNAME " " $SYNO_PASSWORD "
_secure_debug3 admin_users " $cur_admins $SYNO_USERNAME "
# shellcheck disable=SC2086
synogroup --member administrators $cur_admins $SYNO_USERNAME >/dev/null
else
_err "Tool synogroup may be broken, please set SYNO_USERNAME and SYNO_PASSWORD instead."
return 1
fi
else
_err "Unsupported synogroup tool detected, please set SYNO_USERNAME and SYNO_PASSWORD instead."
return 1
fi
# havig a workaround to temporary disable enforce 2FA-OTP
otp_enforce_option = $( synogetkeyvalue /etc/synoinfo.conf otp_enforce_option)
if [ -n " $otp_enforce_option " ] && [ " ${ otp_enforce_option :- "none" } " != "none" ] ; then
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option none
_info "Temporary disabled enforce 2FA-OTP to complete authentication."
_info "previous_otp_enforce_option" " $otp_enforce_option "
else
otp_enforce_option = ""
fi
fi
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 " )
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 " )
if [ -n " $SYNO_USE_TEMP_ADMIN " ] && [ -n " $otp_enforce_option " ] ; then
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option " $otp_enforce_option "
_info "Restored previous enforce 2FA-OTP option."
fi
_debug3 response " $response "
_debug3 response " $response "
# Get device ID if still empty first, otherwise log in right away
# If SYNO_Device_Name is set, we treat that account enabled two-factor authorization, consider SYNO_Device_ID is not set, so it won't be able to login without requiring the OTP code.
elif [ -n " ${ SYNO_Device_Name :- } " ] && [ -z " ${ SYNO_Device_ID :- } " ] ; then
printf "Enter OTP code for user '%s': " " $SYNO_Username "
read -r otp_code
response = $( _get " $_base_url /webapi/ $api_path ?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 " )
fi
fi
error_code = $( echo " $response " | grep '"error"' | grep -oP '(?<="code":)\d+' )
# Account has 2FA-OTP enabled, since error 403 reported.
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Firmware/DSM/All/enu/Synology_DiskStation_Administration_CLI_Guide.pdf
if [ " $error_code " = = "403" ] ; then
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
if [ -n " $SYNO_DEVICE_ID " ] ; then
# Omit OTP code with SYNO_DEVICE_ID.
response = $( _get " $_base_url /webapi/ $api_path ?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 " )
_secure_debug3 response " $response "
else
# Require the OTP code if still unset.
if [ -z " $SYNO_OTP_CODE " ] ; then
printf "Enter OTP code for user '%s': " " $SYNO_USERNAME "
read -r SYNO_OTP_CODE
fi
_secure_debug SYNO_OTP_CODE " ${ SYNO_OTP_CODE :- } "
if [ -z " $SYNO_OTP_CODE " ] ; then
response = '{"error":{"code":404}}'
else
response = $( _get " $_base_url /webapi/ $api_path ?api=SYNO.API.Auth&version= $api_version &method=login&format=sid&account= $encoded_username &passwd= $encoded_password &enable_syno_token=yes&enable_device_token=yes&device_name= $SYNO_DEVICE_NAME &otp_code= $SYNO_OTP_CODE " )
_secure_debug3 response " $response "
_secure_debug3 response " $response "
id_property = 'device_id'
id_property = 'device_id'
[ " ${ api_version } " -gt '6' ] || id_property = 'did'
[ " ${ api_version } " -gt '6' ] || id_property = 'did'
SYNO_Device_ID = $( echo " $response " | grep " $id_property " | sed -n 's/.*"' $id_property '" *: *"\([^"]*\).*/\1/p' )
_secure_debug2 SYNO_Device_ID " $SYNO_Device_ID "
# Otherwise, if SYNO_Device_ID is set, we can just use it to login.
SYNO_DEVICE_ID = $( echo " $response " | grep " $id_property " | sed -n 's/.*"' $id_property '" *: *"\([^"]*\).*/\1/p' )
_secure_debug2 SYNO_DEVICE_ID " $SYNO_DEVICE_ID "
fi
fi
error_code = $( echo " $response " | grep '"error"' | grep -oP '(?<="code":)\d+' )
fi
if [ -n " $error_code " ] ; then
if [ " $error_code " = = "403" ] && [ -n " $SYNO_DEVICE_ID " ] ; then
_cleardeployconf SYNO_DEVICE_ID
_err "Failed to authenticate with SYNO_DEVICE_ID (may expired or invalid), please try again in a new terminal window."
elif [ " $error_code " = = "404" ] ; then
_err "Failed to authenticate with provided 2FA-OTP code, please try again in a new terminal window."
elif [ " $error_code " = = "406" ] ; then
if [ -n " $SYNO_USE_TEMP_ADMIN " ] ; then
_err "SYNO_USE_TEMP_ADMIN=1 is not supported if enforce auth with 2FA-OTP is enabled."
else
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"
_err "Enforce auth with 2FA-OTP enabled, please configure the user to enable 2FA-OTP to continue."
fi
fi
response = $( _get " $_base_url /webapi/ $api_path ?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 " )
_secure_debug3 response " $response "
elif [ " $error_code " = = "400" ] || [ " $error_code " = = "401" ] || [ " $error_code " = = "408" ] || [ " $error_code " = = "409" ] || [ " $error_code " = = "410" ] ; then
_err "Failed to authenticate with a non-existent or disabled account, or the account password is incorrect or has expired."
else
_err " Failed to authenticate with error: $error_code . "
fi
_temp_admin_cleanup " $SYNO_USE_TEMP_ADMIN " " $SYNO_USERNAME "
return 1
fi
fi
sid = $( echo " $response " | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p' )
sid = $( echo " $response " | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p' )
@ -181,11 +290,9 @@ synology_dsm_deploy() {
_debug "Session ID" " $sid "
_debug "Session ID" " $sid "
_debug SynoToken " $token "
_debug SynoToken " $token "
if [ -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:"
_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 "
# Still can't get necessary info even got no errors, may Synology have API updated?
_err " Unable to authenticate to $_base_url , you may report the full log to the community. "
_temp_admin_cleanup " $SYNO_USE_TEMP_ADMIN " " $SYNO_USERNAME "
return 1
return 1
fi
fi
@ -193,39 +300,61 @@ synology_dsm_deploy() {
export _H1
export _H1
_debug2 H1 " ${ _H1 } "
_debug2 H1 " ${ _H1 } "
# Now that we know the username & password are good, save them
_savedeployconf SYNO_Username " $SYNO_Username "
_savedeployconf SYNO_Password " $SYNO_Password "
if [ -z " ${ SYNO_USE_TEMP_ADMIN :- } " ] ; then
_savedeployconf SYNO_Device_Name " $SYNO_Device_Name "
_savedeployconf SYNO_Device_ID " $SYNO_Device_ID "
# Now that we know the username and password are good, save them if not in temp admin mode.
if [ -n " $SYNO_USE_TEMP_ADMIN " ] ; then
_cleardeployconf SYNO_USERNAME
_cleardeployconf SYNO_PASSWORD
_cleardeployconf SYNO_DEVICE_ID
_cleardeployconf SYNO_DEVICE_NAME
_savedeployconf SYNO_USE_TEMP_ADMIN " $SYNO_USE_TEMP_ADMIN "
_savedeployconf SYNO_LOCAL_HOSTNAME " $SYNO_HOSTNAME "
else
_savedeployconf SYNO_USERNAME " $SYNO_USERNAME "
_savedeployconf SYNO_PASSWORD " $SYNO_PASSWORD "
_savedeployconf SYNO_DEVICE_ID " $SYNO_DEVICE_ID "
_savedeployconf SYNO_DEVICE_NAME " $SYNO_DEVICE_NAME "
fi
fi
_info "Getting certificates in Synology DSM"
_info "Getting certificates in Synology DSM... "
response = $( _post " api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid= $sid " " $_base_url /webapi/entry.cgi " )
response = $( _post " api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid= $sid " " $_base_url /webapi/entry.cgi " )
_debug3 response " $response "
_debug3 response " $response "
escaped_certificate = " $( printf "%s" " $SYNO_Certificate " | sed 's/\([].*^$[]\)/\\\1/g;s/"/\\\\"/g' ) "
escaped_certificate = " $( printf "%s" " $SYNO_CERTIFICATE " | sed 's/\([].*^$[]\)/\\\1/g;s/"/\\\\"/g' ) "
_debug escaped_certificate " $escaped_certificate "
_debug escaped_certificate " $escaped_certificate "
id = $( echo " $response " | sed -n " s/.*\"desc\":\" $escaped_certificate \",\"id\":\"\([^\"]*\).*/\1/p " )
id = $( echo " $response " | sed -n " s/.*\"desc\":\" $escaped_certificate \",\"id\":\"\([^\"]*\).*/\1/p " )
_debug2 id " $id "
_debug2 id " $id "
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 "
error_code = $( echo " $response " | grep '"error"' | grep -oP '(?<="code":)\d+' )
if [ -n " $error_code " ] ; then
if [ " $error_code " -eq 105 ] ; then
_err "Current user is not administrator and does not have sufficient permission for deploying."
else
_err " Failed to fetch certificate info with error: $error_code , please try again or contact Synology to learn more. "
fi
_temp_admin_cleanup " $SYNO_USE_TEMP_ADMIN " " $SYNO_USERNAME "
return 1
fi
_migratedeployconf SYNO_Create SYNO_CREATE
_getdeployconf SYNO_CREATE
_debug2 SYNO_CREATE " $SYNO_CREATE "
if [ -z " $id " ] && [ -z " $SYNO_CREATE " ] ; then
_err " Unable to find certificate: $SYNO_CERTIFICATE and $SYNO_CREATE is not set. "
_temp_admin_cleanup " $SYNO_USE_TEMP_ADMIN " " $SYNO_USERNAME "
return 1
return 1
fi
fi
# We've verified this certificate description is a thing, so save it
# We've verified this certificate description is a thing, so save it
_savedeployconf SYNO_Certificate " $SYNO_Certificate " "base64"
_savedeployconf SYNO_CERTIFICATE " $SYNO_CERTIFICATE " "base64"
_info "Generate form POST request"
_info "Generating form POST request... "
nl = "\0015\0012"
nl = "\0015\0012"
delim = " -------------------------- $( _utc_date | tr -d -- '-: ' ) "
delim = " -------------------------- $( _utc_date | tr -d -- '-: ' ) "
content = " -- $delim ${ nl } Content-Disposition: form-data; name=\"key\"; filename=\" $( basename " $_ckey " ) \" ${ nl } Content-Type: application/octet-stream ${ nl } ${ nl } $( cat " $_ckey " ) \0012 "
content = " -- $delim ${ nl } Content-Disposition: form-data; name=\"key\"; filename=\" $( basename " $_ckey " ) \" ${ nl } Content-Type: application/octet-stream ${ nl } ${ nl } $( cat " $_ckey " ) \0012 "
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"cert\"; filename=\" $( basename " $_ccert " ) \" ${ nl } Content-Type: application/octet-stream ${ nl } ${ nl } $( cat " $_ccert " ) \0012 "
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"cert\"; filename=\" $( basename " $_ccert " ) \" ${ nl } Content-Type: application/octet-stream ${ nl } ${ nl } $( cat " $_ccert " ) \0012 "
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"inter_cert\"; filename=\" $( basename " $_cca " ) \" ${ nl } Content-Type: application/octet-stream ${ nl } ${ nl } $( cat " $_cca " ) \0012 "
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"inter_cert\"; filename=\" $( basename " $_cca " ) \" ${ nl } Content-Type: application/octet-stream ${ nl } ${ nl } $( cat " $_cca " ) \0012 "
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"id\" ${ nl } ${ nl } $id "
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"id\" ${ nl } ${ nl } $id "
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"desc\" ${ nl } ${ nl } ${ SYNO_Certificate } "
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"desc\" ${ nl } ${ nl } ${ SYNO_CERTIFICATE } "
if echo " $response " | sed -n " s/.*\"desc\":\" $escaped_certificate \",\([^{]*\).*/\1/p " | grep -- 'is_default":true' >/dev/null; then
if echo " $response " | sed -n " s/.*\"desc\":\" $escaped_certificate \",\([^{]*\).*/\1/p " | grep -- 'is_default":true' >/dev/null; then
_debug2 default "This is the default certificate"
_debug2 default "This is the default certificate"
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"as_default\" ${ nl } ${ nl } true "
content = " $content ${ nl } -- $delim ${ nl } Content-Disposition: form-data; name=\"as_default\" ${ nl } ${ nl } true "
@ -236,22 +365,22 @@ synology_dsm_deploy() {
content = " $( printf "%b_" " $content " ) "
content = " $( printf "%b_" " $content " ) "
content = " ${ content %_ } " # protect trailing \n
content = " ${ content %_ } " # protect trailing \n
_info "Upload certificate to the Synology DSM"
_info "Upload certificate to the Synology DSM. "
response = $( _post " $content " " $_base_url /webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken= $token &_sid= $sid " "" "POST" " multipart/form-data; boundary= ${ delim } " )
response = $( _post " $content " " $_base_url /webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken= $token &_sid= $sid " "" "POST" " multipart/form-data; boundary= ${ delim } " )
_debug3 response " $response "
_debug3 response " $response "
if ! echo " $response " | grep '"error":' >/dev/null; then
if ! echo " $response " | grep '"error":' >/dev/null; then
if echo " $response " | grep '"restart_httpd":true' >/dev/null; then
if echo " $response " | grep '"restart_httpd":true' >/dev/null; then
_info "Restarting HTTP services succeeded"
_info "Restart HTTP services succeeded. "
else
else
_info "Restarting HTTP services failed"
_info "Restart HTTP services failed. "
fi
fi
_remove_ temp_admin " $SYNO_USE_TEMP_ADMIN " " $SYNO_Username "
_temp_admin_cleanup " $SYNO_USE_TEMP_ADMIN " " $SYNO_USERNAME "
_logout
_logout
return 0
return 0
else
else
_remove_ temp_admin " $SYNO_USE_TEMP_ADMIN " " $SYNO_Username "
_err " Unable to update certificate, error code $response "
_temp_admin_cleanup " $SYNO_USE_TEMP_ADMIN " " $SYNO_USERNAME "
_err " Unable to update certificate, got error response: $response . "
_logout
_logout
return 1
return 1
fi
fi
@ -264,12 +393,39 @@ _logout() {
_debug3 response " $response "
_debug3 response " $response "
}
}
_remove_temp_admin( ) {
flag = $1
username = $2
_temp_admin_create( ) {
_username = " $1 "
_password = " $2 "
synouser --del " $_username " >/dev/null 2>/dev/null
synouser --add " $_username " " $_password " "" 0 "scruelt@hotmail.com" 0 >/dev/null
}
_temp_admin_cleanup( ) {
_flag = $1
_username = $2
if [ -n " ${ _flag } " ] ; then
_debug "Cleanuping temp admin info..."
synouser --del " $_username " >/dev/null
fi
}
#_cleardeployconf key
_cleardeployconf( ) {
_cleardomainconf " SAVED_ $1 "
}
if [ -n " ${ flag } " ] ; then
_debug "Removing temp admin user in Synology DSM"
synouser --del " $username " >/dev/null
# key
_check2cleardeployconfexp( ) {
_key = " $1 "
_clear_key = " CLEAR_ $_key "
# Clear saved settings if explicitly requested
if [ -n " $( eval echo \$ " $_clear_key " ) " ] ; then
_debug2 " $_key : value cleared from config, exported value will be ignored. "
_cleardeployconf " $_key "
eval " $_key " =
export " $_key " =
eval SAVED_" $_key " =
export SAVED_" $_key " =
fi
fi
}
}