#!/bin/bash #------------------------------------------------------------------------------ # SET THESE THREE VARIABLES to match your system that you wish to test against. #------------------------------------------------------------------------------ username="myUserName" password="myPassWord" webApiRootUrl="http://192.168.0.88:5000/webapi" #------------------------------------------------------------------------------ # Global variables #------------------------------------------------------------------------------ programname="DSM Authentication Test" cookieFileName="wgetcookies.txt" #------------------------------------------------------------------------------ # Function: Log message to console and, if this script is running on a # Synology NAS, also log to the Synology system log. # # Parameters: $1 - "info" - Log to console stderr and Synology log as info. # "err" - Log to console stderr and Synology log as error. # "dbg" - Log to console stderr, do not log to Synology. # # $2 - The string to log. Synology will always add a period to it. # # Global Variable used: $programname - Prefix all log messages with this. # # NOTE: I'm logging to the STDERR channel (>&2) as a work-around to a problem # where there doesn't appear to be a Bash-compatible way to combine console # logging *and* capturing STDOUT from a function call. Because if I log to # STDOUT, then if I call LogMessage from within any of my functions which # return values to the caller, then the log message output becomes the return # data, and messes everything up. TO DO: Learn the correct way of doing both at # the same time in Bash. #------------------------------------------------------------------------------ LogMessage() { # GitHub issue #85 - Correctly interpret multiline strings when logging. I had # a situation where there was an error in an API, and the error details were # embedded in the JSON response that was returned to the API. However the # JSON response was in "pretty" mode, and so it had nice linefeeds and # indents to go along with the curly braces. When I tried to log that JSON # response, since the bash function call to LogMessage interprets each line # as a separate parameter, only the first of the line of the message (in this # case, parameter $2) was printed to the log. Fix this by re-interpreting all # parameters from $2 on up as the message string. This uses a special bash # parameter expansion command to interpret all of the parameters from 2->n. # Excellent explanation here: https://stackoverflow.com/a/3816747/3621748 logOutputString="${@:2}" # Convenience feature: Logging to the Synology log will always add a trailing # period to the end of the log message. The Synology message template # 0x11800000 that I'm using literally has a period built into it. So before # logging, strip out a trailing period (if any) from the text message, to # prevent double-periods in the log. For a long time, I was just trying to # remember not to add periods at the ends of my log messages, and I would # occasionally forget, and the double period would appear. So strip that # here, and add it back below if it's needed. The technique that I'm using # is to use the Parameter Expansion feature of Bash, and use the special # operator "%" which is meant for trimming characters from the end of an # expansion. In this case, "%." means "Strip the period from the end." logOutputString="${logOutputString%.}" # Log message to shell console. This command has the following features: # - Echo to STDERR on purpose (>&2) so that, if you are logging inside # a Bash "function", the function doesn't accidentally return your # log message as the return value for that function. # - Echo with the "-e" parameter, so that linefeeds are preserved when # echoing to the shell console. This makes output more readable when # you are debugging things like prettified JSON or XML at the console. # - Add a period at the end of the output on purpose, to mimic the # appearance of the Synology log entry, which adds its own period. echo -e "$programname - $logOutputString." >&2 # Only log to synology if the log level is not "dbg" if ! [ "$1" = dbg ] then # Only log to Synology system log if we are running on a Synology NAS # with the correct logging command available. Test for the command # by using "command" to locate the command, and "if -x" to determine # if the file is present and executable. if [ -x "$(command -v synologset1)" ] then # GitHub issue #85 - Ensure that all newlines have been removed from the # string before sending it to the Synology log, so that all of the # message is visible (Synology prints only the first line of multi-line # logs). Note that this command must use the "-e" feature to ensure that # the translate (tr) command will correctly get all of the string, # newlines and all, so that it can strip those newlines. synologyLogOutputString=$(echo -e "$logOutputString" | tr -d '\n') # Special command on Synology to write to its main log file. This uses # an existing log entry in the Synology log message table which allows # us to insert any message we want. The message in the Synology table # already has a period appended to it, so we don't add a period here. synologset1 sys $1 0x11800000 "$programname - $synologyLogOutputString" fi fi } #------------------------------------------------------------------------------ # Function: Web API Auth. Performs a Synology API login and saves the cookie. # # Params: None - uses global variables for the credentials. # Returns: Nothing. If it fails to authenticate, it will exit the script. #------------------------------------------------------------------------------ WebApiAuth() { # Set up strings cookieParametersAuth="--keep-session-cookies --save-cookies $cookieFileName --timeout=10" # Determine if we are running on DSM version 6 or DSM version 7 based on the # API call differences. Start with the variable set to 0 to indicate "unknown". # Only change this variable if one of the tests gets a successful result. dsmVersion="0" # Query for DSM 6.x - This succeeds on DSM 6.x, and I'm not certain if it will # work on 7.x or not. However the 7.x test will be run whether this fails or # not. So the function will prioritize the last test which got a successful # result, even if both get a successful result. LogMessage "dbg" "Querying $webApiRootUrl to see if it is DSM 6.x" versionResult="" versionWebCall="query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth" versionResult=$( wget -qO- "$webApiRootUrl/$versionWebCall" ) LogMessage "dbg" "Version Response: $versionResult" if [[ $versionResult == *"\"success\":true"* ]] then dsmVersion="6" LogMessage "dbg" "DSM version appears to be $dsmVersion - Result: $versionResult" else LogMessage "dbg" "Query did not succeed - Result: $versionResult" fi # Query for DSM 7.x - This fails if running on DSM 6.x, but is supposed to work # on 7.x, according to the documentation. LogMessage "dbg" "Querying $webApiRootUrl to see if it is DSM 7.x" versionResult="" versionWebCall="entry.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth" versionResult=$( wget -qO- "$webApiRootUrl/$versionWebCall" ) if [[ $versionResult == *"\"success\":true"* ]] then dsmVersion="7" LogMessage "dbg" "DSM version appears to be $dsmVersion - Result: $versionResult" else LogMessage "dbg" "Query did not succeed - Result: $versionResult" fi # If neither the version 6 or version 7 queries succeeded, then terminate the program. if [[ $dsmVersion == "0" ]] then LogMessage "err" "Querying $webApiRootUrl for the DSM version did not succeed. Terminating program." # Work-around to problem of being unable to exit the script from within # this function. Send kill signal to mid level PID and then exit # the function to prevent additional commands from being executed. kill -s TERM $WEBAPICALL_PID exit 1 fi # Create string for authenticating with Synology Web API. The possible strings # are mutually exclusive, the v6 string fails on v7, and vice-versa. authWebCall="" LogMessage "dbg" "Attempting to authenticate to DSM version $dsmVersion" if [[ $dsmVersion == "6" ]] then authWebCall="auth.cgi?api=SYNO.API.Auth&version=1&method=login&account=$username&passwd=$password&session=SurveillanceStation&format=cookie" else authWebCall="entry.cgi?api=SYNO.API.Auth&version=3&method=login&account=$username&passwd=$password&session=SurveillanceStation&format=cookie" fi # Debugging output for local machine test runs. Do not use this under normal # circumstances - it prints the password in clear text. # LogMessage "dbg" "Logging into Web API: wget -qO- $cookieParametersAuth \"$webApiRootUrl/$authWebCall\"" # Make the web API call. The expected response from this call will be # {"success":true}. Note: The response is more detailed in version=3 but # still contains the same "success":true string. authResult=$( wget -qO- $cookieParametersAuth "$webApiRootUrl/$authWebCall" ) # Output for debug runs. LogMessage "dbg" "Auth response: $authResult" # Check to make sure our call to the web API succeeded, exit if not. if ! [[ $authResult == *"\"success\":true"* ]] then LogMessage "err" "The call to authenticate with the Synology Web API failed. Exiting program. Response: $authResult" # Work-around to problem of being unable to exit the script from within # this function. Send kill signal to mid level PID and then exit # the function to prevent additional commands from being executed. kill -s TERM $WEBAPICALL_PID exit 1 fi } #------------------------------------------------------------------------------ # MAIN PROGRAM #------------------------------------------------------------------------------ export WEBAPICALL_PID=$BASHPID WebApiAuth