diff --git a/bin/surf-display b/bin/surf-display new file mode 100755 index 0000000..b4e278c --- /dev/null +++ b/bin/surf-display @@ -0,0 +1,349 @@ +#!/bin/bash + +# uncomment for very verbose script debugging... +#set -x + +# Copyright (C) 2012-2017 by Debian Edu project, http://wiki.debian.org/DebianEdu +# 2012-2017, Mike Gabriel +# 2016, Daniel Teichmann +# 2017, Benjamin Schlüter + +# Midori Display is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Midori Display is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +# dependencies: +# wmctrl +# matchbox-window-manager +# pulseaudio-utils +# xprintidle +# xdotool +# xmodmap +# x11-xkb-utils +# +# recommendations: +# unclutter +# pulseaudio +# x11-xserver-utils + +VERSION="0.0.2" + +# Can be configured at "/etc/default/surf-display" +DEFAULT_WWW_URI="file:///usr/share/surf-display/empty-page.html" +DEFAULT_RESOLUTION="" + +# all displays that need to be changed +declare -A DISPLAYS + +# launch pulseaudio daemon if not already running +WITH_PULSEAUDIO="yes" + +# hide idle mouse pointer +HIDE_IDLE_POINTER="yes" + +# disable right and middle pointer device click in Midori sessions while keeping +# scrolling wheels' functionality intact... (consider "pointer" subcommand on +# xmodmap man page for details). +POINTER_BUTTON_MAP="1 0 0 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0" + +# default screensaver settings +SCREENSAVER_SETTINGS="" + +# don't use an HTTP proxy by default +HTTP_PROXY_URL="" + +# URI block list, if any +unset URI_BLOCKLIST + +# log to stderr, if not set to "yes" in one of the config files... +LOG_TO_SYSLOG=no + +# interval of browser inactivity before the session is reset automatically (in seconds) +INACTIVITY_INTERVAL="300" + +if type -p xrandr 1>/dev/null; then + currentOutput=`echo "$(xrandr)" | grep -w 'connected' | sed -r -e 's/connected.*//' | head -n 1` +fi + +if [ -r /etc/default/surf-display ] && [ ! -d /etc/default/surf-display ]; then + . /etc/default/surf-display +fi + +if [ -r $HOME/.surf-display/config ] && [ ! -d $HOME/.surf-display/config ]; then + . $HOME/.surf-display/config +fi + +if [ "x$LOG_TO_SYSLOG" = "xyes" ]; then + OUTPUT="logger -t surf-display" +else + OUTPUT="echo" +fi + +workdir="$HOME/.surf-display" +mkdir -p "$workdir" + +session_lock="$workdir/.session-lock.$$" +browser_lock="$workdir/.midori-lock" + +browser_config_dir=`mktemp -d -p "$workdir" surf-display-profile-XXXXXX` + +# provide pulseaudio support in the browser session, if not +# already available... +if ! pacmd stat 1>/dev/null 2>/dev/null; then + if [ "x$WITH_PULSEAUDIO" = "xyes" ]; then + if which pulseaudio 1>/dev/null; then + pulseaudio -D -n \ + -L 'module-udev-detect' \ + --exit-idle-time=65535 + fi + fi +fi + +# launch matchbox manager +if ! wmctrl -m 1>/dev/null 2>/dev/null; then + if which matchbox-window-manager 1>/dev/null; then + matchbox-window-manager 1>/dev/null 2>/dev/null& + fi +fi + +# use unclutter to hide idle mouse pointers +if [ "x$HIDE_IDLE_POINTER" = "xyes" ]; then + if which unclutter 1>/dev/null; then + unclutter 1>/dev/null 2>/dev/null & + fi +fi + +# hack mouse pointer functionality to e.g. disable "right-click" in Midori session +sanitized_pointer_button_map=$(echo ${POINTER_BUTTON_MAP//[^0-9\ ]/} | sed -e 's/^\s*//' -e 's/\s*$//') +count_buttons_pointer_button_map=$(echo -n "${sanitized_pointer_button_map//[0-9]/}"| wc -m) + +if which xmodmap 1>/dev/null; then + if [ -n "$POINTER_BUTTON_MAP" ] && [ "x$POINTER_BUTTON_MAP" = "x$sanitized_pointer_button_map" ] && \ + [ $count_buttons_pointer_button_map -lt 32 ]; then + xmodmap -e "pointer = $POINTER_BUTTON_MAP" + fi + + # furthermore... let's deactivate the "Control" modifier key to disable most hotkeys in Midori + xmodmap -e "clear Control" + +else + $OUTPUT "WARNING: Cannot strip down mouse/pointer button functionality. Make sure 'xmodmap' is installed." +fi + +if which setxkbmap 1>/dev/null; then + setxkbmap -option "terminate:ctrl_alt_bksp" +fi + +# if FAKE_HOSTNAME is not empty, use that string for hostname +THIS_HOSTNAME=$(hostname -f) +if [ -n "$FAKE_HOSTNAME" ]; then + THIS_HOSTNAME="$FAKE_HOSTNAME" +fi + +if `echo ${!DISPLAYS[@]} | grep -q "$THIS_HOSTNAME"`; then + $OUTPUT "INFO: $THIS_HOSTNAME has extra properties. loading them.." + + if echo ${DISPLAYS[$THIS_HOSTNAME]} | grep -q "www_uri="; then + WWW_URI=`echo ${DISPLAYS[$THIS_HOSTNAME]} | sed -r -e 's/(^|.*\|)www_uri=([^|]*).*/\2/'` + else + WWW_URI="$DEFAULT_WWW_URI" + fi + + if echo ${DISPLAYS[$THIS_HOSTNAME]} | grep -q "res="; then + RESOLUTION=`echo ${DISPLAYS[$THIS_HOSTNAME]} | sed -r -e 's/(^|.*\|)res=([^|]*).*/\2/'` + else + RESOLUTION="$DEFAULT_RESOLUTION" + fi +else + WWW_URI="$DEFAULT_WWW_URI" + RESOLUTION="$DEFAULT_RESOLUTION" +fi + +if ! echo "$WWW_URI" | grep -q -E "^(file://|http://|https://).*"; then + $OUTPUT "ERROR: WWW_URI format not supported: $WWW_URI" + $OUTPUT " Use file:///. or http(s):////.." + $OUTPUT " Doing nothing." + exit -1 +fi + +# if URI_BLOCKLIST is not set, populate it and limit access to the WWW_SERVER that WWW_URI points to only. +if [ ! -v URI_BLOCKLIST ]; then + URI_TYPE=`echo "$WWW_URI" | sed -r -e 's@(file://|http(|s)://)[^/]+/.*@\1@'` + WWW_SERVER="" + if echo "$URI_TYPE" | grep -q -E "^http(|s)://([^/]+)/.*"; then + WWW_SERVER=`echo "$WWW_URI" | sed -r -e 's@^http(|s)://([^/]+)/.*@\2@'` + fi + URI_BLOCKLIST='^((?!'$URI_TYPE'.*'$WWW_SERVER'/).).*$' +fi + +if [ -n "$URI_BLOCKLIST" ]; then + URI_BLOCKLIST="-b $URI_BLOCKLIST" +fi + +if [ -n "${RESOLUTION}" ]; then + if type -p xrandr 1>/dev/null; then + xrandr -d :0 --output "$(echo $currentOutput)" --mode $RESOLUTION + fi +fi + +# Set screensaver settings +if which xset 1>/dev/null; then + xset s ${SCREENSAVER_SETTINGS} +fi + +# set some proxy related env variables, if requested... +if [ -n "$HTTP_PROXY_URL" ]; then + export http_proxy="$HTTP_PROXY_URL" + export https_proxy="$HTTP_PROXY_URL" + export ftp_proxy="$HTTP_PROXY_URL" +fi + +function cleanup { + if type -p xrandr 1>/dev/null; then + $OUTPUT "Info: resetting resolution" + xrandr -d :0 --output "$(echo $currentOutput)" --auto + fi + + if [ -r "$browser_lock" ]; then + browser_pid=$(cat "$browser_lock" | sed -e 's/[^0-9]*//g') + if [ -n "$browser_pid" ]; then + kill -0 $browser_pid 2>/dev/null && kill "$browser_pid" + fi + fi + + if [ -d "$browser_config_dir" ]; then + rm -R "$browser_config_dir" + fi + + for rmfile in $browser_lock \ + $session_lock \ + ; + do + if [ -e "$rmfile" ]; then + rm "$rmfile" + fi + done + +} +trap "cleanup" SIGINT SIGTERM ERR EXIT + +function browser_loop { + if [ "x$INACTIVITY_INTERVAL" != "x0" ]; then + ( + while [ -e "$session_lock" ]; do + sleep 1 + if [ `xprintidle 2>/dev/null || echo 0` -gt $(($INACTIVITY_INTERVAL*1000)) ]; then + echo -n "RESTART" > $browser_lock + $OUTPUT "INFO: Triggering browser restart, too much idling around..." + # reset X11 idle counter by some harmless key event + xdotool key Shift + fi + done + ) & + fi +} + + +function browser_session { + + if which midori 1>/dev/null; then + + while [ -e "$session_lock" ]; do + + $OUTPUT "INFO: Starting a new instance of the midori application." + midori \ + -e Fullscreen \ + -e enable-plugins=false \ + -e enable-page-cache=false \ + -e open-new-pages-in=MIDORI_NEW_PAGE_CURRENT \ + -e close-buttons-on-tabs=false \ + -e show-menubar=false \ + -e show-statusbar=false \ + -e show-bookmarkbar=false \ + -e show-panel=false \ + -e show-crash-dialog=false \ + -e open-tabs-in-the-background=false \ + -e open-tabs-next-to-current=false \ + -e open-popups-in-tabs=false \ + -e enable-xss-auditor=false \ + -e enable-javascript=true \ + -e enable-developer-extras=false \ + -e enable-html5-database=true \ + -e enable-running-of-insecure-content=false \ + -e enable-display-of-insecure-content=false \ + -e javascript-can-access-clipboard=false \ + -e print-without-dialog=true \ + -c "${browser_config_dir}" \ + ${URI_BLOCKLIST} \ + -a "${WWW_URI}" 1>/dev/null 2>/dev/null & + + browser_pid=$! + + echo -n "$browser_pid" > "$browser_lock" + + while [ -r "$browser_lock" ] && [ "$(cat $browser_lock)" != "RESTART" ] && [ -e "$session_lock" ]; do + sleep 1 + if ! kill -0 "$browser_pid" 2>/dev/null; then + if [ -e ${session_lock} ]; then + rm "${session_lock}" + fi + if [ -d "${browser_config_dir}" ]; then + rm -R "${browser_config_dir}" + fi + break + + browser_config_dir=`mktemp -d -p "$workdir" surf-display-profile-XXXXXX` + + fi + done + + kill -0 "$browser_pid" 2>/dev/null && kill "$browser_pid" + $OUTPUT "INFO: The midori application has terminated." + + done + + else + $OUTPUT "ERROR: The midori application is not installed." + fi + +} + + +function create_lock { + + touch "$session_lock" + +} + +### MAIN ### + +$OUTPUT "INFO: midori Display (version $VERSION)" +$OUTPUT "INFO: HOSTNAME set to: $THIS_HOSTNAME" + +if [ -n "$WWW_URI" ]; then + + $OUTPUT "INFO: WWW_URI is configured. Using content from given URL: $WWW_URI" + create_lock + browser_loop + +else + + $OUTPUT "ERROR: WWW_URI hasn't been configured. Doing nothing." + exit 0 + +fi + +browser_session + +exit 0 diff --git a/data/empty-page.html b/data/empty-page.html new file mode 100644 index 0000000..39b840d --- /dev/null +++ b/data/empty-page.html @@ -0,0 +1,21 @@ + + + + +This page intentionally left blank (default) + + + +
+Surf Kiosk Display: this test
page has been intentionally left blank +
+ + + diff --git a/data/surf-display.1 b/data/surf-display.1 new file mode 100644 index 0000000..17d3fbe --- /dev/null +++ b/data/surf-display.1 @@ -0,0 +1,38 @@ +'\" -*- coding: utf-8 -*- +.if \n(.g .ds T< \\FC +.if \n(.g .ds T> \\F[\n[.fam]] +.de URL +\\$2 \(la\\$1\(ra\\$3 +.. +.if \n(.g .mso www.tmac +.TH surf-display 1 "Mar 2017" "Version 0.0.2" "Surf Kiosk Display" +.SH NAME +surf-display \- Fullscreen WWW Display Session Manager +.SH SYNOPSIS +'nh +.fi +.ad l +\fBsurf-display\fR + +.SH DESCRIPTION +\fBsurf-display\fR is a wrapper around Surf. It can turn a system into a browser based display terminal in KIOSK mode. +.PP +\fBsurf-display\fR registers itself as an x-session-manager alternative +and provides a very minimal X11 session, launching the +matchbox-window-manager, pulseaudio (if requested) and unclutter (if +requested) before starting the fullscreen browser session. +.PP +\fBsurf-display\fR locks down mouse pointer right-click behaviour and disables various keyboard shortcuts to hide Surf +functionalities from the user. Out goal is to not let users break out of the given entry WWW site's browsing design. +.PP +With \fBsurf-display\fR you can configure what sites to allow the user access to and what sites to block user access from. +.PP +.SH OPTIONS +\fBsurf-display\fR can easily be configured system-wide via /etc/default/surf-display. Overrides can be configure on a per-user basis +via $HOME/.surf-display/config. +.PP +.SH SEE ALSO +/etc/default/surf-display +.SH AUTHOR +This manual has been written by Mike Gabriel and Benjamin Schlüter for the IT-Zukunft-Schule +project (https://wiki.it-zukunft-schule.de/). diff --git a/data/surf-display.desktop b/data/surf-display.desktop new file mode 100644 index 0000000..d7e9469 --- /dev/null +++ b/data/surf-display.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=Surf Kiosk Display +Comment=Fullscreen browser session +Exec=surf-display +TryExec=surf-display +Icon=x-www-browser +Type=Application +Keywords=browser;kiosk;fullscreen;display; \ No newline at end of file diff --git a/examples/surf-display.default b/examples/surf-display.default new file mode 100644 index 0000000..fef5e5b --- /dev/null +++ b/examples/surf-display.default @@ -0,0 +1,55 @@ +# Surf Kiosk Display: Wrap around surf browser and turn your +# system into a browser screen in KIOSK-mode. + +# default download URI for all display screens if not configured individually +DEFAULT_WWW_URI="file:///usr/share/surf-display/empty-page.html" + +# Enforce fixed resolution for all displays (default: not set): +#DEFAULT_RESOLUTION="1920x1080" + +#FIXME: Configure individual display screens with host specific parameters: +#DISPLAYS['display-host-0']="www_uri=https://www.displayserver.comany.net/display-1/index.html" +#DISPLAYS['display-host-1']="www_uri=https://www.displayserver.comany.net/display-2/index.html" +#DISPLAYS['display-host-2']="www_uri=https://www.displayserver.comany.net/display-3/index.html|res=1920x1280" +#DISPLAYS['display-host-3']="www_uri=https://www.displayserver.comany.net/display-4/index.html"|res=1280x1024" +#DISPLAYS['display-host-local-file']="www_uri=file:///usr/share/doc/surf-display/empty-page.html" + +#### ^^^ use: FAKE_HOSTNAME="display-host-1" surf-display +### to play with other hostnames and their PDF URI / resolution settings... + +# HTTP proxy URL, if needed (default: not set). +#HTTP_PROXY_URL="http://webcache:3128" + +# Setting for internal inactivity timer to restart surf-display +# if the user goes inactive/idle. +#INACTIVITY__INTERVAL="300" + +# log to syslog instead of .xsession-errors +#LOG_TO_SYSLOG="no" + +# Launch pulseaudio daemon if not already running. +#WITH_PULSEAUDIO="yes" + +# screensaver settings, see "man 1 xset" for possible options +#SCREENSAVER_SETTINGS="" + +# URI blocklist, URLs that the Surf Browser should block (default: unset) +# If URI blocklist is unset, the surf-display script will tell +# the Surf Browser to block access to all other servers except the one in +# the WWW_URI. +# (i.e. URI_BLOCKLIST='^((?!'$URI_TYPE'.*'$WWW_SERVER'/).).*$') +#unset URI_BLOCKLIST + +# Other example: block some famous data collection sites +#URI_BLOCKLIST=".*(facebook|google|apple|microsoft|twitter)[^/]+/.*" + +# Or allow access to all sites on the internet +#URI_BLOCKLIST="" + +# disable right and middle pointer device click in browser sessions while keeping +# scrolling wheels' functionality intact... (consider "pointer" subcommand on +# xmodmap man page for details). +#POINTER_BUTTON_MAP="1 0 0 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0" + +# Hide idle mouse pointer. +#HIDE_IDLE_POINTER="yes"