Skip to content

Commit

Permalink
2023.9.0-VALIDATION
Browse files Browse the repository at this point in the history
  • Loading branch information
guyonvarch committed Sep 11, 2023
2 parents a8888d6 + fa22315 commit 0d8ef6a
Show file tree
Hide file tree
Showing 167 changed files with 969 additions and 1,103 deletions.
27 changes: 22 additions & 5 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
# PlayOS

A custom Linux system (built on [NixOS](https://nixos.org/)) to run web applications in a fullscreen kiosk. Built for Dividat Play.
PlayOS is a Linux system to act as an application kiosk. PlayOS is a layer on top of [NixOS](https://nixos.org/).

The base layer functionality of PlayOS is:

- Automatic A/B update mechanism
- Read-only system partitions, with selected persisted configuration data
- Web-based configuration interface for
- network (LAN, WLAN, HTTP proxy, static IP),
- localization,
- system status,
- remote maintenance.
- Installer
- Live system
- Remote maintenance via ZeroTier

The application layer may be defined in a single Nix file.

This repository contains the application layer for running the Dividat Play web app and supporting system services in a fullscreen kiosk.

See the [documentation](docs/arch) for more information.

Expand Down Expand Up @@ -34,10 +51,10 @@ A helper is available to quickly start a virtual machine:
./build vm
```

In order to get the vm system journal, look at the output of `run-playos-in-vm`
In order to get the vm system journal, look at the output of `run-in-vm`
for a command starting with `socat`.

See the output of `run-playos-in-vm --help` for more information.
See the output of `run-in-vm --help` for more information.

#### Guest networking

Expand All @@ -59,7 +76,7 @@ Tests added to `test/integration` are executed via a GitHub Action when pushing

## Deployment

Update bundles are hosted on Amazon S3. The script `bin/deploy-playos-update` will handle signing and uploading of bundle.
Update bundles are hosted on Amazon S3. The script `bin/deploy-update` will handle signing and uploading of bundle.

The arguments `updateUrl` (from where updates will be fetched by PlayOS systems), `deployURL` (where bundles should be deployed to) must be specified. For example: `nix build --arg updateUrl https://dist.dividat.com/releases/playos/master/ --arg deployUrl s3://dist.dividat.ch/releases/playos/master/`.

Expand All @@ -69,7 +86,7 @@ To release an update to the `develop` channel:

```
./build develop
./result/bin/deploy-playos-update --key PATH_TO_KEY.pem
./result/bin/deploy-update --key PATH_TO_KEY.pem
```

### Key switch
Expand Down
182 changes: 182 additions & 0 deletions application.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
rec {
fullProductName = "Dividat PlayOS";
safeProductName = "playos";
version = "2023.9.0-VALIDATION";

greeting = label: ''
_
, -"" "".
,' ____ `.
,' ,' `. `._
(`. _..--.._ ,' ,' \\ \\
(`-.\\ .-"" ""' / ( d _b
(`._ `-"" ,._ ( `-( \\
<_ ` ( <`< \\ `-._\\
<`- (__< < : ${label}
(__ (_<_< ;
-----`------------------------------------------------------ ----------- ------- ----- --- -- -
'';

overlays = [
(import ./application/overlays version)
# Limit virtual terminals that can be switched to
# Virtual terminal 7 is the kiosk, 8 is the status screen
(import ./application/overlays/xorg { activeVirtualTerminals = [ 7 8 ]; })
];

module = { config, lib, pkgs, ... }: {

imports = [ ./application/playos-status.nix ];

# Kiosk runs as a non-privileged user
users.users.play = {
isNormalUser = true;
home = "/home/play";
extraGroups = [
"dialout" # Access to serial ports for the Senso flex
];
};

# Note that setting up "/home" as persistent fails due to https://github.com/NixOS/nixpkgs/issues/6481
playos.storage.persistentFolders."/home/play" = {
mode = "0700";
user = "play";
group = "users";
};

# System-wide packages
environment.systemPackages = with pkgs; [ breeze-contrast-cursor-theme ];

# Kiosk session
services.xserver = let sessionName = "kiosk-browser";
in {
enable = true;

desktopManager = {
xterm.enable = false;
session = [{
name = sessionName;
start = ''
# Disable screen-saver control (screen blanking)
xset s off
xset s noblank
xset -dpms
# Localization for xsession
if [ -f /var/lib/gui-localization/lang ]; then
export LANG=$(cat /var/lib/gui-localization/lang)
fi
if [ -f /var/lib/gui-localization/keymap ]; then
setxkbmap $(cat /var/lib/gui-localization/keymap) || true
fi
# Set preferred screen resolution
scaling_pref=$(cat /var/lib/gui-localization/screen-scaling 2>/dev/null || echo "default")
case "$scaling_pref" in
"default" | "full-hd")
xrandr --size 1920x1080;;
"native")
# Nothing to do, let system decide.
;;
*)
echo "Unknown scaling preference '$scaling_pref'. Ignoring."
;;
esac
# Enable Qt WebEngine Developer Tools (https://doc.qt.io/qt-5/qtwebengine-debugging.html)
export QTWEBENGINE_REMOTE_DEBUGGING="127.0.0.1:3355"
${pkgs.playos-kiosk-browser}/bin/kiosk-browser \
${config.playos.kioskUrl} \
http://localhost:3333/
waitPID=$!
'';
}];
};

displayManager = {
# Always automatically log in play user
lightdm = {
enable = true;
greeter.enable = false;
autoLogin.timeout = 0;
};

autoLogin = {
enable = true;
user = "play";
};

defaultSession = sessionName;

sessionCommands = ''
${pkgs.xorg.xrdb}/bin/xrdb -merge <<EOF
Xcursor.theme: ${pkgs.breeze-contrast-cursor-theme.themeName}
EOF
'';
};
};

# Driver service
systemd.services."dividat-driver" = {
description = "Dividat Driver";
serviceConfig.ExecStart = "${pkgs.dividat-driver}/bin/dividat-driver";
serviceConfig.User = "play";
wantedBy = [ "multi-user.target" ];
};

# Audio
sound.enable = true;
hardware.pulseaudio = {
enable = true;
extraConfig = ''
# Use HDMI output
set-card-profile 0 output:hdmi-stereo
# Respond to changes in connected outputs
load-module module-switch-on-port-available
load-module module-switch-on-connect
'';
};

# Enable avahi for Senso discovery
services.avahi.enable = true;

# Enable pcscd for smart card identification
services.pcscd.enable = true;
# Blacklist NFC modules conflicting with CCID (https://ludovicrousseau.blogspot.com/2013/11/linux-nfc-driver-conflicts-with-ccid.html)
boot.blacklistedKernelModules = [ "pn533_usb" "pn533" "nfc" ];
# Allow play user to access pcsc
security.polkit.extraConfig = ''
polkit.addRule(function(action, subject) {
if (subject.user == "play" && (action.id == "org.debian.pcsc-lite.access_pcsc" || action.id == "org.debian.pcsc-lite.access_card")) {
return polkit.Result.YES;
}
});
'';

playos.remoteMaintenance = {
enable = true;
networks = [ "a09acf02330ccc60" ];
authorizedKeys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDUOwaIpDOHaADuJaS6+bSsEJDvmzRfdkhi8k/infDZimdbSRQvSdbRiRJlPPAeETRaKH8z5eOCJPYLSb3+EHn7oQFsUD6c5Gg+LQAahB/lhja7RoDCPH6/hHaOKYJny5lDfJ+KVSn3fNFiJ0mFJRIjGcoUeI95Rw1PHZJae8ZOapU336Uyy8hB84lvcaFmjzMEIyDkvSxpTrD+RpugG3XJhQE24a6t7fN9z3P6CfprVyFVHA3dkmxAvcYseeXA6TBfIGUbiC3wN1o7GoAgnsiVpwq9q4Ye3jMoRvB3Iw05rvcO/m5WT3JmCAWgeIM1yvWM3Pxc05E7g1jXRaygb0VVk8QendNZt+jlwVVU5N2H+LJ+vwyt+6PCFRGjPkLHjFwpoiLc7S6gHFQH4PcynyjOyAIKvBekn3LxV9hGkadVx7PwXX3C4Eqj4MGaVa095eVdtxZbSdwtUiOclXgA3G3O6Jen/fZDd2hMbX2mXgnGtn9LQjIz8RWFnyg6EU4ZfVhDsZcp8kVznQK8ibax2I++leJfVr95JsCPvVSIwNfxPA1/BDggxiwCSKUq/EvQyZ3/0pHJc3Lfca/1aTb0Hn1q5RPXjUGLlOOnG/yfD/FV1rnF49TgNIESF3tZ852Ba9sbcJohCgSCRBBeAiE7TXM5K84/V1HXlQlmA8JIJfyUlQ== openpgp:0x01C16138"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDXvP3MLATx2TybGzQ7AtWX5NsDl8SC/sL3kTR7VefOAZzxOlCi8hQjRGiAjEqESepx5VTOtDP1p1slhwjkTsPoUmLeZxpRCZfXS4CuXmdJHJ+tLkuDtYhJm6s4lcHByzv3ErE3MGIqTPE0f0meXd1WOCCOSk8BzCot7WmqIHo0VgPMDq9Hb/NSJDnzlL4aZG2yF2hfrmPV31caKMXYCWDVCZWsSPexCmmU10kWfoAYNFzaCrLczPaTsvPNopiobnQ4cmEQk/GDaWy2fobiU9g4/iYh9czGnJNeeaFAPkcr1ivBKmD5qTS613OJwXqnaQy0+rh/HxOoXMpZYH6Hv7uXmtA2PtGTL8Fum5KnCk+M+H/8ohyPluWRVueRUK9MOzIkIvA0HlF4TdTMR+qhBY/yp2RaDg5PDwKypFqZz1RG/lAhCxtTZspqT2NdFvLfcfpT6rqlI3kt+clNTloeprudfSAKfU/rtBGT9qZjCL9CgGE2HB/RhPaBA1NsFXevvLzsJbGQ7ebaCM0Bl6mFkBqS73zqSonz1GOkWkq4tMyO7LH2iW6RHSpKDyHaY4hDmiCHEx8xEH/OlI+6xz0jcVdxe6a6YUwzjIWYi0D457aEMh+G3VAwTRa4PMoNaJe+ynvnUXC5CGsX8iOwXe4vWodLLHtBGcOhWJUNFrQ1AloDnQ== openpgp:0xA3BCEAAB"
];
};

# Enable persistent journaling with low maximum size
playos.storage.persistentFolders."/var/log/journal" = {
mode = "0755";
user = "root";
group = "root";
};
services.journald.extraConfig = ''
Storage=persistent
SystemMaxUse=1G
'';

# Set a low default timeout when stopping services, to prevent the Windows 95 shutdown experience
systemd.extraConfig = "DefaultTimeoutStopSec=15s";

};
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ stdenv, fetchzip, lib, ... }:
{ stdenv, unzip, lib, ... }:

# Inspiration:
# https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=breeze-contrast-cursor-theme
Expand All @@ -7,11 +7,15 @@ stdenv.mkDerivation rec {
version = "1.0";
themeName = "Breeze_Contrast";

src = ./theme;
buildInputs = [ unzip ];

# From mirror at https://code.jpope.org/jpope/breeze_cursor_sources
# We inline the ZIP as the mirror was sometimes unreachable in the past.
src = ./breeze-contrast-cursor-theme.zip;

installPhase = ''
install -d $out/share/icons
cp -r share/icons/${themeName} $out/share/icons/${themeName}
install -d $out/share/icons/${themeName}
cp -rf * $out/share/icons/${themeName}
'';

meta = {
Expand Down
16 changes: 16 additions & 0 deletions application/overlays/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: self: super: {

dividat-driver = (import ./dividat-driver) {
inherit (super) stdenv fetchFromGitHub buildGoModule;
pkgs = self;
};

playos-kiosk-browser = import ../../kiosk {
pkgs = self;
system_name = "PlayOS";
system_version = version;
};

breeze-contrast-cursor-theme = super.callPackage ./breeze-contrast-cursor-theme {};

}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ let
screen=$(xrandr --current | grep '*' | awk '{print $1}')
networkCount=$(connmanctl services | grep wifi | wc -l)
rfid=$(opensc-tool --list-readers | pr -T -o 2)
dataDiskFree=$(df -h /mnt/data | pr -T -o 2)
controller=$(systemctl is-active playos-controller)
time=$(date +'%T %Z')
printf "\033c"
Expand All @@ -19,6 +20,8 @@ let
"Wi-Fi networks found: $networkCount" \
"RFID readers connected:" \
"$rfid" \
"Persistent storage:" \
"$dataDiskFree" \
"Controller: $controller" \
"Updated at: $time" \
> ${ttyPath}
Expand Down
26 changes: 12 additions & 14 deletions system/modules/playos.nix → base/default.nix
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
# This is the toplevel module for all PlayOS related functionalities.

# Things that are injected into the system
{pkgs, version, updateCert, kioskUrl, greeting, playos-controller}:
{pkgs, version, kioskUrl, safeProductName, fullProductName, greeting, playos-controller}:


{config, lib, ...}:
with lib;
{
imports = [
(import ./networking.nix { hostName = safeProductName; inherit lib pkgs config; })
./localization.nix
./remote-maintenance.nix
./self-update
./system-partition.nix
./volatile-root.nix
./playos-status.nix
];

options = {
Expand All @@ -22,31 +25,26 @@ with lib;
playos.kioskUrl = mkOption {
type = types.str;
};

playos.updateCert = mkOption {
type = types.package;
};

};

config = {

# Use overlayed pkgs.
nixpkgs.pkgs = pkgs;
nixpkgs.pkgs = lib.mkDefault pkgs;

# Custom label when identifying OS
system.nixos.label = "PlayOS-${version}";
system.nixos.label = "${safeProductName}-${version}";

# disable installation of bootloader
boot.loader.grub.enable = false;

playos = {
inherit version updateCert kioskUrl;
};
# disable installation of inaccessible documentation
documentation.enable = false;

playos = { inherit version kioskUrl; };

# 'Welcome Screen'
services.getty = {
greetingLine = greeting "Dividat PlayOS (${version})";
greetingLine = greeting "${fullProductName} (${version})";
helpLine = "";
};

Expand Down
2 changes: 1 addition & 1 deletion system/localization.nix → base/localization.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let
in {

# Localization configuration
volatileRoot.persistentFolders."/var/lib/gui-localization" = {
playos.storage.persistentFolders."/var/lib/gui-localization" = {
mode = "0755";
user = "root";
group = "root";
Expand Down
6 changes: 3 additions & 3 deletions system/networking/default.nix → base/networking.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{config, pkgs, lib, ... }:
{config, pkgs, lib, hostName, ... }:

{
# Enable non-free firmware
Expand Down Expand Up @@ -37,7 +37,7 @@
};

networking = {
hostName = "playos";
hostName = hostName;

wireless = {
enable = true;
Expand Down Expand Up @@ -74,7 +74,7 @@
'';

# Make connman folder persistent
volatileRoot.persistentFolders."/var/lib/connman" = {
playos.storage.persistentFolders."/var/lib/connman" = {
mode = "0700";
user = "root";
group = "root";
Expand Down
Loading

0 comments on commit 0d8ef6a

Please sign in to comment.