The frontend has now been secured far better. It now uses its own user

account with limited permissions. Openbox's menu also does not allow the
user to open potentially dangerous programs anymore.

OctoPrint account no longer randomizes its password as it is more
secure to have it not have one at all.

Condensed Nginx listening address interpreter.

Frontend check to see if Nginx and OctoPrint has been improved. It
should now be reliable.

Added touchscreen calibration.

Octo-config service menu is now deeper, which results in a cleaner
interface.

Octo-config now has a somewhat crude system health checking menu.

MJPG's resolution and framerate can now be configured.

Updated TODO
This commit is contained in:
Logan G 2020-08-24 22:01:52 -06:00
parent 9132a8b7f7
commit ef5ab23d6f
Signed by: logan
GPG key ID: E328528C921E7A7A
10 changed files with 181 additions and 69 deletions

View file

@ -3,12 +3,6 @@
## First time/Octo-Config
- Add network configuration (replace nmtui)
- Add hostname configuration (replace nmtui)
- Better service configuration (deeper menu)
- System check
- Touch screen calibration
## Frontend
- Separate frontend from pi account
## Nginx
- Add HTTP basic auth (especially to MJPG)

View file

@ -9,6 +9,7 @@ install -m 644 files/.dialogrc "${ROOTFS_DIR}/etc/skel/.dialogrc"
install -m 644 files/.dialogrc "${ROOTFS_DIR}/root/.dialogrc"
mkdir -p "${ROOTFS_DIR}/etc/skel/.config/openbox"
install -m 644 files/autostart "${ROOTFS_DIR}/etc/skel/.config/openbox/autostart"
install -m 644 files/menu.xml "${ROOTFS_DIR}/etc/skel/.config/openbox/menu.xml"
on_chroot << EOF
if ! id -u ${FIRST_USER_NAME} >/dev/null 2>&1; then
@ -17,7 +18,10 @@ fi
if ! id -u octoprint >/dev/null 2>&1; then
adduser --system --shell /usr/sbin/nologin --group --disabled-password --gecos "" octoprint
fi
if ! id -u kiosk >/dev/null 2>&1; then
adduser --disabled-password --shell /usr/sbin/nologin --gecos "" kiosk
fi
echo "${FIRST_USER_NAME}:${FIRST_USER_PASS}" | chpasswd
echo "octoprint:$(cat /dev/urandom | tr -dc _A-Z-a-z-0-9 | head -c40)" | chpasswd
echo "kiosk:$(cat /dev/urandom | tr -dc _A-Z-a-z-0-9 | head -c40)" | chpasswd
echo "root:$(cat /dev/urandom | tr -dc _A-Z-a-z-0-9 | head -c40)" | chpasswd
EOF

View file

@ -1,25 +1,25 @@
#!/bin/bash
# Grabs the port (and IP) out of the nginx config
LISTEN=$(grep -i listen /etc/nginx/listen.conf | awk '{gsub(";",""); print $2}')
LISTEN=$(awk '/listen/{gsub(";",""); print $2}' /etc/nginx/listen.conf)
# If the value we just grabbed doesn't contain an IP, prepend localhost
if ! echo $LISTEN | grep ":" 2>&1; then
ADDRESS="localhost:$LISTEN"
ADDRESS="https://localhost:$LISTEN"
else
ADDRESS=$LISTEN
ADDRESS="https://$LISTEN"
fi
# Override the automatically detected address if the user wants to
if [[ -f ~/.overrideurl.sh ]]; then source ~/.overrideurl.sh; fi
# Wait until Nginx/override comes up
while ! curl "$ADDRESS" 2>&1 >/dev/null; do
while ! curl -f -k -s -I "$ADDRESS" 2>&1 >/dev/null; do
sleep 1
done
# Wait until OctoPrint comes up if it is enabled
while [[ -f /etc/systemd/system/multi-user.target.wants/octoprint.service ]] && ! curl "localhost:5000"; do
while [[ -f /etc/systemd/system/multi-user.target.wants/octoprint.service ]] && ! curl -f -s -I "localhost:5000"; do
sleep 1
done
@ -31,4 +31,4 @@ done
# -K | Enable kiosk mode (doesn't seem to do anything?)
# -n | Disable web inspector
# -p | Disable plugins
surf -t -F -g -K -n -p "https://$ADDRESS"
surf -t -F -g -K -n -p "$ADDRESS"

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<openbox_menu xmlns="http://openbox.org/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://openbox.org/
file:///usr/share/openbox/menu.xsd">
<menu id="root-menu" label="Openbox 3">
<item label="Restart Browser">
<action name="Execute"><execute>bash ~/.browser.sh</execute></action>
</item>
<separator />
<item label="Restart GUI">
<action name="Exit" />
</item>
</menu>
</openbox_menu>

