mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2024-11-28 19:14:14 +01:00
Merge branch 'feature/KASM-4489_watermark_time' into 'master'
Resolve KASM-4489 "Feature/ watermark time" Closes KASM-4489 See merge request kasm-technologies/internal/KasmVNC!103
This commit is contained in:
commit
b9e9a2d2a0
@ -154,6 +154,9 @@ find_package(PNG REQUIRED)
|
|||||||
# Check for libjpeg
|
# Check for libjpeg
|
||||||
find_package(JPEG REQUIRED)
|
find_package(JPEG REQUIRED)
|
||||||
|
|
||||||
|
find_package(Freetype REQUIRED)
|
||||||
|
include_directories(${FREETYPE_INCLUDE_DIRS})
|
||||||
|
|
||||||
# Staticly link libjpeg-turbo
|
# Staticly link libjpeg-turbo
|
||||||
set(JPEG_LIBRARIES "-Wl,-Bstatic -lturbojpeg -Wl,-Bdynamic")
|
set(JPEG_LIBRARIES "-Wl,-Bstatic -lturbojpeg -Wl,-Bdynamic")
|
||||||
# Warn if it doesn't seem to be the accelerated libjpeg that's found
|
# Warn if it doesn't seem to be the accelerated libjpeg that's found
|
||||||
|
@ -58,7 +58,8 @@ RUN echo 'alias tv="./run-specs spec/vncserver_yaml_validation_spec.py"' >> ~/.b
|
|||||||
RUN echo 'alias ty="./run-specs spec/vncserver_*spec.py"' >> ~/.bashrc
|
RUN echo 'alias ty="./run-specs spec/vncserver_*spec.py"' >> ~/.bashrc
|
||||||
RUN echo 'alias ta="./run-specs"' >> ~/.bashrc
|
RUN echo 'alias ta="./run-specs"' >> ~/.bashrc
|
||||||
RUN echo 'alias vd="vncserver -dry-run"' >> ~/.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 'alias ss="sp; vncserver -select-de xfce"' >> ~/.bashrc
|
||||||
|
ENV SET_PASSWORD_FUNC 'sp() { echo -e "$VNC_PW\\n$VNC_PW\\n" | kasmvncpasswd -w -u $VNC_USER $HOME/.kasmpasswd; }'
|
||||||
RUN echo $SET_PASSWORD_FUNC >> ~/.bashrc
|
RUN echo $SET_PASSWORD_FUNC >> ~/.bashrc
|
||||||
|
|
||||||
ENV LC_ALL=C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
|
@ -7,7 +7,7 @@ License: GPLv2+
|
|||||||
URL: https://github.com/kasmtech/KasmVNC
|
URL: https://github.com/kasmtech/KasmVNC
|
||||||
|
|
||||||
BuildRequires: rsync
|
BuildRequires: rsync
|
||||||
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
|
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, perl-DateTime-TimeZone
|
||||||
Conflicts: tigervnc-server, tigervnc-server-minimal
|
Conflicts: tigervnc-server, tigervnc-server-minimal
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
17
cmake/Modules/FindFreetype.cmake
Normal file
17
cmake/Modules/FindFreetype.cmake
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# - Find freetype
|
||||||
|
# Find the freetype libraries
|
||||||
|
#
|
||||||
|
# This module defines the following variables:
|
||||||
|
# FREETYPE_FOUND - True if freetype is found
|
||||||
|
# FREETYPE_INCLUDE_DIRS - include directories
|
||||||
|
#
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(PC_FREETYPE freetype2)
|
||||||
|
find_path(FREETYPE_INCLUDE_DIRS NAMES ft2build.h HINTS ${PC_FREETYPE_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
set(FPHSA_NAME_MISMATCHED 1)
|
||||||
|
find_package_handle_standard_args(freetype DEFAULT_MSG FREETYPE_INCLUDE_DIRS)
|
||||||
|
unset(FPHSA_NAME_MISMATCHED)
|
||||||
|
mark_as_advanced(FREETYPE_INCLUDE_DIRS)
|
@ -189,6 +189,18 @@ rfb::IntParameter rfb::Server::DLP_WatermarkRepeatSpace
|
|||||||
("DLP_WatermarkRepeatSpace",
|
("DLP_WatermarkRepeatSpace",
|
||||||
"Number of pixels between repeats of the watermark",
|
"Number of pixels between repeats of the watermark",
|
||||||
0, 0, 4096);
|
0, 0, 4096);
|
||||||
|
rfb::IntParameter rfb::Server::DLP_WatermarkFontSize
|
||||||
|
("DLP_WatermarkFontSize",
|
||||||
|
"Font size for -DLP_WatermarkText",
|
||||||
|
48, 8, 256);
|
||||||
|
rfb::IntParameter rfb::Server::DLP_WatermarkTimeOffset
|
||||||
|
("DLP_WatermarkTimeOffset",
|
||||||
|
"Offset from UTC for -DLP_WatermarkText",
|
||||||
|
0, -24, 24);
|
||||||
|
rfb::IntParameter rfb::Server::DLP_WatermarkTimeOffsetMinutes
|
||||||
|
("DLP_WatermarkTimeOffsetMinutes",
|
||||||
|
"Offset from UTC for -DLP_WatermarkText, minutes",
|
||||||
|
0, -24 * 60, 24 * 60);
|
||||||
rfb::StringParameter rfb::Server::DLP_WatermarkImage
|
rfb::StringParameter rfb::Server::DLP_WatermarkImage
|
||||||
("DLP_WatermarkImage",
|
("DLP_WatermarkImage",
|
||||||
"PNG file to use as a watermark",
|
"PNG file to use as a watermark",
|
||||||
@ -201,6 +213,14 @@ rfb::StringParameter rfb::Server::DLP_WatermarkTint
|
|||||||
("DLP_WatermarkTint",
|
("DLP_WatermarkTint",
|
||||||
"Tint the greyscale watermark by this color.",
|
"Tint the greyscale watermark by this color.",
|
||||||
"255,255,255,255");
|
"255,255,255,255");
|
||||||
|
rfb::StringParameter rfb::Server::DLP_WatermarkText
|
||||||
|
("DLP_WatermarkText",
|
||||||
|
"Use this text instead of an image for the watermark, with strftime time formatting",
|
||||||
|
"");
|
||||||
|
rfb::StringParameter rfb::Server::DLP_WatermarkFont
|
||||||
|
("DLP_WatermarkFont",
|
||||||
|
"Use this font for -DLP_WatermarkText instead of the bundled one",
|
||||||
|
"");
|
||||||
|
|
||||||
rfb::StringParameter rfb::Server::maxVideoResolution
|
rfb::StringParameter rfb::Server::maxVideoResolution
|
||||||
("MaxVideoResolution",
|
("MaxVideoResolution",
|
||||||
|
@ -49,12 +49,17 @@ namespace rfb {
|
|||||||
static IntParameter DLP_ClipDelay;
|
static IntParameter DLP_ClipDelay;
|
||||||
static IntParameter DLP_KeyRateLimit;
|
static IntParameter DLP_KeyRateLimit;
|
||||||
static IntParameter DLP_WatermarkRepeatSpace;
|
static IntParameter DLP_WatermarkRepeatSpace;
|
||||||
|
static IntParameter DLP_WatermarkFontSize;
|
||||||
|
static IntParameter DLP_WatermarkTimeOffset;
|
||||||
|
static IntParameter DLP_WatermarkTimeOffsetMinutes;
|
||||||
static StringParameter DLP_ClipLog;
|
static StringParameter DLP_ClipLog;
|
||||||
static StringParameter DLP_Region;
|
static StringParameter DLP_Region;
|
||||||
static StringParameter DLP_Clip_Types;
|
static StringParameter DLP_Clip_Types;
|
||||||
static StringParameter DLP_WatermarkImage;
|
static StringParameter DLP_WatermarkImage;
|
||||||
static StringParameter DLP_WatermarkLocation;
|
static StringParameter DLP_WatermarkLocation;
|
||||||
static StringParameter DLP_WatermarkTint;
|
static StringParameter DLP_WatermarkTint;
|
||||||
|
static StringParameter DLP_WatermarkText;
|
||||||
|
static StringParameter DLP_WatermarkFont;
|
||||||
static BoolParameter DLP_RegionAllowClick;
|
static BoolParameter DLP_RegionAllowClick;
|
||||||
static BoolParameter DLP_RegionAllowRelease;
|
static BoolParameter DLP_RegionAllowRelease;
|
||||||
static IntParameter jpegVideoQuality;
|
static IntParameter jpegVideoQuality;
|
||||||
|
@ -974,6 +974,11 @@ void VNCServerST::writeUpdate()
|
|||||||
blackOut();
|
blackOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (watermarkData && Server::DLP_WatermarkText[0] && watermarkTextNeedsUpdate(true)) {
|
||||||
|
// If using a text watermark, we have to mark everything as changed...
|
||||||
|
refreshClients();
|
||||||
|
}
|
||||||
|
|
||||||
comparer->getUpdateInfo(&ui, pb->getRect());
|
comparer->getUpdateInfo(&ui, pb->getRect());
|
||||||
toCheck = ui.changed.union_(ui.copied);
|
toCheck = ui.changed.union_(ui.copied);
|
||||||
|
|
||||||
|
@ -20,10 +20,14 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <rfb/LogWriter.h>
|
#include <rfb/LogWriter.h>
|
||||||
#include <rfb/ServerCore.h>
|
#include <rfb/ServerCore.h>
|
||||||
#include <rfb/VNCServerST.h>
|
#include <rfb/VNCServerST.h>
|
||||||
|
#include "font.h"
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
#include "Watermark.h"
|
#include "Watermark.h"
|
||||||
|
|
||||||
@ -36,6 +40,10 @@ watermarkInfo_t watermarkInfo;
|
|||||||
uint8_t *watermarkData, *watermarkUnpacked, *watermarkTmp;
|
uint8_t *watermarkData, *watermarkUnpacked, *watermarkTmp;
|
||||||
uint32_t watermarkDataLen;
|
uint32_t watermarkDataLen;
|
||||||
static uint16_t rw, rh;
|
static uint16_t rw, rh;
|
||||||
|
static time_t lastUpdate;
|
||||||
|
|
||||||
|
static FT_Library ft = NULL;
|
||||||
|
static FT_Face face;
|
||||||
|
|
||||||
#define MAXW 4096
|
#define MAXW 4096
|
||||||
#define MAXH 4096
|
#define MAXH 4096
|
||||||
@ -92,15 +100,151 @@ static bool loadimage(const char path[]) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: w and h are absolute
|
||||||
|
static void str(uint8_t *buf, const char *txt, const uint32_t x_, const uint32_t y_,
|
||||||
|
const uint32_t w, const uint32_t h,
|
||||||
|
const uint32_t stride) {
|
||||||
|
|
||||||
|
unsigned ucs[256], i, ucslen;
|
||||||
|
unsigned len = strlen(txt);
|
||||||
|
i = 0;
|
||||||
|
ucslen = 0;
|
||||||
|
while (len > 0 && txt[i]) {
|
||||||
|
size_t ret = rfb::utf8ToUCS4(&txt[i], len, &ucs[ucslen]);
|
||||||
|
i += ret;
|
||||||
|
len -= ret;
|
||||||
|
ucslen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t x, y;
|
||||||
|
|
||||||
|
x = x_;
|
||||||
|
y = y_;
|
||||||
|
for (i = 0; i < ucslen; i++) {
|
||||||
|
if (FT_Load_Char(face, ucs[i], FT_LOAD_RENDER))
|
||||||
|
continue;
|
||||||
|
const FT_Bitmap * const map = &(face->glyph->bitmap);
|
||||||
|
|
||||||
|
if (FT_HAS_KERNING(face) && i) {
|
||||||
|
FT_Vector delta;
|
||||||
|
FT_Get_Kerning(face, ucs[i - 1], ucs[i], ft_kerning_default, &delta);
|
||||||
|
x += delta.x >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t row, col;
|
||||||
|
for (row = 0; row < (uint32_t) map->rows; row++) {
|
||||||
|
int ny = row + y - face->glyph->bitmap_top;
|
||||||
|
if (ny < 0)
|
||||||
|
continue;
|
||||||
|
if ((unsigned) ny >= h)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t *dst = (uint8_t *) buf;
|
||||||
|
dst += ny * stride + x;
|
||||||
|
|
||||||
|
const uint8_t *src = map->buffer + map->pitch * row;
|
||||||
|
for (col = 0; col < (uint32_t) map->width; col++) {
|
||||||
|
if (col + x >= w)
|
||||||
|
continue;
|
||||||
|
const uint8_t out = (src[col] + 8) >> 4;
|
||||||
|
dst[col] = out < 16 ? out : 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x += face->glyph->advance.x >> 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t drawnwidth(const char *txt) {
|
||||||
|
|
||||||
|
unsigned ucs[256], i, ucslen;
|
||||||
|
unsigned len = strlen(txt);
|
||||||
|
i = 0;
|
||||||
|
ucslen = 0;
|
||||||
|
while (len > 0 && txt[i]) {
|
||||||
|
size_t ret = rfb::utf8ToUCS4(&txt[i], len, &ucs[ucslen]);
|
||||||
|
i += ret;
|
||||||
|
len -= ret;
|
||||||
|
ucslen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t x;
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
for (i = 0; i < ucslen; i++) {
|
||||||
|
if (FT_Load_Char(face, ucs[i], FT_LOAD_DEFAULT))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (FT_HAS_KERNING(face) && i) {
|
||||||
|
FT_Vector delta;
|
||||||
|
FT_Get_Kerning(face, ucs[i - 1], ucs[i], ft_kerning_default, &delta);
|
||||||
|
x += delta.x >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
x += face->glyph->advance.x >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool drawtext(const char fmt[], const int16_t utcOff, const char fontpath[],
|
||||||
|
const uint8_t fontsize) {
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
|
||||||
|
if (!ft) {
|
||||||
|
if (FT_Init_FreeType(&ft))
|
||||||
|
abort();
|
||||||
|
if (fontpath[0]) {
|
||||||
|
if (FT_New_Face(ft, fontpath, 0, &face))
|
||||||
|
abort();
|
||||||
|
} else {
|
||||||
|
if (FT_New_Memory_Face(ft, font_otf, sizeof(font_otf), 0, &face))
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
FT_Set_Pixel_Sizes(face, fontsize, fontsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t now = lastUpdate = time(NULL);
|
||||||
|
now += utcOff * 60;
|
||||||
|
|
||||||
|
struct tm *tm = gmtime(&now);
|
||||||
|
size_t len = strftime(buf, PATH_MAX, fmt, tm);
|
||||||
|
if (!len)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
free(watermarkInfo.src);
|
||||||
|
const uint32_t h = fontsize + 4;
|
||||||
|
const uint32_t w = drawnwidth(buf);
|
||||||
|
|
||||||
|
watermarkInfo.w = w;
|
||||||
|
watermarkInfo.h = h;
|
||||||
|
watermarkInfo.src = (uint8_t *) calloc(w, h);
|
||||||
|
|
||||||
|
str(watermarkInfo.src, buf, 0, fontsize, w, h, w);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool watermarkInit() {
|
bool watermarkInit() {
|
||||||
memset(&watermarkInfo, 0, sizeof(watermarkInfo_t));
|
memset(&watermarkInfo, 0, sizeof(watermarkInfo_t));
|
||||||
watermarkData = watermarkUnpacked = watermarkTmp = NULL;
|
watermarkData = watermarkUnpacked = watermarkTmp = NULL;
|
||||||
rw = rh = 0;
|
rw = rh = 0;
|
||||||
|
|
||||||
if (!Server::DLP_WatermarkImage[0])
|
if (!Server::DLP_WatermarkImage[0] && !Server::DLP_WatermarkText[0])
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!loadimage(Server::DLP_WatermarkImage))
|
if (Server::DLP_WatermarkImage[0] && Server::DLP_WatermarkText[0]) {
|
||||||
|
vlog.error("WatermarkImage and WatermarkText can't be used together");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Server::DLP_WatermarkImage[0] && !loadimage(Server::DLP_WatermarkImage))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Server::DLP_WatermarkText[0] &&
|
||||||
|
!drawtext(Server::DLP_WatermarkText,
|
||||||
|
Server::DLP_WatermarkTimeOffset * 60 + Server::DLP_WatermarkTimeOffsetMinutes,
|
||||||
|
Server::DLP_WatermarkFont, Server::DLP_WatermarkFontSize))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Server::DLP_WatermarkRepeatSpace && Server::DLP_WatermarkLocation[0]) {
|
if (Server::DLP_WatermarkRepeatSpace && Server::DLP_WatermarkLocation[0]) {
|
||||||
@ -136,10 +280,22 @@ bool watermarkInit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update the screen-size rendered watermark whenever the screen is resized
|
// update the screen-size rendered watermark whenever the screen is resized
|
||||||
|
// or if using text, every frame
|
||||||
void VNCServerST::updateWatermark() {
|
void VNCServerST::updateWatermark() {
|
||||||
if (rw == pb->width() &&
|
if (rw == pb->width() &&
|
||||||
rh == pb->height())
|
rh == pb->height()) {
|
||||||
return;
|
|
||||||
|
if (Server::DLP_WatermarkImage[0])
|
||||||
|
return;
|
||||||
|
if (!watermarkTextNeedsUpdate(false))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Server::DLP_WatermarkText[0] && watermarkTextNeedsUpdate(false)) {
|
||||||
|
drawtext(Server::DLP_WatermarkText,
|
||||||
|
Server::DLP_WatermarkTimeOffset * 60 + Server::DLP_WatermarkTimeOffsetMinutes,
|
||||||
|
Server::DLP_WatermarkFont, Server::DLP_WatermarkFontSize);
|
||||||
|
}
|
||||||
|
|
||||||
rw = pb->width();
|
rw = pb->width();
|
||||||
rh = pb->height();
|
rh = pb->height();
|
||||||
@ -246,3 +402,15 @@ void packWatermark(const Region &changed) {
|
|||||||
|
|
||||||
watermarkDataLen = destLen;
|
watermarkDataLen = destLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Limit changes to once per second
|
||||||
|
bool watermarkTextNeedsUpdate(const bool early) {
|
||||||
|
static time_t now;
|
||||||
|
|
||||||
|
// We're called a couple times per frame, only grab the
|
||||||
|
// time on the first time so it doesn't change inside a frame
|
||||||
|
if (early)
|
||||||
|
now = time(NULL);
|
||||||
|
|
||||||
|
return now != lastUpdate;
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@ extern watermarkInfo_t watermarkInfo;
|
|||||||
|
|
||||||
bool watermarkInit();
|
bool watermarkInit();
|
||||||
void packWatermark(const rfb::Region &changed); // filter and pack the watermark for sending
|
void packWatermark(const rfb::Region &changed); // filter and pack the watermark for sending
|
||||||
|
bool watermarkTextNeedsUpdate(const bool early);
|
||||||
|
|
||||||
extern uint8_t *watermarkData;
|
extern uint8_t *watermarkData;
|
||||||
extern uint32_t watermarkDataLen;
|
extern uint32_t watermarkDataLen;
|
||||||
|
3107
common/rfb/font.h
Normal file
3107
common/rfb/font.h
Normal file
File diff suppressed because it is too large
Load Diff
2
debian/control
vendored
2
debian/control
vendored
@ -14,7 +14,7 @@ Architecture: amd64 arm64
|
|||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, ssl-cert, xauth,
|
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, ssl-cert, xauth,
|
||||||
x11-xkb-utils, xkb-data, procps, libswitch-perl, libyaml-tiny-perl,
|
x11-xkb-utils, xkb-data, procps, libswitch-perl, libyaml-tiny-perl,
|
||||||
libhash-merge-simple-perl, libscalar-list-utils-perl, liblist-moreutils-perl,
|
libhash-merge-simple-perl, libscalar-list-utils-perl, liblist-moreutils-perl,
|
||||||
libtry-tiny-perl, libgbm1
|
libtry-tiny-perl, libdatetime-timezone-perl, libgbm1
|
||||||
Provides: vnc-server
|
Provides: vnc-server
|
||||||
Description: KasmVNC provides remote web-based access to a Desktop or application.
|
Description: KasmVNC provides remote web-based access to a Desktop or application.
|
||||||
While VNC is in the name, KasmVNC differs from other VNC variants such
|
While VNC is in the name, KasmVNC differs from other VNC variants such
|
||||||
|
@ -7,7 +7,7 @@ License: GPLv2+
|
|||||||
URL: https://github.com/kasmtech/KasmVNC
|
URL: https://github.com/kasmtech/KasmVNC
|
||||||
|
|
||||||
BuildRequires: rsync
|
BuildRequires: rsync
|
||||||
Requires: xorg-x11-xauth, xkeyboard-config, xkbcomp, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, mesa-libgbm, libxshmfence
|
Requires: xorg-x11-xauth, xkeyboard-config, xkbcomp, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, perl-DateTime-TimeZone, mesa-libgbm, libxshmfence
|
||||||
Conflicts: tigervnc-server, tigervnc-server-minimal
|
Conflicts: tigervnc-server, tigervnc-server-minimal
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
@ -7,7 +7,7 @@ License: GPLv2+
|
|||||||
URL: https://github.com/kasmtech/KasmVNC
|
URL: https://github.com/kasmtech/KasmVNC
|
||||||
|
|
||||||
BuildRequires: rsync
|
BuildRequires: rsync
|
||||||
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, libgbm1, libxshmfence1
|
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, perl-DateTime-TimeZone, libgbm1, libxshmfence1
|
||||||
Conflicts: tigervnc, tigervnc-x11vnc
|
Conflicts: tigervnc, tigervnc-x11vnc
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
@ -7,7 +7,7 @@ License: GPLv2+
|
|||||||
URL: https://github.com/kasmtech/KasmVNC
|
URL: https://github.com/kasmtech/KasmVNC
|
||||||
|
|
||||||
BuildRequires: rsync
|
BuildRequires: rsync
|
||||||
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, hostname, mesa-libgbm, libxshmfence
|
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, perl-DateTime-TimeZone, hostname, mesa-libgbm, libxshmfence
|
||||||
Conflicts: tigervnc-server, tigervnc-server-minimal
|
Conflicts: tigervnc-server, tigervnc-server-minimal
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
@ -7,7 +7,7 @@ License: GPLv2+
|
|||||||
URL: https://github.com/kasmtech/KasmVNC
|
URL: https://github.com/kasmtech/KasmVNC
|
||||||
|
|
||||||
BuildRequires: rsync
|
BuildRequires: rsync
|
||||||
Requires: xorg-x11-xauth, xkeyboard-config, xorg-x11-server-utils, xkbcomp, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, hostname, mesa-libgbm, libxshmfence
|
Requires: xorg-x11-xauth, xkeyboard-config, xorg-x11-server-utils, xkbcomp, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, perl-DateTime-TimeZone, hostname, mesa-libgbm, libxshmfence
|
||||||
Conflicts: tigervnc-server, tigervnc-server-minimal
|
Conflicts: tigervnc-server, tigervnc-server-minimal
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
from mamba import description, context, fcontext, it, fit, before, after
|
from mamba import description, context, fcontext, it, fit, _it, before, after
|
||||||
from expects import expect, equal, contain, match
|
from expects import expect, equal, contain, match
|
||||||
|
|
||||||
from helper.spec_helper import start_xvnc, kill_xvnc, run_cmd, clean_env, \
|
from helper.spec_helper import start_xvnc, kill_xvnc, run_cmd, clean_env, \
|
||||||
@ -268,6 +268,18 @@ with description('YAML to CLI') as self:
|
|||||||
completed_process.stdout)
|
completed_process.stdout)
|
||||||
expect(cli_option).to(equal("-geometry '1024x768'"))
|
expect(cli_option).to(equal("-geometry '1024x768'"))
|
||||||
|
|
||||||
|
with it("allows wide utf characters"):
|
||||||
|
write_config('''
|
||||||
|
data_loss_prevention:
|
||||||
|
watermark:
|
||||||
|
text:
|
||||||
|
template: "星街すいせい"
|
||||||
|
''')
|
||||||
|
completed_process = run_vncserver()
|
||||||
|
cli_option = pick_cli_option('DLP_WatermarkText',
|
||||||
|
completed_process.stdout)
|
||||||
|
expect(cli_option).to(equal("-DLP_WatermarkText '星街すいせい'"))
|
||||||
|
|
||||||
with it("ignores empty section override"):
|
with it("ignores empty section override"):
|
||||||
write_config('''
|
write_config('''
|
||||||
security:
|
security:
|
||||||
|
9
t
Normal file
9
t
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use DateTime::TimeZone;
|
||||||
|
|
||||||
|
my $timezone = $ARGV[0];
|
||||||
|
|
||||||
|
if (DateTime::TimeZone->is_valid_name($timezone)) {
|
||||||
|
print "Valid timezone\n";
|
||||||
|
} else {
|
||||||
|
print "Invalid timezone\n";
|
||||||
|
}
|
11
t2
Normal file
11
t2
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use DateTime;
|
||||||
|
use DateTime::TimeZone;
|
||||||
|
|
||||||
|
#my $timezone_name = 'America/New_York';
|
||||||
|
my $timezone_name = 'UTC';
|
||||||
|
|
||||||
|
my $dt = DateTime->now(time_zone => $timezone_name);
|
||||||
|
my $offset = $dt->offset();
|
||||||
|
|
||||||
|
print "Timezone: $timezone_name\n";
|
||||||
|
print "Offset: $offset seconds\n";
|
37
unix/KasmVNC/CallbackValidator.pm
Normal file
37
unix/KasmVNC/CallbackValidator.pm
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package KasmVNC::CallbackValidator;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use v5.10;
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
use KasmVNC::Utils;
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ($class, $args) = @_;
|
||||||
|
my $self = bless {
|
||||||
|
isValidCallback => $args->{isValidCallback},
|
||||||
|
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 ($self->{isValidCallback}($value)) {
|
||||||
|
$self->{configKey}->addErrorMessage($self->{errorMessage});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
@ -45,6 +45,8 @@ sub isPresent {
|
|||||||
sub deriveBoolean {
|
sub deriveBoolean {
|
||||||
my $value = shift;
|
my $value = shift;
|
||||||
|
|
||||||
|
return $value if containsWideSymbols($value);
|
||||||
|
|
||||||
switch($value) {
|
switch($value) {
|
||||||
case 'true' {
|
case 'true' {
|
||||||
return 1;
|
return 1;
|
||||||
@ -63,4 +65,12 @@ sub printStackTrace {
|
|||||||
print { *STDERR } $trace->as_string;
|
print { *STDERR } $trace->as_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub containsWideSymbols {
|
||||||
|
my $string = shift;
|
||||||
|
|
||||||
|
return 1 unless defined($string);
|
||||||
|
|
||||||
|
$string =~ /[^\x00-\xFF]/;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -92,6 +92,11 @@ data_loss_prevention:
|
|||||||
# location: 10,10
|
# location: 10,10
|
||||||
# tint: 255,20,20,128
|
# tint: 255,20,20,128
|
||||||
# repeat_spacing: 10
|
# repeat_spacing: 10
|
||||||
|
text:
|
||||||
|
template: "${USER} %H:%M"
|
||||||
|
font: auto
|
||||||
|
font_size: 48
|
||||||
|
timezone_name: Australia/Adelaide
|
||||||
logging:
|
logging:
|
||||||
# "verbose" SETTING LOGS YOUR PRIVATE INFORMATION. Keypresses and clipboard content
|
# "verbose" SETTING LOGS YOUR PRIVATE INFORMATION. Keypresses and clipboard content
|
||||||
level: off
|
level: off
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
use v5.10;
|
use v5.10;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use utf8;
|
||||||
|
|
||||||
sub DEVENV() { $ENV{KASMVNC_DEVELOPMENT} };
|
sub DEVENV() { $ENV{KASMVNC_DEVELOPMENT} };
|
||||||
use if DEVENV, Devel::StackTrace;
|
use if DEVENV, Devel::StackTrace;
|
||||||
@ -38,11 +39,14 @@ use List::Util qw(first);
|
|||||||
use List::MoreUtils qw(any uniq);
|
use List::MoreUtils qw(any uniq);
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
use Try::Tiny;
|
use Try::Tiny;
|
||||||
|
use DateTime;
|
||||||
|
use DateTime::TimeZone;
|
||||||
|
|
||||||
use KasmVNC::CliOption;
|
use KasmVNC::CliOption;
|
||||||
use KasmVNC::ConfigKey;
|
use KasmVNC::ConfigKey;
|
||||||
use KasmVNC::PatternValidator;
|
use KasmVNC::PatternValidator;
|
||||||
use KasmVNC::EnumValidator;
|
use KasmVNC::EnumValidator;
|
||||||
|
use KasmVNC::CallbackValidator;
|
||||||
use KasmVNC::Config;
|
use KasmVNC::Config;
|
||||||
use KasmVNC::Users;
|
use KasmVNC::Users;
|
||||||
use KasmVNC::TextOption;
|
use KasmVNC::TextOption;
|
||||||
@ -56,6 +60,7 @@ use constant {
|
|||||||
OPTIONAL_ARG_VALUE => 2
|
OPTIONAL_ARG_VALUE => 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UseUtfStdio();
|
||||||
InitLogger();
|
InitLogger();
|
||||||
|
|
||||||
CheckWeCanRunInThisEnvironment();
|
CheckWeCanRunInThisEnvironment();
|
||||||
@ -1765,6 +1770,79 @@ sub DefineConfigToCLIConversion {
|
|||||||
})
|
})
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
KasmVNC::CliOption->new({
|
||||||
|
name => 'DLP_WatermarkText',
|
||||||
|
configKeys => [
|
||||||
|
KasmVNC::ConfigKey->new({
|
||||||
|
name => "data_loss_prevention.watermark.text.template",
|
||||||
|
validator => KasmVNC::CallbackValidator->new({
|
||||||
|
isValidCallback => sub {
|
||||||
|
my $value = shift;
|
||||||
|
|
||||||
|
isBlank(ConfigValue("data_loss_prevention.watermark.image"));
|
||||||
|
},
|
||||||
|
errorMessage => "Watermark image and text can't be used at the same time"
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
KasmVNC::CliOption->new({
|
||||||
|
name => 'DLP_WatermarkFont',
|
||||||
|
configKeys => [
|
||||||
|
KasmVNC::ConfigKey->new({
|
||||||
|
name => "data_loss_prevention.watermark.text.font",
|
||||||
|
type => KasmVNC::ConfigKey::ANY
|
||||||
|
})
|
||||||
|
],
|
||||||
|
isActiveSub => sub {
|
||||||
|
$self = shift;
|
||||||
|
|
||||||
|
my $value = $self->configValue();
|
||||||
|
isPresent($value) && $value ne "auto";
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
KasmVNC::CliOption->new({
|
||||||
|
name => 'DLP_WatermarkFontSize',
|
||||||
|
configKeys => [
|
||||||
|
KasmVNC::ConfigKey->new({
|
||||||
|
name => "data_loss_prevention.watermark.text.font_size",
|
||||||
|
validator => KasmVNC::CallbackValidator->new({
|
||||||
|
isValidCallback => sub {
|
||||||
|
my $value = shift;
|
||||||
|
|
||||||
|
return 0 unless $value =~ /^\d+$/;
|
||||||
|
|
||||||
|
$value >= 8 && $value <= 256;
|
||||||
|
},
|
||||||
|
errorMessage => "must be in range 8..256"
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
KasmVNC::CliOption->new({
|
||||||
|
name => 'DLP_WatermarkTimeOffsetMinutes',
|
||||||
|
configKeys => [
|
||||||
|
KasmVNC::ConfigKey->new({
|
||||||
|
name => "data_loss_prevention.watermark.text.timezone_name",
|
||||||
|
validator => KasmVNC::CallbackValidator->new({
|
||||||
|
isValidCallback => sub {
|
||||||
|
my $timezone_name = shift;
|
||||||
|
|
||||||
|
DateTime::TimeZone->is_valid_name($timezone_name);
|
||||||
|
},
|
||||||
|
errorMessage => "must be a valid timezone name like Australia/Adelaide"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
],
|
||||||
|
deriveValueSub => sub {
|
||||||
|
my $self = shift;
|
||||||
|
my $timezone_name = $self->configValue();
|
||||||
|
my $dt = DateTime->now(time_zone => $timezone_name);
|
||||||
|
my $offset_in_seconds = $dt->offset();
|
||||||
|
|
||||||
|
$offset_in_seconds/60;
|
||||||
|
}
|
||||||
|
}),
|
||||||
KasmVNC::CliOption->new({
|
KasmVNC::CliOption->new({
|
||||||
name => 'DLP_Log',
|
name => 'DLP_Log',
|
||||||
configKeys => [
|
configKeys => [
|
||||||
@ -2835,3 +2913,7 @@ sub InitLogger {
|
|||||||
my $debugEnabled = any { $_ eq "-debug" } @ARGV;
|
my $debugEnabled = any { $_ eq "-debug" } @ARGV;
|
||||||
$logger = KasmVNC::Logger->new({ level => $debugEnabled ? "debug" : "warn" });
|
$logger = KasmVNC::Logger->new({ level => $debugEnabled ? "debug" : "warn" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub UseUtfStdio {
|
||||||
|
use open qw( :std :encoding(UTF-8) );
|
||||||
|
}
|
||||||
|
@ -52,7 +52,8 @@ Xvnc_CPPFLAGS = $(XVNC_CPPFLAGS) -DKASMVNC -DNO_MODULE_EXTS \
|
|||||||
-I$(top_srcdir)/dri3 @LIBDRM_CFLAGS@
|
-I$(top_srcdir)/dri3 @LIBDRM_CFLAGS@
|
||||||
|
|
||||||
Xvnc_LDADD = $(XVNC_LIBS) libvnccommon.la $(COMMON_LIBS) \
|
Xvnc_LDADD = $(XVNC_LIBS) libvnccommon.la $(COMMON_LIBS) \
|
||||||
$(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XVNC_SYS_LIBS) -lX11 -lwebp -lssl -lcrypto -lcrypt
|
$(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XVNC_SYS_LIBS) -lX11 -lwebp -lssl -lcrypto -lcrypt \
|
||||||
|
-lfreetype
|
||||||
|
|
||||||
Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) -fopenmp
|
Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) -fopenmp
|
||||||
|
|
||||||
|
@ -243,6 +243,8 @@ Default \fB-1\fP.
|
|||||||
.B \-WebpVideoQuality \fInum\fP
|
.B \-WebpVideoQuality \fInum\fP
|
||||||
The WEBP quality to use when in video mode.
|
The WEBP quality to use when in video mode.
|
||||||
Default \fB-1\fP.
|
Default \fB-1\fP.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
.B \-MaxVideoResolution \fI1920x1080\fP
|
.B \-MaxVideoResolution \fI1920x1080\fP
|
||||||
When in video mode, downscale the screen to max this size. Keeps aspect ratio.
|
When in video mode, downscale the screen to max this size. Keeps aspect ratio.
|
||||||
Default \fB1920x1080\fP.
|
Default \fB1920x1080\fP.
|
||||||
@ -372,6 +374,28 @@ The color components can be used to colorize the greyscale watermark, and the al
|
|||||||
can be used to make it fainter.
|
can be used to make it fainter.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-DLP_WatermarkText \fI"foo %H:%M"\fP
|
||||||
|
Instead of an image, render this text as the watermark. Takes time formatting options
|
||||||
|
for \fBstrftime\fP.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.B \-DLP_WatermarkFont \fI/path/to/font.ttf\fP
|
||||||
|
Use a different font for -DLP_WatermarkText than the bundled one. TTF and OTF fonts
|
||||||
|
are accepted.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.B \-DLP_WatermarkFontSize \fI48\fP
|
||||||
|
Font size for -DLP_WatermarkText. Default \fI48\fP.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.B \-DLP_WatermarkTimeOffset \fI0\fP
|
||||||
|
Time offset from UTC, hours. Default \fI0\fP.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.B \-DLP_WatermarkTimeOffsetMinutes \fI0\fP
|
||||||
|
Time offset from UTC, minutes. Default \fI0\fP.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
.B \-selfBench
|
.B \-selfBench
|
||||||
Run a set of self-benchmarks and exit.
|
Run a set of self-benchmarks and exit.
|
||||||
.
|
.
|
||||||
|
Loading…
Reference in New Issue
Block a user