diff --git a/README.md b/README.md index 64ff1e1..2ce04cf 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ TODO - If OctoPrint is enabled, you can access it at `https://RPI-IP`, replacing RPI-IP with the IP address of your Raspberry Pi. ### Configuring TouchPrint -- TouchPrint can be configured either over SSH or in a TTY using the `octo-config` script. This script is provided to make management of core features easier and to consolidate TouchPrint's settings into one place. +- TouchPrint can be configured either over SSH or in a TTY using the `tp-config` script. This script is provided to make management of core features easier and to consolidate TouchPrint's settings into one place. - OctoPrint can be configured through the OctoPrint UI as normal. # Reporting Bugs diff --git a/TODO.md b/TODO.md index 9297912..9e355be 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,9 @@ # TODO: -## First time/Octo-Config +## First time/TP-Config - Add network configuration (replace nmtui) - Add hostname configuration (replace nmtui) +- Add Enclosure plugin to suggested ## Misc - More security diff --git a/stage2/04-octoprint/files/config.yaml b/stage2/04-octoprint/files/config.yaml index 8504664..d7c437f 100644 --- a/stage2/04-octoprint/files/config.yaml +++ b/stage2/04-octoprint/files/config.yaml @@ -1,3 +1,7 @@ +accessControl: + autologinLocal: true + localNetworks: + - 127.0.0.0/8 webcam: stream: /webcam/ ffmpeg: /usr/bin/ffmpeg diff --git a/stage2/06-utils/00-packages b/stage2/06-utils/00-packages new file mode 100644 index 0000000..ecb5ab1 --- /dev/null +++ b/stage2/06-utils/00-packages @@ -0,0 +1 @@ +python3-pip diff --git a/stage2/06-utils/00-run.sh b/stage2/06-utils/00-run.sh index 5c24ad2..3f91090 100755 --- a/stage2/06-utils/00-run.sh +++ b/stage2/06-utils/00-run.sh @@ -2,9 +2,10 @@ set -e mkdir -p "${ROOTFS_DIR}/usr/local/bin/" -install -m 755 files/octo-config "${ROOTFS_DIR}/usr/local/bin/octo-config" +install -m 755 files/tp-config "${ROOTFS_DIR}/usr/local/bin/tp-config" +install -m 755 files/octo-settings "${ROOTFS_DIR}/usr/local/bin/octo-settings" install -m 755 files/first-time.sh "${ROOTFS_DIR}/etc/profile.d/first-time.sh" -install -m 755 files/octo-lib.sh "${ROOTFS_DIR}/usr/local/lib/octo-lib.sh" +install -m 755 files/tp-lib.sh "${ROOTFS_DIR}/usr/local/lib/tp-lib.sh" # Autologin on first boot mkdir -p ${ROOTFS_DIR}/etc/systemd/system/getty@tty1.service.d/ @@ -14,7 +15,9 @@ ExecStart= ExecStart=-/usr/sbin/agetty --autologin root --noclear %I $TERM EOF -# Don't boot to a GUI on_chroot << EOF +# Install PyYAML +pip3 install pyyaml +# Don't boot to a GUI systemctl set-default multi-user.target EOF diff --git a/stage2/06-utils/files/first-time.sh b/stage2/06-utils/files/first-time.sh index f261a68..ae6fc53 100755 --- a/stage2/06-utils/files/first-time.sh +++ b/stage2/06-utils/files/first-time.sh @@ -2,13 +2,13 @@ # This should never happen, no harm in checking though ;) if [ "$EUID" -ne 0 ]; then - echo "This image has not been configured properly. Please complain to Logan" + echo "This image has not been configured properly. Please file an issue at https://github.com/logan2611/touchprint/issues" bash exit 1 fi # Import common functions -source /usr/local/lib/octo-lib.sh +source /usr/local/lib/tp-lib.sh install_package () { echo "==========Installing $1==========" >>/home/pi/install.log @@ -21,7 +21,7 @@ error_install () { } recommended_menu () { - local RECOMMEND_MENU=$(dialog --nocancel --title "Plugin Manager | Recommended Plugins" --checklist "Check plugins that you wish to install" 0 0 0 \ + local RECOMMEND_MENU=$(dialog --nocancel --title "Plugin Manager | Recommended Plugins" --checklist "Check plugins that you wish to install." 0 0 0 \ "OctoPrint-Dashboard" "Adds a nice dashboard to OctoPrint." ON \ "ExcludeRegion" "Select regions of the bed where you don't want to print." ON \ "NavbarTemp" "Shows the temperature of the Pi, extruder(s) and bed in the navigation bar." ON \ @@ -45,7 +45,7 @@ recommended_menu () { } suggested_menu () { - local SUGGEST_MENU=$(dialog --nocancel --title "Plugin Manager | Suggested Plugins" --checklist "Check plugins that you wish to install" 0 0 0 \ + local SUGGEST_MENU=$(dialog --nocancel --title "Plugin Manager | Suggested Plugins" --checklist "Check plugins that you wish to install.\n\nSome of these may conflict with the recommended plugins." 0 0 0 \ "Themeify" "Adds theming supports and a few themes to OctoPrint." OFF \ "Preheat" "Adds a preheat button to preheat the bed and extruder to the temperature set in the selected gcode file." OFF \ "ConsolidatedTabs" "Allows you to combine several tabs into one larger tab with draggable and resizable panels." OFF \ @@ -64,11 +64,14 @@ suggested_menu () { done } -dialog --title "NOTICE" --nocancel --colors --msgbox "This collection of software is currently in beta. It is lacking several critical features. \Zb\Z1DO NOT\Zn use this in a production environment." 10 50 +dialog --title "NOTICE" --nocancel --colors --msgbox "This collection of software is currently in beta, it may contain several bugs. This software is \Zb\Z1NOT\Zn recommended for a production environment." 10 50 + +# 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 # Force the user to change the pi user's password before the RPi gets botnetted change_password -# Randomize the root and frontend password +# Randomize the root password 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 @@ -82,12 +85,15 @@ 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 +# If a touchscreen is detected, and the GUI is enabled, ask the user if they want to calibrate it +if ( udevadm info --export-db | grep ID_INPUT_TOUCHSCREEN=1 >/dev/null ) && [[ $(readlink -f /etc/systemd/system/default.target) == "/usr/lib/systemd/system/graphical.target" ]] && 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 +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 +# If OctoPrint and the GUI are running locally, ask the user if they want to change the autologin user +if [[ -f /etc/systemd/system/multi-user.target.wants/octoprint.service ]] && [[ $(readlink -f /etc/systemd/system/default.target) == "/usr/lib/systemd/system/graphical.target" ]] && dialog --title "OctoPrint AutoLogin" --yesno "Do you wish to configure the user that the GUI auto logs in as in OctoPrint?\nThis is required if you wish to enable access control in OctoPrint." 10 60; then + octo_autologin +fi # If OctoPrint/MJPG Streamer is running locally, ask if the user wants to change the default listening port/IP (optional) if ( [[ -f /etc/systemd/system/multi-user.target.wants/octoprint.service ]] || [[ -f /etc/systemd/system/multi-user.target.wants/mjpg-streamer.service ]] ) && dialog --title "Nginx Config" --defaultno --yesno "Do you wish to change the default Nginx listening address and/or port?" 10 60; then @@ -112,6 +118,7 @@ fi rm /etc/systemd/system/getty@tty1.service.d/override.conf rm /etc/profile.d/first-time.sh +dialog --title "TouchPrint Config" --colors --msgbox "Congratulations! Your install of TouchPrint has been successfully configured.\n\n\Z1To change these settings later, login to your Raspberry Pi and run \"\Z1\Zbtp-config\Zn\Z1\"." 0 0 dialog --title "TouchPrint Config" --infobox "Rebooting..." 0 0 sleep 1 reboot diff --git a/stage2/06-utils/files/octo-settings b/stage2/06-utils/files/octo-settings new file mode 100644 index 0000000..aa35f17 --- /dev/null +++ b/stage2/06-utils/files/octo-settings @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +import yaml +import sys + +def loadConfig(path): + with open(path, 'r') as f: + return yaml.full_load(f) + +def writeConfig(path, config): + with open(path, 'w') as f: + return yaml.dump(config, f) + + +def getValue(config, args): + cur = config + for arg in args: + if arg not in cur.keys(): + return + else: + cur = cur[arg] + + return cur + +def setValue(config, args, value): + cur = config + for arg in args[:-1]: + if arg not in cur.keys(): + cur[arg] = {} + cur = cur[arg] + + cur[args[-1]] = value + +if __name__ == '__main__': + if len(sys.argv) > 2: + config = loadConfig(r'/home/octoprint/.octoprint/config.yaml') + if sys.argv[1] == 'read': + print(getValue(config, sys.argv[2:])) + elif sys.argv[1] == 'write': + print(sys.argv[2:-1]) + print(sys.argv[-1]) + setValue(config, sys.argv[2:-1], sys.argv[-1]) + writeConfig(r'/home/octoprint/.octoprint/config.yaml', config) + else: + print('Octo-Settings v1 - A command line utility to change and read OctoPrint\'s settings.') + print('') + print('Usage: ', sys.argv[0], 'read [KEY1] [KEY2] ...') + print(' ', sys.argv[0], 'write [KEY1] [KEY2] ... [VALUE]') + + diff --git a/stage2/06-utils/files/octo-config b/stage2/06-utils/files/tp-config similarity index 81% rename from stage2/06-utils/files/octo-config rename to stage2/06-utils/files/tp-config index 4afd96c..f8dd527 100755 --- a/stage2/06-utils/files/octo-config +++ b/stage2/06-utils/files/tp-config @@ -1,12 +1,20 @@ -#!/bin/bash +#!/usr/bin/env bash + +if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then + echo -e "TP-Config - Configures TouchPrint" + echo -e "Usage: $0" +fi if [ "$EUID" -ne 0 ]; then echo "This script needs to be run as root." exit 1 fi +# Define ASK_REBOOT +ASK_REBOOT=false + # Import shared functions -source /usr/local/lib/octo-lib.sh +source /usr/local/lib/tp-lib.sh main_menu () { local MAINMENU=$(dialog --nocancel --title "TouchPrint Setup" --menu "" 10 50 0 \ @@ -36,14 +44,16 @@ services_menu () { "2" "Service health check" \ "3" "Configure Nginx" \ "4" "Configure MJPG" \ - "5" "Go Back" 3>&1 1>&2 2>&3) + "5" "Configure OctoPrint" \ + "6" "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_menu; services_menu; return 0;; "4") video_menu; services_menu; return 0;; - "5") return 0;; + "5") octo_menu; services_menu; return 0;; + "6") return 0;; esac } @@ -94,9 +104,20 @@ video_menu () { "2") video_config; video_menu; return 0;; "3") return 0;; esac -} +} + +octo_menu () { + local OCTOMENU=$(dialog --title "OctoPrint Config" --menu "" 10 50 0 \ + "1" "Autologin User" \ + "2" "Go Back" 3>&1 1>&2 2>&3) + + case $OCTOMENU in + "1") octo_autologin; octo_menu; return 0;; + "2") return 0;; + esac +} main_menu -if dialog --title "Reboot Confirmation" --yesno "Some changes require a reboot to take effect.\nDo you want to reboot now?" 10 50; then +if [[ $ASK_REBOOT == true ]] && dialog --title "Reboot Confirmation" --yesno "Some changes require a reboot to take effect.\nDo you want to reboot now?" 10 50; then reboot fi diff --git a/stage2/06-utils/files/octo-lib.sh b/stage2/06-utils/files/tp-lib.sh similarity index 83% rename from stage2/06-utils/files/octo-lib.sh rename to stage2/06-utils/files/tp-lib.sh index 4d99c67..22da1e1 100644 --- a/stage2/06-utils/files/octo-lib.sh +++ b/stage2/06-utils/files/tp-lib.sh @@ -2,20 +2,23 @@ change_password () { local PASSWORD="$(dialog --title "Change Password" --nocancel --insecure --passwordbox "Enter new password for user \"pi\"" 10 50 3>&1 1>&2 2>&3)" # If the password field was left blank, exit if [[ $? -ne 0 ]] || [[ $PASSWORD == "" ]]; then return 1; fi + # If the password is raspberry, tell the user he is an idiot if [[ "$PASSWORD" == "raspberry" ]]; then dialog --title "Change Password" --nocancel --msgbox "That password sucks. Please use a different one :)" 10 50 change_password return 0 fi + if [[ "$(dialog --nocancel --insecure --passwordbox "Confirm new password for user \"pi\"" 10 50 3>&1 1>&2 2>&3)" == "$PASSWORD" ]]; then if [[ $? != 0 ]]; then return 1; fi echo -e "pi:$PASSWORD" | chpasswd else - dialog --title "Change Password" --nocancel --msgbox "Passwords did not match!" 10 50 + dialog --title "Change Password" --nocancel --colors --msgbox "\Z1\ZbPasswords did not match!" 5 30 change_password return 0 fi + unset PASSWORD } @@ -75,6 +78,8 @@ service_toggle () { systemctl disable ssh fi + ASK_REBOOT=true + << 'EOF' for ((i = 0; i <= 3; i++)); do for n in "${SERVICE_MENU[@]}"; do @@ -106,6 +111,19 @@ screen_timeout () { xset -dpms xset s noblank EOF + + if [[ $(readlink -f /etc/systemd/system/default.target) == "/usr/lib/systemd/system/graphical.target" ]]; then + ASK_REBOOT=true + fi +} + +octo_autologin () { + local AUTOLOGIN_MENU="$(dialog --title "OctoPrint AutoLogin" --nocancel --inputbox "Enter the username of the user that you want the GUI to autologin as on startup." 10 50 $(octo-settings read accessControl autologinAs) 3>&1 1>&2 2>&3)" + octo-settings write accessControl autologinAs $AUTOLOGIN_MENU + + if [[ -f /etc/systemd/system/multi-user.target.wants/octoprint.service ]]; then + systemctl restart octoprint + fi } nginx_listen () { @@ -124,6 +142,11 @@ nginx_listen () { # Write new value to nginx echo "listen $LISTEN;" > /etc/nginx/listen.conf + + if [[ -f /etc/systemd/system/multi-user.target.wants/nginx.service ]]; then + systemctl restart nginx + ASK_REBOOT=true + fi } nginx_auth () { @@ -141,7 +164,7 @@ nginx_auth () { # If only one of them is blank, make the user start over if [[ ${NGINXAUTH_MENU[0]} == "" ]] || [[ ${NGINXAUTH_MENU[1]} == "" ]]; then - dialog --title "Error" --msgbox "Invalid input!" 10 50 + dialog --title "Nginx Config" --colors --msgbox "\Z1\ZbInvalid input!" 5 20 nginx_auth return 0 fi @@ -155,12 +178,16 @@ nginx_auth () { # Set perms so that no one steals our precious password hashes chown root:www-data /etc/nginx/.htpasswd chmod 640 /etc/nginx/.htpasswd + + if [[ -f /etc/systemd/system/multi-user.target.wants/nginx.service ]]; then + systemctl restart nginx + fi } 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 + dialog --title "Video Config" --colors --msgbox "\Z1\ZbNo video devices detected!" 5 30 return 1 fi @@ -186,7 +213,11 @@ video_select () { [[ "$DEVICE_MENU" == "" ]] && return 0 # 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 + echo -e "VIDEO_DEVICE=$DEVICE_MENU\nVIDEO_SIZE=$VIDEO_SIZE\nFRAMERATE=$FRAMERATE" > /usr/local/etc/mjpg-server/config.sh + + if [[ -f /etc/systemd/system/multi-user.target.wants/mjpg-streamer.service ]]; then + systemctl restart mjpg-streamer + fi } video_config () { @@ -211,4 +242,8 @@ video_config () { # 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 + + if [[ -f /etc/systemd/system/multi-user.target.wants/mjpg-streamer.service ]]; then + systemctl restart mjpg-streamer + fi }