commit f9591d14ad0322557d2dae02d80501ff203b5fcc Author: Felix Stupp Date: Fri Apr 17 00:36:06 2020 +0200 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e0cad8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,78 @@ + +# Created by https://www.gitignore.io/api/code,vim,linux,windows +# Edit at https://www.gitignore.io/?templates=code,vim,linux,windows + +### Code ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist + +# Auto-generated tag files +tags + +# Persistent undo +[._]*.un~ + +# Coc configuration directory +.vim + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.gitignore.io/api/code,vim,linux,windows + diff --git a/debian-inst/.gitignore b/debian-inst/.gitignore new file mode 100644 index 0000000..224de35 --- /dev/null +++ b/debian-inst/.gitignore @@ -0,0 +1,5 @@ +** +!/* +!/isolinux/** +*.iso +*.img diff --git a/debian-inst/image_info.txt b/debian-inst/image_info.txt new file mode 100644 index 0000000..5ffb002 --- /dev/null +++ b/debian-inst/image_info.txt @@ -0,0 +1 @@ +https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-10.3.0-amd64-netinst.iso diff --git a/debian-inst/isolinux/menu.cfg b/debian-inst/isolinux/menu.cfg new file mode 100644 index 0000000..f6142de --- /dev/null +++ b/debian-inst/isolinux/menu.cfg @@ -0,0 +1,16 @@ +menu hshift 4 +menu width 70 + +menu title ImageViewer for Kiosk Installer +include stdmenu.cfg +label kioskinstall + menu label ^Install ImageViewer + kernel /install.amd/vmlinuz + append vga=788 initrd=/install.amd/initrd_mod.gz --- quiet +menu begin installer + menu label Default Debian GNU/Linux installer menu + label kioskmenu + menu label ^Back.. + menu exit + include menu_installer.cfg +menu end diff --git a/debian-inst/makefile b/debian-inst/makefile new file mode 100644 index 0000000..cfc67bb --- /dev/null +++ b/debian-inst/makefile @@ -0,0 +1,44 @@ +preseed:=preseed.cfg +iso_dir:=iso_dir +install_dir:=${iso_dir}/install.amd +initrd:=${install_dir}/initrd +initrd_mod:=${initrd}_mod +boot_dir:=${iso_dir}/isolinux +sum_type:=md5sum +chksum_file:=${iso_dir}/${sum_type}.txt + +.PHONY: main +main: build + +.PHONY: build +build: modified.iso + +modified.iso: orig.iso makefile ${preseed} isolinux ../playbook + if [ -d "${iso_dir}" ]; then chmod +w -R "${iso_dir}" && rm -rf "${iso_dir}"; fi + 7z x -o"${iso_dir}" "$<" + chmod +w -R "${install_dir}" + < "${initrd}.gz" gzip -d > "${initrd_mod}" + echo "${preseed}" | fakeroot cpio -H newc -o -A -F "${initrd_mod}" + gzip "${initrd_mod}" + chmod -w -R "${install_dir}" + mv "${boot_dir}/menu.cfg" "${boot_dir}/menu_installer.cfg" + cp -r isolinux/* "${boot_dir}" + cp -r ../playbook "${iso_dir}/playbook" + echo "localhost ansible_connection=local" > "${iso_dir}/playbook/hosts" + rm -rf "${iso_dir}/playbook/credentials" + chmod +w "${chksum_file}" + cd "$(dir ${chksum_file})" && "${sum_type}" `find . -follow -type f \! -name "$(notdir ${chksum_file})"` > "$(notdir ${chksum_file})" + chmod -w "${chksum_file}" + genisoimage -r -J -b "isolinux/isolinux.bin" -c "isolinux/boot.cat" -no-emul-boot -boot-load-size 4 -boot-info-table -o "$@" "${iso_dir}" + #chmod +w -R "${iso_dir}" && rm -rf "${iso_dir}" + +orig.iso: image_info.txt + curl --location "$$(cat "$<")" > "$@" + +.PHONY: clean +clean: + rm -rf modified.iso + +.PHONY: clean-all +clean-all: clean + rm -rf orig.iso diff --git a/debian-inst/preseed.cfg b/debian-inst/preseed.cfg new file mode 100644 index 0000000..cf27420 --- /dev/null +++ b/debian-inst/preseed.cfg @@ -0,0 +1,398 @@ +#### Contents of the preconfiguration file (for buster) +### Localization +# Preseeding only locale sets language, country and locale. +d-i debian-installer/locale string de_DE.UTF-8 + +# The values can also be preseeded individually for greater flexibility. +#d-i debian-installer/language string en +#d-i debian-installer/country string NL +#d-i debian-installer/locale string en_GB.UTF-8 +# Optionally specify additional locales to be generated. +d-i localechooser/supported-locales multiselect en_US.UTF-8 + +# Keyboard selection. +d-i keyboard-configuration/xkb-keymap select de +# d-i keyboard-configuration/toggle select No toggling + +### Network configuration +# Disable network configuration entirely. This is useful for cdrom +# installations on non-networked devices where the network questions, +# warning and long timeouts are a nuisance. +#d-i netcfg/enable boolean false + +# netcfg will choose an interface that has link if possible. This makes it +# skip displaying a list if there is more than one interface. +d-i netcfg/choose_interface select auto + +# To pick a particular interface instead: +#d-i netcfg/choose_interface select eth1 + +# To set a different link detection timeout (default is 3 seconds). +# Values are interpreted as seconds. +#d-i netcfg/link_wait_timeout string 10 + +# If you have a slow dhcp server and the installer times out waiting for +# it, this might be useful. +#d-i netcfg/dhcp_timeout string 60 +#d-i netcfg/dhcpv6_timeout string 60 + +# If you prefer to configure the network manually, uncomment this line and +# the static network configuration below. +#d-i netcfg/disable_autoconfig boolean true + +# If you want the preconfiguration file to work on systems both with and +# without a dhcp server, uncomment these lines and the static network +# configuration below. +#d-i netcfg/dhcp_failed note +#d-i netcfg/dhcp_options select Configure network manually + +# Static network configuration. +# +# IPv4 example +#d-i netcfg/get_ipaddress string 192.168.1.42 +#d-i netcfg/get_netmask string 255.255.255.0 +#d-i netcfg/get_gateway string 192.168.1.1 +#d-i netcfg/get_nameservers string 192.168.1.1 +#d-i netcfg/confirm_static boolean true +# +# IPv6 example +#d-i netcfg/get_ipaddress string fc00::2 +#d-i netcfg/get_netmask string ffff:ffff:ffff:ffff:: +#d-i netcfg/get_gateway string fc00::1 +#d-i netcfg/get_nameservers string fc00::1 +#d-i netcfg/confirm_static boolean true + +# Any hostname and domain names assigned from dhcp take precedence over +# values set here. However, setting the values still prevents the questions +# from being shown, even if values come from dhcp. +d-i netcfg/get_hostname string imageviewer +d-i netcfg/get_domain string local + +# If you want to force a hostname, regardless of what either the DHCP +# server returns or what the reverse DNS entry for the IP is, uncomment +# and adjust the following line. +d-i netcfg/hostname string imageviewer + +# Disable that annoying WEP key dialog. +d-i netcfg/wireless_wep string +# The wacky dhcp hostname that some ISPs use as a password of sorts. +#d-i netcfg/dhcp_hostname string radish + +# If non-free firmware is needed for the network or other hardware, you can +# configure the installer to always try to load it, without prompting. Or +# change to false to disable asking. +d-i hw-detect/load_firmware boolean true + +### Network console +# Use the following settings if you wish to make use of the network-console +# component for remote installation over SSH. This only makes sense if you +# intend to perform the remainder of the installation manually. +#d-i anna/choose_modules string network-console +#d-i network-console/authorized_keys_url string http://10.0.0.1/openssh-key +#d-i network-console/password password r00tme +#d-i network-console/password-again password r00tme + +### Mirror settings +# If you select ftp, the mirror/country string does not need to be set. +#d-i mirror/protocol string ftp +d-i mirror/country string manual +#d-i mirror/http/hostname string ftp.de.debian.org +d-i mirror/http/hostname string 10.11.11.64:9999 +d-i mirror/http/directory string /debian +d-i mirror/http/proxy string + +# Suite to install. +#d-i mirror/suite string testing +# Suite to use for loading installer components (optional). +#d-i mirror/udeb/suite string testing + +### Account setup +# Skip creation of a root account (normal user account will be able to +# use sudo). +d-i passwd/root-login boolean true +# Alternatively, to skip creation of a normal user account. +d-i passwd/make-user boolean false + +# Root password, either in clear text +d-i passwd/root-password password r00tme +d-i passwd/root-password-again password r00tme +# or encrypted using a crypt(3) hash. +#d-i passwd/root-password-crypted password [crypt(3) hash] + +# To create a normal user account. +#d-i passwd/user-fullname string Debian User +#d-i passwd/username string debian +# Normal user's password, either in clear text +#d-i passwd/user-password password insecure +#d-i passwd/user-password-again password insecure +# or encrypted using a crypt(3) hash. +#d-i passwd/user-password-crypted password [crypt(3) hash] +# Create the first user with the specified UID instead of the default. +#d-i passwd/user-uid string 1010 + +# The user account will be added to some standard initial groups. To +# override that, use this. +#d-i passwd/user-default-groups string audio cdrom video + +### Clock and time zone setup +# Controls whether or not the hardware clock is set to UTC. +d-i clock-setup/utc boolean true + +# You may set this to any valid setting for $TZ; see the contents of +# /usr/share/zoneinfo/ for valid values. +d-i time/zone string Europe/Berlin + +# Controls whether to use NTP to set the clock during the install +d-i clock-setup/ntp boolean true +# NTP server to use. The default is almost always fine here. +#d-i clock-setup/ntp-server string ntp.example.com + +### Partitioning +## Partitioning example +# If the system has free space you can choose to only partition that space. +# This is only honoured if partman-auto/method (below) is not set. +#d-i partman-auto/init_automatically_partition select biggest_free + +# Alternatively, you may specify a disk to partition. If the system has only +# one disk the installer will default to using that, but otherwise the device +# name must be given in traditional, non-devfs format (so e.g. /dev/sda +# and not e.g. /dev/discs/disc0/disc). +# For example, to use the first SCSI/SATA hard disk: +#d-i partman-auto/disk string /dev/sda +# In addition, you'll need to specify the method to use. +# The presently available methods are: +# - regular: use the usual partition types for your architecture +# - lvm: use LVM to partition the disk +# - crypto: use LVM within an encrypted partition +d-i partman-auto/method string regular + +# You can define the amount of space that will be used for the LVM volume +# group. It can either be a size with its unit (eg. 20 GB), a percentage of +# free space or the 'max' keyword. +d-i partman-auto-lvm/guided_size string max + +# If one of the disks that are going to be automatically partitioned +# contains an old LVM configuration, the user will normally receive a +# warning. This can be preseeded away... +d-i partman-lvm/device_remove_lvm boolean true +# The same applies to pre-existing software RAID array: +d-i partman-md/device_remove_md boolean true +# And the same goes for the confirmation to write the lvm partitions. +d-i partman-lvm/confirm boolean true +d-i partman-lvm/confirm_nooverwrite boolean true + +# You can choose one of the three predefined partitioning recipes: +# - atomic: all files in one partition +# - home: separate /home partition +# - multi: separate /home, /var, and /tmp partitions +d-i partman-auto/choose_recipe select atomic + +# Or provide a recipe of your own... +# If you have a way to get a recipe file into the d-i environment, you can +# just point at it. +#d-i partman-auto/expert_recipe_file string /hd-media/recipe + +# If not, you can put an entire recipe into the preconfiguration file in one +# (logical) line. This example creates a small /boot partition, suitable +# swap, and uses the rest of the space for the root partition: +#d-i partman-auto/expert_recipe string \ +# boot-root :: \ +# 40 50 100 ext3 \ +# $primary{ } $bootable{ } \ +# method{ format } format{ } \ +# use_filesystem{ } filesystem{ ext3 } \ +# mountpoint{ /boot } \ +# . \ +# 500 10000 1000000000 ext3 \ +# method{ format } format{ } \ +# use_filesystem{ } filesystem{ ext3 } \ +# mountpoint{ / } \ +# . \ +# 64 512 300% linux-swap \ +# method{ swap } format{ } \ +# . + +# The full recipe format is documented in the file partman-auto-recipe.txt +# included in the 'debian-installer' package or available from D-I source +# repository. This also documents how to specify settings such as file +# system labels, volume group names and which physical devices to include +# in a volume group. + +# This makes partman automatically partition without confirmation, provided +# that you told it what to do using one of the methods above. +d-i partman-partitioning/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true + +# When disk encryption is enabled, skip wiping the partitions beforehand. +#d-i partman-auto-crypto/erase_disks boolean false + +# This makes partman automatically partition without confirmation. +d-i partman-md/confirm boolean true +d-i partman-partitioning/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true + +## Controlling how partitions are mounted +# The default is to mount by UUID, but you can also choose "traditional" to +# use traditional device names, or "label" to try filesystem labels before +# falling back to UUIDs. +d-i partman/mount_style select uuid + +### Base system installation +# Configure APT to not install recommended packages by default. Use of this +# option can result in an incomplete system and should only be used by very +# experienced users. +#d-i base-installer/install-recommends boolean false + +# The kernel image (meta) package to be installed; "none" can be used if no +# kernel is to be installed. +#d-i base-installer/kernel/image string linux-image-686 + +### Apt setup +# You can choose to install non-free and contrib software. +#d-i apt-setup/non-free boolean true +#d-i apt-setup/contrib boolean true +# Uncomment this if you don't want to use a network mirror. +#d-i apt-setup/use_mirror boolean false +# Select which update services to use; define the mirrors to be used. +# Values shown below are the normal defaults. +#d-i apt-setup/services-select multiselect security, updates +#d-i apt-setup/security_host string security.debian.org + +# Additional repositories, local[0-9] available +#d-i apt-setup/local0/repository string \ +# http://local.server/debian stable main +#d-i apt-setup/local0/comment string local server +# Enable deb-src lines +#d-i apt-setup/local0/source boolean true +# URL to the public key of the local repository; you must provide a key or +# apt will complain about the unauthenticated repository and so the +# sources.list line will be left commented out +#d-i apt-setup/local0/key string http://local.server/key + +# By default the installer requires that repositories be authenticated +# using a known gpg key. This setting can be used to disable that +# authentication. Warning: Insecure, not recommended. +#d-i debian-installer/allow_unauthenticated boolean true + +# Uncomment this to add multiarch configuration for i386 +#d-i apt-setup/multiarch string i386 + +# Do not ask for cdroms +d-i apt-setup/cdrom/set-first boolean false + + +### Package selection +tasksel tasksel/first multiselect standard + +# Individual additional packages to install +# Added packages required for ansible execution and bootstrap role +d-i pkgsel/include string ansible +# Whether to upgrade packages after debootstrap. +# Allowed values: none, safe-upgrade, full-upgrade +d-i pkgsel/upgrade select safe-upgrade + +# Some versions of the installer can report back on what software you have +# installed, and what software you use. The default is not to report back, +# but sending reports helps the project determine what software is most +# popular and include it on CDs. +popularity-contest popularity-contest/participate boolean false + +### Boot loader installation +# Grub is the default boot loader (for x86). If you want lilo installed +# instead, uncomment this: +#d-i grub-installer/skip boolean true +# To also skip installing lilo, and install no bootloader, uncomment this +# too: +#d-i lilo-installer/skip boolean true + + +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true + +# This one makes grub-installer install to the MBR if it also finds some other +# OS, which is less safe as it might not be able to boot that other OS. +d-i grub-installer/with_other_os boolean true + +# Due notably to potential USB sticks, the location of the MBR can not be +# determined safely in general, so this needs to be specified: +#d-i grub-installer/bootdev string /dev/sda +# To install to the first device (assuming it is not a USB stick): +d-i grub-installer/bootdev string default + +# Alternatively, if you want to install to a location other than the mbr, +# uncomment and edit these lines: +#d-i grub-installer/only_debian boolean false +#d-i grub-installer/with_other_os boolean false +#d-i grub-installer/bootdev string (hd0,1) +# To install grub to multiple disks: +#d-i grub-installer/bootdev string (hd0,1) (hd1,1) (hd2,1) + +# Optional password for grub, either in clear text +#d-i grub-installer/password password r00tme +#d-i grub-installer/password-again password r00tme +# or encrypted using an MD5 hash, see grub-md5-crypt(8). +#d-i grub-installer/password-crypted password [MD5 hash] + +# Use the following option to add additional boot parameters for the +# installed system (if supported by the bootloader installer). +# Note: options passed to the installer will be added automatically. +#d-i debian-installer/add-kernel-opts string nousb + +### Finishing up the installation +# During installations from serial console, the regular virtual consoles +# (VT1-VT6) are normally disabled in /etc/inittab. Uncomment the next +# line to prevent this. +#d-i finish-install/keep-consoles boolean true + +# Avoid that last message about the install being complete. +d-i finish-install/reboot_in_progress note + +# This will prevent the installer from ejecting the CD during the reboot, +# which is useful in some situations. +#d-i cdrom-detect/eject boolean false + +# This is how to make the installer shutdown when finished, but not +# reboot into the installed system. +#d-i debian-installer/exit/halt boolean true +# This will power off the machine instead of just halting it. +#d-i debian-installer/exit/poweroff boolean true + +### Preseeding other packages +# Depending on what software you choose to install, or if things go wrong +# during the installation process, it's possible that other questions may +# be asked. You can preseed those too, of course. To get a list of every +# possible question that could be asked during an install, do an +# installation, and then run these commands: +# debconf-get-selections --installer > file +# debconf-get-selections >> file + + +#### Advanced options +### Running custom commands during the installation +# d-i preseeding is inherently not secure. Nothing in the installer checks +# for attempts at buffer overflows or other exploits of the values of a +# preconfiguration file like this one. Only use preconfiguration files from +# trusted locations! To drive that home, and because it's generally useful, +# here's a way to run any shell command you'd like inside the installer, +# automatically. + +# This first command is run as early as possible, just after +# preseeding is read. +#d-i preseed/early_command string anna-install some-udeb +# This command is run immediately before the partitioner starts. It may be +# useful to apply dynamic partitioner preseeding that depends on the state +# of the disks (which may not be visible when preseed/early_command runs). +#d-i partman/early_command \ +# string debconf-set partman-auto/disk "$(list-devices disk | head -n1)" +# This command is run just before the install finishes, but when there is +# still a usable /target directory. You can chroot to /target and use it +# directly, or use the apt-install and in-target commands to easily install +# packages and run commands in the target system. +#d-i preseed/late_command string apt-install zsh; in-target chsh -s /bin/zsh +#d-i preseed/late_command string cp -r /cdrom/playbook /target/playbook && in-target /bin/bash /playbook/install_cron.sh +d-i preseed/late_command string cp -r /cdrom/playbook /target/playbook && in-target sh -c '(crontab -l 2>/dev/null; echo "TERM=linux"; echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; echo "#Ansible: setup call playbook"; echo "@reboot openvt --switch -- /bin/bash /playbook/execute.sh") | crontab -' diff --git a/playbook/.gitignore b/playbook/.gitignore new file mode 100644 index 0000000..4430d52 --- /dev/null +++ b/playbook/.gitignore @@ -0,0 +1,2 @@ +host_vars/** +hosts diff --git a/playbook/_common.sh b/playbook/_common.sh new file mode 100644 index 0000000..dfb98f8 --- /dev/null +++ b/playbook/_common.sh @@ -0,0 +1,61 @@ +set -euo pipefail; +export TERM="${TERM:-linux}"; # Fix term var if launched without term +if [ "$TERM" = "dumb" ]; then + export TERM=linux; +fi +tput civis; # Hide cursor + +function read_key() { + read -n 1 -s "$@"; +} + +function setup_failed() { + cat </dev/null 2>&1 && pwd )"; +source "$DIR/_common.sh"; + +cd "$DIR"; +if ansible-playbook site.yml; then + echo "Dieses Passwort wurde für das admin-Konto generiert:" + echo "$(cat credentials/admin)"; + ask_yes_no change_pass "Möchten Sie das Passwort ändern?"; + if $change_pass; then + retry_on_fail "Fehler bei der Passwortänderung, bitte versuchen sie es erneut!" passwd admin; + fi + setup_finished; + exit 1; +fi + +setup_failed; +exit 1; diff --git a/playbook/group_vars/all.yml b/playbook/group_vars/all.yml new file mode 100644 index 0000000..fde21df --- /dev/null +++ b/playbook/group_vars/all.yml @@ -0,0 +1,17 @@ +--- + +app_name: "Foto Anzeige für Oma" + +admin_user: admin +admin_pass: "{{ lookup('password', 'credentials/admin length=20 chars=ascii_letters,digits') }}" +admin_home: "/home/{{ admin_user }}" +ui_user: ui +ui_pass: "123465" +ui_home: "/home/{{ ui_user }}" +shared_dir: "/home/images" + +ansible_user: "{{ admin_user }}" +ansible_become: yes +ansible_become_pass: "{{ admin_pass }}" + +LOCAL_SALT: "o8hAvjdHzUxN9mKqc2mAyQUs838jb9ZVL55gsZe459bsoKw66YrH7mWMMhcyDC7t8ZdAhbucVgsM3vkb" diff --git a/playbook/old/detect-usb.rules b/playbook/old/detect-usb.rules new file mode 100644 index 0000000..c5cf6e0 --- /dev/null +++ b/playbook/old/detect-usb.rules @@ -0,0 +1 @@ +ACTION=="add", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="/usr/local/sbin/usb_on_add.sh" diff --git a/playbook/old/usb_on_add.sh b/playbook/old/usb_on_add.sh new file mode 100644 index 0000000..2d6ac17 --- /dev/null +++ b/playbook/old/usb_on_add.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash + +set -euo pipefail; + +LOGFILE="/tmp/usb_automount.log"; +USERNAME={{ admin_user | quote }}; +PROCNAME="caja"; +MANAGER_NAME="caja"; + +function log() { + if [ -z "${1:-}" ]; then + /usr/bin/env ts '[%Y-%m-%d %H:%M:%S]' >> "$LOGFILE"; + else + echo "$@" | log; + fi +} + +function mkdirU() { + log "Ensure $2 exists and is owned by $1"; + mkdir -p "$2" 2>&1 | log; + chown "$1:$1" "$2" 2>&1 | log; +} + +function getVal() { + grep --only-matching --perl-regexp '(?<=\s'"$1"'=")[0-9A-Za-z-]+(?=")' || true; +} + +function getMountDir() { + local info="$(blkid "$2")"; + local label="$(<<<"$info" getVal LABEL)"; + local uuid="$(<<<"$info" getVal UUID)"; + local partuuid="$(<<<"$info" getVal PARTUUID)"; + if [ -n "$label" ]; then + echo "$1/$label"; + elif [ -n "$uuid" ]; then + echo "$1/$uuid"; + elif [ -n "$partuuid" ]; then + echo "$1/$partuuid"; + else + mktemp -d "$1/usb.XXXXXXXX"; + fi +} + +log "Inserted device $DEVNAME"; + +mountDir="/media/$USERNAME"; +mkdirU "$USERNAME" "$mountDir"; + +log "Get userId and groupId of $USERNAME"; +userId=$(id -u "$USERNAME"); +groupId=$(id -g "$USERNAME"); + +log "Get directory to mount $DEVNAME"; +mountDir="$(getMountDir "$mountDir" "$DEVNAME")"; +mkdirU "$USERNAME" "$mountDir"; +log "Mount device $DEVNAME to $mountDir" +if ! mount -o ro,uid=$userId,gid=$groupId "$DEVNAME" "$mountDir" 2>&1 | log; then + log "Failed to mount $DEVNAME"; + exit 2; +fi + +procId="$( (ps --user "$USERNAME" --format pid=,cmd= | grep --only-matching --perl-regexp '(? do not open file manager"; + exit 0; +fi + +while read -r -d "" record; do + if [[ $record =~ ^[a-zA-Z_][a-zA-Z0-9_]*= ]]; then + export "$(printf %q "$record")"; + fi +done < /proc/"$procId"/environ; +log "Try to launch $MANAGER_NAME on DISPLAY=$DISPLAY"; +sudo -u "$USERNAME" "$MANAGER_NAME" "$mountDir" & +log "Launched file manager"; diff --git a/playbook/roles/bootstrap/README.md b/playbook/roles/bootstrap/README.md new file mode 100644 index 0000000..aae5518 --- /dev/null +++ b/playbook/roles/bootstrap/README.md @@ -0,0 +1,21 @@ +# Ansible Bootstrap Role + +This role will manage to use another user to connect to the server, +if your server hoster configures another root / sudo user as you want to use. +This allows you to build one simple playbook and execute it +no matter if your server is already configured or not. + +## Example + +My server hoster allows me to define a password for root while configuring the server, +then I can connect via SSH using this password to this new server, +however I prefer to use another account with sudo privileges. + +Now you can use this role to etablish this workflow to Ansible. +Configure Ansible's `remote_user` to be the user you want to give sudo privileges to. +Define this role to be the first executed and set the variable `bootstrap_sudo_user` +to the user your hoster configures for you. +Ansible will try to log in as `remote_user` at first, +if this fails, then it will try to log in as `bootstrap_sudo_user`. +As long as one of both connection attempts succeeds, +the execution of the playbook will continue using the privileges of the first succeeded login. \ No newline at end of file diff --git a/playbook/roles/bootstrap/defaults/main.yml b/playbook/roles/bootstrap/defaults/main.yml new file mode 100644 index 0000000..08a266a --- /dev/null +++ b/playbook/roles/bootstrap/defaults/main.yml @@ -0,0 +1,4 @@ +bootstrap_used: false + +bootstrap_user: root +bootstrap_become_pass: "" diff --git a/playbook/roles/bootstrap/tasks/deprivilege.yml b/playbook/roles/bootstrap/tasks/deprivilege.yml new file mode 100644 index 0000000..82f17f4 --- /dev/null +++ b/playbook/roles/bootstrap/tasks/deprivilege.yml @@ -0,0 +1,10 @@ +--- + +- name: Remove temporary privileged user + user: + name: "{{ bootstrap_user }}" + state: absent + become: yes + when: + - bootstrap_user != "root" + - bootstrap_user != bootstrap_expected_user diff --git a/playbook/roles/bootstrap/tasks/main.yml b/playbook/roles/bootstrap/tasks/main.yml new file mode 100644 index 0000000..f42c867 --- /dev/null +++ b/playbook/roles/bootstrap/tasks/main.yml @@ -0,0 +1,19 @@ +--- + +- name: Store facts given by configuration + set_fact: + bootstrap_expected_user: "{{ ansible_user }}" + bootstrap_expected_become_pass: "{{ ansible_become_pass }}" + +- name: Bootstrap shift if required + include_tasks: try_else_shift.yml + +- name: Privilege expected user + include_tasks: privilege.yml + +- name: Bootstrap shift back if was shifted + include_tasks: shift_back.yml + when: bootstrap_used + +- name: Deprivilege bootstrap user + include_tasks: deprivilege.yml diff --git a/playbook/roles/bootstrap/tasks/privilege.yml b/playbook/roles/bootstrap/tasks/privilege.yml new file mode 100644 index 0000000..69d2c5d --- /dev/null +++ b/playbook/roles/bootstrap/tasks/privilege.yml @@ -0,0 +1,65 @@ +--- + +- name: Install required packages + apt: + state: present + name: + - psmisc + - sudo + +- name: Create new user {{ bootstrap_expected_user }} + user: + state: present + name: "{{ bootstrap_expected_user }}" + groups: + - sudo + append: yes + password: "{{ bootstrap_expected_become_pass | password_hash('sha512', LOCAL_SALT) }}" + update_password: on_create + register: bootstrap_expected_user_data + +- name: Copy SSH Keys if bootstraped now + when: bootstrap_used + block: + - name: Retrieve data from user {{ bootstrap_user }} + user: + name: "{{ bootstrap_user }}" + state: present + register: bootstrap_user_data + - name: Be sure old user has .ssh directory + file: + state: directory + path: "{{ bootstrap_user_data.home }}/.ssh" + owner: "{{ bootstrap_user }}" + group: "{{ bootstrap_user }}" + mode: "u=rwx,g=rx,o=" + - name: Be sure old user has authorized_keys file + file: + state: touch + path: "{{ bootstrap_user_data.home }}/.ssh/authorized_keys" + owner: "{{ bootstrap_user }}" + group: "{{ bootstrap_user }}" + mode: "u=rw,g=r,o=" + - name: Create .ssh directory for user {{ bootstrap_expected_user }} + file: + path: "{{ bootstrap_expected_user_data.home }}/.ssh" + state: directory + owner: "{{ bootstrap_expected_user }}" + group: "{{ bootstrap_expected_user }}" + become: yes + - name: Transfer SSH keys to new user + copy: + remote_src: yes + src: "{{ bootstrap_user_data.home }}/.ssh/authorized_keys" + dest: "{{ bootstrap_expected_user_data.home }}/.ssh/authorized_keys" + owner: "{{ bootstrap_expected_user }}" + group: "{{ bootstrap_expected_user }}" + mode: u=rw,g=r,o= + become: yes + +- name: Configure given SSH key for new user + authorized_key: + state: present + user: "{{ bootstrap_expected_user }}" + key: "{{ lookup('file', '/home/zocker/.ssh/id_ed25519.pub') }}" + when: inventory_hostname != "localhost" diff --git a/playbook/roles/bootstrap/tasks/shift_back.yml b/playbook/roles/bootstrap/tasks/shift_back.yml new file mode 100644 index 0000000..97bdf98 --- /dev/null +++ b/playbook/roles/bootstrap/tasks/shift_back.yml @@ -0,0 +1,18 @@ +--- + +- name: Set variables for shifting back + set_fact: + bootstrap_used: no + ansible_user: '{{ bootstrap_expected_user }}' + ansible_become_pass: '{{ bootstrap_expected_become_pass }}' + +- name: Reset connection to remove privileged user + meta: reset_connection + +- name: Kill processes associated with the temporary privileged user + command: >- + /usr/bin/killall + --quiet + --wait + --user {{ bootstrap_user }} + changed_when: false diff --git a/playbook/roles/bootstrap/tasks/try_else_shift.yml b/playbook/roles/bootstrap/tasks/try_else_shift.yml new file mode 100644 index 0000000..b01ac2a --- /dev/null +++ b/playbook/roles/bootstrap/tasks/try_else_shift.yml @@ -0,0 +1,14 @@ +--- + +- name: Try to ping host with expected credentials + action: ping + ignore_unreachable: true + ignore_errors: yes + register: pingtest +- meta: clear_host_errors +- name: Shift if ping fails + set_fact: + bootstrap_used: yes + ansible_user: '{{ bootstrap_user }}' + ansible_become_pass: '{{ bootstrap_become_pass }}' + when: pingtest.failed | d(pingtest.unreachable) | d(false) diff --git a/playbook/site.yml b/playbook/site.yml new file mode 100644 index 0000000..e1800b4 --- /dev/null +++ b/playbook/site.yml @@ -0,0 +1,244 @@ +--- + +- name: Do bootstrap + hosts: all + gather_facts: false + roles: + - role: bootstrap + bootstrap_user: debian + ansible_ssh_pass: debian + bootstrap_become_pass: debian + bootstrap_expected_user: "{{ admin_user }}" + bootstrap_expected_become_pass: "{{ admin_pass }}" + +- name: Configure ImageViewer + hosts: all + handlers: + - name: update-grub + command: /usr/sbin/update-grub + - name: rebuild initrd + command: /usr/sbin/update-initramfs -u + tasks: + - name: Update and upgrade packages + apt: + upgrade: safe + allow_unauthenticated: no + update_cache: yes + cache_valid_time: 3600 + install_recommends: no + autoclean: yes + autoremove: yes + - name: Install required packages + apt: + state: present + name: + # Backend + - aptitude # Package manager (used by auto update) + - git # For auto updating Ansible playbook + - python3 # For Ansible and kiosk script + - ufw # Firewall + - policykit-1 # For communication between privileged and non-privileged applications + - ntfs-3g # For supporting NTFS partitions + - gvfs-backends # For automatic mount by pcmanfm + - gvfs-fuse # For automatic mount by pcmanfm + - network-manager # For using wifi connections (for auto update) + # Frontend dependencies + - plymouth # Bootup Splash + - plymouth-themes # Bootup Splash Theme + - lightdm # Desktop Manager, autologin and relogin to admin account + - lightdm-gtk-greeter # Greeter for Desktop Manager + - xorg # XServer + - i3-wm # Window Manager + - i3status # Status infos for i3-bar + - suckless-tools # Tools for i3 config + - fonts-dejavu-core # Font for fancy i3 / urxvt + # Frontend applications + - rxvt-unicode # Terminal for admin account and kiosk script + - pcmanfm # File Manager for admin account + - lxde-icon-theme # For icons in pcmanfm + - imv # Image Viewer + # Dev + - bash-completion + - curl + - vim + - wget + allow_unauthenticated: no + update_cache: yes + cache_valid_time: 3600 + install_recommends: no + autoclean: yes + autoremove: yes + - name: Allow SSH through firewall + ufw: + rule: allow + port: '22' + proto: tcp + - name: Enable firewall + ufw: + state: enabled + policy: deny + direction: incoming + - name: Configure GRUB + template: + src: global/default_grub.txt + dest: /etc/default/grub + owner: root + group: root + mode: u=rw,g=r,o=r + notify: + - update-grub + - name: Configure Plymouth + template: + src: global/plymouthd.conf + dest: /etc/plymouth/plymouthd.conf + owner: root + group: root + mode: u=rw,g=r,o=r + notify: + - rebuild initrd + - name: Configure SystemD LoginD + lineinfile: + path: /etc/systemd/logind.conf + regexp: '^#?{{ item.key }}=' + line: "{{ item.key }}={{ item.value }}" + loop: "{{ entries | dict2items }}" + vars: + entries: + HandlePowerKey: poweroff + HandleSuspendKey: suspend + HandleHibernateKey: suspend + HandleLidSwitch: suspend + HandleLidSwitchExternalPower: suspend + HandleLidSwitchDocked: suspend + - name: Create group autologin for LightDM + group: + state: present + name: autologin + - name: Configure system settings + template: + src: "global/{{ item.key }}" + dest: "{{ item.value }}" + owner: root + group: root + mode: u=rw,g=r,o=r + loop: "{{ config_files | dict2items }}" + vars: + config_files: + lightdm.conf: /etc/lightdm/lightdm.conf + lightdm-gtk-greeter.conf: /etc/lightdm/lightdm-gtk-greeter.conf + # Admin User Configuration + - name: Configure admin user + user: + state: present + name: "{{ admin_user }}" + home: "{{ admin_home }}" + create_home: yes + move_home: yes + shell: /bin/bash + groups: + - audio + - video + - netdev + - plugdev + - sudo + append: yes + password: "{{ admin_pass | password_hash('sha512', LOCAL_SALT) }}" + update_password: on_create + - name: Create admin user configuration directories + file: + state: directory + path: "{{ admin_home }}/{{ item }}" + owner: "{{ admin_user }}" + group: "{{ admin_user }}" + mode: u=rwx,g=rx,o= + loop: + - .config/i3 + - .config/i3status + - name: Configure environment for admin user + template: + src: "admin/{{ item.key }}" + dest: "{{ admin_home }}/{{ item.value }}" + owner: "{{ admin_user }}" + group: "{{ admin_user }}" + mode: u=rw,g=r,o= + loop: "{{ config_files | dict2items }}" + vars: + config_files: + i3.cfg: .config/i3/config + i3status.cfg: .config/i3status/config + status.sh: .config/i3status/call + Xresources: .Xresources + # UI User Configuration + - name: Configure UI user + user: + state: present + name: "{{ ui_user }}" + home: "{{ ui_home }}" + create_home: yes + move_home: yes + shell: /bin/bash + groups: + - audio + - autologin + - video + append: yes + password: "{{ ui_pass | password_hash('sha512', LOCAL_SALT) }}" + update_password: on_create + - name: Create UI user configuration directories + file: + state: directory + path: "{{ ui_home }}/{{ item }}" + owner: root + group: "{{ ui_user }}" + mode: u=rwx,g=rx,o= + loop: + - bin + - .config/i3 + - .config/imv + - name: Configure environment for UI user + template: + src: "ui/{{ item.key }}" + dest: "{{ ui_home }}/{{ item.value }}" + owner: root + group: "{{ ui_user }}" + mode: u=rw,g=r,o= + loop: "{{ config_files | dict2items }}" + vars: + config_files: + i3.cfg: .config/i3/config + imv.conf: .config/imv/config + Xresources: .Xresources + - name: Install client for kiosk + template: + src: client.py + dest: "{{ ui_home }}/bin/client.py" + owner: root + group: "{{ ui_user }}" + mode: u=rwx,g=rx,o= + # Shared directory + - name: Create shared directory structure for both users + file: + state: directory + path: "{{ shared_dir }}" + owner: "{{ admin_user }}" + group: "{{ ui_user }}" + mode: u=rwx,g=rx,o=rx + # Test Images + - name: Unpack test images + unarchive: + src: "test-images.tar.gz" + dest: "{{ shared_dir }}" + owner: "{{ admin_user }}" + group: "{{ ui_user }}" + mode: u=rwx,g=rx,o=rx + # Post Setup + - name: Disable root access + user: + state: present + name: root + password: '!' + - name: Remove setup crontab entry + cron: + state: absent + name: setup call playbook + user: root diff --git a/playbook/templates/admin/Xresources b/playbook/templates/admin/Xresources new file mode 100644 index 0000000..7579be2 --- /dev/null +++ b/playbook/templates/admin/Xresources @@ -0,0 +1,8 @@ +URxvt*background: #002244 +URxvt*color0: #002244 +URxvt*foreground: #ffffff +URxvt*color8: #ffffff +URxvt*font: xft:DejaVu Sans Mono:pixelsize=14 +URxvt*print-pipe: "cat > /dev/null" +URxvt*scrollBar: true +URxvt*pointerBlank: true diff --git a/playbook/templates/admin/i3.cfg b/playbook/templates/admin/i3.cfg new file mode 100644 index 0000000..5939cf3 --- /dev/null +++ b/playbook/templates/admin/i3.cfg @@ -0,0 +1,176 @@ +# This file has been auto-generated by i3-config-wizard(1). +# It will not be overwritten, so edit it as you like. +# +# Should you change your keyboard layout some time, delete +# this file and re-run i3-config-wizard(1). +# + +# German keyboard layout +exec --no-startup-id setxkbmap de + +# i3 config file (v4) +# +# Please see https://i3wm.org/docs/userguide.html for a complete reference! + +# Meta key as modifier +set $mod Mod4 + +# Font for window titles. Will also be used by the bar unless a different font +# is used in the bar {} block below. +#font pango:monospace 8 + +# This font is widely installed, provides lots of unicode glyphs, right-to-left +# text rendering and scalability on retina/hidpi displays (thanks to pango). +font pango:DejaVu Sans Mono 10 + +# Before i3 v4.8, we used to recommend this one as the default: +# font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 +# The font above is very space-efficient, that is, it looks good, sharp and +# clear in small sizes. However, its unicode glyph coverage is limited, the old +# X core fonts rendering does not support right-to-left and this being a bitmap +# font, it doesn’t scale on retina/hidpi displays. + +# Use Mouse+$mod to drag floating windows to their wanted position +floating_modifier $mod + +# kill focused window +bindsym $mod+Shift+q kill + +# start dmenu (a program launcher) +bindsym $mod+d exec --no-startup-id dmenu_run +# There also is the (new) i3-dmenu-desktop which only displays applications +# shipping a .desktop file. It is a wrapper around dmenu, so you need that +# installed. +# bindsym $mod+d exec --no-startup-id i3-dmenu-desktop + +# change focus +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# alternatively, you can use the cursor keys: +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# move focused window +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# alternatively, you can use the cursor keys: +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right + +# split in horizontal orientation +bindsym $mod+h split h + +# split in vertical orientation +bindsym $mod+v split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# change container layout (stacked, tabbed, toggle split) +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +bindsym $mod+space focus mode_toggle + +# focus the parent container +bindsym $mod+a focus parent + +# focus the child container +#bindsym $mod+d focus child + +# Define names for default workspaces for which we configure key bindings later on. +# We use variables to avoid repeating the names in multiple places. +set $ws1 "1: File Manager" +set $ws2 "2: Network" +set $ws3 "3: Terminal" + +# start a terminal +bindsym $mod+Return workspace $ws3; exec urxvt + +# switch to workspace +bindsym $mod+1 workspace $ws1 +bindsym $mod+2 workspace $ws2 +bindsym $mod+3 workspace $ws3 + +# move focused container to workspace +bindsym $mod+Shift+1 move container to workspace $ws1 +bindsym $mod+Shift+2 move container to workspace $ws2 +bindsym $mod+Shift+3 move container to workspace $ws3 + +# Configure certain applications on special workspaces +for_window [class="Pcmanfm"] move container to workspace $ws1 +for_window [instance="nmtui"] move container to workspace $ws2 +for_window [instance="urxvt"] move container to workspace $ws3 + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'" + +# poweroff computer +bindsym $mod+Control+s exec systemctl poweroff +# reboot computer +bindsym $mod+Control+r exec systemctl reboot +# start updater +bindsym $mod+Control+u exec openvt --switch -- /bin/bash /playbook/update.sh + +# resize window (you can also use the mouse for that) +mode "resize" { + # These bindings trigger as soon as you enter the resize mode + + # Pressing left will shrink the window’s width. + # Pressing right will grow the window’s width. + # Pressing up will shrink the window’s height. + # Pressing down will grow the window’s height. + bindsym j resize shrink width 10 px or 10 ppt + bindsym k resize grow height 10 px or 10 ppt + bindsym l resize shrink height 10 px or 10 ppt + bindsym semicolon resize grow width 10 px or 10 ppt + + # same bindings, but for the arrow keys + bindsym Left resize shrink width 10 px or 10 ppt + bindsym Down resize grow height 10 px or 10 ppt + bindsym Up resize shrink height 10 px or 10 ppt + bindsym Right resize grow width 10 px or 10 ppt + + # back to normal: Enter or Escape or $mod+r + bindsym Return mode "default" + bindsym Escape mode "default" + bindsym $mod+r mode "default" +} + +bindsym $mod+r mode "resize" + +# Start i3bar to display a workspace bar (plus the system information i3status +# finds out, if available) +bar { + status_command /usr/bin/env bash ~/.config/i3status/call +} + +# Set background color +exec --no-startup-id xsetroot -solid "#002244" + +# Launch startup applications +exec --no-startup-id pcmanfm +exec --no-startup-id urxvt -name nmtui -e sh -c 'while true; do nmtui; done' +exec --no-startup-id urxvt + +# Switch to first workspace +#workspace $ws1 diff --git a/playbook/templates/admin/i3status.cfg b/playbook/templates/admin/i3status.cfg new file mode 100644 index 0000000..bd9f0c7 --- /dev/null +++ b/playbook/templates/admin/i3status.cfg @@ -0,0 +1,34 @@ +general { + output_format = "i3bar" + colors = true + interval = 5 +} + +order += "wireless _first_" +order += "ethernet _first_" +order += "battery 0" +order += "tztime local" + +wireless _first_ { + format_up = "WLAN: %quality at %essid" + format_down = "" +} + +ethernet _first_ { + format_up = "Ethernet up" + format_down = "" +} + +battery 0 { + format = "%status %percentage for %remaining" + format_down = "" + status_chr = "Charging" + status_bat = "Battery" + status_unk = "Unknown Battery" + status_full = "Charged" + low_threshold = 15 +} + +tztime local { + format = "%Y-%m-%d %H:%M" +} diff --git a/playbook/templates/admin/status.sh b/playbook/templates/admin/status.sh new file mode 100644 index 0000000..a400d90 --- /dev/null +++ b/playbook/templates/admin/status.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +i3status | sed --unbuffered 's/| |/|/g' diff --git a/playbook/templates/client.py b/playbook/templates/client.py new file mode 100755 index 0000000..4b4ce65 --- /dev/null +++ b/playbook/templates/client.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +import argparse +import curses +from pathlib import Path +import subprocess +import sys +from time import sleep + +binding_up = [ord('k'), curses.KEY_UP] +binding_down = [ord('j'), curses.KEY_DOWN] +binding_accept = [ord('l'), ord(' '), ord('\n')] +binding_back = [ord('h'), ord('q'), curses.KEY_BACKSPACE] +binding_exit = [ord('Q')] + +def show_pictures(path): + files = sorted([str(f) for f in path.iterdir() if f.is_file() and f.suffix in ['.png', '.jpg', '.jpeg', '.gif']]) + files.insert(0, '/usr/bin/imvr') + subprocess.call(files) + return True + +def show_select(win, path): + if not path.is_dir(): + raise Exception("'" + str(path) + "' is not a directory!") + dirs = sorted([d for d in path.iterdir() if d.is_dir()]) + if len(dirs) <= 0: + return show_pictures(path) + def setup(): + win.clear() + setup() + sel = 0 + while True: + for y, d in enumerate(dirs): + win.addstr(y, 0, ("➤ " if y == sel else " ") + d.name + (" " * (curses.COLS - 2 - len(d.name))), curses.A_STANDOUT if y == sel else curses.A_NORMAL) + c = win.getch() + if c in binding_up: + sel = max(0, sel - 1) + elif c in binding_down: + sel = min(len(dirs) - 1, sel + 1) + elif c in binding_accept: + if not show_select(win, dirs[sel]): + return False + setup() + elif c in binding_back: + return True + elif c in binding_exit: + return False + +def select_ui(win, args): + curses.curs_set(0) + while show_select(win, args.dir) and args.kiosk: + pass + if args.kiosk: + subprocess.call(['systemctl', 'poweroff']) + + +def main(): + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument('--base-dir', type=Path, dest='dir', required=True) + parser.add_argument('--kiosk', dest='kiosk', action='store_true') + parser.add_argument('--build-desc-of', type=Path, dest='desc_path', default=None) + args = parser.parse_args() + if args.desc_path is not None: + rel_path = args.desc_path.relative_to(args.dir) + parts = list(rel_path.parts[:-1]) + parts.append(rel_path.stem) + parts = [part.replace('_', ' ') for part in parts] + print(str(' - '.join(parts))) + return + curses.wrapper(select_ui, args) + +if __name__ == '__main__': + main() diff --git a/playbook/templates/global/default_grub.txt b/playbook/templates/global/default_grub.txt new file mode 100644 index 0000000..bdcfd9e --- /dev/null +++ b/playbook/templates/global/default_grub.txt @@ -0,0 +1,30 @@ +# Configured by Ansible + +GRUB_DEFAULT=0 +GRUB_TIMEOUT=0 +GRUB_TIMEOUT_STYLE="hidden" +GRUB_DISTRIBUTOR="ImageViewer (`lsb_release -i -s 2> /dev/null || echo Debian`)" +GRUB_CMDLINE_LINUX_DEFAULT="quiet splash loglevel=0 rd.systemd.show_status=quiet rd.udev.log-priority=3 vt.global_cursor_default=0" +GRUB_CMDLINE_LINUX="" + +# Uncomment to enable BadRAM filtering, modify to suit your needs +# This works with Linux (no patch required) and with any kernel that obtains +# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...) +#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef" + +# Uncomment to disable graphical terminal (grub-pc only) +#GRUB_TERMINAL=console + +# The resolution used on graphical terminal +# note that you can use only modes which your graphic card supports via VBE +# you can see them in real GRUB with the command `vbeinfo' +#GRUB_GFXMODE=640x480 + +# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux +#GRUB_DISABLE_LINUX_UUID=true + +# Uncomment to disable generation of recovery mode menu entries +GRUB_DISABLE_RECOVERY="true" + +# Uncomment to get a beep at grub start +#GRUB_INIT_TUNE="480 440 1" diff --git a/playbook/templates/global/getty-hide.conf b/playbook/templates/global/getty-hide.conf new file mode 100644 index 0000000..1f35511 --- /dev/null +++ b/playbook/templates/global/getty-hide.conf @@ -0,0 +1,3 @@ +[Service] +ExecStart= +ExecStart=-/sbin/agetty --login-pause -o '-p -- \\u' --noclear tty1 $TERM diff --git a/playbook/templates/global/lightdm-gtk-greeter.conf b/playbook/templates/global/lightdm-gtk-greeter.conf new file mode 100644 index 0000000..3d6fea8 --- /dev/null +++ b/playbook/templates/global/lightdm-gtk-greeter.conf @@ -0,0 +1,66 @@ +# LightDM GTK+ Configuration +# Available configuration options listed below. +# +# Appearance: +# theme-name = GTK+ theme to use +# icon-theme-name = Icon theme to use +# cursor-theme-name = Cursor theme to use +# cursor-theme-size = Cursor size to use +# background = Background file to use, either an image path or a color (e.g. #772953) +# user-background = false|true ("true" by default) Display user background (if available) +# transition-duration = Length of time (in milliseconds) to transition between background images ("500" by default) +# transition-type = ease-in-out|linear|none ("ease-in-out" by default) +# +# Fonts: +# font-name = Font to use +# xft-antialias = false|true Whether to antialias Xft fonts +# xft-dpi = Resolution for Xft in dots per inch (e.g. 96) +# xft-hintstyle = none|slight|medium|hintfull What degree of hinting to use +# xft-rgba = none|rgb|bgr|vrgb|vbgr Type of subpixel antialiasing +# +# Login window: +# active-monitor = Monitor to display greeter window (name or number). Use #cursor value to display greeter at monitor with cursor. Can be a semicolon separated list +# position = x y ("50% 50%" by default) Login window position +# default-user-image = Image used as default user icon, path or #icon-name +# hide-user-image = false|true ("false" by default) +# +# Panel: +# panel-position = top|bottom ("top" by default) +# clock-format = strftime-format string, e.g. %H:%M +# indicators = semi-colon ";" separated list of allowed indicator modules. Built-in indicators include "~a11y", "~language", "~session", "~power", "~clock", "~host", "~spacer". Unity indicators can be represented by short name (e.g. "sound", "power"), service file name, or absolute path +# +# Accessibility: +# a11y-states = states of accessibility features: "name" - save state on exit, "-name" - disabled at start (default value for unlisted), "+name" - enabled at start. Allowed names: contrast, font, keyboard, reader. +# keyboard = command to launch on-screen keyboard (e.g. "onboard") +# keyboard-position = x y[;width height] ("50%,center -0;50% 25%" by default) Works only for "onboard" +# reader = command to launch screen reader (e.g. "orca") +# at-spi-enabled = false|true ("true" by default) Enables accessibility at-spi-command if the greeter is built with it enabled +# +# Security: +# allow-debugging = false|true ("false" by default) +# screensaver-timeout = Timeout (in seconds) until the screen blanks when the greeter is called as lockscreen +# +# Template for per-monitor configuration: +# [monitor: name] +# background = overrides default value +# user-background = overrides default value +# laptop = false|true ("false" by default) Marks monitor as laptop display +# transition-duration = overrides default value +# +[greeter] +#background="#002244" # TODO Fix +user-background=false +hide-user-image=true +#theme-name= +#icon-theme-name= +#font-name= +#xft-antialias= +#xft-dpi= +#xft-hintstyle= +#xft-rgba= +#indicators= +#clock-format= +#keyboard= +#reader= +#position= +#screensaver-timeout= diff --git a/playbook/templates/global/lightdm.conf b/playbook/templates/global/lightdm.conf new file mode 100644 index 0000000..a794de3 --- /dev/null +++ b/playbook/templates/global/lightdm.conf @@ -0,0 +1,169 @@ +# +# General configuration +# +# start-default-seat = True to always start one seat if none are defined in the configuration +# greeter-user = User to run greeter as +# minimum-display-number = Minimum display number to use for X servers +# minimum-vt = First VT to run displays on +# lock-memory = True to prevent memory from being paged to disk +# user-authority-in-system-dir = True if session authority should be in the system location +# guest-account-script = Script to be run to setup guest account +# logind-check-graphical = True to on start seats that are marked as graphical by logind +# log-directory = Directory to log information to +# run-directory = Directory to put running state in +# cache-directory = Directory to cache to +# sessions-directory = Directory to find sessions +# remote-sessions-directory = Directory to find remote sessions +# greeters-directory = Directory to find greeters +# backup-logs = True to move add a .old suffix to old log files when opening new ones +# dbus-service = True if LightDM provides a D-Bus service to control it +# +[LightDM] +#start-default-seat=true +#greeter-user=lightdm +#minimum-display-number=0 +#minimum-vt=7 +#lock-memory=true +#user-authority-in-system-dir=false +#guest-account-script=guest-account +#logind-check-graphical=false +#log-directory=/var/log/lightdm +#run-directory=/var/run/lightdm +#cache-directory=/var/cache/lightdm +#sessions-directory=/usr/share/lightdm/sessions:/usr/share/xsessions:/usr/share/wayland-sessions +#remote-sessions-directory=/usr/share/lightdm/remote-sessions +#greeters-directory=$XDG_DATA_DIRS/lightdm/greeters:$XDG_DATA_DIRS/xgreeters +#backup-logs=true +#dbus-service=true + +# +# Seat configuration +# +# Seat configuration is matched against the seat name glob in the section, for example: +# [Seat:*] matches all seats and is applied first. +# [Seat:seat0] matches the seat named "seat0". +# [Seat:seat-thin-client*] matches all seats that have names that start with "seat-thin-client". +# +# type = Seat type (local, xremote, unity) +# pam-service = PAM service to use for login +# pam-autologin-service = PAM service to use for autologin +# pam-greeter-service = PAM service to use for greeters +# xserver-backend = X backend to use (mir) +# xserver-command = X server command to run (can also contain arguments e.g. X -special-option) +# xmir-command = Xmir server command to run (can also contain arguments e.g. Xmir -special-option) +# xserver-config = Config file to pass to X server +# xserver-layout = Layout to pass to X server +# xserver-allow-tcp = True if TCP/IP connections are allowed to this X server +# xserver-share = True if the X server is shared for both greeter and session +# xserver-hostname = Hostname of X server (only for type=xremote) +# xserver-display-number = Display number of X server (only for type=xremote) +# xdmcp-manager = XDMCP manager to connect to (implies xserver-allow-tcp=true) +# xdmcp-port = XDMCP UDP/IP port to communicate on +# xdmcp-key = Authentication key to use for XDM-AUTHENTICATION-1 (stored in keys.conf) +# unity-compositor-command = Unity compositor command to run (can also contain arguments e.g. unity-system-compositor -special-option) +# unity-compositor-timeout = Number of seconds to wait for compositor to start +# greeter-session = Session to load for greeter +# greeter-hide-users = True to hide the user list +# greeter-allow-guest = True if the greeter should show a guest login option +# greeter-show-manual-login = True if the greeter should offer a manual login option +# greeter-show-remote-login = True if the greeter should offer a remote login option +# user-session = Session to load for users +# allow-user-switching = True if allowed to switch users +# allow-guest = True if guest login is allowed +# guest-session = Session to load for guests (overrides user-session) +# session-wrapper = Wrapper script to run session with +# greeter-wrapper = Wrapper script to run greeter with +# guest-wrapper = Wrapper script to run guest sessions with +# display-setup-script = Script to run when starting a greeter session (runs as root) +# display-stopped-script = Script to run after stopping the display server (runs as root) +# greeter-setup-script = Script to run when starting a greeter (runs as root) +# session-setup-script = Script to run when starting a user session (runs as root) +# session-cleanup-script = Script to run when quitting a user session (runs as root) +# autologin-guest = True to log in as guest by default +# autologin-user = User to log in with by default (overrides autologin-guest) +# autologin-user-timeout = Number of seconds to wait before loading default user +# autologin-session = Session to load for automatic login (overrides user-session) +# autologin-in-background = True if autologin session should not be immediately activated +# exit-on-failure = True if the daemon should exit if this seat fails +# +[Seat:*] +#type=local +#pam-service=lightdm +#pam-autologin-service=lightdm-autologin +#pam-greeter-service=lightdm-greeter +#xserver-backend= +#xserver-command=X +#xmir-command=Xmir +#xserver-config= +#xserver-layout= +#xserver-allow-tcp=false +#xserver-share=true +#xserver-hostname= +#xserver-display-number= +#xdmcp-manager= +#xdmcp-port=177 +#xdmcp-key= +#unity-compositor-command=unity-system-compositor +#unity-compositor-timeout=60 +#greeter-session=example-gtk-gnome +#greeter-hide-users=false +#greeter-allow-guest=true +#greeter-show-manual-login=false +#greeter-show-remote-login=true +#user-session=default +#allow-user-switching=true +#allow-guest=true +#guest-session= +#session-wrapper=lightdm-session +#greeter-wrapper= +#guest-wrapper= +#display-setup-script= +#display-stopped-script= +#greeter-setup-script= +#session-setup-script= +#session-cleanup-script= +#autologin-guest=false +autologin-user={{ ui_user }} +#autologin-user-timeout=0 +#autologin-in-background=false +autologin-session=i3 +#exit-on-failure=false + +# +# XDMCP Server configuration +# +# enabled = True if XDMCP connections should be allowed +# port = UDP/IP port to listen for connections on +# listen-address = Host/address to listen for XDMCP connections (use all addresses if not present) +# key = Authentication key to use for XDM-AUTHENTICATION-1 or blank to not use authentication (stored in keys.conf) +# hostname = Hostname to report to XDMCP clients (defaults to system hostname if unset) +# +# The authentication key is a 56 bit DES key specified in hex as 0xnnnnnnnnnnnnnn. Alternatively +# it can be a word and the first 7 characters are used as the key. +# +[XDMCPServer] +#enabled=false +#port=177 +#listen-address= +#key= +#hostname= + +# +# VNC Server configuration +# +# enabled = True if VNC connections should be allowed +# command = Command to run Xvnc server with +# port = TCP/IP port to listen for connections on +# listen-address = Host/address to listen for VNC connections (use all addresses if not present) +# width = Width of display to use +# height = Height of display to use +# depth = Color depth of display to use +# +[VNCServer] +#enabled=false +#command=Xvnc +#port=5900 +#listen-address= +#width=1024 +#height=768 +#depth=8 diff --git a/playbook/templates/global/plymouthd.conf b/playbook/templates/global/plymouthd.conf new file mode 100644 index 0000000..0aae794 --- /dev/null +++ b/playbook/templates/global/plymouthd.conf @@ -0,0 +1,2 @@ +[Daemon] +Theme=spinner diff --git a/playbook/templates/ui/Xresources b/playbook/templates/ui/Xresources new file mode 100644 index 0000000..b9c95db --- /dev/null +++ b/playbook/templates/ui/Xresources @@ -0,0 +1,8 @@ +URxvt*background: #002244 +URxvt*color0: #002244 +URxvt*foreground: #000000 +URxvt*color8: #000000 +URxvt*font: xft:DejaVu Sans Mono:pixelsize=24 +URxvt*print-pipe: "cat > /dev/null" +URxvt*scrollBar: false +URxvt*pointerBlank: true diff --git a/playbook/templates/ui/i3.cfg b/playbook/templates/ui/i3.cfg new file mode 100644 index 0000000..ca98cf0 --- /dev/null +++ b/playbook/templates/ui/i3.cfg @@ -0,0 +1,102 @@ +# This file has been auto-generated by i3-config-wizard(1). +# It will not be overwritten, so edit it as you like. +# +# Should you change your keyboard layout some time, delete +# this file and re-run i3-config-wizard(1). +# + +# German keyboard layout +exec --no-startup-id setxkbmap de + +# i3 config file (v4) +# +# Please see https://i3wm.org/docs/userguide.html for a complete reference! + +# Meta key as modifier +set $mod Mod4 + +# Font for window titles. Will also be used by the bar unless a different font +# is used in the bar {} block below. +#font pango:monospace 8 + +# This font is widely installed, provides lots of unicode glyphs, right-to-left +# text rendering and scalability on retina/hidpi displays (thanks to pango). +font pango:DejaVu Sans 12 + +# Before i3 v4.8, we used to recommend this one as the default: +# font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 +# The font above is very space-efficient, that is, it looks good, sharp and +# clear in small sizes. However, its unicode glyph coverage is limited, the old +# X core fonts rendering does not support right-to-left and this being a bitmap +# font, it doesn’t scale on retina/hidpi displays. + +# change focus +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# alternatively, you can use the cursor keys: +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# move focused window +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# alternatively, you can use the cursor keys: +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right + +# split in horizontal orientation +bindsym $mod+h split h + +# split in vertical orientation +bindsym $mod+v split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# change container layout (stacked, tabbed, toggle split) +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# change focus between tiling / floating windows +bindsym $mod+space focus mode_toggle + +# focus the parent container +bindsym $mod+a focus parent + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-msg exit" + +# poweroff computer +bindsym $mod+Control+s exec "systemctl poweroff" +# reboot computer +bindsym $mod+Control+r exec "systemctl reboot" + +exec --no-startup-id xsetroot -solid "#002244" + +# class border backgr. text indicator child_border +client.focused #000044 #000044 #ffffff #000044 #000044 +client.focused_inactive #000044 #000044 #ffffff #000044 #000044 +client.unfocused #000044 #000044 #ffffff #000044 #000044 +client.urgent #000044 #000044 #ffffff #000044 #000044 +client.placeholder #000044 #000044 #ffffff #000044 #000044 + +client.background #002244 + +exec --no-startup-id "urxvt -title '{{ app_name }}' -e '{{ ui_home }}/bin/client.py' --kiosk --base-dir {{ shared_dir }}" + +bindsym $mod+t exec --no-startup-id "urxvt" diff --git a/playbook/templates/ui/imv.conf b/playbook/templates/ui/imv.conf new file mode 100644 index 0000000..cfd8e29 --- /dev/null +++ b/playbook/templates/ui/imv.conf @@ -0,0 +1,19 @@ +[options] +background = 000000 +fullscreen = true +list_files_at_exit = false +loop_input = true +overlay = true +overlay_font = DejaVu Sans:20 +overlay_text = $({{ ui_home | quote }}/bin/client.py --base-dir {{ shared_dir | quote }} --build-desc-of "$imv_current_file") +scaling_mode = full +suppress_default_binds = true + +[binds] + = select_rel -1 + = select_rel -1 + = select_rel 1 + = select_rel 1 + = quit + = quit + = quit diff --git a/playbook/test-images.tar.gz b/playbook/test-images.tar.gz new file mode 100644 index 0000000..fc588ee Binary files /dev/null and b/playbook/test-images.tar.gz differ diff --git a/playbook/update.sh b/playbook/update.sh new file mode 100644 index 0000000..02cc40c --- /dev/null +++ b/playbook/update.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +GIT_URL="https://git.banananet.work/zocker/imageviewer.git" + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"; +source "$DIR/_common.sh"; + +echo "Beende grafische Benutzeroberfläche ..."; +systemctl stop lightdm; +echo "Lade Updates herunter ..." +dir="$(mktemp -d)"; +if ! git clone --depth 1 "$GIT_URL" "$dir"; then + setup_failed; + exit 1; +fi +rm -rf "$DIR.old"; +mv "$DIR" "$DIR.old"; +cp -r "$dir/playbook" "$DIR"; +$DIR/execute.sh; +exit 1;