View file

@ -46,6 +46,9 @@ done
for GRP in dialout plugdev video users; do
adduser octoprint \$GRP
done
for GRP in users; do
adduser kiosk \$GRP
done
EOF
on_chroot << EOF

View file

@ -68,6 +68,9 @@ dialog --title "NOTICE" --nocancel --colors --msgbox "This collection of softwar
# Force the user to change the pi user's password before the RPi gets botnetted
change_password
# Randomize the root and frontend password
echo "kiosk:$(cat /dev/urandom | tr -dc _A-Z-a-z-0-9 | head -c40)" | chpasswd
echo "root:$(cat /dev/urandom | tr -dc _A-Z-a-z-0-9 | head -c40)" | chpasswd
dialog --title "Network Configuration" --nocancel --msgbox "Setup will now open nmtui, a program to help configure your ethernet/wireless interfaces. Hit Quit when you are done." 10 50
nmtui
@ -76,10 +79,14 @@ nmtui
dpkg-reconfigure tzdata
# Enable/disable OctoPrint, GUI, MJPG and SSH
service_select
service_toggle
screen_timeout
if ( udevadm info --export-db | grep ID_INPUT_TOUCHSCREEN=1 >/dev/null ) && dialog --title "Touchscreen Calibration" --defaultno --yesno "Do you wish to calibrate your touchscreen?\nMost touchscreens are calibrated out of the factory, so this is usually not needed." 10 60; then
startx $(which xinput_calibrator) --no-timeout --output-filename /etc/X11/xorg.conf.d/99-calibration.conf
fi
# Makes a certificate and key for Nginx HTTPS
openssl req -x509 -nodes -days 36500 -newkey rsa:4096 -subj "/C=/ST=/L=/O=/OU=/CN=*/emailAddress=" -out /etc/ssl/certs/nginx-octoprint.crt -keyout /etc/ssl/private/nginx-octoprint.key
@ -90,6 +97,7 @@ fi
# If MJPG service is enabled, ask user which video device to use
if [[ -f /etc/systemd/system/multi-user.target.wants/mjpg-streamer.service ]]; then
video_select
video_config
fi

View file

@ -9,23 +9,74 @@ fi
source /usr/local/lib/octo-lib.sh
main_menu () {
local MAINMENU=$(dialog --nocancel --title "Pi Setup" --menu "" 10 50 0 \
local MAINMENU=$(dialog --nocancel --title "TouchPrint Setup" --menu "" 10 50 0 \
"1" "Configure networking" \
"2" "Change password for pi" \
"3" "Configure services" \
"4" "Configure screen timeout" \
"5" "Configure Nginx" \
"6" "Configure MJPG" \
"7" "Exit" 3>&1 1>&2 2>&3)
"5" "Calibrate touchscreen" \
"6" "Exit" 3>&1 1>&2 2>&3)
case $MAINMENU in
"1") nmtui; main_menu; return 0;;
"2") change_password; main_menu; return 0;;
"3") service_select; main_menu; return 0;;
"3") services_menu; main_menu; return 0;;
"4") screen_timeout; main_menu; return 0;;
"5") nginx_config; main_menu; return 0;;
"6") video_config; main_menu; return 0;;
"7") return 0;;
"5") dialog --title "Touchscreen Calibration" --infobox "Waiting for touchscreen calibrator to close..." 3 50; DISPLAY=:0 xinput_calibrator --no-timeout --output-filename /etc/X11/xorg.conf.d/99-calibration.conf; main_menu; return 0;;
"6") return 0;;
esac
}
services_menu () {
local SERVICESMENU=$(dialog --nocancel --title "Services Select" --menu "" 10 50 0 \
"1" "Enable/disable services" \
"2" "Service health check" \
"3" "Configure Nginx" \
"4" "Configure MJPG" \
"5" "Go Back" 3>&1 1>&2 2>&3)
case $SERVICESMENU in
"1") service_toggle; services_menu; return 0;;
"2") service_health; services_menu; return 0;;
"3") nginx_config; services_menu; return 0;;
"4") video_menu; services_menu; return 0;;
"5") return 0;;
esac
}
service_health () {
# Grab listening address/port from Nginx config
if [[ -f /etc/nginx/listen.conf ]]; then
LISTEN=$(awk '/listen/{gsub(";",""); print $2}' /etc/nginx/listen.conf)
else
LISTEN="443"
fi
# If Nginx config didn't contain a port, assume localhost
if ! echo $LISTEN | grep ":" 2>&1; then
ADDRESS="localhost:$LISTEN"
else
ADDRESS=$LISTEN
fi
# I hate bash, and soon you will too
dialog --colors --title "Service Health" --msgbox "\
\ZnOctoPrint: \Zb$(if curl -s -I 127.0.0.1:5000 >/dev/null; then echo '\Z2Online'; elif [[ ! -f /etc/systemd/system/multi-user.target.wants/octoprint.service ]]; then echo "Disabled"; else echo '\Z1Offline'; fi)
\ZnMJPG: \Zb$(if curl -s -I 127.0.0.1:9000 >/dev/null; then echo '\Z2Online'; elif [[ ! -f /etc/systemd/system/multi-user.target.wants/mjpg-streamer.service ]]; then echo "Disabled"; else echo '\Z1Offline'; fi)
\ZnNginx: \Zb$(if curl -k -s -I https://$ADDRESS >/dev/null; then echo '\Z2Online'; elif [[ ! -f /etc/systemd/system/multi-user.target.wants/nginx.service ]]; then echo "Disabled"; else echo '\Z1Offline'; fi)
\ZnSSH: \Zb$(if pgrep sshd >/dev/null; then echo '\Z2Online'; elif [[ ! -f /etc/systemd/system/multi-user.target.wants/sshd.service ]]; then echo "Disabled"; else echo '\Z1Offline'; fi)" 0 0
}
video_menu () {
local VIDEOMENU=$(dialog --title "MJPG Config" --menu "" 10 50 0 \
"1" "Camera Selection" \
"2" "Video Settings" \
"3" "Go Back" 3>&1 1>&2 2>&3)
case $VIDEOMENU in
"1") video_select; video_menu; return 0;;
"2") video_config; video_menu; return 0;;
"3") return 0;;
esac
}

