Skip to content

Instantly share code, notes, and snippets.

@voidbert
Last active February 13, 2024 00:15
Show Gist options
  • Save voidbert/061bd997280c0ae17c2404e121b80635 to your computer and use it in GitHub Desktop.
Save voidbert/061bd997280c0ae17c2404e121b80635 to your computer and use it in GitHub Desktop.
Termux script for getting the QR code to eat at UMinho's cafeterias
#!/bin/sh
#!/data/data/com.termux/files/usr/bin/sh
# \
# \_ Choose the correct shebang depending on whether you use Termux or a
# regular Linux system.
# ----------------------------------- ABOUT -----------------------------------
#
# Script to automatically download the QR code used to eat at UMinho's
# cafeterias, avoiding the (absolutely) proprietary app.
#
# Usage:
#
# ---------------------------------- LICENSE ----------------------------------
#
# Copyright 2023 Humberto Gomes
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ---------------------------------- CONFIG -----------------------------------
# Location of login email and password (plain text) file.
CREDENTIALS_FILE="$HOME/.ossum"
# Program used to open the QR code.
# Example values:
# Termux: "termux-open"
# Linux: "xdg-open"
IMAGE_VIEWER="termux-open"
# ---------------------------------- SCRIPT -----------------------------------
# Works like read -rp "$1" $2, but doesn't require bash.
#
# Arguments:
# $1 - Prompt to be shown to the user
# $2 - Variable name of where to place the inputted value (like read)
read_prompt() {
stdbuf -o 0 printf "$1"
read -r "$2"
}
API_ENDPOINT="https://sasum.scl.pt/app.php"
DASHBOARD_URL="https://um.sincelo.pt/portal/index.php"
# HTTP, as SSL sometimes fails
SASUM_ICON="http://www.sas.uminho.pt/wp-content/uploads/2023/04/Imagem23.png"
USER_AGENT="Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/118.0"
CURL_MAX_TIME=10
# Checks if all required programs are installed. An error message will be
# printed for the first missing command found.
#
# Return value:
# 0 - All needed commands are installed
# 1 - At least one command is missing.
assert_programs() {
assert_program() {
if ! command -v "$1" > /dev/null; then
printf "%s is not installed! Please install it and try " "$1" >&2
echo "again. Leaving ..." >&2
return 1
fi
}
assert_program curl || return 1
assert_program "$(echo "$IMAGE_VIEWER" | sed 's/ .*//')" || return 1
}
# Checks if the current system is a Termux system.
#
# Return value:
# 0 - Regular Linux system
# 1 - Termux system
is_termux() {
(echo "$HOME" | grep "com.termux" > /dev/null) || return $?
}
# Stores the user's email in $email and their password in $password.
# This data will be loaded from $CREDENTIALS_FILE, provided it exists.
# Otherwise, the user is asked to input that information and $CREDENTIALS_FILE
# is generated.
login() {
if [ -f "$CREDENTIALS_FILE" ]; then
email="$(head -n 1 "$CREDENTIALS_FILE")"
password="$(tail -n 1 "$CREDENTIALS_FILE")"
return
fi
read_prompt "Email: " email
stty -echo
read_prompt "Password: " password
echo # New line, because the user's press of ENTER isn't echoed
stty echo
printf "%s\n%s\n" "$email" "$password" > "$CREDENTIALS_FILE"
chmod 600 "$CREDENTIALS_FILE"
}
# Removes $CREDENTIALS_FILE if it exists. May return 1 on failure.
#
# Arguments:
# $1 - true or false, whether or not to print messages. This may be undesirable
# for removing credentials after a failed login, for example.
logout() {
if [ -f "$CREDENTIALS_FILE" ]; then
if rm "$CREDENTIALS_FILE"; then
$1 && echo "Successfully logged out!"
return 0
else
$1 && echo "Failed to log out!" >&2
return 1
fi
else
$1 && echo "Already logged out!"
return 0
fi
}
# Gets the hash parameter resulting from SASUM's authentication. On failure,
# this will return 1 and, if that failure results from failure to authenticate
# (not network-related), $CREDENTIALS_FILE will be deleted.
#
# Arguments:
# $1 - email (see login)
# $2 - password (see login)
#
# Return value:
# stdout - Value of the hash
# 0 - Success
# 1 - Login falure (network or authentication)
get_hash() {
# Gets a string property from SASUM's JSON response. There's no support for
# escaped quotes. A full JSON parser (like jq) isn't used to reduce the
# number of dependencies.
#
# Arguments:
# stdin - input JSON
# $1 - name of the property
#
# Return value:
# stdout - value of the property
get_json_property() {
match="$(grep -o "\"$1\":\"[^\"]*\"")"
if [ $? -ne 0 ]; then
echo "Bad response from SASUM! (authentication)" >&2
return 1 # No match
fi
echo "$match" | tail "-c+$((${#1} + 5))" | head -c-2
}
response_file="$(mktemp)"
if curl -s -o "$response_file" --max-time "$CURL_MAX_TIME" \
-X GET -G "$API_ENDPOINT" \
--data-urlencode "auth=$1" --data-urlencode "pin=$2"; then
request_status="$(< "$response_file" get_json_property "status")"
if [ $? -ne 0 ]; then rm "$response_file" ; return 1 ; fi
if [ "$request_status" != "OK" ]; then
echo "Failure to authenticate!" >&2
logout false
rm "$response_file"
return $?
fi
request_hash="$(< "$response_file" get_json_property "hash")"
if [ $? -ne 0 ]; then rm "$response_file" ; return 1 ; fi
echo "$request_hash"
fi
rm "$response_file"
}
# Gets the QR code from SASUM's webpage and writes it to a temporary PNG file.
# May return 1 on failure (the QR code is deleted in those cases).
#
# Arguments:
# $1 - hash (see get_hash)
#
# Return value:
# stdout - path to the file
get_qr() {
response_file="$(mktemp)"
if curl -s -o "$response_file" --max-time "$CURL_MAX_TIME" \
-X GET -G "$DASHBOARD_URL" -H "user-agent: $USER_AGENT" \
--data-urlencode "hash=$1" --data-urlencode "sb=1"; then
if ! grep "src='data:image/png;base64," "$response_file" \
> /dev/null; then
echo "Bad response from SASUM! (QR code)" >&2
rm "$response_file"
return 1 # No match
fi
grep -o "src='data:image/png;base64,[^']*'" "$response_file" | \
tail -c+28 | head -c-2 > "${response_file}_b64"
if is_termux; then
qr_code_file="/sdcard/.sasum.png"
else
qr_code_file="$(mktemp)"
fi
if ! base64 -d "${response_file}_b64" > "$qr_code_file"; then
echo "Bad response from SASUM! (QR code)" >&2
rm "$response_file" "${response_file}_b64"
return 1
fi
echo "$qr_code_file"
rm "$response_file" "${response_file}_b64"
fi
}
# Installs the script to Termux Widget's shortcuts.
#
# Return value:
# 0 - Success
# 1 - Failure
install() {
if ! [ -d "$HOME/.shortcuts" ]; then
if ! mkdir -m 700 "$HOME/.shortcuts"; then
echo "Failed to create .shortcuts directory" >&2
return 1
fi
fi
if ! [ -d "$HOME/.shortcuts/icons" ]; then
if ! mkdir -m 700 "$HOME/.shortcuts/icons"; then
echo "Failed to create .shortcuts/icons directory" >&2
return 1
fi
fi
if ! (cp "$0" "$HOME/.shortcuts/SASUM" && \
chmod 700 "$HOME/.shortcuts/SASUM"); then
echo "Failed to create .shortcuts/SASUM script" >&2
return 1
fi
if ! (curl -so "$HOME/.shortcuts/icons/SASUM.png" \
--max-time "$CURL_MAX_TIME" "$SASUM_ICON" && \
chmod 700 "$HOME/.shortcuts/SASUM"); then
echo "Failed to download SASUM's icon" >&2
return 1
fi
}
assert_programs || exit 1
if [ "$1" = "logout" ]; then
logout true
exit $?
elif [ "$1" = "install" ]; then
if ! is_termux; then
echo "Installation is only available on Termux systems" >&2
return 1
fi
install
exit $?
elif [ "$#" -eq 0 ]; then
login
auth_hash="$(get_hash "$email" "$password")"
if [ $? -ne 0 ]; then exit 1; fi
echo "Authenticated successfully!"
echo "In case of failure, try to go to $DASHBOARD_URL?hash=$auth_hash&sb=1"
png_file="$(get_qr "$auth_hash")"
if [ $? -ne 0 ]; then exit 1; fi
echo "Got QR code!"
$IMAGE_VIEWER "$png_file"
sleep 10 && rm "$png_file"
read _ # Allow time for copying the URL on failure
exit $?
else
if [ "$1" != "help" ] || [ "$#" -ne 1 ]; then
printf "Incorrect program usage!\n\n" >&2
fi
echo "./ossum.sh - Get QR code"
echo "./ossum.sh logout - Delete login credentials"
echo "./ossum.sh install - Termux widget installation"
echo "./ossum.sh help - See this message"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment