Merge pull request #17 from kasmtech/chromeclip

Chromeclip
This commit is contained in:
mmcclaskey 2021-10-15 15:40:17 -04:00 committed by GitHub
commit 0bd3813949
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 330 additions and 74 deletions

View File

@ -30,9 +30,11 @@ window.updateSetting = (name, value) => {
} }
} }
import "core-js/stable";
import "regenerator-runtime/runtime";
import * as Log from '../core/util/logging.js'; import * as Log from '../core/util/logging.js';
import _, { l10n } from './localization.js'; import _, { l10n } from './localization.js';
import { isTouchDevice, isSafari, hasScrollbarGutter, dragThreshold } import { isTouchDevice, isSafari, hasScrollbarGutter, dragThreshold, supportsBinaryClipboard, isFirefox }
from '../core/util/browser.js'; from '../core/util/browser.js';
import { setCapture, getPointerEvent } from '../core/util/events.js'; import { setCapture, getPointerEvent } from '../core/util/events.js';
import KeyTable from "../core/input/keysym.js"; import KeyTable from "../core/input/keysym.js";
@ -1100,20 +1102,12 @@ const UI = {
}, },
clipboardReceive(e) { clipboardReceive(e) {
if (UI.rfb.clipboardDown && UI.rfb.clipboardSeamless ) { if (UI.rfb.clipboardDown) {
var curvalue = document.getElementById('noVNC_clipboard_text').value; var curvalue = document.getElementById('noVNC_clipboard_text').value;
if (curvalue != e.detail.text) { if (curvalue != e.detail.text) {
Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0, 40) + "..."); Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0, 40) + "...");
document.getElementById('noVNC_clipboard_text').value = e.detail.text; document.getElementById('noVNC_clipboard_text').value = e.detail.text;
Log.Debug("<< UI.clipboardReceive"); Log.Debug("<< UI.clipboardReceive");
if (navigator.clipboard && navigator.clipboard.writeText){
navigator.clipboard.writeText(e.detail.text)
.then(function () {
//UI.popupMessage("Selection Copied");
}, function () {
console.error("Failed to write system clipboard (trying to copy from NoVNC clipboard)")
});
}
} }
} }
}, },
@ -1142,26 +1136,22 @@ const UI = {
UI.copyFromLocalClipboard(); UI.copyFromLocalClipboard();
}, },
copyFromLocalClipboard: function copyFromLocalClipboard() { copyFromLocalClipboard: function copyFromLocalClipboard() {
if (!document.hasFocus()) {
Log.Debug("window does not have focus");
return;
}
if (UI.rfb && UI.rfb.clipboardUp && UI.rfb.clipboardSeamless) { if (UI.rfb && UI.rfb.clipboardUp && UI.rfb.clipboardSeamless) {
UI.readClipboard(function (text) {
var maximumBufferSize = 10000;
var clipVal = document.getElementById('noVNC_clipboard_text').value;
if (clipVal != text) { if (UI.rfb.clipboardBinary) {
document.getElementById('noVNC_clipboard_text').value = text; // The websocket has a maximum buffer array size navigator.clipboard.read().then((data) => {
if (UI.rfb) {
if (text.length > maximumBufferSize) { UI.rfb.clipboardPasteDataFrom(data);
UI.popupMessage("Clipboard contents too large. Data truncated", 2000);
UI.rfb.clipboardPasteFrom(text.slice(0, maximumBufferSize));
} else {
//UI.popupMessage("Copied from Local Clipboard");
UI.rfb.clipboardPasteFrom(text);
} }
} // Reset flag to prevent checking too often UI.needToCheckClipboardChange = false;
}, (err) => {
Log.Debug("No data in clipboard");
UI.needToCheckClipboardChange = false; });
}); }
} }
}, },
@ -1304,6 +1294,13 @@ const UI = {
UI.rfb.clipboardUp = UI.getSetting('clipboard_up'); UI.rfb.clipboardUp = UI.getSetting('clipboard_up');
UI.rfb.clipboardDown = UI.getSetting('clipboard_down'); UI.rfb.clipboardDown = UI.getSetting('clipboard_down');
UI.rfb.clipboardSeamless = UI.getSetting('clipboard_seamless'); UI.rfb.clipboardSeamless = UI.getSetting('clipboard_seamless');
UI.rfb.clipboardBinary = supportsBinaryClipboard() && UI.rfb.clipboardSeamless;
//Only explicitly request permission to clipboard on browsers that support binary clipboard access
if (supportsBinaryClipboard()) {
// explicitly request permission to the clipboard
navigator.permissions.query({ name: "clipboard-read" }).then((result) => { Log.Debug('binary clipboard enabled') });
}
// KASM-960 workaround, disable seamless on Safari // KASM-960 workaround, disable seamless on Safari
if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent))
{ {

View File

@ -10,6 +10,7 @@
import { toUnsigned32bit, toSigned32bit } from './util/int.js'; import { toUnsigned32bit, toSigned32bit } from './util/int.js';
import * as Log from './util/logging.js'; import * as Log from './util/logging.js';
import { encodeUTF8, decodeUTF8 } from './util/strings.js'; import { encodeUTF8, decodeUTF8 } from './util/strings.js';
import { hashUInt8Array } from './util/int.js';
import { dragThreshold, supportsCursorURIs, isTouchDevice, isWindows, isMac } from './util/browser.js'; import { dragThreshold, supportsCursorURIs, isTouchDevice, isWindows, isMac } from './util/browser.js';
import { clientToElement } from './util/element.js'; import { clientToElement } from './util/element.js';
import { setCapture } from './util/events.js'; import { setCapture } from './util/events.js';
@ -140,6 +141,7 @@ export default class RFB extends EventTargetMixin {
this._frameRate = 30; this._frameRate = 30;
this._maxVideoResolutionX = 960; this._maxVideoResolutionX = 960;
this._maxVideoResolutionY = 540; this._maxVideoResolutionY = 540;
this._clipboardBinary = true;
this._trackFrameStats = false; this._trackFrameStats = false;
@ -332,10 +334,14 @@ export default class RFB extends EventTargetMixin {
this._qualityLevel = 6; this._qualityLevel = 6;
this._compressionLevel = 2; this._compressionLevel = 2;
this._clipHash = 0;
} }
// ===== PROPERTIES ===== // ===== PROPERTIES =====
get clipboardBinary() { return this._clipboardMode; }
set clipboardBinary(val) { this._clipboardMode = val; }
get videoQuality() { return this._videoQuality; } get videoQuality() { return this._videoQuality; }
set videoQuality(quality) { this._videoQuality = quality; } set videoQuality(quality) { this._videoQuality = quality; }
@ -763,21 +769,94 @@ export default class RFB extends EventTargetMixin {
clipboardPasteFrom(text) { clipboardPasteFrom(text) {
if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; } if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; }
if (!(typeof text === 'string' && text.length > 0)) { return; }
this.sentEventsCounter+=1; this.sentEventsCounter+=1;
if (this._clipboardServerCapabilitiesFormats[extendedClipboardFormatText] &&
this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) {
this._clipboardText = text; let data = new Uint8Array(text.length);
RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]); for (let i = 0; i < text.length; i++) {
} else { data[i] = text.charCodeAt(i);
let data = new Uint8Array(text.length);
for (let i = 0; i < text.length; i++) {
// FIXME: text can have values outside of Latin1/Uint8
data[i] = text.charCodeAt(i);
}
RFB.messages.clientCutText(this._sock, data);
} }
let h = hashUInt8Array(data);
if (h === this._clipHash) {
Log.Debug('No clipboard changes');
return;
} else {
this._clipHash = h;
}
let dataset = [];
let mimes = [ 'text/plain' ];
dataset.push(data);
RFB.messages.sendBinaryClipboard(this._sock, dataset, mimes);
}
async clipboardPasteDataFrom(clipdata) {
if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; }
this.sentEventsCounter+=1;
let dataset = [];
let mimes = [];
let h = 0;
for (let i = 0; i < clipdata.length; i++) {
for (let ti = 0; ti < clipdata[i].types.length; ti++) {
let mime = clipdata[i].types[ti];
switch (mime) {
case 'image/png':
case 'text/plain':
case 'text/html':
let blob = await clipdata[i].getType(mime);
if (!blob) {
continue;
}
let buff = await blob.arrayBuffer();
let data = new Uint8Array(buff);
if (!h) {
h = hashUInt8Array(data);
if (h === this._clipHash) {
Log.Debug('No clipboard changes');
return;
} else {
this._clipHash = h;
}
}
if (mimes.includes(mime)) {
continue;
}
mimes.push(mime);
dataset.push(data);
Log.Debug('Sending mime type: ' + mime);
break;
default:
Log.Info('skipping clip send mime type: ' + mime)
}
}
}
//if png is present and text/plain is not, remove other variations of images to save bandwidth
//if png is present with text/plain, then remove png. Word will put in a png of copied text
if (mimes.includes('image/png') && !mimes.includes('text/plain')) {
let i = mimes.indexOf('image/png');
mimes = mimes.slice(i, i+1);
dataset = dataset.slice(i, i+1);
} else if (mimes.includes('image/png') && mimes.includes('text/plain')) {
let i = mimes.indexOf('image/png');
mimes.splice(i, 1);
dataset.splice(i, 1);
}
if (dataset.length > 0) {
RFB.messages.sendBinaryClipboard(this._sock, dataset, mimes);
}
} }
requestBottleneckStats() { requestBottleneckStats() {
@ -980,7 +1059,7 @@ export default class RFB extends EventTargetMixin {
try { try {
if (x > 1280 && limited && this.videoQuality == 1) { if (x > 1280 && limited && this.videoQuality == 1) {
var ratio = y / x; var ratio = y / x;
console.log(ratio); Log.Debug(ratio);
x = 1280; x = 1280;
y = x * ratio; y = x * ratio;
} }
@ -989,7 +1068,7 @@ export default class RFB extends EventTargetMixin {
y = 720; y = 720;
} }
} catch (err) { } catch (err) {
console.log(err); Log.Debug(err);
} }
return { w: x, return { w: x,
@ -2383,6 +2462,100 @@ export default class RFB extends EventTargetMixin {
return true; return true;
} }
_handleBinaryClipboard() {
Log.Debug("HandleBinaryClipboard");
if (this._sock.rQwait("Binary Clipboard header", 2, 1)) { return false; }
let num = this._sock.rQshift8(); // how many different mime types
let mimes = [];
let clipItemData = {};
let buffByteLen = 2;
let textdata = '';
Log.Info(num + ' Clipboard items recieved.');
Log.Debug('Started clipbooard processing with Client sockjs buffer size ' + this._sock.rQlen);
for (let i = 0; i < num; i++) {
if (this._sock.rQwait("Binary Clipboard mimelen", 1, buffByteLen)) { return false; }
buffByteLen++;
let mimelen = this._sock.rQshift8();
if (this._sock.rQwait("Binary Clipboard mime", Math.abs(mimelen), buffByteLen)) { return false; }
buffByteLen+=mimelen;
let mime = this._sock.rQshiftStr(mimelen);
if (this._sock.rQwait("Binary Clipboard data len", 4, buffByteLen)) { return false; }
buffByteLen+=4;
let len = this._sock.rQshift32();
if (this._sock.rQwait("Binary Clipboard data", Math.abs(len), buffByteLen)) { return false; }
let data = this._sock.rQshiftBytes(len);
buffByteLen+=len;
switch(mime) {
case "image/png":
case "text/html":
case "text/plain":
mimes.push(mime);
if (mime == "text/plain") {
//textdata = new TextDecoder().decode(data);
for (let i = 0; i < data.length; i++) {
textdata+=String.fromCharCode(data[i]);
}
if ((textdata.length > 0) && "\0" === textdata.charAt(textdata.length - 1)) {
textdata = textdata.slice(0, -1);
}
Log.Debug("Plain text clipboard recieved and placed in text element, size: " + textdata.length);
this.dispatchEvent(new CustomEvent(
"clipboard",
{ detail: { text: textdata } })
);
}
if (!this.clipboardBinary) { continue; }
Log.Info("Processed binary clipboard of MIME " + mime + " of length " + len);
clipItemData[mime] = new Blob([data], { type: mime });
break;
default:
Log.Debug('Mime type skipped: ' + mime);
break;
}
}
Log.Debug('Finished processing binary clipboard with client sockjs buffer size ' + this._sock.rQlen);
if (Object.keys(clipItemData).length > 0) {
if (this.clipboardBinary) {
this._clipHash = 0;
navigator.clipboard.write([new ClipboardItem(clipItemData)]).then(
function() {},
function(err) {
Log.Error("Error writing to client clipboard: " + err);
// Lets try writeText
if (textdata.length > 0) {
navigator.clipboard.writeText(textdata).then(
function() {},
function(err2) {
Log.Error("Error writing text to client clipboard: " + err2);
}
);
}
}
);
}
}
return true;
}
_handle_server_stats_msg() { _handle_server_stats_msg() {
this._sock.rQskipBytes(3); // Padding this._sock.rQskipBytes(3); // Padding
const length = this._sock.rQshift32(); const length = this._sock.rQshift32();
@ -2390,8 +2563,8 @@ export default class RFB extends EventTargetMixin {
const text = this._sock.rQshiftStr(length); const text = this._sock.rQshiftStr(length);
console.log("Received KASM bottleneck stats:"); Log.Debug("Received KASM bottleneck stats:");
console.log(text); Log.Debug(text);
this.dispatchEvent(new CustomEvent( this.dispatchEvent(new CustomEvent(
"bottleneck_stats", "bottleneck_stats",
{ detail: { text: text } })); { detail: { text: text } }));
@ -2523,6 +2696,9 @@ export default class RFB extends EventTargetMixin {
this._trackFrameStats = true; this._trackFrameStats = true;
return true; return true;
case 180: // KASM binary clipboard
return this._handleBinaryClipboard();
case 248: // ServerFence case 248: // ServerFence
return this._handleServerFenceMsg(); return this._handleServerFenceMsg();
@ -3184,6 +3360,61 @@ RFB.messages = {
}, },
sendBinaryClipboard(sock, dataset, mimes) {
const buff = sock._sQ;
let offset = sock._sQlen;
buff[offset] = 180; // msg-type
buff[offset + 1] = dataset.length; // how many mime types
sock._sQlen += 2;
offset += 2;
for (let i=0; i < dataset.length; i++) {
let mime = mimes[i];
let data = dataset[i];
buff[offset++] = mime.length;
for (let i = 0; i < mime.length; i++) {
buff[offset++] = mime.charCodeAt(i); // change to [] if not a string
}
let length = data.length;
Log.Info('Clipboard data sent mime type ' + mime + ' len ' + length);
buff[offset++] = length >> 24;
buff[offset++] = length >> 16;
buff[offset++] = length >> 8;
buff[offset++] = length;
sock._sQlen += 1 + mime.length + 4;
// We have to keep track of from where in the data we begin creating the
// buffer for the flush in the next iteration.
let dataOffset = 0;
let remaining = data.length;
while (remaining > 0) {
let flushSize = Math.min(remaining, (sock._sQbufferSize - sock._sQlen));
for (let i = 0; i < flushSize; i++) {
buff[sock._sQlen + i] = data[dataOffset + i];
}
sock._sQlen += flushSize;
sock.flush();
remaining -= flushSize;
dataOffset += flushSize;
}
offset = sock._sQlen;
}
},
setDesktopSize(sock, width, height, id, flags) { setDesktopSize(sock, width, height, id, flags) {
const buff = sock._sQ; const buff = sock._sQ;
const offset = sock._sQlen; const offset = sock._sQlen;

View File

@ -101,3 +101,9 @@ export function isFirefox() {
return navigator && !!(/firefox/i).exec(navigator.userAgent); return navigator && !!(/firefox/i).exec(navigator.userAgent);
} }
export function supportsBinaryClipboard() {
//Safari does support the clipbaord API but has a lot of security restrictions
if (isSafari()) { return false; }
return (navigator.clipboard && typeof navigator.clipboard.read === "function");
}

View File

@ -13,3 +13,14 @@ export function toUnsigned32bit(toConvert) {
export function toSigned32bit(toConvert) { export function toSigned32bit(toConvert) {
return toConvert | 0; return toConvert | 0;
} }
/*
* Fast hashing function with low entropy, not for security uses.
*/
export function hashUInt8Array(data) {
let h;
for (let i = 0; i < data.length; i++) {
h = Math.imul(31, h) + data[i] | 0;
}
return h;
}

54
package-lock.json generated
View File

@ -22,7 +22,7 @@
"chai": "*", "chai": "*",
"clean-webpack-plugin": "^3.0.0", "clean-webpack-plugin": "^3.0.0",
"commander": "*", "commander": "*",
"core-js": "*", "core-js": "^3.18.3",
"css-loader": "^5.0.1", "css-loader": "^5.0.1",
"css-minimizer-webpack-plugin": "^1.1.5", "css-minimizer-webpack-plugin": "^1.1.5",
"es-module-loader": "*", "es-module-loader": "*",
@ -48,6 +48,7 @@
"po2json": "*", "po2json": "*",
"postcss-loader": "^4.1.0", "postcss-loader": "^4.1.0",
"preload-webpack-plugin": "^3.0.0-beta.4", "preload-webpack-plugin": "^3.0.0-beta.4",
"regenerator-runtime": "^0.13.9",
"requirejs": "*", "requirejs": "*",
"rollup": "*", "rollup": "*",
"rollup-plugin-node-resolve": "*", "rollup-plugin-node-resolve": "*",
@ -4010,9 +4011,9 @@
} }
}, },
"node_modules/core-js": { "node_modules/core-js": {
"version": "3.16.2", "version": "3.18.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.2.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.3.tgz",
"integrity": "sha512-P0KPukO6OjMpjBtHSceAZEWlDD1M2Cpzpg6dBbrjFqFhBHe/BwhxaP820xKOjRn/lZRQirrCusIpLS/n2sgXLQ==", "integrity": "sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"funding": { "funding": {
@ -18310,7 +18311,8 @@
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true "dev": true,
"requires": {}
}, },
"acorn-node": { "acorn-node": {
"version": "1.8.2", "version": "1.8.2",
@ -18364,13 +18366,15 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
"integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
"dev": true "dev": true,
"requires": {}
}, },
"ajv-keywords": { "ajv-keywords": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true "dev": true,
"requires": {}
}, },
"alphanum-sort": { "alphanum-sort": {
"version": "1.0.2", "version": "1.0.2",
@ -18684,7 +18688,8 @@
"version": "10.0.0", "version": "10.0.0",
"resolved": "https://registry.npmjs.org/babelify/-/babelify-10.0.0.tgz", "resolved": "https://registry.npmjs.org/babelify/-/babelify-10.0.0.tgz",
"integrity": "sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg==", "integrity": "sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg==",
"dev": true "dev": true,
"requires": {}
}, },
"babylon": { "babylon": {
"version": "6.18.0", "version": "6.18.0",
@ -19806,9 +19811,9 @@
"dev": true "dev": true
}, },
"core-js": { "core-js": {
"version": "3.16.2", "version": "3.18.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.2.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.3.tgz",
"integrity": "sha512-P0KPukO6OjMpjBtHSceAZEWlDD1M2Cpzpg6dBbrjFqFhBHe/BwhxaP820xKOjRn/lZRQirrCusIpLS/n2sgXLQ==", "integrity": "sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw==",
"dev": true "dev": true
}, },
"core-js-compat": { "core-js-compat": {
@ -20819,7 +20824,8 @@
"version": "7.4.6", "version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
"dev": true "dev": true,
"requires": {}
} }
} }
}, },
@ -22436,7 +22442,8 @@
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
"dev": true "dev": true,
"requires": {}
}, },
"ieee754": { "ieee754": {
"version": "1.2.1", "version": "1.2.1",
@ -23347,19 +23354,22 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/karma-safari-launcher/-/karma-safari-launcher-1.0.0.tgz", "resolved": "https://registry.npmjs.org/karma-safari-launcher/-/karma-safari-launcher-1.0.0.tgz",
"integrity": "sha1-lpgqLMR9BmquccVTursoMZEVos4=", "integrity": "sha1-lpgqLMR9BmquccVTursoMZEVos4=",
"dev": true "dev": true,
"requires": {}
}, },
"karma-script-launcher": { "karma-script-launcher": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/karma-script-launcher/-/karma-script-launcher-1.0.0.tgz", "resolved": "https://registry.npmjs.org/karma-script-launcher/-/karma-script-launcher-1.0.0.tgz",
"integrity": "sha1-zQF8TeXvCeWp2nkydhdhCN1LVC0=", "integrity": "sha1-zQF8TeXvCeWp2nkydhdhCN1LVC0=",
"dev": true "dev": true,
"requires": {}
}, },
"karma-sinon-chai": { "karma-sinon-chai": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/karma-sinon-chai/-/karma-sinon-chai-2.0.2.tgz", "resolved": "https://registry.npmjs.org/karma-sinon-chai/-/karma-sinon-chai-2.0.2.tgz",
"integrity": "sha512-SDgh6V0CUd+7ruL1d3yG6lFzmJNGRNQuEuCYXLaorruNP9nwQfA7hpsp4clx4CbOo5Gsajh3qUOT7CrVStUKMw==", "integrity": "sha512-SDgh6V0CUd+7ruL1d3yG6lFzmJNGRNQuEuCYXLaorruNP9nwQfA7hpsp4clx4CbOo5Gsajh3qUOT7CrVStUKMw==",
"dev": true "dev": true,
"requires": {}
}, },
"kew": { "kew": {
"version": "0.7.0", "version": "0.7.0",
@ -25647,7 +25657,8 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
"dev": true "dev": true,
"requires": {}
}, },
"postcss-modules-local-by-default": { "postcss-modules-local-by-default": {
"version": "4.0.0", "version": "4.0.0",
@ -26312,7 +26323,8 @@
"version": "3.0.0-beta.4", "version": "3.0.0-beta.4",
"resolved": "https://registry.npmjs.org/preload-webpack-plugin/-/preload-webpack-plugin-3.0.0-beta.4.tgz", "resolved": "https://registry.npmjs.org/preload-webpack-plugin/-/preload-webpack-plugin-3.0.0-beta.4.tgz",
"integrity": "sha512-6hhh0AswCbp/U4EPVN4fbK2wiDkXhmgjjgEYEmXa21UYwjYzCIgh3ZRMXM21ZPLfbQGpdFuSL3zFslU+edjpwg==", "integrity": "sha512-6hhh0AswCbp/U4EPVN4fbK2wiDkXhmgjjgEYEmXa21UYwjYzCIgh3ZRMXM21ZPLfbQGpdFuSL3zFslU+edjpwg==",
"dev": true "dev": true,
"requires": {}
}, },
"prelude-ls": { "prelude-ls": {
"version": "1.2.1", "version": "1.2.1",
@ -27246,7 +27258,8 @@
"version": "2.14.0", "version": "2.14.0",
"resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-2.14.0.tgz", "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-2.14.0.tgz",
"integrity": "sha512-9stIF1utB0ywNHNT7RgiXbdmen8QDCRsrTjw+G9TgKt1Yexjiv8TOWZ6WHsTPz57Yky3DIswZvEqX8fpuHNDtQ==", "integrity": "sha512-9stIF1utB0ywNHNT7RgiXbdmen8QDCRsrTjw+G9TgKt1Yexjiv8TOWZ6WHsTPz57Yky3DIswZvEqX8fpuHNDtQ==",
"dev": true "dev": true,
"requires": {}
}, },
"slash": { "slash": {
"version": "2.0.0", "version": "2.0.0",
@ -29645,7 +29658,8 @@
"version": "8.2.0", "version": "8.2.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.0.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.0.tgz",
"integrity": "sha512-uYhVJ/m9oXwEI04iIVmgLmugh2qrZihkywG9y5FfZV2ATeLIzHf93qs+tUNqlttbQK957/VX3mtwAS+UfIwA4g==", "integrity": "sha512-uYhVJ/m9oXwEI04iIVmgLmugh2qrZihkywG9y5FfZV2ATeLIzHf93qs+tUNqlttbQK957/VX3mtwAS+UfIwA4g==",
"dev": true "dev": true,
"requires": {}
}, },
"xml-name-validator": { "xml-name-validator": {
"version": "3.0.0", "version": "3.0.0",

View File

@ -30,29 +30,27 @@
"url": "git+https://github.com/kasmtech/noVNC.git" "url": "git+https://github.com/kasmtech/noVNC.git"
}, },
"author": "Kasm Technologies (https://www.kasmweb.com)", "author": "Kasm Technologies (https://www.kasmweb.com)",
"contributors": [ "contributors": [],
],
"license": "MPL-2.0", "license": "MPL-2.0",
"bugs": { "bugs": {
"url": "https://github.com/kasmtech/noVNC/issues" "url": "https://github.com/kasmtech/noVNC/issues"
}, },
"homepage": "https://github.com/kasmtech/noVNC", "homepage": "https://github.com/kasmtech/noVNC",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.10", "@babel/cli": "*",
"@babel/preset-env": "^7.12.11",
"@babel/core": "*", "@babel/core": "*",
"babel-loader": "^8.2.2",
"@babel/plugin-syntax-dynamic-import": "*", "@babel/plugin-syntax-dynamic-import": "*",
"@babel/plugin-transform-modules-commonjs": "*", "@babel/plugin-transform-modules-commonjs": "*",
"@babel/preset-env": "*", "@babel/preset-env": "*",
"@babel/cli": "*", "@chiragrupani/karma-chromium-edge-launcher": "*",
"babel-loader": "^8.2.2",
"babel-plugin-import-redirect": "*", "babel-plugin-import-redirect": "*",
"browserify": "*",
"babelify": "*", "babelify": "*",
"core-js": "*", "browserify": "*",
"chai": "*", "chai": "*",
"clean-webpack-plugin": "^3.0.0", "clean-webpack-plugin": "^3.0.0",
"commander": "*", "commander": "*",
"core-js": "^3.18.3",
"css-loader": "^5.0.1", "css-loader": "^5.0.1",
"css-minimizer-webpack-plugin": "^1.1.5", "css-minimizer-webpack-plugin": "^1.1.5",
"es-module-loader": "*", "es-module-loader": "*",
@ -64,11 +62,10 @@
"html-webpack-plugin": "^4.5.0", "html-webpack-plugin": "^4.5.0",
"jsdom": "*", "jsdom": "*",
"karma": "*", "karma": "*",
"karma-mocha": "*",
"karma-chrome-launcher": "*", "karma-chrome-launcher": "*",
"@chiragrupani/karma-chromium-edge-launcher": "*",
"karma-firefox-launcher": "*", "karma-firefox-launcher": "*",
"karma-ie-launcher": "*", "karma-ie-launcher": "*",
"karma-mocha": "*",
"karma-mocha-reporter": "*", "karma-mocha-reporter": "*",
"karma-safari-launcher": "*", "karma-safari-launcher": "*",
"karma-script-launcher": "*", "karma-script-launcher": "*",
@ -79,6 +76,7 @@
"po2json": "*", "po2json": "*",
"postcss-loader": "^4.1.0", "postcss-loader": "^4.1.0",
"preload-webpack-plugin": "^3.0.0-beta.4", "preload-webpack-plugin": "^3.0.0-beta.4",
"regenerator-runtime": "^0.13.9",
"requirejs": "*", "requirejs": "*",
"rollup": "*", "rollup": "*",
"rollup-plugin-node-resolve": "*", "rollup-plugin-node-resolve": "*",
@ -90,7 +88,6 @@
"webpack": "^4.29.6", "webpack": "^4.29.6",
"webpack-cli": "^3.2.3" "webpack-cli": "^3.2.3"
}, },
"dependencies": {},
"keywords": [ "keywords": [
"vnc", "vnc",
"rfb", "rfb",