View file

@ -19,7 +19,7 @@ change_password () {
unset PASSWORD
}
service_select () {
service_toggle () {
# Toggle the checkboxes if the service is active or not
local SERVICE_MENU=$(dialog --separate-output --nocancel --title "Select services" --checklist "Enable/disable services" 0 0 0 \
"1" "OctoPrint" $(if [[ -f /etc/systemd/system/multi-user.target.wants/octoprint.service ]]; then echo "ON"; else echo "OFF"; fi) \
@ -69,7 +69,6 @@ service_select () {
systemctl disable ssh
fi
<< 'EOF'
for ((i = 0; i <= 3; i++)); do
for n in "${SERVICE_MENU[@]}"; do
@ -93,7 +92,10 @@ EOF
screen_timeout () {
local TIMEOUT=$(dialog --nocancel --title "Screen Timeout" --inputbox "Input your desired screen timeout in seconds.\nEnter \"off\" to disable the screen timeout.\n\nAdding a screen timeout can reduce screen burn in.\n\nDefault: off" 12 60 "off" 3>&1 1>&2 2>&3)
cat > /home/pi/.xtimeout << EOF
[[ "$TIMEOUT" == "" ]] && return 0
cat > /home/kiosk/.xtimeout << EOF
xset s ${TIMEOUT}
xset -dpms
EOF
@ -104,24 +106,29 @@ nginx_config () {
# Grab the variable from the nginx conf if it exists, otherwise use default
if [[ -f /etc/nginx/listen.conf ]]; then
LISTEN=$(grep -i listen /etc/nginx/listen.conf | awk '{gsub(";",""); print $2}')
LISTEN=$(awk '/listen/{gsub(";",""); print $2}' /etc/nginx/listen.conf)
else
LISTEN="443"
fi
LISTEN=$(dialog --title "Nginx Config" --nocancel --inputbox "Configure what port and IP Nginx should listen on.\nTo listen on all IPs, just enter the port.\nDefault: 443" 11 50 "$LISTEN" 3>&1 1>&2 2>&3)
[[ "$LISTEN" == "" ]] && return 0
# Write new value to nginx
echo "listen $LISTEN;" > /etc/nginx/listen.conf
}
video_config () {
video_select () {
# In the unlikely event that there are no video devices, don't continue
if ! ls /dev/video* 2>&1 >/dev/null; then
dialog --title "Error" --msgbox "No video devices detected!" 10 50
return 1
fi
# Grab config values
source /usr/local/etc/mjpg-server/config.sh
# Grab all video devices
local DEVICES=($(ls /dev/video*))
@ -129,13 +136,41 @@ video_config () {
# Generate a menu from said video devices
for ((i = 0; i < ${#DEVICES[@]}; i++)); do
if [[ "$VIDEO_DEVICE" == ${DEVICES[$i]} ]]; then
DEVICELIST+="${DEVICES[$i]} $i ON "
else
DEVICELIST+="${DEVICES[$i]} $i OFF "
fi
done
local DEVICE_MENU=$(dialog --title "Video Config" --nocancel --radiolist "Choose which video device you wish to use for MJPG-Streamer" 10 50 0 $DEVICELIST 3>&1 1>&2 2>&3)
local DEVICE_MENU=$(dialog --title "MJPG Config" --nocancel --radiolist "Choose which video device you wish to use for MJPG-Streamer" 10 50 0 $DEVICELIST 3>&1 1>&2 2>&3)
[[ "$DEVICE_MENU" == "" ]] && return 0
# Write selected value to startup script
echo -e '#!/bin/bash'"\n/usr/local/bin/mjpeg-server -a 127.0.0.1:9000 -- ffmpeg -i $DEVICE_MENU -f v4l2 -f mpjpeg -" > /usr/local/bin/start-mjpg
# Write selected value to config file
echo -e "VIDEO_DEVICE=$DEVICE_MENU\nVIDEO_SIZE=$VIDEO_SIZE\nFRAMERATE=$FRAMERATE" > /usr/local/etc/mjpg-server/config.sh
}
video_config () {
# Include config values
source /usr/local/etc/mjpg-server/config.sh
# Set video device to a resonable default if it isn't set for some reason
if [[ "$VIDEO_DEVICE" == "" ]]; then
VIDEO_DEVICE="/dev/video0"
fi
local VIDEOCONFIG_MENU=$(dialog --nocancel --title "MJPG Config" --form "Choose desired camera resolution and framerate." 10 50 0\
"Resolution: " 1 1 "$VIDEO_SIZE" 1 13 10 0 \
"Framerate: " 2 1 "$FRAMERATE" 2 12 3 0 3>&1 1>&2 2>&3)
VIDEOCONFIG_MENU=($VIDEOCONFIG_MENU)
if [[ "$VIDEOCONFIG_MENU[0]" == "" ]] || [[ "$VIDEOCONFIG_MENU[1]" == "" ]]; then
dialog --title "Error" --msgbox "Invalid input!" 10 50
video_config
return 0
fi
# Write values to config file
echo -e "VIDEO_DEVICE=$VIDEO_DEVICE\nVIDEO_SIZE=${VIDEOCONFIG_MENU[0]}\nFRAMERATE=${VIDEOCONFIG_MENU[1]}" > /usr/local/etc/mjpg-server/config.sh
}

View file

@ -1,41 +1,7 @@
#!/bin/bash -e
#echo -n -e "NODM_USER=${FIRST_USER_NAME}\nNODM_XSESSION=/home/${FIRST_USER_NAME}/.xprofile" > ${ROOTFS_DIR}/etc/nodm.conf
cat > ${ROOTFS_DIR}/etc/default/nodm << EOF
# nodm configuration
# Set NODM_ENABLED to something different than 'false' to enable nodm
NODM_ENABLED=true
# User to autologin for
NODM_USER=${FIRST_USER_NAME}
# First vt to try when looking for free VTs
NODM_FIRST_VT=7
# X session
NODM_XSESSION=/home/${FIRST_USER_NAME}/.xprofile
# Options for nodm itself
NODM_OPTIONS=
# Options for the X server.
#
# Format: [/usr/bin/<Xserver>] [:<disp>] <Xserver-options>
#
# The Xserver executable and the display name can be omitted, but should
# be placed in front, if nodm's defaults shall be overridden.
NODM_X_OPTIONS='-nolisten tcp'
# If an X session will run for less than this time in seconds, nodm will wait an
# increasing bit of time before restarting the session.
NODM_MIN_SESSION_TIME=60
# Timeout (in seconds) to wait for X to be ready to accept connections. If X is
# not ready before this timeout, it is killed and restarted.
NODM_X_TIMEOUT=300
EOF
mkdir -p ${ROOTFS_DIR}/etc/default
install -m 644 files/nodm ${ROOTFS_DIR}/etc/default/nodm
# Probably not needed
on_chroot << EOF

View file

@ -0,0 +1,33 @@
# nodm configuration
# Set NODM_ENABLED to something different than 'false' to enable nodm
NODM_ENABLED=true
# User to autologin for
NODM_USER=kiosk
# First vt to try when looking for free VTs
NODM_FIRST_VT=7
# X session
NODM_XSESSION=/home/kiosk/.xprofile
# Options for nodm itself
NODM_OPTIONS=
# Options for the X server.
#
# Format: [/usr/bin/<Xserver>] [:<disp>] <Xserver-options>
#
# The Xserver executable and the display name can be omitted, but should
# be placed in front, if nodm's defaults shall be overridden.
NODM_X_OPTIONS='-nolisten tcp'
# If an X session will run for less than this time in seconds, nodm will wait an
# increasing bit of time before restarting the session.
NODM_MIN_SESSION_TIME=60
# Timeout (in seconds) to wait for X to be ready to accept connections. If X is
# not ready before this timeout, it is killed and restarted.
NODM_X_TIMEOUT=300