#!/usr/bin/env bash # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2, June 1991. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see , # or in pdf format at # Copyright 2012-2014 - Øyvind 'bolt' Hvidsten # Description: # # telenorsms is a script that connects to the Norwegian cell operator Telenor and sends SMS messages # # It requires curl or wget, xxd, tr, cat and sed. "tempfile" is also recommended, though the script should manage # to generate tempfiles itself. # # Your username (email) and password for your Telenor account need to be stored in ~/.telenorsms on two # separate lines: # ------------------------------------------ # username=me@provider.com # password=awesome1 # grabber=/home/me/bin/grabber # ------------------------------------------ # As shown above, it is also strongly recommended to indicate the path to the "grabber" library, # which should be available where this script was downloaded from. Grabber does not need to be executable. # # You must have sent at least one message through the online interface, as it will ask you to verify your # cell phone number by entering a code received by SMS, the first time you use it. # # telenorsms supports using numbers and names stored in your online address book in the SMS section of # Telenor's pages. Messages can be sent to stored numbers using complete names or partial numbers. # # Examples: # ./telenorsms Joe Hey man, how's it going? # ./telenorsms +4711223344 This is a message. # ./telenorsms 1122 This is a message. # # Comments welcome, improvements/patches twice as welcome. # # Version history: # # 2009-02-03: Initial version - ivc # 2009-08-19: Support for local phonebook and various bug fixes - Håvard Gulldahl # 2012-07-29: Rewrite for Bash 4 with support for new "MineSider" setup and online phonebook - Øyvind 'bolt' Hvidsten # 2013-04-07: Minor style changes and comment cleanup - Øyvind 'bolt' Hvidsten # 2013-04-20: Updated to comply with changes on Telenor's website # 2013-06-15: Retry 3 times because of random cases of Ubuntu bug #965371 occuring on Telenor's server: # GnuTLS: A TLS packet with unexpected length was received. # Unable to establish SSL connection. # 2014-04-04: Updated to comply with changes on Telenor's website # 2014-08-26: Support for complaining about "technical error" on Telenor's website # 2014-08-27: Support for the -d (dry run) option, testing most of the script without sending a message # 2014-08-28: Support for the -a (force address book) option, used during debugging # 2014-10-01: Spelling error fix # 2014-10-18: Rewrote URL grabbing to use curl, as Telenor screwed up their TLS negotiation # Use of wget can still be forced by adding [-w] # Added several debugging features # Note from debugging: URL encoding the "+" sign in "Logg+inn" breaks Telenor's form # 2014-10-19: Pushed the HTTP grabbing functionality to a separate file in order to unify the methods used # across several scripts I'm maintaining that all have similar functionality. # Deeply sorry for any inconvenience caused. # 2014-10-24: They changed the text "gjenstående SMS" to "gjenstående gratis SMS" for no reason. OK. # 2015-01-04: Added detection of the SMS counter breaking - no longer exiting with non-zero unless debugging # 2015-05-01: Minimal fix to support new link format for the login page # 2015-05-16: Updated to comply with changes to grabber # 2016-01-16: Updated to comply with changes to grabber (again) # 2016-12-29: Fix "bad substitution" error in Debian Stretch Bash # 2017-02-03: Support for accounts with multiple phone numbers # In related news: support for the minemeldinger.no API in development # 2017-07-21: Code cleanup, hopefully no functional changes # 2017-11-19: Implemented support for Telenor's new oAuth login # _scriptname="telenorsms" set -e set -u # Options dryrun=false GRABBER_DEBUG=false forceaddressbook=false GRABBER="curl" OPTIND=1 while getopts ":adDw" opt; do case "$opt" in a) forceaddressbook=true ;; d) dryrun=true ;; D) GRABBER_DEBUG=true ;; w) GRABBER="wget" ;; [?]) echo "Unknown option -${OPTARG}" >&2 exit 1 ;; :) echo "Option -${OPTARG} requires an argument" >&2 exit 1 ;; esac done shift $((OPTIND-1)) if [[ "${1:-}" = "--" ]]; then shift; fi # Settings config="$HOME/.${_scriptname}" # Smart Sourcing function ssource { while (( $# )); do if [[ -f "$1" ]] && [[ -r "$1" ]]; then source "$1" return fi shift done return 1 } # Grabber grabber=$(grep -m 1 "^grabber=" "$config" 2>/dev/null | cut -d = -f 2) if ! ssource /cathedral/src/lib/grabber "${grabber:-"$HOME/.grabber"}" "$(dirname "${BASH_SOURCE[0]}")/grabber"; then echo "grabber library was not found" >&2 echo "Please download \"grabber\" from the same place you got this script," >&2 echo "Put it at $grabber or point at it in $config." >&2 exit 2 fi # Config username=$(grep -m 1 "^username=" "$config" 2>/dev/null | cut -d = -f 2 | sf_urlencode) password=$(grep -m 1 "^password=" "$config" 2>/dev/null | cut -d = -f 2 | sf_urlencode) subscription=$(grep -m 1 "^subscription=" "$config" 2>/dev/null | cut -d = -f 2) [[ -z "${1:-}" ]] || { recipient=$1 && shift; } [[ -z "${1:-}" ]] || { message=$(sf_urlencode "$@"); } # Sanity if [[ -z "${username:-}" ]] || [[ -z "${password:-}" ]]; then echo "Username or password unset. please put both in $config!" >&2 exit 1 fi if [[ -z "${recipient:-}" ]] || [[ -z "${message:-}" ]]; then echo -e "Missing required arguments!\\n\\nUsage: $_scriptname [-d] " >&2 exit 0 fi # Get login URL grabber_task "Getting login URL" grab -hrn "https://www.telenor.no/privat/minesider/logginn" || : cat "$f_stderr" >>"$f_stdout" assert 'Location: ' read -r login_url < <(grep -m 1 "Location: " <"$f_stdout" | cut -d ':' -f 2- | tr -d '\r\n') || : # Get cookie grabber_task "Getting cookie" grab "$login_url" assert 'action="#"' # Login grabber_task "Logging in" grab_data="username=$username&password=$password" \ grab_ref="$login_url" \ grab "$login_url" assert "Authentication successful" # Get form data grabber_task "Getting form data" function field_value { local name=$1 local regex="]+name=\"$name\"[^>]+value=\"([^\"]+)" if [[ "$(tr -d '\r\n' <"$f_stdout")" =~ $regex ]]; then printf '%s' "${BASH_REMATCH[1]}" else grabber_fail fi } fdata_1=$(field_value "samlResponse") fdata_2=$(field_value "telenor_id") fdata_3=$(field_value "last_success_login_date") grabber_ok # Login grabber_task "Accessing service" up=false while true; do grab_data="samlResponse=$(sf_urlencode "${fdata_1}")&telenor_id=$(sf_urlencode "${fdata_2}")&last_success_login_date=$(sf_urlencode "${fdata_3}")" \ grab_ref="$login_url" \ grab "https://apigw.telenor.no/oauth/v2/storeSaml" if found 'SEND_SMS'; then echo "OK" break elif found 'action="/privat/minesider/minprofil/oppdatereMinProfil.cms"'; then if ! $up; then echo "Profile update needed!" grabber_task "Updating profile" grab_data="confirmProfile=true&lbAction=Bekreft" \ grab_ref="https://www.telenor.no/privat/minesider/minprofil/oppdatereMinProfil.cms" \ grab "https://www.telenor.no/privat/minesider/minprofil/oppdatereMinProfil.cms" up=true else grabber_fail fi else grabber_fail fi done # Subscription test grabber_task "Looking for subscription" smsurl="https://www.telenor.no/privat/minesider/norm/win/sms/send.do" grab_ref="https://www.telenor.no/privat/minesider/minside/minSidePage.cms" \ grab "$smsurl" if found '

