Config-based KasmVNC

This commit is contained in:
Dmitry Maksyoma 2022-08-19 17:54:11 +00:00 committed by Anthony Merrill
parent d9cf46f83e
commit 36a1ffc5e4
78 changed files with 6214 additions and 954 deletions

1
.gitignore vendored
View File

@ -14,6 +14,7 @@ config.h
builder/build/
builder/www/
spec/tmp
# Deb building artefacts
debian/.debhelper/

View File

@ -15,6 +15,7 @@ variables:
stages:
- www
- build
- test
- upload
.prepare_build: &prepare_build
@ -371,6 +372,13 @@ build_opensuse_15_arm:
paths:
- output/
test:
stage: test
before_script:
- *prepare_build
script:
- bash builder/test-vncserver
upload:
stage: upload
image: ubuntu:focal

15
Pipfile Normal file
View File

@ -0,0 +1,15 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
mamba = "*"
expects = "*"
"path.py" = "*"
pexpect = "*"
[dev-packages]
[requires]
python_version = "3.8"

136
Pipfile.lock generated Normal file
View File

@ -0,0 +1,136 @@
{
"_meta": {
"hash": {
"sha256": "6745d5e5d90e44a18d73a0e23bc3d3e68acb950af0b87df50b45272d25b9e615"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"args": {
"hashes": [
"sha256:a785b8d837625e9b61c39108532d95b85274acd679693b71ebb5156848fcf814"
],
"version": "==0.1.0"
},
"clint": {
"hashes": [
"sha256:05224c32b1075563d0b16d0015faaf9da43aa214e4a2140e51f08789e7a4c5aa"
],
"version": "==0.5.1"
},
"coverage": {
"hashes": [
"sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c",
"sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6",
"sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45",
"sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a",
"sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03",
"sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529",
"sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a",
"sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a",
"sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2",
"sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6",
"sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759",
"sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53",
"sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a",
"sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4",
"sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff",
"sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502",
"sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793",
"sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb",
"sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905",
"sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821",
"sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b",
"sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81",
"sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0",
"sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b",
"sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3",
"sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184",
"sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701",
"sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a",
"sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82",
"sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638",
"sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5",
"sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083",
"sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6",
"sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90",
"sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465",
"sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a",
"sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3",
"sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e",
"sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066",
"sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf",
"sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b",
"sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae",
"sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669",
"sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873",
"sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b",
"sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6",
"sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb",
"sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160",
"sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c",
"sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079",
"sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d",
"sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==5.5"
},
"expects": {
"hashes": [
"sha256:419902ccafe81b7e9559eeb6b7a07ef9d5c5604eddb93000f0642b3b2d594f4c"
],
"index": "pypi",
"version": "==0.9.0"
},
"mamba": {
"hashes": [
"sha256:75cfc6dfd287dcccaf86dd753cf48e0a7337487c7c3fafda05a6a67ded6da496"
],
"index": "pypi",
"version": "==0.11.2"
},
"path": {
"hashes": [
"sha256:2de925e8d421f93bcea80d511b81accfb6a7e6b249afa4a5559557b0cf817097",
"sha256:340054c5bb459fc9fd40e7eb6768c5989f3e599d18224238465b5333bc8faa7d"
],
"markers": "python_version >= '3.6'",
"version": "==16.2.0"
},
"path.py": {
"hashes": [
"sha256:8d885e8b2497aed005703d94e0fd97943401f035e42a136810308bff034529a8",
"sha256:a43e82eb2c344c3fd0b9d6352f6b856f40b8b7d3d65cc05978b42c3715668496"
],
"index": "pypi",
"version": "==12.5.0"
},
"pexpect": {
"hashes": [
"sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937",
"sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"
],
"index": "pypi",
"version": "==4.8.0"
},
"ptyprocess": {
"hashes": [
"sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35",
"sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"
],
"version": "==0.7.0"
}
},
"develop": {}
}

View File

@ -56,41 +56,34 @@ wget <package_url>
sudo apt-get install ./kasmvncserver_*.deb
# We provide an example script to run KasmVNC at #
# /usr/share/doc/kasmvncserver/examples/kasmvncserver-easy-start. It runs a VNC
# server on display :10 and on interface 0.0.0.0. If you're happy with those
# defaults you can just use it as is:
sudo ln -s /usr/share/doc/kasmvncserver/examples/kasmvncserver-easy-start /usr/bin/
# Add your user to the ssl-cert group
sudo addgroup $USER ssl-cert
# You will need to re-connect in order to pick up the group change
# Create a KasmVNC user able to use keyboard and mouse:
vncpasswd -u $USER -w
# On the first run, vncserver will ask you to create a KasmVNC user and choose a desktop
# environment you want to run. It can detect Cinnamon, Mate, LXDE, LXQT, KDE, Gnome,
# XFCE. You can also choose to manually edit xstartup.
# After you chose a desktop environment or to manually edit xstartup,
# vncserver won't ask you again, unless you run it as:
vncserver -select-de
# Create ~/.vnc directory and corresponding files.
kasmvncserver-easy-start -d && kasmvncserver-easy-start -kill
# Modify vncstartup to launch your environment of choice, in this example LXDE
# This may be optional depending on your system configuration
echo '/usr/bin/lxsession -s LXDE &' >> ~/.vnc/xstartup
# Start KasmVNC with debug logging:
kasmvncserver-easy-start -d
# You can select a specific Desktop Environment like this:
vncserver -select-de mate
# Tail the logs
tail -f ~/.vnc/`hostname`:10.log
tail -f ~/.vnc/*.log
```
Now navigate to your system at https://[ip-address]:8443/
Now navigate to your system at the urls printed by `vncserver`.
To stop a running KasmVNC:
To stop the KasmVNC you started earlier on display 10:
```sh
kasmvncserver-easy-start -kill
vncserver -kill <display_number>
```
Settings can be modified via editing `/etc/kasmvnc/kasmvnc.yaml` or `~/.vnc/kasmvnc.yaml`.
The options for vncserver:
| Argument | Description |

View File

@ -110,6 +110,37 @@ prepare_upload_filename "bionic/kasmvncserver_0.9.1~beta-1+libjpeg-turbo-latest_
echo $upload_filename;'
```
# vncserver development
## Building a Ubuntu Focal package
```
builder/build-package ubuntu focal
```
You don't need to `build-package` every time you change something, but you need
`Xvnc` and other files.
## Running a development environment
```
builder/devenv-vncserver
```
`devenv-vncserver` starts a dockerized development environment. Edit
`vncserver`, its modules, and configuration files as usual. When you
run`vncserver`, not `/usr/bin/vncserver` will be used, but `./unix/vncserver`.
Same for configuration files.
Python specs can be run with `ty` alias inside devenv.
### Debug output
To see `vncserver` output, run `ty -d`. Anything you print inside `vncserver`
with `say` should be visible that way.
### Finding which spec produces a warning
By default, each passing test is represented as a dot. `-v` flag causes tests to
emit test descriptions alongside the program's output. Run `ty -v`.
# ARM
KasmVNC is supported on ARM, however, the build process needs to be broken into two parts with one occuring on a x64 system and the other on an ARM system. All our testing and official builds are done on AWS Graviton instances.

View File

@ -23,7 +23,7 @@ cd /tmp
# default to the version of x in Ubuntu 18.04, otherwise caller will need to specify
XORG_VER=${XORG_VER:-"1.19.6"}
XORG_PATCH=$(echo "$XORG_VER" | grep -Po '^\d.\d+' | sed 's#\.##')
wget https://www.x.org/archive/individual/xserver/xorg-server-${XORG_VER}.tar.bz2
wget --no-check-certificate https://www.x.org/archive/individual/xserver/xorg-server-${XORG_VER}.tar.bz2
#git clone https://kasmweb@bitbucket.org/kasmtech/kasmvnc.git
#cd kasmvnc

1
builder/common.sh Normal file
View File

@ -0,0 +1 @@
VNC_PORT=8443

20
builder/devenv-vncserver Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
set -e
default_os=ubuntu
default_os_codename=focal
cd "$(dirname "$0")/.."
. ./builder/os_ver_cli.sh
. ./builder/common.sh
docker build --build-arg KASMVNC_PACKAGE_DIR="builder/build/${os_codename}" \
-t kasmvncdevenv_${os}:$os_codename \
-f builder/dockerfile.${os}_${os_codename}.vncserver_devenv.test .
docker run -it -v $(realpath ${PWD}):/src -p "443:$VNC_PORT" -p "$VNC_PORT:$VNC_PORT" \
-p 8444:8444 \
-p 8445:8445 --rm \
-e KASMVNC_VERBOSE_LOGGING=$KASMVNC_VERBOSE_LOGGING \
-e "VNC_USER=foo" -e "VNC_PW=foobar" \
kasmvncdevenv_${os}:$os_codename

View File

@ -1,18 +1,20 @@
FROM centos:centos7
ENV STARTUPDIR=/dockerstartup
RUN yum install -y xterm
RUN yum install -y vim less
RUN yum install -y redhat-lsb-core
RUN yum install -y epel-release
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp/
RUN yum localinstall -y /tmp/*.rpm
RUN useradd -m foo
RUN mkdir -p $STARTUPDIR
COPY startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert
RUN mkdir ~/.vnc && echo '/usr/bin/xterm &' >> ~/.vnc/xstartup && \
chmod +x ~/.vnc/xstartup
ENTRYPOINT bash -c "echo -e \"$VNC_PW\n$VNC_PW\n\" | kasmvncpasswd -w -u \"$VNC_USER\" && vncserver :1 -interface 0.0.0.0 && vncserver -kill :1 && vncserver :1 -depth 24 -geometry 1280x1050 -websocketPort 8443 -cert /etc/pki/tls/private/kasmvnc.pem -sslOnly -FrameRate=24 -interface 0.0.0.0 -httpd /usr/share/kasmvnc/www && tail -f $HOME/.vnc/*.log "
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View File

@ -41,13 +41,16 @@ RUN yum install -y vim less
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./centos/kasmvncserver.spec /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
RUN yum localinstall -y /tmp/*.rpm
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp/
RUN /tmp/scripts/install_kasmvncserver_package
### END CUSTOM STUFF ###

View File

@ -37,13 +37,16 @@ RUN apt-get update && apt-get -y install lsb-release
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
RUN /tmp/scripts/install_kasmvncserver_package
### END CUSTOM STUFF ###

View File

@ -1,19 +1,19 @@
FROM debian:buster-slim
ENV STARTUPDIR=/dockerstartup
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN rm -f /tmp/kasmvncserver_*+*.deb; apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
RUN /tmp/scripts/install_kasmvncserver_package
RUN apt-get update && apt-get -y install xterm
COPY startup/deb/kasmvncserver-easy-start /usr/local/bin
RUN mkdir -p $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:ssl-cert
RUN mkdir ~/.vnc && echo '/usr/bin/xterm &' >> ~/.vnc/xstartup && \
chmod +x ~/.vnc/xstartup
ENTRYPOINT bash -c "echo -e \"$VNC_PW\n$VNC_PW\n\" | \
kasmvncpasswd -w -u $VNC_USER $HOME/.kasmpasswd && \
kasmvncserver-easy-start && tail -f $HOME/.vnc/*.log"
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View File

@ -34,16 +34,26 @@ RUN apt-get purge -y pm-utils xscreensaver*
RUN apt-get update && apt-get install -y vim less
RUN apt-get update && apt-get -y install lsb-release
RUN apt-get update && apt-get install -y task-cinnamon-desktop
RUN apt-get update && apt-get install -y task-gnome-desktop
RUN mkdir -p /usr/share/man/man1
RUN apt-get update && apt-get install -y apt-utils openjdk-11-jre
RUN apt-get update && apt-get install -y task-lxde-desktop
RUN apt-get update && apt-get install -y task-mate-desktop
RUN apt-get update && apt-get install -y task-kde-desktop
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
RUN /tmp/scripts/install_kasmvncserver_package
### END CUSTOM STUFF ###

View File

@ -1,18 +1,19 @@
FROM fedora:33
ENV STARTUPDIR=/dockerstartup
RUN dnf install -y xterm
RUN dnf install -y vim less
RUN yum install -y redhat-lsb-core
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp/
RUN dnf localinstall -y /tmp/*.rpm
RUN useradd -m foo
RUN mkdir -p $STARTUPDIR
COPY startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert
RUN mkdir ~/.vnc && echo '/usr/bin/xterm &' >> ~/.vnc/xstartup && \
chmod +x ~/.vnc/xstartup
ENTRYPOINT bash -c "echo -e \"$VNC_PW\n$VNC_PW\n\" | kasmvncpasswd -w -u \"$VNC_USER\" && vncserver :1 -interface 0.0.0.0 && vncserver -kill :1 && vncserver :1 -depth 24 -geometry 1280x1050 -websocketPort 8443 -cert /etc/pki/tls/private/kasmvnc.pem -sslOnly -FrameRate=24 -interface 0.0.0.0 -httpd /usr/share/kasmvnc/www && tail -f $HOME/.vnc/*.log "
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View File

@ -35,22 +35,24 @@ RUN dnf install -y xorg-x11-xauth xorg-x11-xkb-utils \
xkeyboard-config xorg-x11-server-utils
# xorg-x11-server-Xorg
# RUN dnf install -y @xfce-desktop-environment
RUN dnf group install -y lxde-desktop
RUN dnf erase -y pm-utils xscreensaver*
RUN dnf install -y redhat-lsb-core
RUN dnf install -y vim less
RUN dnf install -y @xfce-desktop-environment
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./centos/kasmvncserver.spec /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp/
# RUN dnf remove -y tigervnc-server-minimal
RUN dnf localinstall -y --allowerasing /tmp/*.rpm
RUN /tmp/scripts/install_kasmvncserver_package
### END CUSTOM STUFF ###
@ -58,7 +60,4 @@ RUN chown -R 1000:0 $HOME
USER 1000:kasmvnc-cert
WORKDIR $HOME
RUN mkdir ~/.vnc && echo '/usr/bin/lxsession -s LXDE &' >> ~/.vnc/xstartup && \
chmod +x ~/.vnc/xstartup
ENTRYPOINT [ "/dockerstartup/vnc_startup.sh" ]

View File

@ -37,13 +37,15 @@ RUN apt-get update && apt-get -y install lsb-release
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
RUN /tmp/scripts/install_kasmvncserver_package
### END CUSTOM STUFF ###

View File

@ -1,5 +1,7 @@
FROM opensuse/leap:15.3
ENV STARTUPDIR=/dockerstartup
# base tools
RUN zypper -n install -y \
less \
@ -27,11 +29,10 @@ ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
RUN zypper install -y --allow-unsigned-rpm /tmp/*.rpm
RUN useradd -m foo
RUN mkdir -p $STARTUPDIR
COPY startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert
RUN mkdir ~/.vnc && echo '/usr/bin/xterm &' >> ~/.vnc/xstartup && \
chmod +x ~/.vnc/xstartup
ENTRYPOINT bash -c "echo -e \"$VNC_PW\n$VNC_PW\n\" | kasmvncpasswd -w -u \"$VNC_USER\" && vncserver :1 -interface 0.0.0.0 && vncserver -kill :1 && vncserver :1 -depth 24 -geometry 1280x1050 -websocketPort 8443 -cert /etc/pki/tls/private/kasmvnc.pem -sslOnly -FrameRate=24 -interface 0.0.0.0 -httpd /usr/share/kasmvnc/www && tail -f $HOME/.vnc/*.log "
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View File

@ -1,20 +1,23 @@
FROM oraclelinux:8
ENV STARTUPDIR=/dockerstartup
RUN dnf install -y \
less \
redhat-lsb-core \
vim \
xterm
RUN dnf config-manager --set-enabled ol8_codeready_builder
RUN dnf install -y oracle-epel-release-el8
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
RUN dnf localinstall -y /tmp/*.rpm
RUN useradd -m foo
RUN mkdir -p $STARTUPDIR
COPY startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert
RUN mkdir ~/.vnc && echo '/usr/bin/xterm &' >> ~/.vnc/xstartup && \
chmod +x ~/.vnc/xstartup
ENTRYPOINT bash -c "echo -e \"$VNC_PW\n$VNC_PW\n\" | kasmvncpasswd -w -u \"$VNC_USER\" && vncserver :1 -interface 0.0.0.0 && vncserver -kill :1 && vncserver :1 -depth 24 -geometry 1280x1050 -websocketPort 8443 -cert /etc/pki/tls/private/kasmvnc.pem -sslOnly -FrameRate=24 -interface 0.0.0.0 -httpd /usr/share/kasmvnc/www && tail -f $HOME/.vnc/*.log "
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View File

@ -4,7 +4,7 @@ RUN apt-get update && \
apt-get -y install vim build-essential devscripts equivs
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/libjpeg-turbo*deb /tmp
COPY $KASMVNC_PACKAGE_DIR/libjpeg-turbo*deb /tmp/
RUN apt-get install /tmp/libjpeg-turbo*deb
# Install build-deps for the package.

View File

@ -37,17 +37,19 @@ RUN apt-get update && apt-get -y install lsb-release
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/libjpeg-turbo_*.deb /tmp
COPY $KASMVNC_PACKAGE_DIR/libjpeg-turbo_*.deb /tmp/
RUN apt-get install /tmp/libjpeg-turbo*deb
ARG BUILD_DEBIAN_REVISION
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*$BUILD_DEBIAN_REVISION*.deb /tmp
RUN dpkg -i /tmp/*.deb; apt-get -yf install
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*$BUILD_DEBIAN_REVISION*.deb /tmp/
RUN /tmp/scripts/install_kasmvncserver_package "$BUILD_DEBIAN_REVISION"
### END CUSTOM STUFF ###

View File

@ -37,13 +37,16 @@ RUN apt-get update && apt-get -y install lsb-release
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
RUN /tmp/scripts/install_kasmvncserver_package
### END CUSTOM STUFF ###

View File

@ -35,7 +35,7 @@ RUN apt-get purge -y pm-utils xscreensaver*
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####

View File

@ -1,15 +1,16 @@
FROM ubuntu:focal
ENV STARTUPDIR=/dockerstartup
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN rm -f /tmp/kasmvncserver_*+*.deb; apt-get update && dpkg -i /tmp/*.deb; apt-get -yf install
RUN apt-get update && apt-get -y install xterm lsb-release
RUN useradd -m foo && addgroup foo ssl-cert
RUN mkdir -p $STARTUPDIR
COPY builder/startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo && addgroup foo ssl-cert
USER foo
RUN mkdir ~/.vnc && echo '/usr/bin/xterm &' >> ~/.vnc/xstartup && \
chmod +x ~/.vnc/xstartup
ENTRYPOINT bash -c "echo -e \"$VNC_PW\n$VNC_PW\n\" | kasmvncpasswd -w -u \"$VNC_USER\" && vncserver :1 -interface 0.0.0.0 && vncserver -kill :1 && vncserver :1 -depth 24 -geometry 1280x1050 -websocketPort 8443 -cert /etc/ssl/certs/ssl-cert-snakeoil.pem -key /etc/ssl/private/ssl-cert-snakeoil.key -sslOnly -FrameRate=24 -interface 0.0.0.0 -httpd /usr/share/kasmvnc/www && tail -f $HOME/.vnc/*.log "
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View File

@ -37,13 +37,16 @@ RUN apt-get update && apt-get -y install lsb-release
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
RUN /tmp/scripts/install_kasmvncserver_package
RUN mkdir ~/.vnc && echo '/usr/bin/xfce4-session &' >> ~/.vnc/xstartup && \
chmod +x ~/.vnc/xstartup

View File

@ -0,0 +1,30 @@
FROM ubuntu:focal
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y vim less
RUN apt-get update && apt-get install -y python3-pip
RUN apt-get update && apt-get install -y strace silversearcher-ag xfonts-base
RUN apt-get update && apt-get install -y cinnamon
RUN apt-get update && apt-get install -y mate
RUN useradd -m docker
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN apt-get install -y /tmp/*$(dpkg --print-architecture).deb
ENV USER docker
ENV HOME /home/docker
RUN chown -R 1000:0 $HOME
USER 1000:ssl-cert
WORKDIR $HOME
RUN pip3 install --user pipenv
RUN echo 'PATH="~/.local/bin/:$PATH"' >> ~/.bashrc
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
ENTRYPOINT ["/bin/bash", "-ic", "/src/builder/run-specs-inside-docker"]

View File

@ -35,7 +35,7 @@ RUN apt-get purge -y pm-utils xscreensaver*
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####

View File

@ -0,0 +1,67 @@
FROM ubuntu:focal
ENV DEBIAN_FRONTEND=noninteractive
ENV VNC_PORT 8443
ENV VNC_PORT2 8444
ENV VNC_PORT3 8445
EXPOSE $VNC_PORT
EXPOSE $VNC_PORT2
EXPOSE $VNC_PORT3
RUN apt-get update && apt-get install -y supervisor xfce4 xfce4-terminal xterm libnss-wrapper gettext wget
RUN apt-get update && apt-get install -y vim less
RUN apt-get update && apt-get -y install lsb-release
RUN apt-get update && apt-get -y install net-tools
# RUN mkdir -p /usr/share/man/man1
# RUN apt-get update && apt-get install -y apt-utils openjdk-11-jre
RUN apt-get update && apt-get install -y ubuntu-mate-desktop
RUN apt-get update && apt-get install -y lxde
RUN apt-get update && apt-get install -y lxqt
RUN apt-get update && apt-get install -y kde-plasma-desktop
RUN apt-get update && apt-get install -y cinnamon
RUN apt-get update && apt-get install -y gnome-session
RUN apt-get purge -y pm-utils xscreensaver*
RUN apt-get purge -y clipit magnus kgpg
RUN apt-get update && apt-get install -y python3-pip
RUN apt-get update && apt-get install -y strace
RUN apt-get update && apt-get install -y silversearcher-ag
RUN apt-get update && apt-get install -y libdevel-stacktrace-perl
RUN useradd -m docker
ENV USER docker
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN /tmp/scripts/install_kasmvncserver_package
ENV KASMVNC_DEVELOPMENT 1
ENV HOME /home/docker
RUN chown -R 1000:0 $HOME
USER 1000:ssl-cert
WORKDIR $HOME
RUN pip3 install --user pipenv
RUN echo 'PATH="/src/unix:~/.local/bin/:$PATH"' >> ~/.bashrc
RUN echo 'export PERL5LIB="/src/unix"' >> ~/.bashrc
RUN echo 'ulimit -c 0' >> ~/.bashrc
RUN echo 'alias s="vncserver"' >> ~/.bashrc
RUN echo 'alias k="vncserver -kill :1; pkill baloo_file; pkill gpg-agent; pkill ssh-agent; pkill xiccd"' >> ~/.bashrc
RUN echo 'alias r="k; s"' >> ~/.bashrc
RUN echo 'alias go="vncserver; vncserver -kill :1"' >> ~/.bashrc
RUN echo 'alias ns="netstat -nltup"' >> ~/.bashrc
RUN echo 'alias tv="./run-specs spec/vncserver_yaml_validation_spec.py"' >> ~/.bashrc
RUN echo 'alias ty="./run-specs spec/vncserver_*spec.py"' >> ~/.bashrc
RUN echo 'alias ta="./run-specs"' >> ~/.bashrc
RUN echo 'alias vd="vncserver -dry-run"' >> ~/.bashrc
ENV SET_PASSWORD_FUNC 'sp() { echo -e "$VNC_PW\\n$VNC_PW\\n" | kasmvncpasswd -w -u $USER $HOME/.kasmpasswd; }'
RUN echo $SET_PASSWORD_FUNC >> ~/.bashrc
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
ENTRYPOINT ["bash", "-ic", "cd /src && pipenv install; exec bash"]

View File

@ -37,7 +37,7 @@ RUN apt-get update && apt-get -y install lsb-release
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY startup/ $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####

View File

@ -1,9 +1,9 @@
default_os=ubuntu
default_os_codename=bionic
default_os=${default_os:-ubuntu}
default_os_codename=${default_os_codename:-bionic}
os=${1:-$default_os}
os_codename=${2:-$default_os_codename}
build_tag="${3:-}"
build_tag="$3"
if [[ -n "$build_tag" ]]; then
build_tag_for_images="_${build_tag#+}"
build_debian_revision="$(echo $build_tag | tr _ -)"

18
builder/run-specs-inside-docker Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
logfile=/tmp/specs.log
red='\033[0;31m'
no_color='\033[0m'
fail_on_perl_warnings() {
if grep -qP 'line \d+\.$' "$logfile"; then
echo -e "${red}Failure: Perl warnings were found${no_color}"
false
fi
}
cd /src
pipenv install
./run-specs 2>&1 | tee "$logfile"
fail_on_perl_warnings

View File

@ -0,0 +1,64 @@
#!/bin/bash
set -e
if [[ -n "$1" ]]; then
tag="$1"
fi
is_debian() {
[[ -f /etc/debian_version ]]
}
check_package_version_exists() {
if ! stat /tmp/kasmvncserver_"$package_version"*.deb; then
>&2 echo "No package found for version $package_version"
exit 1
fi
}
remove_tagged_debs_unless_tag_used() {
if [[ -n "$tag" ]]; then
return
fi
rm -f /tmp/kasmvncserver_*+*.deb
}
detect_rpm_package_manager() {
if command -v dnf >/dev/null; then
rpm_package_manager=dnf
else
rpm_package_manager=yum
fi
}
install_package_built_for_current_branch_package_version_deb() {
remove_tagged_debs_unless_tag_used
apt-get update
apt-get install -y dpkg-dev
package_version=$(dpkg-parsechangelog --show-field Version \
--file /tmp/changelog)
check_package_version_exists
apt-get install -y /tmp/kasmvncserver_"$package_version"*"$tag"*.deb
}
install_package_built_for_current_branch_package_version_rpm() {
detect_rpm_package_manager
$rpm_package_manager install -y rpmdevtools
package_version=$(rpmspec -q --qf '%{version}\n' /tmp/kasmvncserver.spec 2>/dev/null)
if [[ $rpm_package_manager = "dnf" ]]; then
dnf localinstall -y --allowerasing /tmp/kasmvncserver-"$package_version"*.rpm
else
yum install -y /tmp/kasmvncserver-"$package_version"*.rpm
fi
}
if is_debian ; then
install_package_built_for_current_branch_package_version_deb
else
install_package_built_for_current_branch_package_version_rpm
fi

View File

@ -0,0 +1,50 @@
#!/bin/bash
debug() {
if [ -z "$debug" ]; then return; fi
echo "$@"
}
enable_debug() {
debug=1
log_option="-log *:stderr:100"
}
kill_vnc_server() {
vncserver -kill $display
}
process_cli_options() {
for option in "$@"; do
case "$option" in
--help)
show_help
exit
;;
-d|--debug)
enable_debug
;;
-k|--kill)
kill_vnc_server
exit
;;
-s|--select-de)
action=select-de-and-start
;;
*)
echo >&2 "Unsupported argument: $option"
exit 1
esac
done
}
show_help() {
cat >&2 <<-USAGE
Usage: $(basename "$0") [options]
-d, --debug Debug output
-k, --kill Kill vncserver
-s, --select-de Select desktop environent to run
--help Show this help
USAGE
}

View File

@ -4,43 +4,8 @@ set -e
display=:10
interface=0.0.0.0
cert_group=ssl-cert
if [[ "$1" = "--help" ]]; then
cat >&2 <<-USAGE
Usage: `basename $0` [options]
-d Debug output
-kill Kill vncserver
--help show this help
USAGE
exit
fi
if [[ "$1" = "-d" ]]; then
log_option="-log *:stderr:100"
fi
action=start
if [[ "$1" = "-kill" ]]; then
action=kill
fi
if groups | grep -qvw ssl-cert; then
cat <<-EOF
Can't access TLS certificate.
Please add your user to $cert_group via 'addgroup <user> ssl-cert'
EOF
exit 1
fi
if [[ "$action" = "kill" ]]; then
vncserver -kill $display
exit
fi
vncserver $display -interface $interface
vncserver -kill $display
vncserver $display -depth 24 -geometry 1280x1050 -websocketPort 8443 \
-cert /etc/ssl/certs/ssl-cert-snakeoil.pem \
-key /etc/ssl/private/ssl-cert-snakeoil.key -sslOnly -FrameRate=24 \
-interface $interface -httpd /usr/share/kasmvnc/www $log_option
-interface $interface -httpd /usr/share/kasmvnc/www

266
builder/startup/deb/select-de.sh Executable file
View File

@ -0,0 +1,266 @@
#!/bin/bash
set -e
xstartup_script=~/.vnc/xstartup
de_was_selected_file="$HOME/.vnc/.de-was-selected"
debug() {
if [ -z "$debug" ]; then return; fi
echo "$@"
}
enable_debug() {
debug=1
}
process_cli_options() {
while [ $# -gt 0 ]; do
local option="$1"
shift
case "$option" in
--help|-h)
show_help
exit
;;
-d|--debug)
enable_debug
;;
-y|--assume-yes)
assume_yes=1
;;
-s|--select-de)
action=select-de
if [[ -n "$1" && "${1:0:1}" != "-" ]]; then
selected_de="$1"
assume_yes_for_xstartup_overwrite=1
if [ "$selected_de" = "manual" ]; then
selected_de="$manual_xstartup_choice"
fi
shift
fi
;;
*)
echo >&2 "Unsupported argument: $option"
exit 1
esac
done
}
show_help() {
cat >&2 <<-USAGE
Usage: $(basename "$0") [options]
-d, --debug Debug output
-y, --assume-yes Automatic "yes" to prompts
-s, --select-de Select desktop environent to run
--help Show this help
USAGE
}
add_uppercase_desktop_environment_keys() {
local de_cmd
for de in "${!all_desktop_environments[@]}"; do
de_cmd=${all_desktop_environments[$de]};
all_desktop_environments[${de^^}]="$de_cmd"
done
}
manual_xstartup_choice="Manually edit xstartup"
process_cli_options "$@"
declare -A all_desktop_environments=(
[Cinnamon]="exec cinnamon-session"
[Mate]="XDG_CURRENT_DESKTOP=MATE exec dbus-launch --exit-with-session mate-session"
[LXDE]="exec lxsession"
[Lxqt]="exec startlxqt"
[KDE]="exec startkde"
[Gnome]="XDG_CURRENT_DESKTOP=GNOME exec dbus-launch --exit-with-session /usr/bin/gnome-session"
[XFCE]="exec xfce4-session")
readarray -t sorted_desktop_environments < <(for de in "${!all_desktop_environments[@]}"; do echo "$de"; done | sort)
all_desktop_environments[$manual_xstartup_choice]=""
sorted_desktop_environments+=("$manual_xstartup_choice")
add_uppercase_desktop_environment_keys
detected_desktop_environments=()
declare -A numbered_desktop_environments
print_detected_desktop_environments() {
declare -i i=1
echo "Please choose Desktop Environment to run:"
for detected_de in "${detected_desktop_environments[@]}"; do
echo "[$i] $detected_de"
numbered_desktop_environments[$i]=$detected_de
i+=1
done
}
detect_desktop_environments() {
for de_name in "${sorted_desktop_environments[@]}"; do
if [[ "$de_name" = "$manual_xstartup_choice" ]]; then
detected_desktop_environments+=("$de_name")
continue;
fi
local executable=${all_desktop_environments[$de_name]}
executable=($executable)
executable=${executable[-1]}
if detect_desktop_environment "$de_name" "$executable"; then
detected_desktop_environments+=("$de_name")
fi
done
}
ask_user_to_choose_de() {
while : ; do
print_detected_desktop_environments
read -r de_number_to_run
if [[ -z "$de_number_to_run" ]]; then
continue
fi
de_name_from_number "$de_number_to_run"
if [[ -n "$de_name" ]]; then
break;
fi
echo "Incorrect number: $de_number_to_run"
echo
done
}
remember_de_choice() {
touch "$de_was_selected_file"
}
de_was_selected_on_previous_run() {
[[ -f "$de_was_selected_file" ]]
}
detect_desktop_environment() {
local de_name="$1"
local executable="$2"
if command -v "$executable" &>/dev/null; then
return 0
fi
return 1
}
did_user_forbid_replacing_xstartup() {
grep -q -v KasmVNC-safe-to-replace-this-file "$xstartup_script"
}
de_cmd_from_name() {
de_cmd=${all_desktop_environments[${de_name^^}]}
}
de_name_from_number() {
local de_number_to_run="$1"
de_name=${numbered_desktop_environments[$de_number_to_run]}
}
warn_xstartup_will_be_overwriten() {
if [[ -n "$assume_yes" || -n "$assume_yes_for_xstartup_overwrite" ]]; then
return 0
fi
if [ ! -f "$xstartup_script" ]; then
return 0
fi
echo -n "WARNING: $xstartup_script will be overwritten y/N?"
read -r do_overwrite_xstartup
if [[ "$do_overwrite_xstartup" = "y" || "$do_overwrite_xstartup" = "Y" ]]; then
return 0
fi
return 1
}
setup_de_to_run_via_xstartup() {
warn_xstartup_will_be_overwriten
generate_xstartup "$de_name"
}
generate_xstartup() {
local de_name="$1"
de_cmd_from_name
cat <<-SCRIPT > "$xstartup_script"
#!/bin/sh
$de_cmd
SCRIPT
chmod +x "$xstartup_script"
}
user_asked_to_select_de() {
[[ "$action" = "select-de" ]]
}
user_specified_de() {
[ -n "$selected_de" ]
}
check_de_name_is_valid() {
local selected_de="$1"
if [[ "$selected_de" = "$manual_xstartup_choice" ]]; then
return 0;
fi
local de_cmd=${all_desktop_environments["${selected_de^^}"]:-}
if [ -z "$de_cmd" ]; then
echo >&2 "'$selected_de': not supported Desktop Environment"
return 1
fi
}
de_installed() {
local de_name="${1^^}"
for de in "${detected_desktop_environments[@]}"; do
if [ "${de^^}" = "$de_name" ]; then
return 0
fi
done
return 1
}
check_de_installed() {
local de_name="$1"
if ! de_installed "$de_name"; then
echo >&2 "'$de_name': Desktop Environment not installed"
return 1
fi
}
if user_asked_to_select_de || ! de_was_selected_on_previous_run; then
if user_specified_de; then
check_de_name_is_valid "$selected_de"
fi
detect_desktop_environments
if user_specified_de; then
check_de_installed "$selected_de"
de_name="$selected_de"
else
ask_user_to_choose_de
fi
debug "You selected $de_name desktop environment"
if [[ "$de_name" != "$manual_xstartup_choice" ]]; then
setup_de_to_run_via_xstartup
fi
remember_de_choice
fi

View File

@ -12,28 +12,6 @@ cleanup () {
}
trap cleanup SIGINT SIGTERM
detect_www_dir() {
local package_www_dir="/usr/share/kasmvnc/www"
if [[ -d "$package_www_dir" ]]; then
package_www_dir_option="-httpd $package_www_dir"
fi
}
detect_cert_location() {
local tarball_cert="$HOME/.vnc/self.pem"
local deb_cert="/etc/ssl/certs/ssl-cert-snakeoil.pem"
local deb_key="/etc/ssl/private/ssl-cert-snakeoil.key"
local rpm_cert="/etc/pki/tls/private/kasmvnc.pem"
if [[ -f "$deb_cert" ]]; then
cert_option="-cert $deb_cert -key $deb_key"
elif [[ -f "$rpm_cert" ]]; then
cert_option="-cert $rpm_cert"
else
cert_option="-cert $tarball_cert"
fi
}
add_vnc_user() {
local username="$1"
local password="$2"
@ -61,9 +39,6 @@ kasmvncpasswd -d -u "$VNC_USER-to-delete" $HOME/.kasmpasswd
chmod 0600 $HOME/.kasmpasswd
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout $HOME/.vnc/self.pem -out $HOME/.vnc/self.pem -subj "/C=US/ST=VA/L=None/O=None/OU=DoFu/CN=kasm/emailAddress=none@none.none"
vncserver :1 -interface 0.0.0.0
vncserver -kill :1
if [[ -f $PASSWD_PATH ]]; then
rm -f $PASSWD_PATH
fi
@ -84,12 +59,10 @@ vncserver -kill $DISPLAY &> $HOME/.vnc/vnc_startup.log \
|| echo "no locks present"
detect_www_dir
detect_cert_location
[ -n "$KASMVNC_VERBOSE_LOGGING" ] && verbose_logging_option="-log *:stderr:100"
[ -n "$KASMVNC_VERBOSE_LOGGING" ] && verbose_logging_option="-debug"
echo -e "start vncserver with param: VNC_COL_DEPTH=$VNC_COL_DEPTH, VNC_RESOLUTION=$VNC_RESOLUTION\n..."
vncserver $DISPLAY -depth $VNC_COL_DEPTH -geometry $VNC_RESOLUTION -FrameRate=$MAX_FRAME_RATE -websocketPort $VNC_PORT $cert_option -sslOnly -interface 0.0.0.0 $VNCOPTIONS $package_www_dir_option $verbose_logging_option #&> $STARTUPDIR/no_vnc_startup.log
vncserver $DISPLAY -select-de xfce -depth $VNC_COL_DEPTH -geometry $VNC_RESOLUTION -FrameRate=$MAX_FRAME_RATE -websocketPort $VNC_PORT $VNCOPTIONS $verbose_logging_option #&> $STARTUPDIR/no_vnc_startup.log
PID_SUN=$!

View File

@ -0,0 +1,22 @@
#!/bin/bash
set -euo pipefail
set_xterm_to_run() {
mkdir "$config_dir"
echo '/usr/bin/xterm &' >> "$xstartup"
chmod +x "$xstartup"
}
create_kasm_user() {
echo -e "$VNC_PW\n$VNC_PW\n" | kasmvncpasswd -w -u "$VNC_USER"
}
config_dir="$HOME/.vnc"
xstartup="$config_dir/xstartup"
set_xterm_to_run
create_kasm_user
vncserver -select-de manual -websocketPort "$VNC_PORT"
tail -f "$config_dir"/*.log

View File

@ -2,15 +2,17 @@
set -e
cd "$(dirname "$0")"
. ./os_ver_cli.sh
cd "$(dirname "$0")/.."
. ./builder/os_ver_cli.sh
. ./builder/common.sh
tester_image=kasmvnctester_${os}:$os_codename${build_tag_for_images}
docker build --build-arg KASMVNC_PACKAGE_DIR="build/${os_codename}" \
tester_image="builder/kasmvnctester_${os}:$os_codename${build_tag_for_images}"
docker build --build-arg KASMVNC_PACKAGE_DIR="builder/build/${os_codename}" \
--build-arg BUILD_DEBIAN_REVISION="$build_debian_revision" \
-t "$tester_image" \
-f dockerfile.${os}_${os_codename}${build_tag}.deb.test .
docker run -it -p 443:8443 --rm \
-f "builder/dockerfile.${os}_${os_codename}${build_tag}.deb.test" .
docker run -it -p "443:$VNC_PORT" --rm \
-e KASMVNC_VERBOSE_LOGGING=$KASMVNC_VERBOSE_LOGGING \
-e "VNC_USER=foo" -e "VNC_PW=foobar" \
-e "VNC_PORT=$VNC_PORT" \
"$tester_image"

View File

@ -2,13 +2,15 @@
set -e
cd "$(dirname "$0")"
cd "$(dirname "$0")/.."
. ./builder/common.sh
os="${1:-debian}"
os_codename="${2:-buster}"
docker build --build-arg KASMVNC_PACKAGE_DIR="build/${os_codename}" \
docker build --build-arg KASMVNC_PACKAGE_DIR="builder/build/${os_codename}" \
-t kasmvnctester_barebones_${os}:$os_codename \
-f dockerfile.${os}_${os_codename}.barebones.deb.test .
-f builder/dockerfile.${os}_${os_codename}.barebones.deb.test .
echo
docker run -it -p 443:8443 --rm -e "VNC_USER=foo" -e "VNC_PW=foobar" \
docker run -it -p "443:$VNC_PORT" --rm -e "VNC_USER=foo" -e "VNC_PW=foobar" \
-e "VNC_PORT=$VNC_PORT" \
kasmvnctester_barebones_${os}:$os_codename

View File

@ -2,16 +2,18 @@
set -e
cd "$(dirname "$0")"
. ./os_ver_cli.sh
cd "$(dirname "$0")/.."
. ./builder/os_ver_cli.sh
. ./builder/common.sh
echo kasmvnctester_${os}:$os_codename
docker build --build-arg \
KASMVNC_PACKAGE_DIR="build/${os}_${os_codename}" \
KASMVNC_PACKAGE_DIR="builder/build/${os}_${os_codename}" \
-t kasmvnctester_${os}:$os_codename \
-f dockerfile.${os}_${os_codename}.rpm.test .
-f builder/dockerfile.${os}_${os_codename}.rpm.test .
docker run -it -p 443:8443 --rm \
docker run -it -p "443:$VNC_PORT" --rm \
-e KASMVNC_VERBOSE_LOGGING=$KASMVNC_VERBOSE_LOGGING \
-e "VNC_USER=foo" -e "VNC_PW=foobar" \
-e "VNC_PORT=$VNC_PORT" \
kasmvnctester_${os}:$os_codename

View File

@ -3,11 +3,13 @@
set -e
cd "$(dirname "$0")"
. ./common.sh
os="${1:-centos}"
os_codename="${2:-core}"
docker build --build-arg KASMVNC_PACKAGE_DIR="build/${os}_${os_codename}" \
-t kasmvnctester_barebones_${os}:$os_codename \
-f dockerfile.${os}_${os_codename}.barebones.rpm.test .
docker run -it -p 443:8443 --rm -e "VNC_USER=foo" -e "VNC_PW=foobar" \
docker run -it -p "443:$VNC_PORT" --rm -e "VNC_USER=foo" -e "VNC_PW=foobar" \
-e "VNC_PORT=$VNC_PORT" \
kasmvnctester_barebones_${os}:$os_codename

23
builder/test-vncserver Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
set -e
default_os=ubuntu
default_os_codename=focal
. ./builder/os_ver_cli.sh
if [[ -n "$GITLAB_CI" ]]; then
package_dir="output/${os_codename}"
else
package_dir="builder/build/${os_codename}"
fi
docker build --build-arg KASMVNC_PACKAGE_DIR="$package_dir" \
-t kasmvnctester_${os}:$os_codename \
-f builder/dockerfile.${os}_${os_codename}.specs.test .
docker run -v $(realpath ${PWD}):/src \
--rm \
-e KASMVNC_VERBOSE_LOGGING=$KASMVNC_VERBOSE_LOGGING \
-e "VNC_USER=foo" -e "VNC_PW=foobar" \
kasmvnctester_${os}:$os_codename

View File

@ -7,7 +7,7 @@ License: GPLv2+
URL: https://github.com/kasmtech/KasmVNC
BuildRequires: rsync
Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl
Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny
Conflicts: tigervnc-server, tigervnc-server-minimal
%description
@ -31,6 +31,8 @@ create a by default secure, web based experience.
Simplicity - KasmVNC aims at being simple to deploy and configure.
WARNING: this package requires EPEL.
%prep
%install
@ -48,17 +50,28 @@ DESTDIR=$RPM_BUILD_ROOT
DST_MAN=$DESTDIR/usr/share/man/man1
mkdir -p $DESTDIR/usr/bin $DESTDIR/usr/share/man/man1 \
$DESTDIR/usr/share/doc/kasmvncserver
$DESTDIR/usr/share/doc/kasmvncserver $DESTDIR/usr/lib \
$DESTDIR/usr/share/perl5 $DESTDIR/etc/kasmvnc
cp $SRC_BIN/Xvnc $DESTDIR/usr/bin;
cp $SRC_BIN/vncserver $DESTDIR/usr/bin;
cp -a $SRC_BIN/KasmVNC $DESTDIR/usr/share/perl5/
cp $SRC_BIN/vncconfig $DESTDIR/usr/bin;
cp $SRC_BIN/kasmvncpasswd $DESTDIR/usr/bin;
cp $SRC_BIN/kasmxproxy $DESTDIR/usr/bin;
cp -r $SRC/lib/kasmvnc/ $DESTDIR/usr/lib/kasmvncserver
cd $DESTDIR/usr/bin && ln -s kasmvncpasswd vncpasswd;
cp -r $SRC/share/doc/kasmvnc*/* $DESTDIR/usr/share/doc/kasmvncserver/
rsync -r --exclude '.git*' --exclude po2js --exclude xgettext-html \
--exclude www/utils/ --exclude .eslintrc \
--exclude www/utils/ --exclude .eslintrc --exclude configure \
$SRC/share/kasmvnc $DESTDIR/usr/share
sed -i -e 's!pem_certificate: .\+$!pem_certificate: /etc/pki/tls/private/kasmvnc.pem!' \
$DESTDIR/usr/share/kasmvnc/kasmvnc_defaults.yaml
sed -i -e 's!pem_key: .\+$!pem_key: /etc/pki/tls/private/kasmvnc.pem!' \
$DESTDIR/usr/share/kasmvnc/kasmvnc_defaults.yaml
sed -e 's/^\([^#]\)/# \1/' $DESTDIR/usr/share/kasmvnc/kasmvnc_defaults.yaml > \
$DESTDIR/etc/kasmvnc/kasmvnc.yaml
cp $SRC/man/man1/Xvnc.1 $DESTDIR/usr/share/man/man1/;
cp $SRC/share/man/man1/vncserver.1 $DST_MAN;
cp $SRC/share/man/man1/vncconfig.1 $DST_MAN;
@ -68,9 +81,13 @@ cd $DST_MAN && ln -s vncpasswd.1 kasmvncpasswd.1;
%files
%config(noreplace) /etc/kasmvnc
/usr/bin/*
/usr/lib/kasmvncserver
/usr/share/man/man1/*
/usr/share/kasmvnc/www
/usr/share/perl5/KasmVNC
/usr/share/kasmvnc
%license /usr/share/doc/kasmvncserver/LICENSE.TXT
%doc /usr/share/doc/kasmvncserver/README.md

View File

@ -11,16 +11,22 @@ install: unpack_tarball
echo "TAR_DATA: $(TAR_DATA)"
echo "installing files"
mkdir -p $(DESTDIR)/usr/bin $(DESTDIR)/usr/share/man/man1 \
$(DESTDIR)/usr/share/doc/kasmvncserver
$(DESTDIR)/usr/share/doc/kasmvncserver $(DESTDIR)/usr/lib \
$(DESTDIR)/usr/share/perl5 \
$(DESTDIR)/etc/kasmvnc
cp $(SRC_BIN)/Xvnc $(DESTDIR)/usr/bin/Xkasmvnc
cp $(SRC_BIN)/vncserver $(DESTDIR)/usr/bin/kasmvncserver
cp -r $(SRC_BIN)/KasmVNC $(DESTDIR)/usr/share/perl5/
cp $(SRC_BIN)/vncconfig $(DESTDIR)/usr/bin/kasmvncconfig
cp $(SRC_BIN)/kasmvncpasswd $(DESTDIR)/usr/bin/
cp $(SRC_BIN)/kasmxproxy $(DESTDIR)/usr/bin/
cp -r $(SRC)/lib/kasmvnc/ $(DESTDIR)/usr/lib/kasmvncserver
cp -r $(SRC)/share/doc/kasmvnc*/* $(DESTDIR)/usr/share/doc/kasmvncserver/
rsync -r --exclude '.git*' --exclude po2js --exclude xgettext-html \
--exclude www/utils/ --exclude .eslintrc \
$(SRC)/share/kasmvnc $(DESTDIR)/usr/share
sed -e 's/^\([^#]\)/# \1/' $(SRC)/share/kasmvnc/kasmvnc_defaults.yaml > \
$(DESTDIR)/etc/kasmvnc/kasmvnc.yaml
cp $(SRC)/man/man1/Xvnc.1 $(DESTDIR)/usr/share/man/man1/Xkasmvnc.1
cp $(SRC)/share/man/man1/vncserver.1 $(DST_MAN)/kasmvncserver.1
cp $(SRC)/share/man/man1/kasmxproxy.1 $(DST_MAN)/kasmxproxy.1

4
debian/control vendored
View File

@ -12,7 +12,9 @@ Homepage: https://github.com/kasmtech/KasmVNC
Package: kasmvncserver
Architecture: amd64 arm64
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, ssl-cert, xauth,
x11-xkb-utils, xkb-data, procps
x11-xkb-utils, xkb-data, procps, libswitch-perl, libyaml-tiny-perl,
libhash-merge-simple-perl, libscalar-list-utils-perl, liblist-moreutils-perl,
libtry-tiny-perl
Provides: vnc-server
Description: VNC server accessible from a web browser
VNC stands for Virtual Network Computing. It is, in essence, a remote

11
doc/YAML config FAQ.md Normal file
View File

@ -0,0 +1,11 @@
### logging.log_dest
Log to the instance's log file in `~/.vnc`, or syslog. You can find the right
log file by the display number. For example, in `9b1d402e204c:1.log`, `:1` is
the display number. When you start a new instance with `vncserver`, it prints
the display number it uses.
### logging.level
For the initial setup, it's a good idea to use 100. With 100, you're able to see
login attempts and reasons they fail.

763
doc/YAML config.md Normal file
View File

@ -0,0 +1,763 @@
### desktop.resolution.width, desktop.resolution.height
Set a fixed desktop resolution. Set `desktop.allow_resize` to `false` for
this to work.
Unit: pixels
<br>
Default: 1024x768
### desktop.allow_resize
If turned on, resizing browser window changes desktop resolution to fit the
window.
Set to `false` to have a fixed resolution (you need to set
[desktop.resolution.width and
desktop.resolution.heigh](#desktop.resolution.width%2C-desktop.resolution.height)).
Unit: boolean
<br>
Default: `true`
### desktop.pixel_depth
Pixel depth in bits. Possible values are 16, 24, 32. These values are fail-safe.
You can specify any bit value via command-line.
Unit: bits
<br>
Default: `24`
### network.protocol
With KasmVNC, you can use a web browser client (set value to `http`) or a
traditional VNC client (set value to `vnc`).
If you use `vnc` protocol, you're on your own. Passing `Xvnc` options via
command-line is required in this case. Most config settings are ignored.
Unit: `http`, `vnc`
<br>
Default: `http`
### network.interface
IP address or host name to listen on. Set to `0.0.0.0` to listen on all network
interfaces.
Unit: ip address or host name
<br>
Default: `0.0.0.0`
### network.websocket_port
Listen for websocket connections on this port. `auto` translates to 8443 + X
display number.
Unit: integer
<br>
Default: `auto`
### network.use_ipv4
Use IPv4 for incoming and outgoing connections.
Unit: boolean
<br>
Default: `true`
### network.use_ipv6
Use IPv6 for incoming and outgoing connections.
Unit: boolean
<br>
Default: `true`
### network.udp.public_ip
KasmVNC server needs to know its IP from the perspective of the client. With `auto`,
it finds that out automatically (by using a public STUN server).
If the server and client are on the same private network, and not connected
to internet, you need to specify a private IP address of the server, accessible
to the client.
Unit: IP address, `auto`.
<br>
Default: `auto`
### network.udp.port
Set UDP port to use. With `auto`,
value is inherited from [network.websocket_port](#network.websocket_port).
Unit: `auto`, integer
<br>
Default: `auto`
### network.ssl.pem_certificate
SSL pem certificate to use for websocket connections.
Unit: path
<br>
Default: standard snake oil certificate on Debian-based distros. Auto-generated
on Fedora-based distros.
### network.ssl.pem_key
SSL pem key to use for websocket connections. If you have private and public
keys in one file, using
[network.ssl.pem_certificate](#network.ssl.pem_certificate) is enough to set
both.
Unit: path
<br>
Default: standard snake oil certificate on Debian-based distros. Auto-generated
on Fedora-based distros.
### network.ssl.require_ssl
Require SSL for websocket connections.
Unit: boolean
<br>
Default: `true`
### user_session.session_type
* `shared` - allow multiple sessions for a single desktop.
* `exclusive` - only one user session can work with the desktop.
If set, overrides client settings.
When combined with
[concurrent_connections_prompt](#user_session.concurrent_connections_prompt) ,
the user is asked to let the incoming connection in.
Unit: `shared`, `exclusive`
<br>
Default: not set, client settings are used
## user_session.new_session_disconnects_existing_exclusive_session
Only applies if [session_type](#user_session.session_type) is set to
`exclusive`. The user working with the desktop is kicked out by a new session.
New session takes over the desktop.
When combined with
[concurrent_connections_prompt](#user_session.concurrent_connections_prompt),
the user is asked to confirm session takeover.
Unit: boolean
<br>
Default: `false`
### user_session.concurrent_connections_prompt
Prompts the user of the desktop to explicitly accept or reject incoming
connections.
The vncconfig(1) program must be running on the desktop.
Unit: boolean
<br>
Default: `false`
### user_session.concurrent_connections_prompt_timeout
Active only if
[concurrent_connections_prompt](#user_session.concurrent_connections_prompt),
is turned on.
Number of seconds to show the Accept Connection dialog before rejecting the
connection.
Unit: seconds
<br>
Default: `10`
### user_session.idle_timeout
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
The number of seconds after which an idle session is dropped.
Unit: seconds
<br>
Default: `never`
### keyboard.remap_keys
Set up 1-to-1 character replacement. For example, to exchange the " and @
symbols you would specify the following: `0x22->0x40`. Similar to tr(1).
Unit: hex numbers in the format <from_character>-><to_character>
<br>
Default: not set
### keyboard.ignore_numlock
-- TODO
Key affected by NumLock often require a fake Shift to be inserted in order for
the correct symbol to be generated. Turning on this setting avoids these extra
fake Shift events but may result in a slightly different symbol (for example, a
Return instead of a keypad Enter).
Unit: boolean
<br>
Default: `false`
### keyboard.raw_keyboard
Send keyboard events straight through and avoid mapping them to the current
keyboard layout. This effectively makes the keyboard behave according to the
layout configured on the server instead of the layout configured on the client.
Unit: boolean
<br>
Default: `false`
### pointer.enabled
Allows clicks from mice, trackpads, etc.
Unit: boolean
<br>
Default: `true`
### runtime_configuration.allow_client_to_override_kasm_server_settings
KasmVNC exposes a few settings to the client the standard VNC does not. You can
let the client override these settings or forbid overriding.
Unit: boolean
<br>
Default: `true`
### runtime_configuration.allow_override_standard_vnc_server_settings
If turned on, VNC settings defined in
[runtime_configuration.allow_override_list](#runtime_configuration.allow_override_list)
can be changed at runtime.
Unit: boolean
<br>
Default: `true`
### runtime_configuration.allow_override_list
You can modify listed settings at runtime. Settings can be modified, for
example, using vncconfig(1) program from inside a running session.
The list must contain absolute config keys like
[pointer.enable](#pointer.enable). To actually change
[pointer.enable](#pointer.enable), you need to pass the corresponding
command-line option `AcceptPointerEvents` to vncconfig(1).
Unit: list of absolute config keys
<br>
Default:
```
pointer.enabled
data_loss_prevention.clipboard.server_to_client.enabled
data_loss_prevention.clipboard.client_to_server.enabled
data_loss_prevention.clipboard.server_to_client.primary_clipboard_enabled
```
### logging.log_writer_name
Log all subsystems of KasmVNC by setting to `all`. To log a specific subsystem,
consult source code for `LogWriter` instances. For example, `static LogWriter
vlog("STrayIcon");`. `STrayIcon` is the log writer name here.
Unit: `all`, \<log writer name found in source code\>
<br>
Default: `all`
### logging.log_dest
Log to the instance's log file in `~/.vnc`, or syslog.
Unit: `logfile`, `syslog`
<br>
Default: `logfile`
### logging.level
Logging verbosity level. Can be in the 0.\.100 range. 100 meaning most verbose
output, 0 meaning most concise.
Unit: integer in the 0.\.100 range
<br>
Default: `30`
### security.brute_force_protection.blacklist_threshold
The number of unauthenticated connection attempts allowed from any individual
host before that host is black-listed.
Unit: integer
<br>
Default: `5`
### security.brute_force_protection.blacklist_timeout
The initial timeout applied when a host is first black-listed by failing to
authenticate
[blacklist_threshold](#security.brute_force_protection.blacklist_threshold)
times. The host cannot re-attempt a connection until the timeout expires.
Unit: seconds
<br>
Default: `10`
### data_loss_prevention.visible_region.top, data_loss_prevention.visible_region.left, data_loss_prevention.visible_region.right, data_loss_prevention.visible_region.bottom
The regions feature allows you to select a region of the screen to render to the
user. Concealed portions of the screen are blacked out.
#### Absolute coordinates
Select a region using pixels:
```
top: 10
left: 10
right: 40
bottom: 40
```
#### Offset coordinates
Use negative numbers to offset from the screen boundary. For `left` and `top`,
this means 0 plus the provided number. In the below example that would be 10.
For `right` and `bottom`, that means the maximum horizontal or vertical
resolution minus the provided number.
If the resolution was 1080x720 in the below example that would equate to a
`right` of 1070 and `bottom` of 710. Therefore, the example below would be
translated to 10, 10, 1070, 710. Using offset coordinates has an advantage of
scaling with screen size changes versus using absolute values.
Select a region using pixel offsets:
```
top: -10
left: -10
right: -10
bottom: -10
```
You can combine absolute values with offset values, such as the following
example:
```
top: 50
left: 10
right: -10
bottom: -10
```
#### Percentages
Regions does support percent values, which are evaluated as a border that is a
percent of the total width and height respectively. Regions does not support
mixing percent values and absolute or offset values.
For example:
```
top: 10%
left: 10%
right: 20%
bottom: 20%
```
Unit: pixels, offset pixels, percentages
<br>
Default: not set
### data_loss_prevention.visible_region.concealed_region.allow_click_down
Allow mouse button down events within the concealed regions, by default they are
blocked.
Unit: boolean
<br>
Default: `false`
### data_loss_prevention.visible_region.concealed_region.allow_click_release
Allow mouse button releases within the concealed regions, by default they are
blocked until the cursor returns to the visible region.
Unit: boolean
<br>
Default: `false`
### data_loss_prevention.clipboard.delay_between_operations
This many milliseconds must pass between clipboard actions.
Unit: milliseconds, `none`
<br>
Default: `none`
### data_loss_prevention.clipboard.allow_mimetypes
Allowed binary clipboard mimetypes.
Unit: mimetype
<br>
Default:
```
chromium/x-web-custom-data
text/html
image/png`
```
### data_loss_prevention.clipboard.server_to_client.enabled
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
Whether to send desktop clipboard changes to clients.
Unit: boolean
<br>
Default: `false`
### data_loss_prevention.clipboard.server_to_client.size
Limit clipboard bytes to send to clients in one transaction.
Unit: number of bytes, `unlimited`
<br>
Default: `unlimited`
### data_loss_prevention.clipboard.server_to_client.primary_clipboard_enabled
Send the primary selection to the client. Meaning, mouse-selected text is copied
to clipboard. Only works in Chromium-based browsers.
Unit: boolean
<br>
Default: `false`
### data_loss_prevention.clipboard.client_to_server.enabled
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
Accept clipboard updates from clients.
Unit: boolean
<br>
Default: `false`
### data_loss_prevention.clipboard.client_to_server.size
Limit clipboard bytes to receive from clients in one transaction.
Unit: number of bytes, `unlimited`
<br>
Default: `unlimited`
### data_loss_prevention.keyboard.enabled
Accept key press and release events from clients.
Unit: boolean
<br>
Default: `true`
### data_loss_prevention.keyboard.rate_limit
Reject keyboard presses over this many per second.
Unit: integer, `unlimited`
<br>
Default: `unlimited`
### data_loss_prevention.logging.level
Log clipboard and keyboard actions. `info` logs just clipboard direction and
size, `verbose` adds the contents for both.
Unit: `off`, `info`, `verbose`
<br>
Default: `off`
### encoding.max_frame_rate
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
The maximum number of updates per second sent to clients. If the screen
updates any faster then those changes are aggregated and sent in a single
update to the client. Note that this only controls the maximum rate and a client
may get a lower rate when resources are limited.
Unit: integer
<br>
Default: `60`
### encoding.full_frame_updates
KasmVNC cuts the screen up into smaller rectangles and only sends sections of
the screen that change. When using UDP, some rectangles can be dropped, so this
option forces a full screen update every X frames.
Unit: `none`, positive integer
<br>
Default: `none`
### encoding.rect_encoding_mode.min_quality
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
The minimum quality setting for JPEG/WEBP encoding. Rendering automatically
degrades JPEG quality when there is a lot of motion in a particular block. This
setting controls the minimum quality to use when there is a high degree of
change. The accepted values are 0.\.9 where 0 is low and 9 is high.
Unit: integer in the 0.\.9 range
<br>
Default: `7`
### encoding.rect_encoding_mode.max_quality
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
The maximum quality setting for JPEG/WEBP encoding. Rendering automatically
degrades JPEG quality when there is a lot of motion in a particular block. This
setting controls the maximum quality to use when there is no or little motion.
The accepted values are 0.\.9 where 0 is low and 9 is high.
Unit: integer in the 0.\.9 range
<br>
Default: `8`
### encoding.rect_encoding_mode.consider_lossless_quality
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
KasmVNC dynamically adjusts the JPEG/WEBP quality based on how much change
there is in a particular section. Every x number of frames it sends a
'lossless' update. That way, if you are scrolling, the text blurs a little while
you scroll but as soon as you stop, it should clear up on the next lossless
update. `consider_lossless_quality` means "treat this quality as lossless."
Assuming the min quality of 3, the max of 7 and treat lossless of 5. KasmVNC
would constantly adjust the quality of images sent anywhere from 3 to 7
depending on the rate of change. If the last rectangle sent was at 5 then it
would not send a lossless update for that part of the screen.
Unit: integer in the 0.\.10 range
<br>
Default: `10`
### encoding.rect_encoding_mode.rectangle_compress_threads
Use this many threads to compress rectangles in parallel. `auto` sets threads to
match the core count.
Unit: integer, `auto`.
<br>
Default: `auto`
### encoding.video_encoding_mode.jpeg_quality
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
The JPEG quality to use when in video mode. The accepted values are 0.\.9 where
0 is low and 9 is high. A value of -1 keeps the quality level used in normal
mode.
Unit: integer in the -1..9 range
<br>
Default: `-1`
### encoding.video_encoding_mode.webp_quality
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
The WEBP quality to use when in video mode. The accepted values are 0.\.9 where 0
is low and 9 is high. A value of -1 keeps the quality level used in normal mode.
Unit: integer in the -1..9 range
<br>
Default: `-1`
### encoding.video_encoding_mode.max_resolution.width, encoding.video_encoding_mode.max_resolution.height
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
When in Video Mode, downscale the screen to this maximum size. Keeps aspect
ratio with client's actual resolution.
Unit: pixels
<br>
Default: 1920x1080
### encoding.video_encoding_mode.enter_video_encoding_mode.time_threshold
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
Number of seconds that a high rate of change most occur before switching to
video mode. Setting to 0 forces Video Mode at all times.
Unit: seconds
<br>
Default: `5`
### encoding.video_encoding_mode.enter_video_encoding_mode.area_threshold
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
The percent of the screen that must be seeing high rates of change to meet the
threshold of Video Mode. This percentage of the screen must see rapid changes
for the amount of time specified by [encoding.video_encoding_mode.enter_video_encoding_mode.time_threshold](#encoding.video_encoding_mode.enter_video_encoding_mode.time_threshold).
Unit: percentage of screen
<br>
Default: `45%`
### encoding.video_encoding_mode.exit_video_encoding_mode.time_threshold
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
When in Video Mode, high rates of change must subside for this many seconds
before dropping out of video mode.
Unit: seconds
<br>
Default: `3`
### encoding.video_encoding_mode.logging.level
Print the detected video area % value. This is useful when trying to tune your
settings for your particular use case.
Unit: `info`, `off`
<br>
Default: `off`
### encoding.video_encoding_mode.scaling_algorithm
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
The scaling method to use in video mode.
Unit: `nearest`, `bilinear`, `progressive_bilinear`
<br>
Default: `progressive_bilinear`
### encoding.compare_framebuffer
Perform pixel comparison on frame buffer to reduce unnecessary updates.
Unit: `off`, `always`, `auto`
<br>
Default: `auto`
### encoding.zrle_zlib_level
⚠️ This setting only applies, when
[allow_client_to_override_kasm_server_settings](#runtime_configuration.allow_client_to_override_kasm_server_settings)
is turned off.
Zlib compression level for ZRLE encoding (it does not affect Tight encoding).
Acceptable values are between 0.\.9. Set to `auto` to use the standard
compression level provided by the zlib(3) compression library.
Unit: integer in the 0.\.9 range, `auto`
<br>
Default: `auto`
### encoding.hextile_improved_compression
Use improved compression algorithm for Hextile encoding which achieves better
compression ratios by the cost of using slightly more CPU time.
Unit: boolean
<br>
Default: `true`
### server.advanced.x_font_path
Specify X font path.
Unit: path, `auto`
<br>
Default: `auto`
### server.advanced.httpd_directory
Run a mini-HTTP server which serves files from the given directory. Normally the
directory contains the kasmweb client.
Unit: path
<br>
Default: `/usr/share/kasmvnc/www`
### server.advanced.kasm_password_file
Password file for Basic authentication, created with the `kasmvncpasswd(1)`
utility.
Unit: path
<br>
Default: `${HOME}/.kasmpasswd`
### server.advanced.x_authority_file
Set to X authority file. X authority file stores credentials in cookies used by
`xauth(1)` for authentication of X sessions.
`auto` means using file defined in `$XAUTHORITY` environment variable. If the
variable isn't defined, fallback to using `${HOME}/.Xauthority` file.
Unit: path
<br>
Default: `auto`
### server.auto_shutdown.no_user_session_timeout
Terminate KasmVNC when no client has been connected for this many
seconds.
Unit: seconds, `never`
<br>
Default: `never`
### server.auto_shutdown.active_user_session_timeout
Terminate KasmVNC when a client has been connected for this many
seconds.
Unit: seconds, `never`
<br>
Default: `never`
### server.auto_shutdown.inactive_user_session_timeout
Terminate KasmVNC after this many seconds of user inactivity.
Unit: seconds, `never`
<br>
Default: `never`
### command_line.prompt
Guide the user (by prompting), to ensure that KasmVNC is usable. For example,
prompt to create a KasmVNC user if no users exist or no users can control the
desktop.
Unit: boolean
<br>
Default: `true`

View File

@ -7,7 +7,7 @@ License: GPLv2+
URL: https://github.com/kasmtech/KasmVNC
BuildRequires: rsync
Requires: xauth, libxkbcommon-x11-0, xkeyboard-config, x11-tools, openssl, perl, libpixman-1-0, libjpeg8, libgomp1, libXfont2-2, libXdmcp6, libglvnd, xkbcomp
Requires: xauth, hostname, libxkbcommon-x11-0, xkeyboard-config, x11-tools, openssl, perl, libpixman-1-0, libjpeg8, libgomp1, libXfont2-2, libXdmcp6, libglvnd, xkbcomp, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny
Conflicts: tigervnc, tigervnc-x11vnc
%description
@ -48,17 +48,27 @@ DESTDIR=$RPM_BUILD_ROOT
DST_MAN=$DESTDIR/usr/share/man/man1
mkdir -p $DESTDIR/usr/bin $DESTDIR/usr/share/man/man1 \
$DESTDIR/usr/share/doc/kasmvncserver
$DESTDIR/usr/share/doc/kasmvncserver $DESTDIR/usr/lib \
$DESTDIR/%perl_vendorlib $DESTDIR/etc/kasmvnc
cp $SRC_BIN/Xvnc $DESTDIR/usr/bin;
cp $SRC_BIN/vncserver $DESTDIR/usr/bin;
cp -a $SRC_BIN/KasmVNC $DESTDIR/%perl_vendorlib
cp $SRC_BIN/vncconfig $DESTDIR/usr/bin;
cp $SRC_BIN/kasmvncpasswd $DESTDIR/usr/bin;
cp $SRC_BIN/kasmxproxy $DESTDIR/usr/bin;
cp -r $SRC/lib/kasmvnc/ $DESTDIR/usr/lib/kasmvncserver
cd $DESTDIR/usr/bin && ln -s kasmvncpasswd vncpasswd;
cp -r $SRC/share/doc/kasmvnc*/* $DESTDIR/usr/share/doc/kasmvncserver/
rsync -r --exclude '.git*' --exclude po2js --exclude xgettext-html \
--exclude www/utils/ --exclude .eslintrc \
--exclude www/utils/ --exclude .eslintrc --exclude configure \
$SRC/share/kasmvnc $DESTDIR/usr/share
sed -i -e 's!pem_certificate: .\+$!pem_certificate: /etc/pki/tls/private/kasmvnc.pem!' \
$DESTDIR/usr/share/kasmvnc/kasmvnc_defaults.yaml
sed -i -e 's!pem_key: .\+$!pem_key: /etc/pki/tls/private/kasmvnc.pem!' \
$DESTDIR/usr/share/kasmvnc/kasmvnc_defaults.yaml
sed -e 's/^\([^#]\)/# \1/' $DESTDIR/usr/share/kasmvnc/kasmvnc_defaults.yaml > \
$DESTDIR/etc/kasmvnc/kasmvnc.yaml
cp $SRC/man/man1/Xvnc.1 $DESTDIR/usr/share/man/man1/;
cp $SRC/share/man/man1/vncserver.1 $DST_MAN;
cp $SRC/share/man/man1/vncconfig.1 $DST_MAN;
@ -68,9 +78,13 @@ cd $DST_MAN && ln -s vncpasswd.1 kasmvncpasswd.1;
%files
%config(noreplace) /etc/kasmvnc
/usr/bin/*
/usr/lib/kasmvncserver
/usr/share/man/man1/*
/usr/share/kasmvnc/www
%perl_vendorlib/KasmVNC
/usr/share/kasmvnc
%license /usr/share/doc/kasmvncserver/LICENSE.TXT
%doc /usr/share/doc/kasmvncserver/README.md

View File

@ -7,7 +7,7 @@ License: GPLv2+
URL: https://github.com/kasmtech/KasmVNC
BuildRequires: rsync
Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl
Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny
Conflicts: tigervnc-server, tigervnc-server-minimal
%description
@ -31,6 +31,8 @@ create a by default secure, web based experience.
Simplicity - KasmVNC aims at being simple to deploy and configure.
WARNING: this package requires EPEL and CodeReady builder.
%prep
%install
@ -48,17 +50,27 @@ DESTDIR=$RPM_BUILD_ROOT
DST_MAN=$DESTDIR/usr/share/man/man1
mkdir -p $DESTDIR/usr/bin $DESTDIR/usr/share/man/man1 \
$DESTDIR/usr/share/doc/kasmvncserver
$DESTDIR/usr/share/doc/kasmvncserver $DESTDIR/usr/lib \
$DESTDIR/usr/share/perl5 $DESTDIR/etc/kasmvnc
cp $SRC_BIN/Xvnc $DESTDIR/usr/bin;
cp $SRC_BIN/vncserver $DESTDIR/usr/bin;
cp -a $SRC_BIN/KasmVNC $DESTDIR/usr/share/perl5
cp $SRC_BIN/vncconfig $DESTDIR/usr/bin;
cp $SRC_BIN/kasmvncpasswd $DESTDIR/usr/bin;
cp $SRC_BIN/kasmxproxy $DESTDIR/usr/bin;
cp -r $SRC/lib/kasmvnc/ $DESTDIR/usr/lib/kasmvncserver
cd $DESTDIR/usr/bin && ln -s kasmvncpasswd vncpasswd;
cp -r $SRC/share/doc/kasmvnc*/* $DESTDIR/usr/share/doc/kasmvncserver/
rsync -r --exclude '.git*' --exclude po2js --exclude xgettext-html \
--exclude www/utils/ --exclude .eslintrc \
--exclude www/utils/ --exclude .eslintrc --exclude configure \
$SRC/share/kasmvnc $DESTDIR/usr/share
sed -i -e 's!pem_certificate: .\+$!pem_certificate: /etc/pki/tls/private/kasmvnc.pem!' \
$DESTDIR/usr/share/kasmvnc/kasmvnc_defaults.yaml
sed -i -e 's!pem_key: .\+$!pem_key: /etc/pki/tls/private/kasmvnc.pem!' \
$DESTDIR/usr/share/kasmvnc/kasmvnc_defaults.yaml
sed -e 's/^\([^#]\)/# \1/' $DESTDIR/usr/share/kasmvnc/kasmvnc_defaults.yaml > \
$DESTDIR/etc/kasmvnc/kasmvnc.yaml
cp $SRC/man/man1/Xvnc.1 $DESTDIR/usr/share/man/man1/;
cp $SRC/share/man/man1/vncserver.1 $DST_MAN;
cp $SRC/share/man/man1/vncconfig.1 $DST_MAN;
@ -68,9 +80,13 @@ cd $DST_MAN && ln -s vncpasswd.1 kasmvncpasswd.1;
%files
%config(noreplace) /etc/kasmvnc
/usr/bin/*
/usr/lib/kasmvncserver
/usr/share/man/man1/*
/usr/share/kasmvnc/www
/usr/share/perl5/KasmVNC
/usr/share/kasmvnc
%license /usr/share/doc/kasmvncserver/LICENSE.TXT
%doc /usr/share/doc/kasmvncserver/README.md

View File

@ -51,7 +51,15 @@ if [ $SERVER = 1 ]; then
install -m 644 ./xorg.build/man/man1/Xserver.1 $OUTDIR/man/man1/Xserver.1
mkdir -p $OUTDIR/lib/dri/
install -m 755 ./xorg.build/lib/dri/swrast_dri.so $OUTDIR/lib/dri/
mkdir -p $OUTDIR/share/kasmvnc
mkdir -p $OUTDIR/lib/kasmvnc
install -m 755 $SRCDIR/builder/startup/deb/select-de.sh $OUTDIR/lib/kasmvnc
mkdir -p $OUTDIR/share/kasmvnc
cp -r $SRCDIR/unix/KasmVNC/ $OUTDIR/bin/
cp $SRCDIR/unix/kasmvnc_defaults.yaml $OUTDIR/share/kasmvnc/
mkdir -p $OUTDIR/etc/kasmvnc
cp $SRCDIR/unix/kasmvnc.yaml $OUTDIR/etc/kasmvnc
cp -r $SRCDIR/builder/www $OUTDIR/share/kasmvnc/www
fi

36
run-specs Executable file
View File

@ -0,0 +1,36 @@
#!/bin/bash
set -e
export PYTHONPATH=${PWD}/spec
RUN_CMD="pipenv run mamba"
specs=()
for arg in "$@"; do
if [[ "$arg" = "-d" ]]; then
export KASMVNC_SPEC_DEBUG_OUTPUT=1
continue;
fi
if [[ "$arg" = "-v" ]]; then
verbose=1
continue
fi
specs+=("$arg")
done
set -- "${specs[@]}"
if [[ "$1" = "-h" || "$1" = "--help" ]]; then
echo >&2 "Usage: $(basename "$0") [-d] [-v] <spec...>"
exit 0
fi
if [[ -n "$verbose" ]]; then
RUN_CMD="$RUN_CMD --format=documentation"
fi
if [[ -n "$1" ]]; then
$RUN_CMD "$@"
else
$RUN_CMD spec/*_spec.py
fi

84
spec/fixtures/defaults_config.yaml vendored Normal file
View File

@ -0,0 +1,84 @@
desktop:
resolution:
width: 1024
height: 768
allow_resize: true
pixel_depth: 24
network:
protocol: http
interface: 0.0.0.0
websocket_port: auto
use_ipv4: true
use_ipv6: true
ssl:
pem_certificate: /etc/ssl/certs/ssl-cert-snakeoil.pem
pem_key: /etc/ssl/private/ssl-cert-snakeoil.key
require_ssl: true
security:
brute_force_protection:
blacklist_threshold: 5
blacklist_timeout: 10
data_loss_prevention:
visible_region:
# top: 10
# left: 10
# right: 40
# bottom: 40
concealed_region:
allow_click_down: false
allow_click_release: false
clipboard:
delay_between_operations: none
server_to_client:
enabled: true
size: 10000
primary_clipboard_enabled: false
client_to_server:
enabled: true
size: 10000
keyboard:
enabled: true
rate_limit: unlimited
logging:
level: off
encoding:
max_frame_rate: 60
rect_encoding_mode:
min_quality: 7
max_quality: 8
consider_lossless_quality: 10
rectangle_compress_threads: auto
video_encoding_mode:
jpeg_quality: -1
webp_quality: -1
max_resolution:
width: 1920
height: 1080
enter_video_encoding_mode:
time_threshold: 5
area_threshold: 45%
exit_video_encoding_mode:
time_threshold: 3
logging:
level: off
scaling_algorithm: progressive_bilinear
compare_framebuffer: auto
zrle_zlib_level: auto
hextile_improved_compression: true
server:
advanced:
x_font_path: auto
httpd_directory: /usr/share/kasmvnc/www
kasm_password_file: ~/.kasmpasswd
x_authority_file: auto
auto_shutdown:
no_user_session_timeout: never
active_user_session_timeout: never
inactive_user_session_timeout: never

3
spec/fixtures/global_config.yaml vendored Normal file
View File

@ -0,0 +1,3 @@
security:
brute_force_protection:
blacklist_threshold: 6

4
spec/fixtures/user_config.yaml vendored Normal file
View File

@ -0,0 +1,4 @@
security:
brute_force_protection:
blacklist_threshold: 7
blacklist_timeout: 12

0
spec/helper/__init__.py Normal file
View File

View File

@ -0,0 +1,93 @@
import os
import sys
import shutil
import subprocess
import pexpect
from path import Path
from expects import expect, equal
vncserver_cmd = 'vncserver :1'
running_xvnc = False
debug_output = False
config_dir = "spec/tmp"
config_filename = os.path.join(config_dir, "config.yaml")
if os.getenv('KASMVNC_SPEC_DEBUG_OUTPUT'):
debug_output = True
def write_config(config_text):
os.makedirs(config_dir, exist_ok=True)
with open(config_filename, "w") as f:
f.write(config_text)
def clean_env():
clean_kasm_users()
home_dir = os.environ['HOME']
vnc_dir = os.path.join(home_dir, ".vnc")
Path(vnc_dir).rmtree(ignore_errors=True)
def clean_kasm_users():
home_dir = os.environ['HOME']
password_file = os.path.join(home_dir, ".kasmpasswd")
Path(password_file).remove_p()
def start_xvnc_pexpect(extra_args="", **kwargs):
global running_xvnc
# ":;" is a hack. Without it, Xvnc doesn't run. No idea what happens, but
# when I run top, Xvnc just isn't there. I suspect a race.
child = pexpect.spawn('/bin/bash',
['-ic', f':;{vncserver_cmd} {extra_args}'],
timeout=5, encoding='utf-8', **kwargs)
if debug_output:
child.logfile_read = sys.stderr
running_xvnc = True
return child
def start_xvnc(extra_args="", **kwargs):
global running_xvnc
completed_process = run_cmd(f'{vncserver_cmd} {extra_args}',
print_stderr=False, **kwargs)
if completed_process.returncode == 0:
running_xvnc = True
return completed_process
def run_cmd(cmd, print_stderr=True, **kwargs):
completed_process = subprocess.run(cmd, shell=True, text=True,
capture_output=True,
executable='/bin/bash', **kwargs)
if debug_output:
if len(completed_process.stderr) > 0:
print(completed_process.stderr)
if len(completed_process.stdout) > 0:
print(completed_process.stdout)
elif print_stderr:
if len(completed_process.stderr) > 0:
print(completed_process.stderr)
return completed_process
def add_kasmvnc_user_docker():
completed_process = run_cmd('echo -e "password\\npassword\\n" | vncpasswd -u docker -w')
expect(completed_process.returncode).to(equal(0))
def kill_xvnc():
global running_xvnc
if not running_xvnc:
return
run_cmd('vncserver -kill :1', print_stderr=False)
running_xvnc = False

42
spec/kasmvnc.yaml Normal file
View File

@ -0,0 +1,42 @@
desktop:
resolution:
width: 1024
height: 768
allow_resize: true
pixel_depth: 24
security:
brute_force_protection:
blacklist_threshold: 1
blacklist_timeout: 10
logging:
log_writer_name: all
log_dest: logfile
# 0 - silent(?), 100 - most verbose
level: 100
data_loss_prevention:
visible_region:
# top: 10
# left: 10
# right: 40
# bottom: 40
concealed_region:
allow_click_down: false
allow_click_release: false
clipboard:
delay_between_operations: none
# Cut buffers and CLIPBOARD selection.
server_to_client:
enabled: true
size: unlimited
primary_clipboard_enabled: false
keyboard:
remap_keys:
- 0x22->0x40
- 0x24->0x40
command_line:
prompt: true

View File

@ -0,0 +1,10 @@
from mamba import description, context, it, fit, before, after
from expects import expect, equal, contain, match
from helper.spec_helper import start_xvnc, kill_xvnc, run_cmd, clean_env, \
add_kasmvnc_user_docker, clean_kasm_users, start_xvnc_pexpect, \
write_config, config_filename
with description("Perl warnings"):
with it("treats Perl warning as error"):
completed_process = run_cmd("vncserver -dry-run")
expect(completed_process.stderr).not_to(match(r'line \d+\.$'))

View File

@ -0,0 +1,155 @@
import os
import sys
import pexpect
from mamba import description, context, it, fit, before, after
from expects import expect, equal
from helper.spec_helper import start_xvnc, kill_xvnc, run_cmd, clean_env, \
add_kasmvnc_user_docker, clean_kasm_users, start_xvnc_pexpect
# WIP. Plan to move to start_xvnc_pexpect(), because pexpect provides a way to
# wait for vncserver output. start_xvnc() just blindly prints input to vncserver
# without knowing what it prints back.
def select_de(de_name):
try:
extra_args = f'-select-de {de_name}'
completed_process = start_xvnc(extra_args)
expect(completed_process.returncode).to(equal(0))
finally:
kill_xvnc()
def check_de_was_setup_to_run(de_name):
completed_process = run_cmd(f'grep -q {de_name} ~/.vnc/xstartup')
expect(completed_process.returncode).to(equal(0))
with description('vncserver') as self:
with before.each:
clean_env()
with after.each:
kill_xvnc()
with context('on the first run'):
with before.each:
add_kasmvnc_user_docker()
with it('asks user to select a DE'):
child = start_xvnc_pexpect()
child.expect(r'\[1\] Cinnamon.+Manually edit')
child.sendline("1\n")
child.wait()
expect(child.exitstatus).to(equal(0))
check_de_was_setup_to_run('cinnamon')
with it("doesn't prompt user to select a DE if prompting is disabled"):
child = start_xvnc_pexpect("-prompt 0")
child.expect(r'Warning: the Desktop Environment.+wasn\'t selected')
child.wait()
expect(child.exitstatus).to(equal(0))
with it('asks to select a DE, when ran with -select-de'):
child = start_xvnc_pexpect('-select-de')
child.expect(r'\[1\] Cinnamon.+Manually edit')
child.sendline("1\n")
child.wait()
expect(child.exitstatus).to(equal(0))
check_de_was_setup_to_run('cinnamon')
with it("doesn't prompt user to select a DE if prompting is disabled"):
child = start_xvnc_pexpect("-select-de -prompt 0")
child.expect(r'Warning: the Desktop Environment.+wasn\'t selected')
child.wait()
expect(child.exitstatus).to(equal(0))
with it('selects passed DE with -s'):
select_de('mate')
check_de_was_setup_to_run('mate')
with it('selects manual xstartup editing, not a DE'):
select_de('manual')
check_de_was_setup_to_run('twm')
with context('after DE was selected'):
with before.each:
add_kasmvnc_user_docker()
with it("don't ask to choose DE by default"):
select_de('mate')
completed_process = start_xvnc()
expect(completed_process.returncode).to(equal(0))
check_de_was_setup_to_run('mate')
with it('asks to select a DE, when ran with -select-de'):
select_de('mate')
choose_cinnamon_and_answer_yes = "1\ny\n"
completed_process = start_xvnc('-select-de',
input=choose_cinnamon_and_answer_yes)
expect(completed_process.returncode).to(equal(0))
check_de_was_setup_to_run('cinnamon')
with it("doesn't ask user to select a DE if prompting is disabled"):
child = start_xvnc_pexpect("-select-de -prompt 0")
child.expect(r'Warning: the Desktop Environment.+wasn\'t selected')
child.wait()
expect(child.exitstatus).to(equal(0))
with it('selects passed DE with -s'):
select_de('mate')
completed_process = start_xvnc('-select-de cinnamon')
expect(completed_process.returncode).to(equal(0))
check_de_was_setup_to_run('cinnamon')
with context('guided user creation'):
with it('asks to create a user if none exist'):
clean_kasm_users()
child = start_xvnc_pexpect('-select-de cinnamon')
child.expect('Provide selection number:')
child.sendline('1')
child.expect('Enter username')
child.sendline()
child.expect('Password:')
child.sendline('password')
child.expect('Verify:')
child.sendline('password')
child.expect(pexpect.EOF)
child.close()
expect(child.exitstatus).to(equal(0))
home_dir = os.environ['HOME']
user = os.environ['USER']
completed_process = run_cmd(f'grep -qw {user} {home_dir}/.kasmpasswd')
expect(completed_process.returncode).to(equal(0))
with it('specify custom username'):
custom_username = 'custom_username'
child = start_xvnc_pexpect('-select-de cinnamon')
child.expect('Provide selection number:')
child.sendline('1')
child.expect('Enter username')
child.sendline(custom_username)
child.expect('Password:')
child.sendline('password')
child.expect('Verify:')
child.sendline('password')
child.expect(pexpect.EOF)
child.wait()
expect(child.exitstatus).to(equal(0))
home_dir = os.environ['HOME']
completed_process = run_cmd(f'grep -qw {custom_username} {home_dir}/.kasmpasswd')
expect(completed_process.returncode).to(equal(0))

View File

@ -0,0 +1,297 @@
import os
import re
import shutil
from os.path import expanduser
from mamba import description, context, fcontext, it, fit, before, after
from expects import expect, equal, contain, match
from helper.spec_helper import start_xvnc, kill_xvnc, run_cmd, clean_env, \
add_kasmvnc_user_docker, clean_kasm_users, start_xvnc_pexpect, \
write_config, config_filename
home_dir = expanduser("~")
vnc_dir = f'{home_dir}/.vnc'
user_config = f'{vnc_dir}/kasmvnc.yaml'
def run_vncserver():
return run_cmd(f'vncserver -dry-run -config {config_filename}')
def pick_cli_option(cli_option, xvnc_cmd):
cli_option_regex = re.compile(f'\'?-{cli_option}\'?(?:\s+[^-][^\s]*|$)')
results = cli_option_regex.findall(xvnc_cmd)
if len(results) == 0:
return None
return ' '.join(results)
def prepare_env():
os.makedirs(vnc_dir, exist_ok=True)
shutil.copyfile('spec/kasmvnc.yaml', user_config)
with description('YAML to CLI') as self:
with before.all:
prepare_env()
with context("convert a boolean key"):
with it("convert true to 1"):
write_config('''
desktop:
allow_resize: true
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('AcceptSetDesktopSize',
completed_process.stdout)
expect(cli_option).to(equal("-AcceptSetDesktopSize '1'"))
with it("convert false to 0"):
write_config('''
desktop:
allow_resize: false
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('AcceptSetDesktopSize',
completed_process.stdout)
expect(cli_option).to(equal("-AcceptSetDesktopSize '0'"))
with it("converts a numeric key to a CLI arg"):
write_config('''
security:
brute_force_protection:
blacklist_threshold: 2
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('BlacklistThreshold',
completed_process.stdout)
expect(cli_option).to(equal("-BlacklistThreshold '2'"))
with it("converts an ANY key to a CLI arg"):
write_config('''
network:
ssl:
pem_certificate: /etc/ssl/certs/ssl-cert-snakeoil.pem
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('cert',
completed_process.stdout)
expect(cli_option).to(
equal("-cert '/etc/ssl/certs/ssl-cert-snakeoil.pem'"))
with it("converts an array key to a CLI arg"):
write_config('''
keyboard:
remap_keys:
- 0x22->0x40
- 0x24->0x40
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('RemapKeys',
completed_process.stdout)
expect(cli_option).to(
equal("-RemapKeys '0x22->0x40,0x24->0x40'"))
with it("converts a constant value to the corresponding numeric value"):
write_config('''
data_loss_prevention:
clipboard:
server_to_client:
size: 20
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('DLP_ClipSendMax',
completed_process.stdout)
expect(cli_option).to(equal("-DLP_ClipSendMax '20'"))
with context("websocketPort"):
with it("converts 'auto' value to calculated value"):
write_config('''
network:
websocket_port: auto
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('websocketPort',
completed_process.stdout)
expect(["-websocketPort '8444'", "-websocketPort '8445'"]). \
to(contain(cli_option))
with it("passes numeric value to CLI option"):
write_config('''
network:
websocket_port: 8555
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('websocketPort',
completed_process.stdout)
expect(cli_option).to(equal("-websocketPort '8555'"))
with it("no key - no CLI option"):
write_config('''
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('websocketPort',
completed_process.stdout)
expect(cli_option).to(equal(None))
with context("option that can yield nothing"):
with it("converts a config value that yields nothing"):
write_config('''
network:
protocol: http
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('noWebsocket',
completed_process.stdout)
expect(cli_option).to(equal(None))
with it("converts a config value that yields CLI option"):
write_config('''
network:
protocol: vnc
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('noWebsocket',
completed_process.stdout)
expect(cli_option).to(equal("-noWebsocket '1'"))
with it("interpolates env variable"):
write_config('''
server:
advanced:
kasm_password_file: ${HOME}/.kasmpasswd
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('KasmPasswordFile',
completed_process.stdout)
expect(cli_option).to(equal("-KasmPasswordFile '/home/docker/.kasmpasswd'"))
with it("converts logging options into one -Log"):
write_config('''
logging:
log_writer_name: all
log_dest: logfile
level: 40
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('Log',
completed_process.stdout)
expect(cli_option).to(equal("-Log '*:stdout:40'"))
with it("converts DLP region options into one -DLP_Region"):
write_config('''
data_loss_prevention:
visible_region:
top: -10
left: 10
right: 40%
bottom: 40
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('DLP_Region',
completed_process.stdout)
expect(cli_option).to(equal("-DLP_Region '10,-10,40%,40'"))
with context("converts x_font_path"):
with it("auto"):
write_config('''
server:
advanced:
x_font_path: auto
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('fp',
completed_process.stdout)
expect(cli_option).to(match(r'/usr/share/fonts'))
with it("none specified"):
write_config('''
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('fp',
completed_process.stdout)
expect(cli_option).to(match(r'/usr/share/fonts'))
with it("path specified"):
write_config('''
server:
advanced:
x_font_path: /src
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('fp', completed_process.stdout)
expect(cli_option).to(equal("-fp '/src'"))
with it("CLI override"):
write_config('''
server:
advanced:
x_font_path: /src
''')
completed_process = \
run_cmd(f'vncserver -dry-run -fp /override -config {config_filename}')
cli_option = pick_cli_option('fp', completed_process.stdout)
expect(cli_option).to(equal("-fp '/override'"))
with it("converts network.interface to -interface"):
write_config('''
network:
interface: 0.0.0.0
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('interface',
completed_process.stdout)
expect(cli_option).to(equal("-interface '0.0.0.0'"))
with it("CLI option directly passed, overrides config"):
write_config('''
encoding:
video_encoding_mode:
jpeg_quality: -1
''')
completed_process = \
run_cmd(f'vncserver -dry-run -JpegVideoQuality 8 -config {config_filename}')
cli_option = pick_cli_option("JpegVideoQuality",
completed_process.stdout)
expect(cli_option).to(equal("'-JpegVideoQuality' '8'"))
with it("converts 2 keys into a single CLI option"):
write_config('''
desktop:
resolution:
width: 1024
height: 768
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('geometry',
completed_process.stdout)
expect(cli_option).to(equal("-geometry '1024x768'"))
with it("ignores empty section override"):
write_config('''
security:
''')
completed_process = \
run_cmd(f'vncserver -dry-run -config spec/fixtures/global_config.yaml,{config_filename}')
cli_option = pick_cli_option('BlacklistThreshold',
completed_process.stdout)
expect(cli_option).to(equal("-BlacklistThreshold '6'"))
with it("overrides default config value with global config value"):
completed_process = run_cmd("vncserver -dry-run -config spec/fixtures/defaults_config.yaml,spec/fixtures/global_config.yaml")
cli_option = pick_cli_option('BlacklistThreshold',
completed_process.stdout)
expect(cli_option).to(equal("-BlacklistThreshold '6'"))
with it("uses default config value even if section was overriden"):
completed_process = run_cmd("vncserver -dry-run -config spec/fixtures/defaults_config.yaml,spec/fixtures/global_config.yaml")
cli_option = pick_cli_option('BlacklistTimeout',
completed_process.stdout)
expect(cli_option).to(equal("-BlacklistTimeout '10'"))
with it("overrides global config with user config value"):
completed_process = run_cmd("vncserver -dry-run -config spec/fixtures/defaults_config.yaml,spec/fixtures/global_config.yaml,spec/fixtures/user_config.yaml")
cli_option = pick_cli_option('BlacklistThreshold',
completed_process.stdout)
expect(cli_option).to(equal("-BlacklistThreshold '7'"))

View File

@ -0,0 +1,111 @@
from mamba import description, context, fit, it, before, after
from expects import expect, equal, contain
from helper.spec_helper import start_xvnc, kill_xvnc, run_cmd, clean_env, \
add_kasmvnc_user_docker, clean_kasm_users, start_xvnc_pexpect, \
config_filename, write_config
with description('YAML validation') as self:
with it("produces error message for an incomplete data clump"):
write_config('''
desktop:
resolution:
width: 1024
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}', print_stderr=False)
expect(completed_process.stderr).to(contain('desktop.resolution.width, desktop.resolution.height: either all keys or none must be present'))
with it("produces error message if int key was set to a string"):
write_config('''
desktop:
resolution:
width: 1024
height: none
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}', print_stderr=False)
expect(completed_process.stderr).to(contain("desktop.resolution.height 'none': must be an integer"))
with it("produces no error for valid boolean values"):
write_config('''
network:
use_ipv4: true
use_ipv6: false
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}')
expect(completed_process.stderr).to(equal(''))
with it("produces an error for invalid boolean values"):
write_config('''
desktop:
allow_resize: 10
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}', print_stderr=False)
expect(completed_process.stderr).to(contain("desktop.allow_resize '10': must be true or false"))
with it("produces an error for invalid enum value"):
write_config('''
desktop:
pixel_depth: none
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}', print_stderr=False)
expect(completed_process.stderr).to(contain("desktop.pixel_depth 'none': must be one of [16, 24, 32]"))
with it("produces an error for invalid pattern enum value"):
write_config('''
desktop:
pixel_depth: 16|24|32
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}', print_stderr=False)
expect(completed_process.stderr).to(contain("desktop.pixel_depth '16|24|32': must be one of [16, 24, 32]"))
with it("produces an error fo partially present enum value"):
write_config('''
network:
protocol: vnc2
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}', print_stderr=False)
expect(completed_process.stderr).to(contain("network.protocol 'vnc2': must be one of [http, vnc]"))
with it("is silent for a valid enum value"):
write_config('''
desktop:
pixel_depth: 16
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}')
expect(completed_process.stderr).to(equal(""))
with it("produces an error for an array value"):
write_config('''
keyboard:
remap_keys:
- 0xzz->0x40
- 0x24->0x40
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}', print_stderr=False)
expect(completed_process.stderr).to(contain("keyboard.remap_keys '0xzz->0x40, 0x24->0x40': must be in the format 0x<hex_number>->0x<hex_number>"))
with context("unsupported keys"):
with it("produces an error for an unsupported top-level key"):
write_config('''
foo: 1
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}', print_stderr=False)
expect(completed_process.stderr).to(
contain("Unsupported config keys found:\nfoo"))
with it("produces an error for an unsupported 2nd-level key"):
write_config('''
bar:
baz: 1
''')
completed_process = run_cmd(f'vncserver -dry-run -test-output-topic validation -config {config_filename}', print_stderr=False)
expect(completed_process.stderr).to(
contain("Unsupported config keys found:\nbar.baz"))

199
unix/KasmVNC/CliOption.pm Normal file
View File

@ -0,0 +1,199 @@
package KasmVNC::CliOption;
use strict;
use warnings;
use v5.10;
use List::Util qw(first);
use List::MoreUtils qw(all);
use Switch;
use Data::Dumper;
use KasmVNC::DataClumpValidator;
use KasmVNC::Utils;
our $fetchValueSub;
$KasmVNC::CliOption::dataClumpValidator = KasmVNC::DataClumpValidator->new();
@KasmVNC::CliOption::isActiveCallbacks = ();
sub new {
my ($class, $args) = @_;
my $self = bless {
name => $args->{name},
configKeys => $args->{configKeys},
deriveValueSub => $args->{deriveValueSub} || sub {
my $self = shift;
my @values = @{ listify($self->configValues()) };
@values = map { deriveBoolean($_) } @values;
join ",", @values;
},
isActiveSub => $args->{isActiveSub} || sub {
my $self = shift;
scalar $self->configValues() > 0;
},
errors => []
}, $class;
}
sub activate {
my $self = shift;
$self->makeKeysWithValuesAccessible();
}
sub beforeIsActive {
my $callback = shift;
push @KasmVNC::CliOption::isActiveCallbacks, $callback;
}
sub isActiveByCallbacks {
my $self = shift;
all { $_->($self) } @KasmVNC::CliOption::isActiveCallbacks;
}
sub makeKeysWithValuesAccessible {
my $self = shift;
foreach my $name (@{ $self->configKeyNames() }) {
my $value = $self->fetchValue($name);
$self->{$name} = $value if defined($value);
}
}
sub isActive {
my $self = shift;
$self->isActiveByCallbacks() && $self->{isActiveSub}->($self);
}
sub toString {
my $self = shift;
return unless $self->isActive();
my $derivedValue = $self->deriveValue();
if (defined($derivedValue)) {
return "-$self->{name} " . "'$derivedValue'";
}
"-$self->{name}";
}
sub toValue {
my $self = shift;
return unless $self->isActive();
$self->deriveValue();
}
sub deriveValue {
my $self = shift;
my $value = $self->{deriveValueSub}->($self);
$self->interpolateEnvVars($value);
}
sub interpolateEnvVars {
my $self = shift;
my $value = shift;
return $value unless defined($value);
while ($value =~ /\$\{(\w+)\}/) {
my $envValue = $ENV{$1};
$value =~ s/\Q$&\E/$envValue/;
}
$value;
}
sub errorMessages {
my $self = shift;
join "\n", @{ $self->{errors} };
}
# private
sub isValid {
my $self = shift;
$self->validate() unless $self->{validated};
$self->isNoErrorsPresent();
}
sub validate {
my $self = shift;
$self->validateDataClump();
$self->validateConfigValues();
$self->{validated} = 1;
}
sub isNoErrorsPresent {
my $self = shift;
scalar @{ $self->{errors} } == 0;
}
sub validateDataClump {
my $self = shift;
$KasmVNC::CliOption::dataClumpValidator->validate($self);
}
sub configValues {
my $self = shift;
map { $self->fetchValue($_->{name}) } @{ $self->{configKeys} };
}
sub configValue {
my $self = shift;
die "Multiple or no config keys defined for $self->{name}"
if (scalar @{ $self->{configKeys} } != 1);
@{ listify($self->configValues()) }[0];
}
sub configKeyNames {
my $self = shift;
my @result = map { $_->{name} } @{ $self->{configKeys} };
\@result;
}
sub hasKey {
my $self = shift;
my $configKey = shift;
first { $_ eq $configKey } @{ $self->configKeyNames() };
}
sub addErrorMessage {
my ($self, $errorMessage) = @_;
push @{ $self->{errors} }, $errorMessage;
}
sub validateConfigValues {
my $self = shift;
map { $_->validate($self) } @{ $self->{configKeys} };
}
sub fetchValue {
my $self = shift;
&$fetchValueSub(shift);
}
1;

86
unix/KasmVNC/Config.pm Normal file
View File

@ -0,0 +1,86 @@
package KasmVNC::Config;
use strict;
use warnings;
use v5.10;
use YAML::Tiny;
use Data::Dumper;
use Hash::Merge::Simple;
use KasmVNC::Utils;
sub merge {
my @configsToMerge = map { $_->{data} } @_;
my $mergedConfig = Hash::Merge::Simple::merge(@configsToMerge) // {};
KasmVNC::Config->new({ data => $mergedConfig });
}
sub new {
my ($class, $args) = @_;
my $self = bless {
filename => $args->{filename},
data => $args->{data}
}, $class;
$self->load() if $self->{filename};
$self;
}
sub load {
my $self = shift;
failIfConfigNotReadable($self->{filename});
$self->{data} = YAML::Tiny->read($self->{filename})->[0];
}
sub get {
my ($self, $absoluteKey) = @_;
my $path = absoluteKeyToHashPath($absoluteKey);
my $config = $self->{data};
my $value = eval "\$config$path";
return unless defined($value);
$value;
}
sub exists {
my ($self, $absoluteKey) = @_;
my $path = absoluteKeyToHashPath($absoluteKey);
my $config = $self->{data};
eval "exists \$config$path";
}
sub delete {
my ($self, $absoluteKey) = @_;
my $path = absoluteKeyToHashPath($absoluteKey);
my $config = $self->{data};
eval "delete \$config$path";
}
sub isEmpty {
my ($self, $absoluteKey) = @_;
my $path = absoluteKeyToHashPath($absoluteKey);
my $config = $self->{data};
$self->exists($absoluteKey) && isBlank($self->get($absoluteKey));
}
sub absoluteKeyToHashPath {
my $absoluteKey = shift;
my @keyParts = split(/\./, $absoluteKey);
@keyParts = map { "->{\"$_\"}" } @keyParts;
join "", @keyParts;
}
sub failIfConfigNotReadable {
my $config = shift;
-r $config || die "Couldn't load config: $config";
}
1;

123
unix/KasmVNC/ConfigKey.pm Normal file
View File

@ -0,0 +1,123 @@
package KasmVNC::ConfigKey;
use strict;
use warnings;
use v5.10;
use Switch;
use Data::Dumper;
use KasmVNC::Utils;
our $fetchValueSub;
use constant {
INT => 0,
STRING => 1,
BOOLEAN => 2,
ANY => 4
};
sub new {
my ($class, $args) = @_;
my $self = bless {
name => $args->{name},
type => $args->{type},
validator => $args->{validator}
}, $class;
}
sub validate {
my $self = shift;
$self->{cliOption} = shift;
return if $self->isValueBlank();
if ($self->{validator}) {
$self->resolveValidatorFromFunction() if (ref $self->{validator} eq "CODE");
$self->{validator}->validate($self);
return;
}
switch($self->{type}) {
case INT {
$self->validateInt();
}
case BOOLEAN {
$self->validateBoolean();
}
}
}
sub resolveValidatorFromFunction {
my $self = shift;
$self->{validator} = $self->{validator}();
}
sub addErrorMessage {
my $self = shift;
my $errorMessage = $self->constructErrorMessage($_[0]);
$self->{cliOption}->addErrorMessage($errorMessage);
}
# private
sub validateBoolean {
my $self = shift;
return if $self->isValidBoolean();
$self->addErrorMessage("must be true or false");
}
sub validateInt {
my $self = shift;
return if $self->isValidInt();
$self->addErrorMessage("must be an integer");
}
sub isValueBlank {
my $self = shift;
my $value = $self->value();
!defined($value) || $value eq "";
}
sub fetchValue {
my $self = shift;
&$fetchValueSub(shift);
}
sub constructErrorMessage {
my $self = shift;
my $staticErrorMessage = shift;
my $name = $self->{name};
my $value = join ", ", @{ listify($self->fetchValue($name)) };
"$name '$value': $staticErrorMessage";
}
sub isValidInt {
my $self = shift;
$self->value() =~ /^(-)?\d+$/;
}
sub isValidBoolean {
my $self = shift;
$self->value() =~ /^true|false$/;
}
sub value {
my $self = shift;
$self->fetchValue($self->{name});
}
our @EXPORT_OK = ('INT', 'STRING', 'BOOLEAN');

View File

@ -0,0 +1,48 @@
package KasmVNC::DataClumpValidator;
use strict;
use warnings;
use v5.10;
use Data::Dumper;
sub new {
my ($class, $args) = @_;
my $self = bless {
}, $class;
}
sub validate {
my $self = shift;
$self->{cliOption} = shift;
if ($self->isDataClump() && !$self->isWhole()) {
$self->{cliOption}->addErrorMessage($self->errorMessage());
}
}
# private
sub isWhole {
my $self = shift;
my $numberOfValues = scalar $self->{cliOption}->configValues();
return 1 if $numberOfValues == 0;
scalar @{ $self->{cliOption}->{configKeys} } == $numberOfValues;
}
sub isDataClump {
my $self = shift;
scalar(@{ $self->{cliOption}->{configKeys} }) > 1;
}
sub errorMessage {
my $self = shift;
my $configKeys = join ", ", @{ $self->{cliOption}->configKeyNames() };
"$configKeys: either all keys or none must be present";
}
1;

View File

@ -0,0 +1,36 @@
package KasmVNC::EnumValidator;
use strict;
use warnings;
use v5.10;
use List::MoreUtils qw(any);
use Data::Dumper;
use KasmVNC::Utils;
sub new {
my ($class, $args) = @_;
my $self = bless {
allowedValues => $args->{allowedValues}
}, $class;
}
sub validate {
my $self = shift;
my $configKey = shift;
my @values = @{ listify($configKey->value()) };
foreach my $value (@values) {
unless (any { $_ eq $value } @{ $self->{allowedValues} }) {
$configKey->addErrorMessage($self->errorMessage());
}
}
}
sub errorMessage {
my $self = shift;
my $allowedValuesText = join ", ", @{ $self->{allowedValues} };
"must be one of [$allowedValuesText]"
}
1;

20
unix/KasmVNC/Logger.pm Normal file
View File

@ -0,0 +1,20 @@
package KasmVNC::Logger;
use strict;
use warnings;
use v5.10;
use Data::Dumper;
sub new {
my ($class, $args) = @_;
my $self = bless {
}, $class;
}
sub warn {
my $self = shift;
say { *STDERR } @_;
}
1;

View File

@ -0,0 +1,37 @@
package KasmVNC::PatternValidator;
use strict;
use warnings;
use v5.10;
use Data::Dumper;
use KasmVNC::Utils;
sub new {
my ($class, $args) = @_;
my $self = bless {
pattern => $args->{pattern},
errorMessage => $args->{errorMessage}
}, $class;
}
sub validate {
my $self = shift;
$self->{configKey} = shift;
my @values = @{ listify($self->{configKey}->value()) };
foreach my $value (@values) {
$self->validateValue($value);
}
}
sub validateValue {
my $self = shift;
my $value = shift;
unless ($value =~ $self->{pattern}) {
$self->{configKey}->addErrorMessage($self->{errorMessage});
}
}
1;

View File

@ -0,0 +1,40 @@
package KasmVNC::TextOption;
use strict;
use warnings;
use v5.10;
use Data::Dumper;
sub new {
my ($class, $args) = @_;
my $self = bless {
description => $args->{description},
callback => $args->{callback} || sub {},
}, $class;
}
use overload fallback => 1, q("") => sub {
my $self = shift;
$self->stringify();
};
sub stringify {
my $self = shift;
$self->{description};
}
sub description {
my $self = shift;
$self->{description};
}
sub callback {
my $self = shift;
$self->{callback};
}
1;

55
unix/KasmVNC/TextUI.pm Normal file
View File

@ -0,0 +1,55 @@
package KasmVNC::TextUI;
use strict;
use warnings;
use v5.10;
use Data::Dumper;
@KasmVNC::TextUI::ISA = qw(Exporter);
our @EXPORT = ('Prompt', 'askUserToChooseOption');
sub askUserToChooseOption {
my %args = @_;
my $banner = $args{banner};
my $prompt = $args{prompt};
my $options = $args{options};
my $userInput;
my $i = 1;
my %numberedOptions = map { $i++ => $_ } @$options;
while (1) {
say $banner;
printOptions(\%numberedOptions);
$userInput = Prompt($prompt . ": ");
last if $numberedOptions{$userInput};
say "Invalid choice: '$userInput'";
}
$numberedOptions{$userInput};
}
sub printOptions {
my $choices = shift;
foreach my $choiceNumber (sort keys %$choices) {
say "[$choiceNumber] " . $choices->{$choiceNumber};
}
print "\n";
}
sub Prompt {
my $prompt = shift;
print($prompt);
my $userInput = <STDIN>;
$userInput =~ s/^\s+|\s+$//g;
return $userInput;
}
1;

54
unix/KasmVNC/User.pm Normal file
View File

@ -0,0 +1,54 @@
package KasmVNC::User;
use strict;
use warnings;
use v5.10;
sub new {
my ($class, $args) = @_;
my $self = bless {
name => $args->{name},
permissions => $args->{permissions}
}, $class;
}
sub permissionsExplanation {
my $self = shift;
my %permissionExplanations = ("w" => "can use keyboard and mouse",
"o" => "can add/remove users",
"" => "can only view");
foreach (qw(ow wo)) {
$permissionExplanations{$_} = "can use keyboard and mouse, add/remove users";
}
$self->{permissions} =~ s/r//g;
$permissionExplanations{$self->{permissions}};
}
sub name {
my $self = shift;
$self->{name};
}
sub permissions {
my $self = shift;
$self->{permissions};
}
sub isOwner {
my $self = shift;
$self->permissions() =~ /o/;
}
sub toString {
my $self = shift;
$self->name() . " (" . $self->permissionsExplanation() . ")";
}
1;

169
unix/KasmVNC/Users.pm Normal file
View File

@ -0,0 +1,169 @@
package KasmVNC::Users;
use strict;
use warnings;
use v5.10;
use Data::Dumper;
use List::MoreUtils qw(any);
use KasmVNC::User;
our $vncPasswdBin;
our $logger;
sub new {
my ($class, $args) = @_;
my $self = bless {
passwordFileName => $args->{passwordFileName},
}, $class;
}
sub loadFrom {
my ($self, $passwordFileName) = @_;
my $users = KasmVNC::Users->new({
passwordFileName => $passwordFileName,
vncPasswdBin => $vncPasswdBin
});
$users->load();
$users;
}
sub optionsToCliOptions {
my %options = @_;
my @cliOptons = ();
push(@cliOptons, "-u \"@{[$options{username}]}\"");
if ($options{permissions}) {
push(@cliOptons, "-" . $options{permissions});
}
if ($options{changePermissions}) {
push(@cliOptons, "-n");
}
join " ", @cliOptons;
}
sub runKasmvncpasswd {
my ($self, $options) = @_;
my @cliOptions = optionsToCliOptions(%{ $options });
system("$vncPasswdBin " . join(" ", @cliOptions) . " " . $self->{passwordFileName});
$? ? 0 : 1;
}
sub findByPermissions {
my ($self, $permissions) = @_;
any { $_->{permissions} =~ /$permissions/ }
(values %{ $self->{store} });
}
sub fetchUser {
my ($self, $username) = @_;
$self->{store}->{$username};
}
sub userExists {
fetchUser @_;
}
sub addUser {
my ($self, $username, $permissions) = @_;
if ($self->userExists($username)) {
$logger->warn("User $username already exists");
return;
}
$self->runKasmvncpasswd({ username => $username, permissions => $permissions });
}
sub checkUserExists {
my ($self, $username) = @_;
unless ($self->fetchUser($username)) {
die "User \"$username\" doesn't exist";
}
}
sub addPermissions {
my ($self, $username, $permissions) = @_;
$self->checkUserExists($username);
my $user = $self->fetchUser($username);
$permissions .= $user->{permissions};
$self->changePermissions($username, $permissions);
}
sub changePermissions {
my ($self, $username, $permissions) = @_;
$self->checkUserExists($username);
$self->runKasmvncpasswd({ username => $username, permissions => $permissions,
changePermissions => 1 });
}
sub load {
my $self = shift;
$self->{store} = $self->_load();
}
sub reload {
my $self = shift;
$self->load();
}
sub count {
my $self = shift;
return scalar(keys %{ $self->{store} });
}
sub is_empty {
my $self = shift;
$self->count() eq 0;
}
sub _load {
my $self = shift;
my $store = {};
open(FH, '<', $self->{passwordFileName}) or return $store;
while(<FH>){
chomp $_;
my ($name, $__, $permissions) = split(':', $_);
$store->{$name} = KasmVNC::User->new({
name => $name,
permissions => $permissions
})
}
close(FH);
$store;
}
sub users {
my $self = shift;
values %{ $self->{store} }
}
sub toString {
my $self = shift;
my @userDescriptions = map { $_->toString() } $self->users();
join "\n", @userDescriptions;
}
1;

66
unix/KasmVNC/Utils.pm Normal file
View File

@ -0,0 +1,66 @@
package KasmVNC::Utils;
use strict;
use warnings;
use v5.10;
use Data::Dumper;
use Switch;
use Exporter;
@KasmVNC::Utils::ISA = qw(Exporter);
our @EXPORT = ('listify', 'flatten', 'isBlank', 'isPresent', 'deriveBoolean',
'printStackTrace');
sub listify {
# Implementation based on Hyper::Functions
if (scalar @_ > 1) {
return [ @_ ];
} elsif (defined $_[0]) {
my $ref_type = ref $_[0];
return ($ref_type && $ref_type eq 'ARRAY') ? $_[0] : [ $_[0] ];
} else {
return [];
}
}
sub flatten {
map { ref $_ ? flatten(@{$_}) : $_ } @_;
}
sub isBlank {
!isPresent(shift);
}
sub isPresent {
my $value = shift;
if (ref($value) eq "HASH") {
return scalar(keys %$value) > 0;
}
defined($value);
}
sub deriveBoolean {
my $value = shift;
switch($value) {
case 'true' {
return 1;
}
case 'false' {
return 0;
}
else {
return $value;
}
}
}
sub printStackTrace {
my $trace = Devel::StackTrace->new;
print { *STDERR } $trace->as_string;
}
1;

0
unix/kasmvnc.yaml Normal file
View File

131
unix/kasmvnc_defaults.yaml Normal file
View File

@ -0,0 +1,131 @@
---
desktop:
resolution:
width: 1024
height: 768
allow_resize: true
pixel_depth: 24
network:
protocol: http
interface: 0.0.0.0
websocket_port: auto
use_ipv4: true
use_ipv6: true
udp:
public_ip: auto
port: auto
ssl:
pem_certificate: /etc/ssl/certs/ssl-cert-snakeoil.pem
pem_key: /etc/ssl/private/ssl-cert-snakeoil.key
require_ssl: true
user_session:
# session_type: shared
new_session_disconnects_existing_exclusive_session: false
concurrent_connections_prompt: false
concurrent_connections_prompt_timeout: 10
idle_timeout: never
keyboard:
remap_keys:
# - 0x22->0x40
ignore_numlock: false
raw_keyboard: false
# Mouse, trackpad, etc.
pointer:
enabled: true
runtime_configuration:
allow_client_to_override_kasm_server_settings: true
allow_override_standard_vnc_server_settings: true
allow_override_list:
- pointer.enabled
- data_loss_prevention.clipboard.server_to_client.enabled
- data_loss_prevention.clipboard.client_to_server.enabled
- data_loss_prevention.clipboard.server_to_client.primary_clipboard_enabled
logging:
log_writer_name: all
log_dest: logfile
# 0 - minimal verbosity, 100 - most verbose
level: 30
security:
brute_force_protection:
blacklist_threshold: 5
blacklist_timeout: 10
data_loss_prevention:
visible_region:
# top: 10
# left: 10
# right: 40
# bottom: 40
concealed_region:
allow_click_down: false
allow_click_release: false
clipboard:
delay_between_operations: none
allow_mimetypes:
- chromium/x-web-custom-data
- text/html
- image/png
# Add to docs: Cut buffers and CLIPBOARD selection.
server_to_client:
enabled: false
size: unlimited
primary_clipboard_enabled: false
client_to_server:
enabled: false
size: unlimited
keyboard:
enabled: true
rate_limit: unlimited
# "verbose" SETTING LOGS YOUR PRIVATE INFORMATION. Keypresses and clipboard
# content.
logging:
level: off
encoding:
max_frame_rate: 60
full_frame_updates: none
rect_encoding_mode:
min_quality: 7
max_quality: 8
consider_lossless_quality: 10
rectangle_compress_threads: auto
video_encoding_mode:
jpeg_quality: -1
webp_quality: -1
max_resolution:
width: 1920
height: 1080
enter_video_encoding_mode:
time_threshold: 5
area_threshold: 45%
exit_video_encoding_mode:
time_threshold: 3
logging:
level: off
scaling_algorithm: progressive_bilinear
compare_framebuffer: auto
zrle_zlib_level: auto
hextile_improved_compression: true
server:
advanced:
x_font_path: auto
httpd_directory: /usr/share/kasmvnc/www
kasm_password_file: ${HOME}/.kasmpasswd
x_authority_file: auto
auto_shutdown:
no_user_session_timeout: never
active_user_session_timeout: never
inactive_user_session_timeout: never
command_line:
prompt: true

3261
unix/vncserver Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,6 @@ vncserver \- start or stop a VNC server
.SH SYNOPSIS
.B vncserver
.RI [: display# ]
.RB [ \-name
.IR desktop-name ]
.RB [ \-geometry
.IR width x height ]
.RB [ \-depth
@ -17,7 +15,7 @@ vncserver \- start or stop a VNC server
.RB [ \-fg ]
.RB [ \-autokill ]
.RB [ \-noxstartup ]
.RB [ \-xstartup
.RB [ \-xstartup
.IR script ]
.RI [ Xvnc-options... ]
.br
@ -53,16 +51,15 @@ In addition to the options listed below, any unrecognised options will be
passed to Xvnc - see the Xvnc man page, or "Xvnc \-help", for details.
.TP
.B \-name \fIdesktop-name\fP
Each VNC desktop has a name which may be displayed by the viewer. The desktop
name defaults to "\fIhost\fP:\fIdisplay#\fP (\fIusername\fP)", but you can
change it with this option. The desktop name option is passed to the xstartup
script via the $VNCDESKTOP environment variable, which allows you to run a
different set of applications depending on the name of the desktop.
.
.B \-select-de [\fIde_name\fP]
Select Desktop Enviromnent to run. Cinnamon, Mate, LXDE, LXQT, KDE, Gnome, XFCE
are supported. If \fIde_name\fP isn't specified, a text UI prompt to select a
Desktop Enviromnent will be shown.
Warning: $HOME/.vnc/xstartup will be overwritten.
.TP
.B \-geometry \fIwidth\fPx\fIheight\fP
Specify the size of the VNC desktop to be created. Default is 1024x768.
Specify the size of the VNC desktop to be created. Default is 1024x768.
.
.TP
.B \-depth \fIdepth\fP
@ -138,45 +135,28 @@ Xvnc. This is useful to run full-screen applications.
.TP
.B \-list
Lists all VNC desktops started by vncserver.
.TP
.B \-dry-run
Print full command VNC server would be run with and exit. Won't run VNC server.
.SH FILES
Several VNC-related files are found in the directory $HOME/.vnc:
.TP
/etc/kasmvnc/kasmvnc.yaml
System-wide KasmVNC config. By default, all settings are commented out. The
commented out settings are the defaults used. Uncomment if you want to change
them. Otherwise, there's no need.
.TP
$HOME/.vnc/kasmvnc.yaml
An optional user-level server config. Settings here override the system-wide
config.
.TP
$HOME/.vnc/xstartup
A shell script specifying X applications to be run when a VNC desktop is
started. If this file does not exist, then vncserver will create a default
xstartup script which attempts to launch your chosen window manager.
.TP
/etc/kasmvnc/vncserver-config-defaults
The optional system-wide equivalent of $HOME/.vnc/config. If this file exists
and defines options to be passed to Xvnc, they will be used as defaults for
users. The user's $HOME/.vnc/config overrides settings configured in this file.
The overall configuration file load order is: this file, $HOME/.vnc/config,
and then /etc/kasmvnc/vncserver-config-mandatory. None are required to exist.
.TP
/etc/kasmvnc/vncserver-config-mandatory
The optional system-wide equivalent of $HOME/.vnc/config. If this file exists
and defines options to be passed to Xvnc, they will override any of the same
options defined in a user's $HOME/.vnc/config. This file offers a mechanism
to establish some basic form of system-wide policy. WARNING! There is
nothing stopping users from constructing their own vncserver-like script
that calls Xvnc directly to bypass any options defined in
/etc/kasmvnc/vncserver-config-mandatory. Likewise, any CLI arguments passed
to vncserver will override ANY config file setting of the same name. The
overall configuration file load order is:
/etc/kasmvnc/vncserver-config-defaults, $HOME/.vnc/config, and then this file.
None are required to exist.
.TP
$HOME/.vnc/config
An optional server config file wherein options to be passed to Xvnc are listed
to avoid hard-coding them to the physical invocation. List options in this file
one per line. For those requiring an argument, simply separate the option from
the argument with an equal sign, for example: "geometry=2000x1200". Options
without an argument are simply listed as a single word, for example: "localhost"
or "alwaysshared".
.TP
$HOME/.vnc/passwd
The VNC password file.
$HOME/.kasmpasswd
The KasmVNC password file.
.TP
$HOME/.vnc/\fIhost\fP:\fIdisplay#\fP.log
The log file for Xvnc and applications started in xstartup.

View File

@ -1,9 +1,9 @@
.TH Xvnc 1 "" "KasmVNC" "Virtual Network Computing"
.SH NAME
Xvnc \- the X VNC server
Xvnc \- the X VNC server
.SH SYNOPSIS
.B Xvnc
.RI [ options ]
.RI [ options ]
.RI : display#
.SH DESCRIPTION
.B Xvnc
@ -50,7 +50,7 @@ depth 16 is RGB565 and for depth 24 and 32 is RGB888.
Listen on interface. By default Xvnc listens on all available interfaces.
.
.TP
.B \-inetd
.B \-inetd
This significantly changes Xvnc's behaviour so that it can be launched from
inetd. See the section below on usage with inetd.
.
@ -145,11 +145,6 @@ Which port to use for UDP. Default same as websocket.
Accept clipboard updates from clients. Default is on.
.
.TP
.B \-MaxCutText \fIbytes\fP
The maximum size of a clipboard update that will be accepted from a client.
Default is \fB262144\fP.
.
.TP
.B \-SendCutText
Send clipboard changes to clients. Default is on.
.