Switch to using only tokens for plexupdate.sh (#169)

* Extract token fetching to extras/get-plex-token
* Have installer store TOKEN instead of EMAIL/PASS
* Provide easy way to pass git owner/branch while testing
* Use path when sourcing get-web-token
* Don't force interactive mode for EMAIL/PASS if they're already stored
* Re-enable getting plex token from server
* Try to read server token as sudo if possible
* Specify branch to clone in installer.sh
* Better checking of where token came from
* Make VERBOSE useful again
* Fix getPlexServerToken if installer.sh is being run from wget
* Extract functions into plexupdate-core
* Use plexupdate-core in installer
* Clean up usage and add --help
* Deprecate FORCEALL
* Make CHECKUPDATE check all program files
* Verify plex.tv is providing a checksum before downloading
* Add some more logging for release handling
* Use info/warn/error in plexupdate-core
* Remove outdated instructions from plexupdate.sh
* Only store tokens if PMS token is unavailable
* Warn users if fetching Plex token fails in installer
* Use local vars in functions and fix getRemoteSHA
* Update README
* Deprecate EMAIL/PASS and add token command-line option
* Quote option names
* Update FAQs
* Add link to FAQ in deprecation notice
* Remove trailing whitespace
* Make cron return 0 when plexupdate returns 10
This commit is contained in:
Alex Malinovich 2017-03-06 21:22:37 -08:00 committed by Henric Andersson
commit 37f75bcd32
5 changed files with 351 additions and 416 deletions

View file

@ -6,17 +6,6 @@
# Server for Linux. It supports both the public versions
# as well as the PlexPass versions.
#
# PlexPass users:
# Create a plexupdate.conf file in your home directory with these
# values:
#
# EMAIL='<whatever your plexpass email was>'
# PASS='<whatever password you used>'
# DOWNLOADDIR='<where you would like to save the downloaded package>'
#
# And run the tool using: ./plexupdate.sh --config plexupdate.conf
# or place the config in /etc/plexupdate.conf
#
# See https://github.com/mrworf/plexupdate for more details.
#
# Returns 0 on success
@ -58,7 +47,6 @@ PLEXPORT=32400
# Defaults
# (aka "Advanced" settings, can be overriden with config file)
FORCE=no
FORCEALL=no
PUBLIC=no
AUTOINSTALL=no
AUTODELETE=no
@ -71,48 +59,11 @@ CHECKUPDATE=yes
NOTIFY=no
CHECKONLY=no
# Default options for package managers, override if needed
REDHAT_INSTALL="dnf -y install"
DEBIAN_INSTALL="dpkg -i"
DISTRO_INSTALL=""
# Current pages we need - Do not change unless Plex.tv changes again
URL_LOGIN='https://plex.tv/users/sign_in.json'
URL_DOWNLOAD='https://plex.tv/api/downloads/1.json?channel=plexpass'
URL_DOWNLOAD_PUBLIC='https://plex.tv/api/downloads/1.json'
#URL for new version check
UPSTREAM_GIT_URL='https://raw.githubusercontent.com/mrworf/plexupdate/master/plexupdate.sh'
#Branch to fetch updates from
BRANCHNAME="master"
#Files "owned" by plexupdate, for autoupdate
PLEXUPDATE_FILES="plexupdate.sh extras/installer.sh extras/cronwrapper"
FILE_POSTDATA=$(mktemp /tmp/plexupdate.postdata.XXXX)
FILE_RAW=$(mktemp /tmp/plexupdate.raw.XXXX)
FILE_FAILCAUSE=$(mktemp /tmp/plexupdate.failcause.XXXX)
FILE_KAKA=$(mktemp /tmp/plexupdate.kaka.XXXX)
FILE_SHA=$(mktemp /tmp/plexupdate.sha.XXXX)
FILE_WGETLOG=$(mktemp /tmp/plexupdate.wget.XXXX)
FILE_LOCAL=$(mktemp /tmp/plexupdate.local.XXXX)
FILE_REMOTE=$(mktemp /tmp/plexupdate.remote.XXXX)
SCRIPT_PATH="$(dirname "$0")"
######################################################################
# Functions for rest of script
warn() {
echo "WARNING: $@" >&1
}
info() {
echo "$@" >&1
}
error() {
echo "ERROR: $@" >&2
}
usage() {
echo "Usage: $(basename $0) [-acdfFhlpPqsuU] [<long options>]"
@ -122,7 +73,6 @@ usage() {
echo " -d Auto delete after auto install"
echo " -f Force download even if it's the same version or file"
echo " already exists unless checksum passes"
echo " -F Force download always"
echo " -h This help"
echo " -l List available builds and distros"
echo " -p Public Plex Media Server version"
@ -134,109 +84,32 @@ usage() {
echo " -v Show additional debug information"
echo ""
echo " Long Argument Options:"
echo " --check-update Check for new version of plex only"
echo " --config <path/to/config/file> Configuration file to use"
echo " --dldir <path/to/download/dir> Download directory to use"
echo " --email <plex.tv email> Plex.TV email address"
echo " --pass <plex.tv password> Plex.TV password"
echo " --server <Plex server address> Address of Plex Server"
echo " --port <Plex server port> Port for Plex Server. Used with --server"
echo " --help This help"
echo " --notify-success Set exit code 10 if update is available/installed"
echo " --check-update Check for new version of plex only"
echo " --port <Plex server port> Port for Plex Server. Used with --server"
echo " --server <Plex server address> Address of Plex Server"
echo " --token Manually specify the token to use to download Plex Pass releases"
echo ""
exit 0
}
running() {
local DATA="$(wget --no-check-certificate -q -O - https://$1:$3/status/sessions?X-Plex-Token=$2)"
local RET=$?
if [ ${RET} -eq 0 ]; then
if [ -z "${DATA}" ]; then
# Odd, but usually means noone is watching
return 1
fi
echo "${DATA}" | grep -q '<MediaContainer size="0">'
if [ $? -eq 1 ]; then
# not found means that one or more medias are being played
return 0
fi
return 1
elif [ ${RET} -eq 4 ]; then
# No response, assume not running
return 1
else
# We do not know what this means...
warn "Unknown response (${RET}) from server >>>"
warn "${DATA}"
return 0
fi
}
trimQuotes() {
local __buffer=$1
# Remove leading single quote
__buffer=${__buffer#\'}
# Remove ending single quote
__buffer=${__buffer%\'}
echo $__buffer
}
# Useful functions
rawurlencode() {
local string="${1}"
local strlen=${#string}
local encoded=""
for (( pos=0 ; pos<strlen ; pos++ )); do
c=${string:$pos:1}
case "$c" in
[-_.~a-zA-Z0-9] ) o="${c}" ;;
* ) printf -v o '%%%02x' "'$c"
esac
encoded+="${o}"
done
echo "${encoded}"
}
keypair() {
local key="$( rawurlencode "$1" )"
local val="$( rawurlencode "$2" )"
echo "${key}=${val}"
}
getPlexServerToken() {
if [ -f /etc/default/plexmediaserver ]; then
source /etc/default/plexmediaserver
fi
# List possible locations to find Plex Server preference file
local VALIDPATHS=("${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR}" "/var/lib/plexmediaserver/Library/Application Support/" "${HOME}/Library/Application Support/")
local PREFFILE="/Plex Media Server/Preferences.xml"
for I in "${VALIDPATHS[@]}" ; do
if [ ! -z "${I}" -a -f "${I}${PREFFILE}" ]; then
sed -n 's/.*PlexOnlineToken="\([[:alnum:]]*\).*".*/\1/p' "${I}${PREFFILE}" 2>/dev/null
if [ $? -ne 0 -a -z "${EMAIL}" -a -z "${PASS}" ]; then
error "Do not have permission to read token from Plex Server preference file (${I}${PREFFILE})"
fi
exit 0
fi
done
}
if ! source "${SCRIPT_PATH}/plexupdate-core"; then
echo "ERROR: plexupdate-core can't be found. Please redownload plexupdate and try again." >2
exit 1
fi
# Setup an exit handler so we cleanup
cleanup() {
for F in "${FILE_RAW}" "${FILE_FAILCAUSE}" "${FILE_POSTDATA}" "${FILE_KAKA}" "${FILE_SHA}" "${FILE_LOCAL}" "${FILE_REMOTE}" "${FILE_WGETLOG}"; do
rm "$F" 2>/dev/null >/dev/null
done
rm "${FILE_SHA}" "${FILE_WGETLOG}" &> /dev/null
}
trap cleanup EXIT
# Parse commandline
ALLARGS=( "$@" )
optstring="-o acCdfFhlpPqrSsuUv -l config:,dldir:,email:,pass:,server:,port:,notify-success,check-update"
optstring="-o acCdfFhlpPqrSsuUv -l config:,dldir:,email:,pass:,server:,port:,token:,notify-success,check-update,help"
GETOPTRES=$(getopt $optstring -- "$@")
if [ $? -eq 1 ]; then
exit 1
@ -256,7 +129,7 @@ done
# We have to double-check that both files exist before trying to stat them. This is going away soon.
if [ -z "${CONFIGFILE}" -a -f ~/.plexupdate -a ! -f /etc/plexupdate.conf ] || \
([ -f "${CONFIGFILE}" -a -f ~/.plexupdate ] && [ `stat -Lc %i "${CONFIGFILE}"` == `stat -Lc %i ~/.plexupdate` ]); then
warn ".plexupdate has been deprecated. Please run $(dirname "$0")/extras/installer.sh to update your configuration."
warn ".plexupdate has been deprecated. Please run ${SCRIPT_PATH}/extras/installer.sh to update your configuration."
if [ -t 1 ]; then
for i in `seq 1 5`; do echo -n .\ ; sleep 1; done
echo .
@ -277,7 +150,7 @@ do
(-C) error "CRON option is deprecated, please use cronwrapper (see README.md)"; exit 255;;
(-d) AUTODELETE=yes;;
(-f) FORCE=yes;;
(-F) FORCEALL=yes;;
(-F) error "FORCEALL/-F option is deprecated, please use FORCE/-f instead"; exit 255;;
(-l) LISTOPTS=yes;;
(-p) PUBLIC=yes;;
(-P) SHOWPROGRESS=yes;;
@ -290,10 +163,12 @@ do
(--config) shift;; #gobble up the paramater and silently continue parsing
(--dldir) shift; DOWNLOADDIR=$(trimQuotes ${1});;
(--email) shift; EMAIL=$(trimQuotes ${1});;
(--pass) shift; PASS=$(trimQuotes ${1});;
(--email) shift; warn "EMAIL is deprecated. Use TOKEN instead."; EMAIL=$(trimQuotes ${1});;
(--pass) shift; warn "PASS is deprecated. Use TOKEN instead."; PASS=$(trimQuotes ${1});;
(--server) shift; PLEXSERVER=$(trimQuotes ${1});;
(--port) shift; PLEXPORT=$(trimQuotes ${1});;
(--token) shift; TOKEN=$(trimQuotes ${1});;
(--help) usage;;
(--notify-success) NOTIFY=yes;;
(--check-update) CHECKONLY=yes;;
@ -329,6 +204,11 @@ if [ "${KEEP}" = "yes" ]; then
exit 255
fi
if [ "${FORCEALL}" = "yes" ]; then
error "FORCEALL is deprecated, please use FORCE instead"
exit 255
fi
if [ ! -z "${RELEASE}" ]; then
error "RELEASE keyword is deprecated and should be removed from config file"
error "Use DISTRO and BUILD instead to manually select what to install (check README.md)"
@ -341,7 +221,7 @@ if [ "${AUTOUPDATE}" = "yes" ]; then
exit 1
fi
pushd "$(dirname "$0")" >/dev/null
pushd "${SCRIPT_PATH}" >/dev/null
if [ ! -d .git ]; then
warn "This is not a git repository. Auto-update only works if you've done a git clone"
@ -440,101 +320,36 @@ else
fi
if [ "${CHECKUPDATE}" = "yes" -a "${AUTOUPDATE}" = "no" ]; then
(wget -q "$UPSTREAM_GIT_URL" -O - 2>/dev/null || echo ERROR) | sha1sum >"${FILE_REMOTE}" 2>/dev/null
ERR1=$?
(cat "$0" 2>/dev/null || echo ERROR) | sha1sum >"${FILE_LOCAL}" 2>/dev/null
ERR2=$?
if [ $ERR1 -ne 0 -o $ERR2 -ne 0 ]; then
error "When checking for version, was unable to confirm version of script"
else
# "709c7506b17090bce0d1e2464f39f4a434cf25f1" is the hash for "ERROR" :)
if grep -sq "709c7506b17090bce0d1e2464f39f4a434cf25f1" "${FILE_LOCAL}" ; then
error "When checking for version, was unable to validate local copy"
elif grep -sq "709c7506b17090bce0d1e2464f39f4a434cf25f1" "${FILE_REMOTE}" ; then
error "When checking for version, was was unable to validate remote copy"
elif ! diff "${FILE_LOCAL}" "${FILE_REMOTE}" >/dev/null 2>/dev/null ; then
info "Newer version of this script is available at https://github.com/mrworf/plexupdate"
pushd "${SCRIPT_PATH}" > /dev/null
for filename in $PLEXUPDATE_FILES; do
[ -f "$filename" ] || error "Update check failed. '$filename' could not be found"
REMOTE_SHA=$(getRemoteSHA "$UPSTREAM_GIT_URL/$filename") || error "Update check failed. Unable to fetch '$UPSTREAM_GIT_URL/$filename'."
LOCAL_SHA=$(getLocalSHA "$filename")
if [ "$REMOTE_SHA" != "$LOCAL_SHA" ]; then
info "Newer version of this script is available at https://github.com/${GIT_OWNER:-mrworf}/plexupdate"
break
fi
fi
rm "${FILE_LOCAL}" 2>/dev/null >/dev/null
rm "${FILE_REMOTE}" 2>/dev/null >/dev/null
done
popd > /dev/null
fi
# Fields we need to submit for login to work
#
# Field Value
# utf8 &#x2713;
# authenticity_token <Need to be obtained from web page>
# user[login] $EMAIL
# user[password] $PASSWORD
# user[remember_me] 0
# commit Sign in
if [ "${PUBLIC}" = "no" ]; then
# Clean old session
rm "${FILE_KAKA}" 2>/dev/null
# Try to obtain token from Plex Server Installation
TOKEN=
if [ -z "${EMAIL}" -o -z "${PASS}" ]; then
TOKEN=$(getPlexServerToken)
if [ "${PUBLIC}" = "no" -a -z "$TOKEN" ]; then
TO_SOURCE="$(dirname "$0")/extras/get-plex-token"
[ -f "$TO_SOURCE" ] && source $TO_SOURCE
if ! getPlexToken; then
error "Unable to get Plex token, falling back to public release"
PUBLIC="yes"
fi
fi
if [ -z "${TOKEN}" ]; then
# If no token, go through regular process
if [ -z "${EMAIL}" -o -z "${PASS}" ]; then
error "Need username & password to download PlexPass version. Otherwise run with -p to download public version."
exit 1
elif [ ! -z "${EMAIL}" ] && [[ "$EMAIL" == *"@"* ]] && [[ "$EMAIL" != *"@"*"."* ]]; then
error "EMAIL field must contain a valid email address"
exit 1
elif [ ! -z "${EMAIL}" -a ! -z "${PASS}" -a "${PUBLIC}" = "yes" ]; then
warn "You have defined email and password but PUBLIC is set to yes, this will not download the PlexPass version"
fi
info "Authenticating with plex.tv using email and password"
# Build post data
echo -ne >"${FILE_POSTDATA}" "$(keypair "user[login]" "${EMAIL}" )"
echo -ne >>"${FILE_POSTDATA}" "&$(keypair "user[password]" "${PASS}" )"
echo -ne >>"${FILE_POSTDATA}" "&$(keypair "user[remember_me]" "0" )"
# Authenticate (using Plex Single Sign On)
wget --header "X-Plex-Client-Identifier: 4a745ae7-1839-e44e-1e42-aebfa578c865" --header "X-Plex-Product: Plex SSO" --load-cookies "${FILE_KAKA}" --save-cookies "${FILE_KAKA}" --keep-session-cookies "${URL_LOGIN}" --post-file="${FILE_POSTDATA}" -q -S -O "${FILE_FAILCAUSE}" 2>"${FILE_RAW}"
# Delete authentication data ... Bad idea to let that stick around
rm "${FILE_POSTDATA}"
# Provide some details to the end user
RESULTCODE=$(head -n1 "${FILE_RAW}" | grep -oe '[1-5][0-9][0-9]')
if [ $RESULTCODE -eq 401 ]; then
error "Username and/or password incorrect"
if [ "$VERBOSE" = "yes" ]; then
info "Tried using \"${EMAIL}\" and \"${PASS}\" "
fi
exit 1
elif [ $RESULTCODE -ne 201 ]; then
error "Failed to login, debug information:"
cat "${FILE_RAW}" >&2
exit 1
fi
# If the system got here, it means the login was successfull, so we set the TOKEN variable to the authToken from the response
# I use cut -c 14- to cut off the "authToken":" string from the grepped result, can probably be done in a different way
TOKEN=$(<"${FILE_FAILCAUSE}" grep -ioe '"authToken":"[^"]*' | cut -c 14-)
# Remove this, since it contains more information than we should leave hanging around
rm "${FILE_FAILCAUSE}"
else
info "Using Plex Server credentials to authenticate"
fi
elif [ "$PUBLIC" != "no" ]; then
# It's a public version, so change URL and make doubly sure that cookies are empty
rm 2>/dev/null >/dev/null "${FILE_KAKA}"
touch "${FILE_KAKA}"
if [ "$PUBLIC" != "no" ]; then
# It's a public version, so change URL
URL_DOWNLOAD=${URL_DOWNLOAD_PUBLIC}
fi
if [ "${LISTOPTS}" = "yes" ]; then
opts="$(wget --load-cookies "${FILE_KAKA}" --save-cookies "${FILE_KAKA}" --keep-session-cookies "${URL_DOWNLOAD}" -O - 2>/dev/null | grep -oe '"label"[^}]*' | grep -v Download | sed 's/"label":"\([^"]*\)","build":"\([^"]*\)","distro":"\([^"]*\)".*/"\3" "\2" "\1"/' | uniq | sort)"
opts="$(wget "${URL_DOWNLOAD}" -O - 2>/dev/null | grep -oe '"label"[^}]*' | grep -v Download | sed 's/"label":"\([^"]*\)","build":"\([^"]*\)","distro":"\([^"]*\)".*/"\3" "\2" "\1"/' | uniq | sort)"
eval opts=( "DISTRO" "BUILD" "DESCRIPTION" "======" "=====" "==============================================" $opts )
BUILD=
@ -558,10 +373,16 @@ fi
info "Retrieving list of available distributions"
# Set "X-Plex-Token" to the auth token, if no token is specified or it is invalid, the list will return public downloads by default
RELEASE=$(wget --header "X-Plex-Token:"${TOKEN}"" --load-cookies "${FILE_KAKA}" --save-cookies "${FILE_KAKA}" --keep-session-cookies "${URL_DOWNLOAD}" -O - 2>/dev/null | grep -ioe '"label"[^}]*' | grep -i "\"distro\":\"${DISTRO}\"" | grep -m1 -i "\"build\":\"${BUILD}\"")
RELEASE=$(wget --header "X-Plex-Token:"${TOKEN}"" "${URL_DOWNLOAD}" -O - 2>/dev/null | grep -ioe '"label"[^}]*' | grep -i "\"distro\":\"${DISTRO}\"" | grep -m1 -i "\"build\":\"${BUILD}\"")
DOWNLOAD=$(echo ${RELEASE} | grep -m1 -ioe 'https://[^\"]*')
CHECKSUM=$(echo ${RELEASE} | grep -ioe '\"checksum\"\:\"[^\"]*' | sed 's/\"checksum\"\:\"//')
if [ "$VERBOSE" = "yes" ]; then
for i in RELEASE DOWNLOAD CHECKSUM; do
info "$i=${!i}"
done
fi
if [ -z "${DOWNLOAD}" ]; then
error "Unable to retrieve the URL needed for download (Query DISTRO: $DISTRO, BUILD: $BUILD)"
if [ ! -z "${RELEASE}" ]; then
@ -569,6 +390,9 @@ if [ -z "${DOWNLOAD}" ]; then
error "Please try https://plex.tv and confirm it works there before reporting this issue"
fi
exit 3
elif [ -z "${CHECKSUM}" ]; then
error "Unable to retrieve a checksum for the download. Please try https://plex.tv/downloads before reporting this issue."
exit 3
fi
FILENAME="$(basename 2>/dev/null ${DOWNLOAD})"
@ -605,48 +429,32 @@ if [ "${CHECKONLY}" = "yes" ]; then
info "Your OS reports Plex $INSTALLED_VERSION installed, newer version is available (${AVAIL})"
exit 7
else
info "You are running latest version of Plex (${INSTALLED_VERSION})"
info "You are running the latest version of Plex (${INSTALLED_VERSION})"
fi
exit 0
fi
if [[ $FILENAME == *$INSTALLED_VERSION* ]] && [ "${FORCE}" != "yes" -a "${FORCEALL}" != "yes" ] && [ ! -z "${INSTALLED_VERSION}" ]; then
if [[ $FILENAME == *$INSTALLED_VERSION* ]] && [ "${FORCE}" != "yes" ] && [ ! -z "${INSTALLED_VERSION}" ]; then
info "Your OS reports the latest version of Plex ($INSTALLED_VERSION) is already installed. Use -f to force download."
exit 0
fi
if [ -f "${DOWNLOADDIR}/${FILENAME}" ]; then
if [ "${FORCE}" != "yes" -a "${FORCEALL}" != "yes" ]; then
sha1sum --status -c "${FILE_SHA}"
if [ $? -eq 0 ]; then
info "File already exists (${FILENAME}), won't download."
if [ "${AUTOINSTALL}" != "yes" ]; then
exit 0
fi
SKIP_DOWNLOAD="yes"
else
info "File exists but fails checksum. Redownloading."
SKIP_DOWNLOAD="no"
if [ -f "${DOWNLOADDIR}/${FILENAME}" -a "${FORCE}" != "yes" ]; then
if sha1sum --status -c "${FILE_SHA}"; then
info "File already exists (${FILENAME}), won't download."
if [ "${AUTOINSTALL}" != "yes" ]; then
exit 0
fi
elif [ "${FORCEALL}" == "yes" ]; then
info "Note! File exists, but asked to overwrite with new copy"
SKIP_DOWNLOAD="yes"
else
sha1sum --status -c "${FILE_SHA}"
if [ $? -ne 0 ]; then
info "File exists but fails checksum. Redownloading."
else
info "File exists and checksum passes, won't redownload."
if [ "${AUTOINSTALL}" != "yes" ]; then
exit 0
fi
SKIP_DOWNLOAD="yes"
fi
info "File exists but fails checksum. Redownloading."
SKIP_DOWNLOAD="no"
fi
fi
if [ "${SKIP_DOWNLOAD}" = "no" ]; then
info "Downloading release \"${FILENAME}\""
wget ${WGETOPTIONS} -o "${FILE_WGETLOG}" --load-cookies "${FILE_KAKA}" --save-cookies "${FILE_KAKA}" --keep-session-cookies "${DOWNLOAD}" -O "${DOWNLOADDIR}/${FILENAME}" 2>&1
wget ${WGETOPTIONS} -o "${FILE_WGETLOG}" "${DOWNLOAD}" -O "${DOWNLOADDIR}/${FILENAME}" 2>&1
CODE=$?
if [ ${CODE} -ne 0 ]; then
@ -657,8 +465,7 @@ if [ "${SKIP_DOWNLOAD}" = "no" ]; then
info "File downloaded"
fi
sha1sum --status -c "${FILE_SHA}"
if [ $? -ne 0 ]; then
if ! sha1sum --status -c "${FILE_SHA}"; then
error "Downloaded file corrupt. Try again."
exit 4
fi