Teknisk feil

'; then grabber_fail '"Teknisk feil" - Have you activated SMS from Web yet?' fi if found '/selectSubscription/process.do'; then >"$f_stderr" # hijack this echo 'It would seem you have more than one subscription' >>"$f_stderr" echo 'Please add one of the following "subscription=..." lines to your configuration file:' >>"$f_stderr" while IFS=$'\t' read -r sub ref; do if [[ "$sub" = "${subscription:-x}" ]]; then smsurl="https://telenormobil.no$ref" break fi echo "subscription=$sub" >>"$f_stderr" done < <( grep '/selectSubscription/process.do' "$f_stdout" | cut -d '"' -f 2,4 --output-delimiter=$'\t' | tr -d ' ' ) # list subscriptions available if [[ -z "$smsurl" ]]; then echo "???" >&2 cat "$f_stderr" >&2 exit 1 fi # attempt to select subscription grabber_ok grabber_task "Number verification" select_url=$smsurl for (( i=0; i<10; i++)); do grab -hrn "$select_url" || : cat "$f_stderr" >>"$f_stdout" read -r select_url < <(grep -m 1 "Location: " <"$f_stdout" | cut -d ':' -f 2- | tr -d '\r\n') || : if [[ "$select_url" = *"send.do" ]]; then break fi done if [[ "$select_url" != *"send.do" ]]; then echo "???" >&2 echo "Failed to select number for sending - have you send a message manually and verified the code yet?" >&2 exit 1 fi fi grabber_ok # Mandatory SMS page get... grabber_task "SMS page get" grab "$smsurl" assert '/send/process.do' # Get the address list grabber_task "Getting address list" grab_ref="https://www.telenor.no/privat/minesider/minside/minSidePage.cms" \ grab "https://telenormobil.no/norm/sms/async/addresslist.do" grabber_ok grabber_task "Parsing..." names=() numbers=() i=0 while read -r line; do # begin stupid address book format [[ "$line" = *'