JavaScript 65.5%
Python 17.8%
CSS 13%
HTML 3.7%
1"use strict";23function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }4Object.defineProperty(exports, "__esModule", {5 value: true6});7exports["default"] = void 0;8var _int = require("./util/int.js");9var Log = _interopRequireWildcard(require("./util/logging.js"));10var _strings = require("./util/strings.js");11var _browser = require("./util/browser.js");12var _element = require("./util/element.js");13var _events = require("./util/events.js");14var _eventtarget = _interopRequireDefault(require("./util/eventtarget.js"));15var _display = _interopRequireDefault(require("./display.js"));16var _inflator = _interopRequireDefault(require("./inflator.js"));17var _deflator = _interopRequireDefault(require("./deflator.js"));18var _keyboard = _interopRequireDefault(require("./input/keyboard.js"));19var _gesturehandler = _interopRequireDefault(require("./input/gesturehandler.js"));20var _cursor = _interopRequireDefault(require("./util/cursor.js"));21var _websock = _interopRequireDefault(require("./websock.js"));22var _keysym = _interopRequireDefault(require("./input/keysym.js"));23var _xtscancodes = _interopRequireDefault(require("./input/xtscancodes.js"));24var _encodings = require("./encodings.js");25var _ra = _interopRequireDefault(require("./ra2.js"));26var _crypto = _interopRequireDefault(require("./crypto/crypto.js"));27var _raw = _interopRequireDefault(require("./decoders/raw.js"));28var _copyrect = _interopRequireDefault(require("./decoders/copyrect.js"));29var _rre = _interopRequireDefault(require("./decoders/rre.js"));30var _hextile = _interopRequireDefault(require("./decoders/hextile.js"));31var _zlib = _interopRequireDefault(require("./decoders/zlib.js"));32var _tight = _interopRequireDefault(require("./decoders/tight.js"));33var _tightpng = _interopRequireDefault(require("./decoders/tightpng.js"));34var _zrle = _interopRequireDefault(require("./decoders/zrle.js"));35var _jpeg = _interopRequireDefault(require("./decoders/jpeg.js"));36var _h = _interopRequireDefault(require("./decoders/h264.js"));37function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }38function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }39function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }40function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, "catch": function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }41function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }42function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }43function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }44function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }45function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }46function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }47function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }48function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }49function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }50function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }51function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }52function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }53function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }54function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }55function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }56function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }57function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }58function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }59function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }60function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }61function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } /*62 * noVNC: HTML5 VNC client63 * Copyright (C) 2020 The noVNC authors64 * Licensed under MPL 2.0 (see LICENSE.txt)65 *66 * See README.md for usage and integration instructions.67 *68 */69// How many seconds to wait for a disconnect to finish70var DISCONNECT_TIMEOUT = 3;71var DEFAULT_BACKGROUND = 'rgb(40, 40, 40)';7273// Minimum wait (ms) between two mouse moves74var MOUSE_MOVE_DELAY = 17;7576// Wheel thresholds77var WHEEL_STEP = 50; // Pixels needed for one step78var WHEEL_LINE_HEIGHT = 19; // Assumed pixels for one line step7980// Gesture thresholds81var GESTURE_ZOOMSENS = 75;82var GESTURE_SCRLSENS = 50;83var DOUBLE_TAP_TIMEOUT = 1000;84var DOUBLE_TAP_THRESHOLD = 50;8586// Security types87var securityTypeNone = 1;88var securityTypeVNCAuth = 2;89var securityTypeRA2ne = 6;90var securityTypeTight = 16;91var securityTypeVeNCrypt = 19;92var securityTypeXVP = 22;93var securityTypeARD = 30;94var securityTypeMSLogonII = 113;9596// Special Tight security types97var securityTypeUnixLogon = 129;9899// VeNCrypt security types100var securityTypePlain = 256;101102// Extended clipboard pseudo-encoding formats103var extendedClipboardFormatText = 1;104/*eslint-disable no-unused-vars */105var extendedClipboardFormatRtf = 1 << 1;106var extendedClipboardFormatHtml = 1 << 2;107var extendedClipboardFormatDib = 1 << 3;108var extendedClipboardFormatFiles = 1 << 4;109/*eslint-enable */110111// Extended clipboard pseudo-encoding actions112var extendedClipboardActionCaps = 1 << 24;113var extendedClipboardActionRequest = 1 << 25;114var extendedClipboardActionPeek = 1 << 26;115var extendedClipboardActionNotify = 1 << 27;116var extendedClipboardActionProvide = 1 << 28;117var RFB = exports["default"] = /*#__PURE__*/function (_EventTargetMixin) {118 function RFB(target, urlOrChannel, options) {119 var _this;120 _classCallCheck(this, RFB);121 if (!target) {122 throw new Error("Must specify target");123 }124 if (!urlOrChannel) {125 throw new Error("Must specify URL, WebSocket or RTCDataChannel");126 }127128 // We rely on modern APIs which might not be available in an129 // insecure context130 if (!window.isSecureContext) {131 Log.Error("noVNC requires a secure context (TLS). Expect crashes!");132 }133 _this = _callSuper(this, RFB);134 _this._target = target;135 if (typeof urlOrChannel === "string") {136 _this._url = urlOrChannel;137 } else {138 _this._url = null;139 _this._rawChannel = urlOrChannel;140 }141142 // Connection details143 options = options || {};144 _this._rfbCredentials = options.credentials || {};145 _this._shared = 'shared' in options ? !!options.shared : true;146 _this._repeaterID = options.repeaterID || '';147 _this._wsProtocols = options.wsProtocols || [];148149 // Internal state150 _this._rfbConnectionState = '';151 _this._rfbInitState = '';152 _this._rfbAuthScheme = -1;153 _this._rfbCleanDisconnect = true;154 _this._rfbRSAAESAuthenticationState = null;155156 // Server capabilities157 _this._rfbVersion = 0;158 _this._rfbMaxVersion = 3.8;159 _this._rfbTightVNC = false;160 _this._rfbVeNCryptState = 0;161 _this._rfbXvpVer = 0;162 _this._fbWidth = 0;163 _this._fbHeight = 0;164 _this._fbName = "";165 _this._capabilities = {166 power: false167 };168 _this._supportsFence = false;169 _this._supportsContinuousUpdates = false;170 _this._enabledContinuousUpdates = false;171 _this._supportsSetDesktopSize = false;172 _this._screenID = 0;173 _this._screenFlags = 0;174 _this._pendingRemoteResize = false;175 _this._lastResize = 0;176 _this._qemuExtKeyEventSupported = false;177 _this._extendedPointerEventSupported = false;178 _this._clipboardText = null;179 _this._clipboardServerCapabilitiesActions = {};180 _this._clipboardServerCapabilitiesFormats = {};181182 // Internal objects183 _this._sock = null; // Websock object184 _this._display = null; // Display object185 _this._flushing = false; // Display flushing state186 _this._keyboard = null; // Keyboard input handler object187 _this._gestures = null; // Gesture input handler object188 _this._resizeObserver = null; // Resize observer object189190 // Timers191 _this._disconnTimer = null; // disconnection timer192 _this._resizeTimeout = null; // resize rate limiting193 _this._mouseMoveTimer = null;194195 // Decoder states196 _this._decoders = {};197 _this._FBU = {198 rects: 0,199 x: 0,200 y: 0,201 width: 0,202 height: 0,203 encoding: null204 };205206 // Mouse state207 _this._mousePos = {};208 _this._mouseButtonMask = 0;209 _this._mouseLastMoveTime = 0;210 _this._viewportDragging = false;211 _this._viewportDragPos = {};212 _this._viewportHasMoved = false;213 _this._accumulatedWheelDeltaX = 0;214 _this._accumulatedWheelDeltaY = 0;215216 // Gesture state217 _this._gestureLastTapTime = null;218 _this._gestureFirstDoubleTapEv = null;219 _this._gestureLastMagnitudeX = 0;220 _this._gestureLastMagnitudeY = 0;221222 // Bound event handlers223 _this._eventHandlers = {224 focusCanvas: _this._focusCanvas.bind(_this),225 handleResize: _this._handleResize.bind(_this),226 handleMouse: _this._handleMouse.bind(_this),227 handleWheel: _this._handleWheel.bind(_this),228 handleGesture: _this._handleGesture.bind(_this),229 handleRSAAESCredentialsRequired: _this._handleRSAAESCredentialsRequired.bind(_this),230 handleRSAAESServerVerification: _this._handleRSAAESServerVerification.bind(_this)231 };232233 // main setup234 Log.Debug(">> RFB.constructor");235236 // Create DOM elements237 _this._screen = document.createElement('div');238 _this._screen.style.display = 'flex';239 _this._screen.style.width = '100%';240 _this._screen.style.height = '100%';241 _this._screen.style.overflow = 'auto';242 _this._screen.style.background = DEFAULT_BACKGROUND;243 _this._canvas = document.createElement('canvas');244 _this._canvas.style.margin = 'auto';245 // Some browsers add an outline on focus246 _this._canvas.style.outline = 'none';247 _this._canvas.width = 0;248 _this._canvas.height = 0;249 _this._canvas.tabIndex = -1;250 _this._screen.appendChild(_this._canvas);251252 // Cursor253 _this._cursor = new _cursor["default"]();254255 // XXX: TightVNC 2.8.11 sends no cursor at all until Windows changes256 // it. Result: no cursor at all until a window border or an edit field257 // is hit blindly. But there are also VNC servers that draw the cursor258 // in the framebuffer and don't send the empty local cursor. There is259 // no way to satisfy both sides.260 //261 // The spec is unclear on this "initial cursor" issue. Many other262 // viewers (TigerVNC, RealVNC, Remmina) display an arrow as the263 // initial cursor instead.264 _this._cursorImage = RFB.cursors.none;265266 // populate decoder array with objects267 _this._decoders[_encodings.encodings.encodingRaw] = new _raw["default"]();268 _this._decoders[_encodings.encodings.encodingCopyRect] = new _copyrect["default"]();269 _this._decoders[_encodings.encodings.encodingRRE] = new _rre["default"]();270 _this._decoders[_encodings.encodings.encodingHextile] = new _hextile["default"]();271 _this._decoders[_encodings.encodings.encodingZlib] = new _zlib["default"]();272 _this._decoders[_encodings.encodings.encodingTight] = new _tight["default"]();273 _this._decoders[_encodings.encodings.encodingTightPNG] = new _tightpng["default"]();274 _this._decoders[_encodings.encodings.encodingZRLE] = new _zrle["default"]();275 _this._decoders[_encodings.encodings.encodingJPEG] = new _jpeg["default"]();276 _this._decoders[_encodings.encodings.encodingH264] = new _h["default"]();277278 // NB: nothing that needs explicit teardown should be done279 // before this point, since this can throw an exception280 try {281 _this._display = new _display["default"](_this._canvas);282 } catch (exc) {283 Log.Error("Display exception: " + exc);284 throw exc;285 }286 _this._keyboard = new _keyboard["default"](_this._canvas);287 _this._keyboard.onkeyevent = _this._handleKeyEvent.bind(_this);288 _this._remoteCapsLock = null; // Null indicates unknown or irrelevant289 _this._remoteNumLock = null;290 _this._gestures = new _gesturehandler["default"]();291 _this._sock = new _websock["default"]();292 _this._sock.on('open', _this._socketOpen.bind(_this));293 _this._sock.on('close', _this._socketClose.bind(_this));294 _this._sock.on('message', _this._handleMessage.bind(_this));295 _this._sock.on('error', _this._socketError.bind(_this));296 _this._expectedClientWidth = null;297 _this._expectedClientHeight = null;298 _this._resizeObserver = new ResizeObserver(_this._eventHandlers.handleResize);299300 // All prepared, kick off the connection301 _this._updateConnectionState('connecting');302 Log.Debug("<< RFB.constructor");303304 // ===== PROPERTIES =====305306 _this.dragViewport = false;307 _this.focusOnClick = true;308 _this._viewOnly = false;309 _this._clipViewport = false;310 _this._clippingViewport = false;311 _this._scaleViewport = false;312 _this._resizeSession = false;313 _this._showDotCursor = false;314 if (options.showDotCursor !== undefined) {315 Log.Warn("Specifying showDotCursor as a RFB constructor argument is deprecated");316 _this._showDotCursor = options.showDotCursor;317 }318 _this._qualityLevel = 6;319 _this._compressionLevel = 2;320 return _this;321 }322323 // ===== PROPERTIES =====324 _inherits(RFB, _EventTargetMixin);325 return _createClass(RFB, [{326 key: "viewOnly",327 get: function get() {328 return this._viewOnly;329 },330 set: function set(viewOnly) {331 this._viewOnly = viewOnly;332 if (this._rfbConnectionState === "connecting" || this._rfbConnectionState === "connected") {333 if (viewOnly) {334 this._keyboard.ungrab();335 } else {336 this._keyboard.grab();337 }338 }339 }340 }, {341 key: "capabilities",342 get: function get() {343 return this._capabilities;344 }345 }, {346 key: "clippingViewport",347 get: function get() {348 return this._clippingViewport;349 }350 }, {351 key: "_setClippingViewport",352 value: function _setClippingViewport(on) {353 if (on === this._clippingViewport) {354 return;355 }356 this._clippingViewport = on;357 this.dispatchEvent(new CustomEvent("clippingviewport", {358 detail: this._clippingViewport359 }));360 }361 }, {362 key: "touchButton",363 get: function get() {364 return 0;365 },366 set: function set(button) {367 Log.Warn("Using old API!");368 }369 }, {370 key: "clipViewport",371 get: function get() {372 return this._clipViewport;373 },374 set: function set(viewport) {375 this._clipViewport = viewport;376 this._updateClip();377 }378 }, {379 key: "scaleViewport",380 get: function get() {381 return this._scaleViewport;382 },383 set: function set(scale) {384 this._scaleViewport = scale;385 // Scaling trumps clipping, so we may need to adjust386 // clipping when enabling or disabling scaling387 if (scale && this._clipViewport) {388 this._updateClip();389 }390 this._updateScale();391 if (!scale && this._clipViewport) {392 this._updateClip();393 }394 }395 }, {396 key: "resizeSession",397 get: function get() {398 return this._resizeSession;399 },400 set: function set(resize) {401 this._resizeSession = resize;402 if (resize) {403 this._requestRemoteResize();404 }405 }406 }, {407 key: "showDotCursor",408 get: function get() {409 return this._showDotCursor;410 },411 set: function set(show) {412 this._showDotCursor = show;413 this._refreshCursor();414 }415 }, {416 key: "background",417 get: function get() {418 return this._screen.style.background;419 },420 set: function set(cssValue) {421 this._screen.style.background = cssValue;422 }423 }, {424 key: "qualityLevel",425 get: function get() {426 return this._qualityLevel;427 },428 set: function set(qualityLevel) {429 if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) {430 Log.Error("qualityLevel must be an integer between 0 and 9");431 return;432 }433 if (this._qualityLevel === qualityLevel) {434 return;435 }436 this._qualityLevel = qualityLevel;437 if (this._rfbConnectionState === 'connected') {438 this._sendEncodings();439 }440 }441 }, {442 key: "compressionLevel",443 get: function get() {444 return this._compressionLevel;445 },446 set: function set(compressionLevel) {447 if (!Number.isInteger(compressionLevel) || compressionLevel < 0 || compressionLevel > 9) {448 Log.Error("compressionLevel must be an integer between 0 and 9");449 return;450 }451 if (this._compressionLevel === compressionLevel) {452 return;453 }454 this._compressionLevel = compressionLevel;455 if (this._rfbConnectionState === 'connected') {456 this._sendEncodings();457 }458 }459460 // ===== PUBLIC METHODS =====461 }, {462 key: "disconnect",463 value: function disconnect() {464 this._updateConnectionState('disconnecting');465 this._sock.off('error');466 this._sock.off('message');467 this._sock.off('open');468 if (this._rfbRSAAESAuthenticationState !== null) {469 this._rfbRSAAESAuthenticationState.disconnect();470 }471 }472 }, {473 key: "approveServer",474 value: function approveServer() {475 if (this._rfbRSAAESAuthenticationState !== null) {476 this._rfbRSAAESAuthenticationState.approveServer();477 }478 }479 }, {480 key: "sendCredentials",481 value: function sendCredentials(creds) {482 this._rfbCredentials = creds;483 this._resumeAuthentication();484 }485 }, {486 key: "sendCtrlAltDel",487 value: function sendCtrlAltDel() {488 if (this._rfbConnectionState !== 'connected' || this._viewOnly) {489 return;490 }491 Log.Info("Sending Ctrl-Alt-Del");492 this.sendKey(_keysym["default"].XK_Control_L, "ControlLeft", true);493 this.sendKey(_keysym["default"].XK_Alt_L, "AltLeft", true);494 this.sendKey(_keysym["default"].XK_Delete, "Delete", true);495 this.sendKey(_keysym["default"].XK_Delete, "Delete", false);496 this.sendKey(_keysym["default"].XK_Alt_L, "AltLeft", false);497 this.sendKey(_keysym["default"].XK_Control_L, "ControlLeft", false);498 }499 }, {500 key: "machineShutdown",501 value: function machineShutdown() {502 this._xvpOp(1, 2);503 }504 }, {505 key: "machineReboot",506 value: function machineReboot() {507 this._xvpOp(1, 3);508 }509 }, {510 key: "machineReset",511 value: function machineReset() {512 this._xvpOp(1, 4);513 }514515 // Send a key press. If 'down' is not specified then send a down key516 // followed by an up key.517 }, {518 key: "sendKey",519 value: function sendKey(keysym, code, down) {520 if (this._rfbConnectionState !== 'connected' || this._viewOnly) {521 return;522 }523 if (down === undefined) {524 this.sendKey(keysym, code, true);525 this.sendKey(keysym, code, false);526 return;527 }528 var scancode = _xtscancodes["default"][code];529 if (this._qemuExtKeyEventSupported && scancode) {530 // 0 is NoSymbol531 keysym = keysym || 0;532 Log.Info("Sending key (" + (down ? "down" : "up") + "): keysym " + keysym + ", scancode " + scancode);533 RFB.messages.QEMUExtendedKeyEvent(this._sock, keysym, down, scancode);534 } else {535 if (!keysym) {536 return;537 }538 Log.Info("Sending keysym (" + (down ? "down" : "up") + "): " + keysym);539 RFB.messages.keyEvent(this._sock, keysym, down ? 1 : 0);540 }541 }542 }, {543 key: "focus",544 value: function focus(options) {545 this._canvas.focus(options);546 }547 }, {548 key: "blur",549 value: function blur() {550 this._canvas.blur();551 }552 }, {553 key: "clipboardPasteFrom",554 value: function clipboardPasteFrom(text) {555 if (this._rfbConnectionState !== 'connected' || this._viewOnly) {556 return;557 }558 if (this._clipboardServerCapabilitiesFormats[extendedClipboardFormatText] && this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) {559 this._clipboardText = text;560 RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);561 } else {562 var length, i;563 var data;564 length = 0;565 // eslint-disable-next-line no-unused-vars566 var _iterator = _createForOfIteratorHelper(text),567 _step;568 try {569 for (_iterator.s(); !(_step = _iterator.n()).done;) {570 var codePoint = _step.value;571 length++;572 }573 } catch (err) {574 _iterator.e(err);575 } finally {576 _iterator.f();577 }578 data = new Uint8Array(length);579 i = 0;580 var _iterator2 = _createForOfIteratorHelper(text),581 _step2;582 try {583 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {584 var _codePoint = _step2.value;585 var code = _codePoint.codePointAt(0);586587 /* Only ISO 8859-1 is supported */588 if (code > 0xff) {589 code = 0x3f; // '?'590 }591 data[i++] = code;592 }593 } catch (err) {594 _iterator2.e(err);595 } finally {596 _iterator2.f();597 }598 RFB.messages.clientCutText(this._sock, data);599 }600 }601 }, {602 key: "getImageData",603 value: function getImageData() {604 return this._display.getImageData();605 }606 }, {607 key: "toDataURL",608 value: function toDataURL(type, encoderOptions) {609 return this._display.toDataURL(type, encoderOptions);610 }611 }, {612 key: "toBlob",613 value: function toBlob(callback, type, quality) {614 return this._display.toBlob(callback, type, quality);615 }616617 // ===== PRIVATE METHODS =====618 }, {619 key: "_connect",620 value: function _connect() {621 Log.Debug(">> RFB.connect");622 if (this._url) {623 Log.Info("connecting to ".concat(this._url));624 this._sock.open(this._url, this._wsProtocols);625 } else {626 Log.Info("attaching ".concat(this._rawChannel, " to Websock"));627 this._sock.attach(this._rawChannel);628 if (this._sock.readyState === 'closed') {629 throw Error("Cannot use already closed WebSocket/RTCDataChannel");630 }631 if (this._sock.readyState === 'open') {632 // FIXME: _socketOpen() can in theory call _fail(), which633 // isn't allowed this early, but I'm not sure that can634 // happen without a bug messing up our state variables635 this._socketOpen();636 }637 }638639 // Make our elements part of the page640 this._target.appendChild(this._screen);641 this._gestures.attach(this._canvas);642 this._cursor.attach(this._canvas);643 this._refreshCursor();644645 // Monitor size changes of the screen element646 this._resizeObserver.observe(this._screen);647648 // Always grab focus on some kind of click event649 this._canvas.addEventListener("mousedown", this._eventHandlers.focusCanvas);650 this._canvas.addEventListener("touchstart", this._eventHandlers.focusCanvas);651652 // Mouse events653 this._canvas.addEventListener('mousedown', this._eventHandlers.handleMouse);654 this._canvas.addEventListener('mouseup', this._eventHandlers.handleMouse);655 this._canvas.addEventListener('mousemove', this._eventHandlers.handleMouse);656 // Prevent middle-click pasting (see handler for why we bind to document)657 this._canvas.addEventListener('click', this._eventHandlers.handleMouse);658 // preventDefault() on mousedown doesn't stop this event for some659 // reason so we have to explicitly block it660 this._canvas.addEventListener('contextmenu', this._eventHandlers.handleMouse);661662 // Wheel events663 this._canvas.addEventListener("wheel", this._eventHandlers.handleWheel);664665 // Gesture events666 this._canvas.addEventListener("gesturestart", this._eventHandlers.handleGesture);667 this._canvas.addEventListener("gesturemove", this._eventHandlers.handleGesture);668 this._canvas.addEventListener("gestureend", this._eventHandlers.handleGesture);669 Log.Debug("<< RFB.connect");670 }671 }, {672 key: "_disconnect",673 value: function _disconnect() {674 Log.Debug(">> RFB.disconnect");675 this._cursor.detach();676 this._canvas.removeEventListener("gesturestart", this._eventHandlers.handleGesture);677 this._canvas.removeEventListener("gesturemove", this._eventHandlers.handleGesture);678 this._canvas.removeEventListener("gestureend", this._eventHandlers.handleGesture);679 this._canvas.removeEventListener("wheel", this._eventHandlers.handleWheel);680 this._canvas.removeEventListener('mousedown', this._eventHandlers.handleMouse);681 this._canvas.removeEventListener('mouseup', this._eventHandlers.handleMouse);682 this._canvas.removeEventListener('mousemove', this._eventHandlers.handleMouse);683 this._canvas.removeEventListener('click', this._eventHandlers.handleMouse);684 this._canvas.removeEventListener('contextmenu', this._eventHandlers.handleMouse);685 this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);686 this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);687 this._resizeObserver.disconnect();688 this._keyboard.ungrab();689 this._gestures.detach();690 this._sock.close();691 try {692 this._target.removeChild(this._screen);693 } catch (e) {694 if (e.name === 'NotFoundError') {695 // Some cases where the initial connection fails696 // can disconnect before the _screen is created697 } else {698 throw e;699 }700 }701 clearTimeout(this._resizeTimeout);702 clearTimeout(this._mouseMoveTimer);703 Log.Debug("<< RFB.disconnect");704 }705 }, {706 key: "_socketOpen",707 value: function _socketOpen() {708 if (this._rfbConnectionState === 'connecting' && this._rfbInitState === '') {709 this._rfbInitState = 'ProtocolVersion';710 Log.Debug("Starting VNC handshake");711 } else {712 this._fail("Unexpected server connection while " + this._rfbConnectionState);713 }714 }715 }, {716 key: "_socketClose",717 value: function _socketClose(e) {718 Log.Debug("WebSocket on-close event");719 var msg = "";720 if (e.code) {721 msg = "(code: " + e.code;722 if (e.reason) {723 msg += ", reason: " + e.reason;724 }725 msg += ")";726 }727 switch (this._rfbConnectionState) {728 case 'connecting':729 this._fail("Connection closed " + msg);730 break;731 case 'connected':732 // Handle disconnects that were initiated server-side733 this._updateConnectionState('disconnecting');734 this._updateConnectionState('disconnected');735 break;736 case 'disconnecting':737 // Normal disconnection path738 this._updateConnectionState('disconnected');739 break;740 case 'disconnected':741 this._fail("Unexpected server disconnect " + "when already disconnected " + msg);742 break;743 default:744 this._fail("Unexpected server disconnect before connecting " + msg);745 break;746 }747 this._sock.off('close');748 // Delete reference to raw channel to allow cleanup.749 this._rawChannel = null;750 }751 }, {752 key: "_socketError",753 value: function _socketError(e) {754 Log.Warn("WebSocket on-error event");755 }756 }, {757 key: "_focusCanvas",758 value: function _focusCanvas(event) {759 if (!this.focusOnClick) {760 return;761 }762 this.focus({763 preventScroll: true764 });765 }766 }, {767 key: "_setDesktopName",768 value: function _setDesktopName(name) {769 this._fbName = name;770 this.dispatchEvent(new CustomEvent("desktopname", {771 detail: {772 name: this._fbName773 }774 }));775 }776 }, {777 key: "_saveExpectedClientSize",778 value: function _saveExpectedClientSize() {779 this._expectedClientWidth = this._screen.clientWidth;780 this._expectedClientHeight = this._screen.clientHeight;781 }782 }, {783 key: "_currentClientSize",784 value: function _currentClientSize() {785 return [this._screen.clientWidth, this._screen.clientHeight];786 }787 }, {788 key: "_clientHasExpectedSize",789 value: function _clientHasExpectedSize() {790 var _this$_currentClientS = this._currentClientSize(),791 _this$_currentClientS2 = _slicedToArray(_this$_currentClientS, 2),792 currentWidth = _this$_currentClientS2[0],793 currentHeight = _this$_currentClientS2[1];794 return currentWidth == this._expectedClientWidth && currentHeight == this._expectedClientHeight;795 }796797 // Handle browser window resizes798 }, {799 key: "_handleResize",800 value: function _handleResize() {801 var _this2 = this;802 // Don't change anything if the client size is already as expected803 if (this._clientHasExpectedSize()) {804 return;805 }806 // If the window resized then our screen element might have807 // as well. Update the viewport dimensions.808 window.requestAnimationFrame(function () {809 _this2._updateClip();810 _this2._updateScale();811 _this2._saveExpectedClientSize();812 });813814 // Request changing the resolution of the remote display to815 // the size of the local browser viewport.816 this._requestRemoteResize();817 }818819 // Update state of clipping in Display object, and make sure the820 // configured viewport matches the current screen size821 }, {822 key: "_updateClip",823 value: function _updateClip() {824 var curClip = this._display.clipViewport;825 var newClip = this._clipViewport;826 if (this._scaleViewport) {827 // Disable viewport clipping if we are scaling828 newClip = false;829 }830 if (curClip !== newClip) {831 this._display.clipViewport = newClip;832 }833 if (newClip) {834 // When clipping is enabled, the screen is limited to835 // the size of the container.836 var size = this._screenSize();837 this._display.viewportChangeSize(size.w, size.h);838 this._fixScrollbars();839 this._setClippingViewport(size.w < this._display.width || size.h < this._display.height);840 } else {841 this._setClippingViewport(false);842 }843844 // When changing clipping we might show or hide scrollbars.845 // This causes the expected client dimensions to change.846 if (curClip !== newClip) {847 this._saveExpectedClientSize();848 }849 }850 }, {851 key: "_updateScale",852 value: function _updateScale() {853 if (!this._scaleViewport) {854 this._display.scale = 1.0;855 } else {856 var size = this._screenSize();857 this._display.autoscale(size.w, size.h);858 }859 this._fixScrollbars();860 }861862 // Requests a change of remote desktop size. This message is an extension863 // and may only be sent if we have received an ExtendedDesktopSize message864 }, {865 key: "_requestRemoteResize",866 value: function _requestRemoteResize() {867 if (!this._resizeSession) {868 return;869 }870 if (this._viewOnly) {871 return;872 }873 if (!this._supportsSetDesktopSize) {874 return;875 }876877 // Rate limit to one pending resize at a time878 if (this._pendingRemoteResize) {879 return;880 }881882 // And no more than once every 100ms883 if (Date.now() - this._lastResize < 100) {884 clearTimeout(this._resizeTimeout);885 this._resizeTimeout = setTimeout(this._requestRemoteResize.bind(this), 100 - (Date.now() - this._lastResize));886 return;887 }888 this._resizeTimeout = null;889 var size = this._screenSize();890891 // Do we actually change anything?892 if (size.w === this._fbWidth && size.h === this._fbHeight) {893 return;894 }895 this._pendingRemoteResize = true;896 this._lastResize = Date.now();897 RFB.messages.setDesktopSize(this._sock, Math.floor(size.w), Math.floor(size.h), this._screenID, this._screenFlags);898 Log.Debug('Requested new desktop size: ' + size.w + 'x' + size.h);899 }900901 // Gets the the size of the available screen902 }, {903 key: "_screenSize",904 value: function _screenSize() {905 var r = this._screen.getBoundingClientRect();906 return {907 w: r.width,908 h: r.height909 };910 }911 }, {912 key: "_fixScrollbars",913 value: function _fixScrollbars() {914 // This is a hack because Safari on macOS screws up the calculation915 // for when scrollbars are needed. We get scrollbars when making the916 // browser smaller, despite remote resize being enabled. So to fix it917 // we temporarily toggle them off and on.918 var orig = this._screen.style.overflow;919 this._screen.style.overflow = 'hidden';920 // Force Safari to recalculate the layout by asking for921 // an element's dimensions922 this._screen.getBoundingClientRect();923 this._screen.style.overflow = orig;924 }925926 /*927 * Connection states:928 * connecting929 * connected930 * disconnecting931 * disconnected - permanent state932 */933 }, {934 key: "_updateConnectionState",935 value: function _updateConnectionState(state) {936 var _this3 = this;937 var oldstate = this._rfbConnectionState;938 if (state === oldstate) {939 Log.Debug("Already in state '" + state + "', ignoring");940 return;941 }942943 // The 'disconnected' state is permanent for each RFB object944 if (oldstate === 'disconnected') {945 Log.Error("Tried changing state of a disconnected RFB object");946 return;947 }948949 // Ensure proper transitions before doing anything950 switch (state) {951 case 'connected':952 if (oldstate !== 'connecting') {953 Log.Error("Bad transition to connected state, " + "previous connection state: " + oldstate);954 return;955 }956 break;957 case 'disconnected':958 if (oldstate !== 'disconnecting') {959 Log.Error("Bad transition to disconnected state, " + "previous connection state: " + oldstate);960 return;961 }962 break;963 case 'connecting':964 if (oldstate !== '') {965 Log.Error("Bad transition to connecting state, " + "previous connection state: " + oldstate);966 return;967 }968 break;969 case 'disconnecting':970 if (oldstate !== 'connected' && oldstate !== 'connecting') {971 Log.Error("Bad transition to disconnecting state, " + "previous connection state: " + oldstate);972 return;973 }974 break;975 default:976 Log.Error("Unknown connection state: " + state);977 return;978 }979980 // State change actions981982 this._rfbConnectionState = state;983 Log.Debug("New state '" + state + "', was '" + oldstate + "'.");984 if (this._disconnTimer && state !== 'disconnecting') {985 Log.Debug("Clearing disconnect timer");986 clearTimeout(this._disconnTimer);987 this._disconnTimer = null;988989 // make sure we don't get a double event990 this._sock.off('close');991 }992 switch (state) {993 case 'connecting':994 this._connect();995 break;996 case 'connected':997 this.dispatchEvent(new CustomEvent("connect", {998 detail: {}999 }));1000 break;1001 case 'disconnecting':1002 this._disconnect();1003 this._disconnTimer = setTimeout(function () {1004 Log.Error("Disconnection timed out.");1005 _this3._updateConnectionState('disconnected');1006 }, DISCONNECT_TIMEOUT * 1000);1007 break;1008 case 'disconnected':1009 this.dispatchEvent(new CustomEvent("disconnect", {1010 detail: {1011 clean: this._rfbCleanDisconnect1012 }1013 }));1014 break;1015 }1016 }10171018 /* Print errors and disconnect1019 *1020 * The parameter 'details' is used for information that1021 * should be logged but not sent to the user interface.1022 */1023 }, {1024 key: "_fail",1025 value: function _fail(details) {1026 switch (this._rfbConnectionState) {1027 case 'disconnecting':1028 Log.Error("Failed when disconnecting: " + details);1029 break;1030 case 'connected':1031 Log.Error("Failed while connected: " + details);1032 break;1033 case 'connecting':1034 Log.Error("Failed when connecting: " + details);1035 break;1036 default:1037 Log.Error("RFB failure: " + details);1038 break;1039 }1040 this._rfbCleanDisconnect = false; //This is sent to the UI10411042 // Transition to disconnected without waiting for socket to close1043 this._updateConnectionState('disconnecting');1044 this._updateConnectionState('disconnected');1045 return false;1046 }1047 }, {1048 key: "_setCapability",1049 value: function _setCapability(cap, val) {1050 this._capabilities[cap] = val;1051 this.dispatchEvent(new CustomEvent("capabilities", {1052 detail: {1053 capabilities: this._capabilities1054 }1055 }));1056 }1057 }, {1058 key: "_handleMessage",1059 value: function _handleMessage() {1060 if (this._sock.rQwait("message", 1)) {1061 Log.Warn("handleMessage called on an empty receive queue");1062 return;1063 }1064 switch (this._rfbConnectionState) {1065 case 'disconnected':1066 Log.Error("Got data while disconnected");1067 break;1068 case 'connected':1069 while (true) {1070 if (this._flushing) {1071 break;1072 }1073 if (!this._normalMsg()) {1074 break;1075 }1076 if (this._sock.rQwait("message", 1)) {1077 break;1078 }1079 }1080 break;1081 case 'connecting':1082 while (this._rfbConnectionState === 'connecting') {1083 if (!this._initMsg()) {1084 break;1085 }1086 }1087 break;1088 default:1089 Log.Error("Got data while in an invalid state");1090 break;1091 }1092 }1093 }, {1094 key: "_handleKeyEvent",1095 value: function _handleKeyEvent(keysym, code, down, numlock, capslock) {1096 // If remote state of capslock is known, and it doesn't match the local led state of1097 // the keyboard, we send a capslock keypress first to bring it into sync.1098 // If we just pressed CapsLock, or we toggled it remotely due to it being out of sync1099 // we clear the remote state so that we don't send duplicate or spurious fixes,1100 // since it may take some time to receive the new remote CapsLock state.1101 if (code == 'CapsLock' && down) {1102 this._remoteCapsLock = null;1103 }1104 if (this._remoteCapsLock !== null && capslock !== null && this._remoteCapsLock !== capslock && down) {1105 Log.Debug("Fixing remote caps lock");1106 this.sendKey(_keysym["default"].XK_Caps_Lock, 'CapsLock', true);1107 this.sendKey(_keysym["default"].XK_Caps_Lock, 'CapsLock', false);1108 // We clear the remote capsLock state when we do this to prevent issues with doing this twice1109 // before we receive an update of the the remote state.1110 this._remoteCapsLock = null;1111 }11121113 // Logic for numlock is exactly the same.1114 if (code == 'NumLock' && down) {1115 this._remoteNumLock = null;1116 }1117 if (this._remoteNumLock !== null && numlock !== null && this._remoteNumLock !== numlock && down) {1118 Log.Debug("Fixing remote num lock");1119 this.sendKey(_keysym["default"].XK_Num_Lock, 'NumLock', true);1120 this.sendKey(_keysym["default"].XK_Num_Lock, 'NumLock', false);1121 this._remoteNumLock = null;1122 }1123 this.sendKey(keysym, code, down);1124 }1125 }, {1126 key: "_handleMouse",1127 value: function _handleMouse(ev) {1128 /*1129 * We don't check connection status or viewOnly here as the1130 * mouse events might be used to control the viewport1131 */11321133 if (ev.type === 'click') {1134 /*1135 * Note: This is only needed for the 'click' event as it fails1136 * to fire properly for the target element so we have1137 * to listen on the document element instead.1138 */1139 if (ev.target !== this._canvas) {1140 return;1141 }1142 }11431144 // FIXME: if we're in view-only and not dragging,1145 // should we stop events?1146 ev.stopPropagation();1147 ev.preventDefault();1148 if (ev.type === 'click' || ev.type === 'contextmenu') {1149 return;1150 }1151 var pos = (0, _element.clientToElement)(ev.clientX, ev.clientY, this._canvas);1152 var bmask = RFB._convertButtonMask(ev.buttons);1153 var down = ev.type == 'mousedown';1154 switch (ev.type) {1155 case 'mousedown':1156 case 'mouseup':1157 if (this.dragViewport) {1158 if (down && !this._viewportDragging) {1159 this._viewportDragging = true;1160 this._viewportDragPos = {1161 'x': pos.x,1162 'y': pos.y1163 };1164 this._viewportHasMoved = false;1165 this._flushMouseMoveTimer(pos.x, pos.y);11661167 // Skip sending mouse events, instead save the current1168 // mouse mask so we can send it later.1169 this._mouseButtonMask = bmask;1170 break;1171 } else {1172 this._viewportDragging = false;11731174 // If we actually performed a drag then we are done1175 // here and should not send any mouse events1176 if (this._viewportHasMoved) {1177 this._mouseButtonMask = bmask;1178 break;1179 }1180 // Otherwise we treat this as a mouse click event.1181 // Send the previously saved button mask, followed1182 // by the current button mask at the end of this1183 // function.1184 this._sendMouse(pos.x, pos.y, this._mouseButtonMask);1185 }1186 }1187 if (down) {1188 (0, _events.setCapture)(this._canvas);1189 }1190 this._handleMouseButton(pos.x, pos.y, bmask);1191 break;1192 case 'mousemove':1193 if (this._viewportDragging) {1194 var deltaX = this._viewportDragPos.x - pos.x;1195 var deltaY = this._viewportDragPos.y - pos.y;1196 if (this._viewportHasMoved || Math.abs(deltaX) > _browser.dragThreshold || Math.abs(deltaY) > _browser.dragThreshold) {1197 this._viewportHasMoved = true;1198 this._viewportDragPos = {1199 'x': pos.x,1200 'y': pos.y1201 };1202 this._display.viewportChangePos(deltaX, deltaY);1203 }12041205 // Skip sending mouse events1206 break;1207 }1208 this._handleMouseMove(pos.x, pos.y);1209 break;1210 }1211 }1212 }, {1213 key: "_handleMouseButton",1214 value: function _handleMouseButton(x, y, bmask) {1215 // Flush waiting move event first1216 this._flushMouseMoveTimer(x, y);1217 this._mouseButtonMask = bmask;1218 this._sendMouse(x, y, this._mouseButtonMask);1219 }1220 }, {1221 key: "_handleMouseMove",1222 value: function _handleMouseMove(x, y) {1223 var _this4 = this;1224 this._mousePos = {1225 'x': x,1226 'y': y1227 };12281229 // Limit many mouse move events to one every MOUSE_MOVE_DELAY ms1230 if (this._mouseMoveTimer == null) {1231 var timeSinceLastMove = Date.now() - this._mouseLastMoveTime;1232 if (timeSinceLastMove > MOUSE_MOVE_DELAY) {1233 this._sendMouse(x, y, this._mouseButtonMask);1234 this._mouseLastMoveTime = Date.now();1235 } else {1236 // Too soon since the latest move, wait the remaining time1237 this._mouseMoveTimer = setTimeout(function () {1238 _this4._handleDelayedMouseMove();1239 }, MOUSE_MOVE_DELAY - timeSinceLastMove);1240 }1241 }1242 }1243 }, {1244 key: "_handleDelayedMouseMove",1245 value: function _handleDelayedMouseMove() {1246 this._mouseMoveTimer = null;1247 this._sendMouse(this._mousePos.x, this._mousePos.y, this._mouseButtonMask);1248 this._mouseLastMoveTime = Date.now();1249 }1250 }, {1251 key: "_sendMouse",1252 value: function _sendMouse(x, y, mask) {1253 if (this._rfbConnectionState !== 'connected') {1254 return;1255 }1256 if (this._viewOnly) {1257 return;1258 } // View only, skip mouse events12591260 // Highest bit in mask is never sent to the server1261 if (mask & 0x8000) {1262 throw new Error("Illegal mouse button mask (mask: " + mask + ")");1263 }1264 var extendedMouseButtons = mask & 0x7f80;1265 if (this._extendedPointerEventSupported && extendedMouseButtons) {1266 RFB.messages.extendedPointerEvent(this._sock, this._display.absX(x), this._display.absY(y), mask);1267 } else {1268 RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), mask);1269 }1270 }1271 }, {1272 key: "_handleWheel",1273 value: function _handleWheel(ev) {1274 if (this._rfbConnectionState !== 'connected') {1275 return;1276 }1277 if (this._viewOnly) {1278 return;1279 } // View only, skip mouse events12801281 ev.stopPropagation();1282 ev.preventDefault();1283 var pos = (0, _element.clientToElement)(ev.clientX, ev.clientY, this._canvas);1284 var bmask = RFB._convertButtonMask(ev.buttons);1285 var dX = ev.deltaX;1286 var dY = ev.deltaY;12871288 // Pixel units unless it's non-zero.1289 // Note that if deltamode is line or page won't matter since we aren't1290 // sending the mouse wheel delta to the server anyway.1291 // The difference between pixel and line can be important however since1292 // we have a threshold that can be smaller than the line height.1293 if (ev.deltaMode !== 0) {1294 dX *= WHEEL_LINE_HEIGHT;1295 dY *= WHEEL_LINE_HEIGHT;1296 }12971298 // Mouse wheel events are sent in steps over VNC. This means that the VNC1299 // protocol can't handle a wheel event with specific distance or speed.1300 // Therefor, if we get a lot of small mouse wheel events we combine them.1301 this._accumulatedWheelDeltaX += dX;1302 this._accumulatedWheelDeltaY += dY;13031304 // Generate a mouse wheel step event when the accumulated delta1305 // for one of the axes is large enough.1306 if (Math.abs(this._accumulatedWheelDeltaX) >= WHEEL_STEP) {1307 if (this._accumulatedWheelDeltaX < 0) {1308 this._handleMouseButton(pos.x, pos.y, bmask | 1 << 5);1309 this._handleMouseButton(pos.x, pos.y, bmask);1310 } else if (this._accumulatedWheelDeltaX > 0) {1311 this._handleMouseButton(pos.x, pos.y, bmask | 1 << 6);1312 this._handleMouseButton(pos.x, pos.y, bmask);1313 }1314 this._accumulatedWheelDeltaX = 0;1315 }1316 if (Math.abs(this._accumulatedWheelDeltaY) >= WHEEL_STEP) {1317 if (this._accumulatedWheelDeltaY < 0) {1318 this._handleMouseButton(pos.x, pos.y, bmask | 1 << 3);1319 this._handleMouseButton(pos.x, pos.y, bmask);1320 } else if (this._accumulatedWheelDeltaY > 0) {1321 this._handleMouseButton(pos.x, pos.y, bmask | 1 << 4);1322 this._handleMouseButton(pos.x, pos.y, bmask);1323 }1324 this._accumulatedWheelDeltaY = 0;1325 }1326 }1327 }, {1328 key: "_fakeMouseMove",1329 value: function _fakeMouseMove(ev, elementX, elementY) {1330 this._handleMouseMove(elementX, elementY);1331 this._cursor.move(ev.detail.clientX, ev.detail.clientY);1332 }1333 }, {1334 key: "_handleTapEvent",1335 value: function _handleTapEvent(ev, bmask) {1336 var pos = (0, _element.clientToElement)(ev.detail.clientX, ev.detail.clientY, this._canvas);13371338 // If the user quickly taps multiple times we assume they meant to1339 // hit the same spot, so slightly adjust coordinates13401341 if (this._gestureLastTapTime !== null && Date.now() - this._gestureLastTapTime < DOUBLE_TAP_TIMEOUT && this._gestureFirstDoubleTapEv.detail.type === ev.detail.type) {1342 var dx = this._gestureFirstDoubleTapEv.detail.clientX - ev.detail.clientX;1343 var dy = this._gestureFirstDoubleTapEv.detail.clientY - ev.detail.clientY;1344 var distance = Math.hypot(dx, dy);1345 if (distance < DOUBLE_TAP_THRESHOLD) {1346 pos = (0, _element.clientToElement)(this._gestureFirstDoubleTapEv.detail.clientX, this._gestureFirstDoubleTapEv.detail.clientY, this._canvas);1347 } else {1348 this._gestureFirstDoubleTapEv = ev;1349 }1350 } else {1351 this._gestureFirstDoubleTapEv = ev;1352 }1353 this._gestureLastTapTime = Date.now();1354 this._fakeMouseMove(this._gestureFirstDoubleTapEv, pos.x, pos.y);1355 this._handleMouseButton(pos.x, pos.y, bmask);1356 this._handleMouseButton(pos.x, pos.y, 0x0);1357 }1358 }, {1359 key: "_handleGesture",1360 value: function _handleGesture(ev) {1361 var magnitude;1362 var pos = (0, _element.clientToElement)(ev.detail.clientX, ev.detail.clientY, this._canvas);1363 switch (ev.type) {1364 case 'gesturestart':1365 switch (ev.detail.type) {1366 case 'onetap':1367 this._handleTapEvent(ev, 0x1);1368 break;1369 case 'twotap':1370 this._handleTapEvent(ev, 0x4);1371 break;1372 case 'threetap':1373 this._handleTapEvent(ev, 0x2);1374 break;1375 case 'drag':1376 if (this.dragViewport) {1377 this._viewportHasMoved = false;1378 this._viewportDragging = true;1379 this._viewportDragPos = {1380 'x': pos.x,1381 'y': pos.y1382 };1383 } else {1384 this._fakeMouseMove(ev, pos.x, pos.y);1385 this._handleMouseButton(pos.x, pos.y, 0x1);1386 }1387 break;1388 case 'longpress':1389 if (this.dragViewport) {1390 // If dragViewport is true, we need to wait to see1391 // if we have dragged outside the threshold before1392 // sending any events to the server.1393 this._viewportHasMoved = false;1394 this._viewportDragPos = {1395 'x': pos.x,1396 'y': pos.y1397 };1398 } else {1399 this._fakeMouseMove(ev, pos.x, pos.y);1400 this._handleMouseButton(pos.x, pos.y, 0x4);1401 }1402 break;1403 case 'twodrag':1404 this._gestureLastMagnitudeX = ev.detail.magnitudeX;1405 this._gestureLastMagnitudeY = ev.detail.magnitudeY;1406 this._fakeMouseMove(ev, pos.x, pos.y);1407 break;1408 case 'pinch':1409 this._gestureLastMagnitudeX = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY);1410 this._fakeMouseMove(ev, pos.x, pos.y);1411 break;1412 }1413 break;1414 case 'gesturemove':1415 switch (ev.detail.type) {1416 case 'onetap':1417 case 'twotap':1418 case 'threetap':1419 break;1420 case 'drag':1421 case 'longpress':1422 if (this.dragViewport) {1423 this._viewportDragging = true;1424 var deltaX = this._viewportDragPos.x - pos.x;1425 var deltaY = this._viewportDragPos.y - pos.y;1426 if (this._viewportHasMoved || Math.abs(deltaX) > _browser.dragThreshold || Math.abs(deltaY) > _browser.dragThreshold) {1427 this._viewportHasMoved = true;1428 this._viewportDragPos = {1429 'x': pos.x,1430 'y': pos.y1431 };1432 this._display.viewportChangePos(deltaX, deltaY);1433 }1434 } else {1435 this._fakeMouseMove(ev, pos.x, pos.y);1436 }1437 break;1438 case 'twodrag':1439 // Always scroll in the same position.1440 // We don't know if the mouse was moved so we need to move it1441 // every update.1442 this._fakeMouseMove(ev, pos.x, pos.y);1443 while (ev.detail.magnitudeY - this._gestureLastMagnitudeY > GESTURE_SCRLSENS) {1444 this._handleMouseButton(pos.x, pos.y, 0x8);1445 this._handleMouseButton(pos.x, pos.y, 0x0);1446 this._gestureLastMagnitudeY += GESTURE_SCRLSENS;1447 }1448 while (ev.detail.magnitudeY - this._gestureLastMagnitudeY < -GESTURE_SCRLSENS) {1449 this._handleMouseButton(pos.x, pos.y, 0x10);1450 this._handleMouseButton(pos.x, pos.y, 0x0);1451 this._gestureLastMagnitudeY -= GESTURE_SCRLSENS;1452 }1453 while (ev.detail.magnitudeX - this._gestureLastMagnitudeX > GESTURE_SCRLSENS) {1454 this._handleMouseButton(pos.x, pos.y, 0x20);1455 this._handleMouseButton(pos.x, pos.y, 0x0);1456 this._gestureLastMagnitudeX += GESTURE_SCRLSENS;1457 }1458 while (ev.detail.magnitudeX - this._gestureLastMagnitudeX < -GESTURE_SCRLSENS) {1459 this._handleMouseButton(pos.x, pos.y, 0x40);1460 this._handleMouseButton(pos.x, pos.y, 0x0);1461 this._gestureLastMagnitudeX -= GESTURE_SCRLSENS;1462 }1463 break;1464 case 'pinch':1465 // Always scroll in the same position.1466 // We don't know if the mouse was moved so we need to move it1467 // every update.1468 this._fakeMouseMove(ev, pos.x, pos.y);1469 magnitude = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY);1470 if (Math.abs(magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {1471 this._handleKeyEvent(_keysym["default"].XK_Control_L, "ControlLeft", true);1472 while (magnitude - this._gestureLastMagnitudeX > GESTURE_ZOOMSENS) {1473 this._handleMouseButton(pos.x, pos.y, 0x8);1474 this._handleMouseButton(pos.x, pos.y, 0x0);1475 this._gestureLastMagnitudeX += GESTURE_ZOOMSENS;1476 }1477 while (magnitude - this._gestureLastMagnitudeX < -GESTURE_ZOOMSENS) {1478 this._handleMouseButton(pos.x, pos.y, 0x10);1479 this._handleMouseButton(pos.x, pos.y, 0x0);1480 this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS;1481 }1482 }1483 this._handleKeyEvent(_keysym["default"].XK_Control_L, "ControlLeft", false);1484 break;1485 }1486 break;1487 case 'gestureend':1488 switch (ev.detail.type) {1489 case 'onetap':1490 case 'twotap':1491 case 'threetap':1492 case 'pinch':1493 case 'twodrag':1494 break;1495 case 'drag':1496 if (this.dragViewport) {1497 this._viewportDragging = false;1498 } else {1499 this._fakeMouseMove(ev, pos.x, pos.y);1500 this._handleMouseButton(pos.x, pos.y, 0x0);1501 }1502 break;1503 case 'longpress':1504 if (this._viewportHasMoved) {1505 // We don't want to send any events if we have moved1506 // our viewport1507 break;1508 }1509 if (this.dragViewport && !this._viewportHasMoved) {1510 this._fakeMouseMove(ev, pos.x, pos.y);1511 // If dragViewport is true, we need to wait to see1512 // if we have dragged outside the threshold before1513 // sending any events to the server.1514 this._handleMouseButton(pos.x, pos.y, 0x4);1515 this._handleMouseButton(pos.x, pos.y, 0x0);1516 this._viewportDragging = false;1517 } else {1518 this._fakeMouseMove(ev, pos.x, pos.y);1519 this._handleMouseButton(pos.x, pos.y, 0x0);1520 }1521 break;1522 }1523 break;1524 }1525 }1526 }, {1527 key: "_flushMouseMoveTimer",1528 value: function _flushMouseMoveTimer(x, y) {1529 if (this._mouseMoveTimer !== null) {1530 clearTimeout(this._mouseMoveTimer);1531 this._mouseMoveTimer = null;1532 this._sendMouse(x, y, this._mouseButtonMask);1533 }1534 }15351536 // Message handlers1537 }, {1538 key: "_negotiateProtocolVersion",1539 value: function _negotiateProtocolVersion() {1540 if (this._sock.rQwait("version", 12)) {1541 return false;1542 }1543 var sversion = this._sock.rQshiftStr(12).substr(4, 7);1544 Log.Info("Server ProtocolVersion: " + sversion);1545 var isRepeater = 0;1546 switch (sversion) {1547 case "000.000":1548 // UltraVNC repeater1549 isRepeater = 1;1550 break;1551 case "003.003":1552 case "003.006":1553 // UltraVNC1554 this._rfbVersion = 3.3;1555 break;1556 case "003.007":1557 this._rfbVersion = 3.7;1558 break;1559 case "003.008":1560 case "003.889": // Apple Remote Desktop1561 case "004.000": // Intel AMT KVM1562 case "004.001": // RealVNC 4.61563 case "005.000":1564 // RealVNC 5.31565 this._rfbVersion = 3.8;1566 break;1567 default:1568 return this._fail("Invalid server version " + sversion);1569 }1570 if (isRepeater) {1571 var repeaterID = "ID:" + this._repeaterID;1572 while (repeaterID.length < 250) {1573 repeaterID += "\0";1574 }1575 this._sock.sQpushString(repeaterID);1576 this._sock.flush();1577 return true;1578 }1579 if (this._rfbVersion > this._rfbMaxVersion) {1580 this._rfbVersion = this._rfbMaxVersion;1581 }1582 var cversion = "00" + parseInt(this._rfbVersion, 10) + ".00" + this._rfbVersion * 10 % 10;1583 this._sock.sQpushString("RFB " + cversion + "\n");1584 this._sock.flush();1585 Log.Debug('Sent ProtocolVersion: ' + cversion);1586 this._rfbInitState = 'Security';1587 }1588 }, {1589 key: "_isSupportedSecurityType",1590 value: function _isSupportedSecurityType(type) {1591 var clientTypes = [securityTypeNone, securityTypeVNCAuth, securityTypeRA2ne, securityTypeTight, securityTypeVeNCrypt, securityTypeXVP, securityTypeARD, securityTypeMSLogonII, securityTypePlain];1592 return clientTypes.includes(type);1593 }1594 }, {1595 key: "_negotiateSecurity",1596 value: function _negotiateSecurity() {1597 if (this._rfbVersion >= 3.7) {1598 // Server sends supported list, client decides1599 var numTypes = this._sock.rQshift8();1600 if (this._sock.rQwait("security type", numTypes, 1)) {1601 return false;1602 }1603 if (numTypes === 0) {1604 this._rfbInitState = "SecurityReason";1605 this._securityContext = "no security types";1606 this._securityStatus = 1;1607 return true;1608 }1609 var types = this._sock.rQshiftBytes(numTypes);1610 Log.Debug("Server security types: " + types);16111612 // Look for a matching security type in the order that the1613 // server prefers1614 this._rfbAuthScheme = -1;1615 var _iterator3 = _createForOfIteratorHelper(types),1616 _step3;1617 try {1618 for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {1619 var type = _step3.value;1620 if (this._isSupportedSecurityType(type)) {1621 this._rfbAuthScheme = type;1622 break;1623 }1624 }1625 } catch (err) {1626 _iterator3.e(err);1627 } finally {1628 _iterator3.f();1629 }1630 if (this._rfbAuthScheme === -1) {1631 return this._fail("Unsupported security types (types: " + types + ")");1632 }1633 this._sock.sQpush8(this._rfbAuthScheme);1634 this._sock.flush();1635 } else {1636 // Server decides1637 if (this._sock.rQwait("security scheme", 4)) {1638 return false;1639 }1640 this._rfbAuthScheme = this._sock.rQshift32();1641 if (this._rfbAuthScheme == 0) {1642 this._rfbInitState = "SecurityReason";1643 this._securityContext = "authentication scheme";1644 this._securityStatus = 1;1645 return true;1646 }1647 }1648 this._rfbInitState = 'Authentication';1649 Log.Debug('Authenticating using scheme: ' + this._rfbAuthScheme);1650 return true;1651 }1652 }, {1653 key: "_handleSecurityReason",1654 value: function _handleSecurityReason() {1655 if (this._sock.rQwait("reason length", 4)) {1656 return false;1657 }1658 var strlen = this._sock.rQshift32();1659 var reason = "";1660 if (strlen > 0) {1661 if (this._sock.rQwait("reason", strlen, 4)) {1662 return false;1663 }1664 reason = this._sock.rQshiftStr(strlen);1665 }1666 if (reason !== "") {1667 this.dispatchEvent(new CustomEvent("securityfailure", {1668 detail: {1669 status: this._securityStatus,1670 reason: reason1671 }1672 }));1673 return this._fail("Security negotiation failed on " + this._securityContext + " (reason: " + reason + ")");1674 } else {1675 this.dispatchEvent(new CustomEvent("securityfailure", {1676 detail: {1677 status: this._securityStatus1678 }1679 }));1680 return this._fail("Security negotiation failed on " + this._securityContext);1681 }1682 }16831684 // authentication1685 }, {1686 key: "_negotiateXvpAuth",1687 value: function _negotiateXvpAuth() {1688 if (this._rfbCredentials.username === undefined || this._rfbCredentials.password === undefined || this._rfbCredentials.target === undefined) {1689 this.dispatchEvent(new CustomEvent("credentialsrequired", {1690 detail: {1691 types: ["username", "password", "target"]1692 }1693 }));1694 return false;1695 }1696 this._sock.sQpush8(this._rfbCredentials.username.length);1697 this._sock.sQpush8(this._rfbCredentials.target.length);1698 this._sock.sQpushString(this._rfbCredentials.username);1699 this._sock.sQpushString(this._rfbCredentials.target);1700 this._sock.flush();1701 this._rfbAuthScheme = securityTypeVNCAuth;1702 return this._negotiateAuthentication();1703 }17041705 // VeNCrypt authentication, currently only supports version 0.2 and only Plain subtype1706 }, {1707 key: "_negotiateVeNCryptAuth",1708 value: function _negotiateVeNCryptAuth() {1709 // waiting for VeNCrypt version1710 if (this._rfbVeNCryptState == 0) {1711 if (this._sock.rQwait("vencrypt version", 2)) {1712 return false;1713 }1714 var major = this._sock.rQshift8();1715 var minor = this._sock.rQshift8();1716 if (!(major == 0 && minor == 2)) {1717 return this._fail("Unsupported VeNCrypt version " + major + "." + minor);1718 }1719 this._sock.sQpush8(0);1720 this._sock.sQpush8(2);1721 this._sock.flush();1722 this._rfbVeNCryptState = 1;1723 }17241725 // waiting for ACK1726 if (this._rfbVeNCryptState == 1) {1727 if (this._sock.rQwait("vencrypt ack", 1)) {1728 return false;1729 }1730 var res = this._sock.rQshift8();1731 if (res != 0) {1732 return this._fail("VeNCrypt failure " + res);1733 }1734 this._rfbVeNCryptState = 2;1735 }1736 // must fall through here (i.e. no "else if"), beacause we may have already received1737 // the subtypes length and won't be called again17381739 if (this._rfbVeNCryptState == 2) {1740 // waiting for subtypes length1741 if (this._sock.rQwait("vencrypt subtypes length", 1)) {1742 return false;1743 }1744 var subtypesLength = this._sock.rQshift8();1745 if (subtypesLength < 1) {1746 return this._fail("VeNCrypt subtypes empty");1747 }1748 this._rfbVeNCryptSubtypesLength = subtypesLength;1749 this._rfbVeNCryptState = 3;1750 }17511752 // waiting for subtypes list1753 if (this._rfbVeNCryptState == 3) {1754 if (this._sock.rQwait("vencrypt subtypes", 4 * this._rfbVeNCryptSubtypesLength)) {1755 return false;1756 }1757 var subtypes = [];1758 for (var i = 0; i < this._rfbVeNCryptSubtypesLength; i++) {1759 subtypes.push(this._sock.rQshift32());1760 }17611762 // Look for a matching security type in the order that the1763 // server prefers1764 this._rfbAuthScheme = -1;1765 for (var _i = 0, _subtypes = subtypes; _i < _subtypes.length; _i++) {1766 var type = _subtypes[_i];1767 // Avoid getting in to a loop1768 if (type === securityTypeVeNCrypt) {1769 continue;1770 }1771 if (this._isSupportedSecurityType(type)) {1772 this._rfbAuthScheme = type;1773 break;1774 }1775 }1776 if (this._rfbAuthScheme === -1) {1777 return this._fail("Unsupported security types (types: " + subtypes + ")");1778 }1779 this._sock.sQpush32(this._rfbAuthScheme);1780 this._sock.flush();1781 this._rfbVeNCryptState = 4;1782 return true;1783 }1784 }1785 }, {1786 key: "_negotiatePlainAuth",1787 value: function _negotiatePlainAuth() {1788 if (this._rfbCredentials.username === undefined || this._rfbCredentials.password === undefined) {1789 this.dispatchEvent(new CustomEvent("credentialsrequired", {1790 detail: {1791 types: ["username", "password"]1792 }1793 }));1794 return false;1795 }1796 var user = (0, _strings.encodeUTF8)(this._rfbCredentials.username);1797 var pass = (0, _strings.encodeUTF8)(this._rfbCredentials.password);1798 this._sock.sQpush32(user.length);1799 this._sock.sQpush32(pass.length);1800 this._sock.sQpushString(user);1801 this._sock.sQpushString(pass);1802 this._sock.flush();1803 this._rfbInitState = "SecurityResult";1804 return true;1805 }1806 }, {1807 key: "_negotiateStdVNCAuth",1808 value: function _negotiateStdVNCAuth() {1809 if (this._sock.rQwait("auth challenge", 16)) {1810 return false;1811 }1812 if (this._rfbCredentials.password === undefined) {1813 this.dispatchEvent(new CustomEvent("credentialsrequired", {1814 detail: {1815 types: ["password"]1816 }1817 }));1818 return false;1819 }18201821 // TODO(directxman12): make genDES not require an Array1822 var challenge = Array.prototype.slice.call(this._sock.rQshiftBytes(16));1823 var response = RFB.genDES(this._rfbCredentials.password, challenge);1824 this._sock.sQpushBytes(response);1825 this._sock.flush();1826 this._rfbInitState = "SecurityResult";1827 return true;1828 }1829 }, {1830 key: "_negotiateARDAuth",1831 value: function _negotiateARDAuth() {1832 if (this._rfbCredentials.username === undefined || this._rfbCredentials.password === undefined) {1833 this.dispatchEvent(new CustomEvent("credentialsrequired", {1834 detail: {1835 types: ["username", "password"]1836 }1837 }));1838 return false;1839 }1840 if (this._rfbCredentials.ardPublicKey != undefined && this._rfbCredentials.ardCredentials != undefined) {1841 // if the async web crypto is done return the results1842 this._sock.sQpushBytes(this._rfbCredentials.ardCredentials);1843 this._sock.sQpushBytes(this._rfbCredentials.ardPublicKey);1844 this._sock.flush();1845 this._rfbCredentials.ardCredentials = null;1846 this._rfbCredentials.ardPublicKey = null;1847 this._rfbInitState = "SecurityResult";1848 return true;1849 }1850 if (this._sock.rQwait("read ard", 4)) {1851 return false;1852 }1853 var generator = this._sock.rQshiftBytes(2); // DH base generator value18541855 var keyLength = this._sock.rQshift16();1856 if (this._sock.rQwait("read ard keylength", keyLength * 2, 4)) {1857 return false;1858 }18591860 // read the server values1861 var prime = this._sock.rQshiftBytes(keyLength); // predetermined prime modulus1862 var serverPublicKey = this._sock.rQshiftBytes(keyLength); // other party's public key18631864 var clientKey = _crypto["default"].generateKey({1865 name: "DH",1866 g: generator,1867 p: prime1868 }, false, ["deriveBits"]);1869 this._negotiateARDAuthAsync(keyLength, serverPublicKey, clientKey);1870 return false;1871 }1872 }, {1873 key: "_negotiateARDAuthAsync",1874 value: function () {1875 var _negotiateARDAuthAsync2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(keyLength, serverPublicKey, clientKey) {1876 var clientPublicKey, sharedKey, username, password, credentials, i, _i2, key, cipher, encrypted;1877 return _regeneratorRuntime().wrap(function _callee$(_context) {1878 while (1) switch (_context.prev = _context.next) {1879 case 0:1880 clientPublicKey = _crypto["default"].exportKey("raw", clientKey.publicKey);1881 sharedKey = _crypto["default"].deriveBits({1882 name: "DH",1883 "public": serverPublicKey1884 }, clientKey.privateKey, keyLength * 8);1885 username = (0, _strings.encodeUTF8)(this._rfbCredentials.username).substring(0, 63);1886 password = (0, _strings.encodeUTF8)(this._rfbCredentials.password).substring(0, 63);1887 credentials = window.crypto.getRandomValues(new Uint8Array(128));1888 for (i = 0; i < username.length; i++) {1889 credentials[i] = username.charCodeAt(i);1890 }1891 credentials[username.length] = 0;1892 for (_i2 = 0; _i2 < password.length; _i2++) {1893 credentials[64 + _i2] = password.charCodeAt(_i2);1894 }1895 credentials[64 + password.length] = 0;1896 _context.next = 11;1897 return _crypto["default"].digest("MD5", sharedKey);1898 case 11:1899 key = _context.sent;1900 _context.next = 14;1901 return _crypto["default"].importKey("raw", key, {1902 name: "AES-ECB"1903 }, false, ["encrypt"]);1904 case 14:1905 cipher = _context.sent;1906 _context.next = 17;1907 return _crypto["default"].encrypt({1908 name: "AES-ECB"1909 }, cipher, credentials);1910 case 17:1911 encrypted = _context.sent;1912 this._rfbCredentials.ardCredentials = encrypted;1913 this._rfbCredentials.ardPublicKey = clientPublicKey;1914 this._resumeAuthentication();1915 case 21:1916 case "end":1917 return _context.stop();1918 }1919 }, _callee, this);1920 }));1921 function _negotiateARDAuthAsync(_x, _x2, _x3) {1922 return _negotiateARDAuthAsync2.apply(this, arguments);1923 }1924 return _negotiateARDAuthAsync;1925 }()1926 }, {1927 key: "_negotiateTightUnixAuth",1928 value: function _negotiateTightUnixAuth() {1929 if (this._rfbCredentials.username === undefined || this._rfbCredentials.password === undefined) {1930 this.dispatchEvent(new CustomEvent("credentialsrequired", {1931 detail: {1932 types: ["username", "password"]1933 }1934 }));1935 return false;1936 }1937 this._sock.sQpush32(this._rfbCredentials.username.length);1938 this._sock.sQpush32(this._rfbCredentials.password.length);1939 this._sock.sQpushString(this._rfbCredentials.username);1940 this._sock.sQpushString(this._rfbCredentials.password);1941 this._sock.flush();1942 this._rfbInitState = "SecurityResult";1943 return true;1944 }1945 }, {1946 key: "_negotiateTightTunnels",1947 value: function _negotiateTightTunnels(numTunnels) {1948 var clientSupportedTunnelTypes = {1949 0: {1950 vendor: 'TGHT',1951 signature: 'NOTUNNEL'1952 }1953 };1954 var serverSupportedTunnelTypes = {};1955 // receive tunnel capabilities1956 for (var i = 0; i < numTunnels; i++) {1957 var capCode = this._sock.rQshift32();1958 var capVendor = this._sock.rQshiftStr(4);1959 var capSignature = this._sock.rQshiftStr(8);1960 serverSupportedTunnelTypes[capCode] = {1961 vendor: capVendor,1962 signature: capSignature1963 };1964 }1965 Log.Debug("Server Tight tunnel types: " + serverSupportedTunnelTypes);19661967 // Siemens touch panels have a VNC server that supports NOTUNNEL,1968 // but forgets to advertise it. Try to detect such servers by1969 // looking for their custom tunnel type.1970 if (serverSupportedTunnelTypes[1] && serverSupportedTunnelTypes[1].vendor === "SICR" && serverSupportedTunnelTypes[1].signature === "SCHANNEL") {1971 Log.Debug("Detected Siemens server. Assuming NOTUNNEL support.");1972 serverSupportedTunnelTypes[0] = {1973 vendor: 'TGHT',1974 signature: 'NOTUNNEL'1975 };1976 }19771978 // choose the notunnel type1979 if (serverSupportedTunnelTypes[0]) {1980 if (serverSupportedTunnelTypes[0].vendor != clientSupportedTunnelTypes[0].vendor || serverSupportedTunnelTypes[0].signature != clientSupportedTunnelTypes[0].signature) {1981 return this._fail("Client's tunnel type had the incorrect " + "vendor or signature");1982 }1983 Log.Debug("Selected tunnel type: " + clientSupportedTunnelTypes[0]);1984 this._sock.sQpush32(0); // use NOTUNNEL1985 this._sock.flush();1986 return false; // wait until we receive the sub auth count to continue1987 } else {1988 return this._fail("Server wanted tunnels, but doesn't support " + "the notunnel type");1989 }1990 }1991 }, {1992 key: "_negotiateTightAuth",1993 value: function _negotiateTightAuth() {1994 if (!this._rfbTightVNC) {1995 // first pass, do the tunnel negotiation1996 if (this._sock.rQwait("num tunnels", 4)) {1997 return false;1998 }1999 var numTunnels = this._sock.rQshift32();2000 if (numTunnels > 0 && this._sock.rQwait("tunnel capabilities", 16 * numTunnels, 4)) {2001 return false;2002 }2003 this._rfbTightVNC = true;2004 if (numTunnels > 0) {2005 this._negotiateTightTunnels(numTunnels);2006 return false; // wait until we receive the sub auth to continue2007 }2008 }20092010 // second pass, do the sub-auth negotiation2011 if (this._sock.rQwait("sub auth count", 4)) {2012 return false;2013 }2014 var subAuthCount = this._sock.rQshift32();2015 if (subAuthCount === 0) {2016 // empty sub-auth list received means 'no auth' subtype selected2017 this._rfbInitState = 'SecurityResult';2018 return true;2019 }2020 if (this._sock.rQwait("sub auth capabilities", 16 * subAuthCount, 4)) {2021 return false;2022 }2023 var clientSupportedTypes = {2024 'STDVNOAUTH__': 1,2025 'STDVVNCAUTH_': 2,2026 'TGHTULGNAUTH': 1292027 };2028 var serverSupportedTypes = [];2029 for (var i = 0; i < subAuthCount; i++) {2030 this._sock.rQshift32(); // capNum2031 var capabilities = this._sock.rQshiftStr(12);2032 serverSupportedTypes.push(capabilities);2033 }2034 Log.Debug("Server Tight authentication types: " + serverSupportedTypes);2035 for (var authType in clientSupportedTypes) {2036 if (serverSupportedTypes.indexOf(authType) != -1) {2037 this._sock.sQpush32(clientSupportedTypes[authType]);2038 this._sock.flush();2039 Log.Debug("Selected authentication type: " + authType);2040 switch (authType) {2041 case 'STDVNOAUTH__':2042 // no auth2043 this._rfbInitState = 'SecurityResult';2044 return true;2045 case 'STDVVNCAUTH_':2046 this._rfbAuthScheme = securityTypeVNCAuth;2047 return true;2048 case 'TGHTULGNAUTH':2049 this._rfbAuthScheme = securityTypeUnixLogon;2050 return true;2051 default:2052 return this._fail("Unsupported tiny auth scheme " + "(scheme: " + authType + ")");2053 }2054 }2055 }2056 return this._fail("No supported sub-auth types!");2057 }2058 }, {2059 key: "_handleRSAAESCredentialsRequired",2060 value: function _handleRSAAESCredentialsRequired(event) {2061 this.dispatchEvent(event);2062 }2063 }, {2064 key: "_handleRSAAESServerVerification",2065 value: function _handleRSAAESServerVerification(event) {2066 this.dispatchEvent(event);2067 }2068 }, {2069 key: "_negotiateRA2neAuth",2070 value: function _negotiateRA2neAuth() {2071 var _this5 = this;2072 if (this._rfbRSAAESAuthenticationState === null) {2073 this._rfbRSAAESAuthenticationState = new _ra["default"](this._sock, function () {2074 return _this5._rfbCredentials;2075 });2076 this._rfbRSAAESAuthenticationState.addEventListener("serververification", this._eventHandlers.handleRSAAESServerVerification);2077 this._rfbRSAAESAuthenticationState.addEventListener("credentialsrequired", this._eventHandlers.handleRSAAESCredentialsRequired);2078 }2079 this._rfbRSAAESAuthenticationState.checkInternalEvents();2080 if (!this._rfbRSAAESAuthenticationState.hasStarted) {2081 this._rfbRSAAESAuthenticationState.negotiateRA2neAuthAsync()["catch"](function (e) {2082 if (e.message !== "disconnect normally") {2083 _this5._fail(e.message);2084 }2085 }).then(function () {2086 _this5._rfbInitState = "SecurityResult";2087 return true;2088 })["finally"](function () {2089 _this5._rfbRSAAESAuthenticationState.removeEventListener("serververification", _this5._eventHandlers.handleRSAAESServerVerification);2090 _this5._rfbRSAAESAuthenticationState.removeEventListener("credentialsrequired", _this5._eventHandlers.handleRSAAESCredentialsRequired);2091 _this5._rfbRSAAESAuthenticationState = null;2092 });2093 }2094 return false;2095 }2096 }, {2097 key: "_negotiateMSLogonIIAuth",2098 value: function _negotiateMSLogonIIAuth() {2099 if (this._sock.rQwait("mslogonii dh param", 24)) {2100 return false;2101 }2102 if (this._rfbCredentials.username === undefined || this._rfbCredentials.password === undefined) {2103 this.dispatchEvent(new CustomEvent("credentialsrequired", {2104 detail: {2105 types: ["username", "password"]2106 }2107 }));2108 return false;2109 }2110 var g = this._sock.rQshiftBytes(8);2111 var p = this._sock.rQshiftBytes(8);2112 var A = this._sock.rQshiftBytes(8);2113 var dhKey = _crypto["default"].generateKey({2114 name: "DH",2115 g: g,2116 p: p2117 }, true, ["deriveBits"]);2118 var B = _crypto["default"].exportKey("raw", dhKey.publicKey);2119 var secret = _crypto["default"].deriveBits({2120 name: "DH",2121 "public": A2122 }, dhKey.privateKey, 64);2123 var key = _crypto["default"].importKey("raw", secret, {2124 name: "DES-CBC"2125 }, false, ["encrypt"]);2126 var username = (0, _strings.encodeUTF8)(this._rfbCredentials.username).substring(0, 255);2127 var password = (0, _strings.encodeUTF8)(this._rfbCredentials.password).substring(0, 63);2128 var usernameBytes = new Uint8Array(256);2129 var passwordBytes = new Uint8Array(64);2130 window.crypto.getRandomValues(usernameBytes);2131 window.crypto.getRandomValues(passwordBytes);2132 for (var i = 0; i < username.length; i++) {2133 usernameBytes[i] = username.charCodeAt(i);2134 }2135 usernameBytes[username.length] = 0;2136 for (var _i3 = 0; _i3 < password.length; _i3++) {2137 passwordBytes[_i3] = password.charCodeAt(_i3);2138 }2139 passwordBytes[password.length] = 0;2140 usernameBytes = _crypto["default"].encrypt({2141 name: "DES-CBC",2142 iv: secret2143 }, key, usernameBytes);2144 passwordBytes = _crypto["default"].encrypt({2145 name: "DES-CBC",2146 iv: secret2147 }, key, passwordBytes);2148 this._sock.sQpushBytes(B);2149 this._sock.sQpushBytes(usernameBytes);2150 this._sock.sQpushBytes(passwordBytes);2151 this._sock.flush();2152 this._rfbInitState = "SecurityResult";2153 return true;2154 }2155 }, {2156 key: "_negotiateAuthentication",2157 value: function _negotiateAuthentication() {2158 switch (this._rfbAuthScheme) {2159 case securityTypeNone:2160 if (this._rfbVersion >= 3.8) {2161 this._rfbInitState = 'SecurityResult';2162 } else {2163 this._rfbInitState = 'ClientInitialisation';2164 }2165 return true;2166 case securityTypeXVP:2167 return this._negotiateXvpAuth();2168 case securityTypeARD:2169 return this._negotiateARDAuth();2170 case securityTypeVNCAuth:2171 return this._negotiateStdVNCAuth();2172 case securityTypeTight:2173 return this._negotiateTightAuth();2174 case securityTypeVeNCrypt:2175 return this._negotiateVeNCryptAuth();2176 case securityTypePlain:2177 return this._negotiatePlainAuth();2178 case securityTypeUnixLogon:2179 return this._negotiateTightUnixAuth();2180 case securityTypeRA2ne:2181 return this._negotiateRA2neAuth();2182 case securityTypeMSLogonII:2183 return this._negotiateMSLogonIIAuth();2184 default:2185 return this._fail("Unsupported auth scheme (scheme: " + this._rfbAuthScheme + ")");2186 }2187 }2188 }, {2189 key: "_handleSecurityResult",2190 value: function _handleSecurityResult() {2191 if (this._sock.rQwait('VNC auth response ', 4)) {2192 return false;2193 }2194 var status = this._sock.rQshift32();2195 if (status === 0) {2196 // OK2197 this._rfbInitState = 'ClientInitialisation';2198 Log.Debug('Authentication OK');2199 return true;2200 } else {2201 if (this._rfbVersion >= 3.8) {2202 this._rfbInitState = "SecurityReason";2203 this._securityContext = "security result";2204 this._securityStatus = status;2205 return true;2206 } else {2207 this.dispatchEvent(new CustomEvent("securityfailure", {2208 detail: {2209 status: status2210 }2211 }));2212 return this._fail("Security handshake failed");2213 }2214 }2215 }2216 }, {2217 key: "_negotiateServerInit",2218 value: function _negotiateServerInit() {2219 if (this._sock.rQwait("server initialization", 24)) {2220 return false;2221 }22222223 /* Screen size */2224 var width = this._sock.rQshift16();2225 var height = this._sock.rQshift16();22262227 /* PIXEL_FORMAT */2228 var bpp = this._sock.rQshift8();2229 var depth = this._sock.rQshift8();2230 var bigEndian = this._sock.rQshift8();2231 var trueColor = this._sock.rQshift8();2232 var redMax = this._sock.rQshift16();2233 var greenMax = this._sock.rQshift16();2234 var blueMax = this._sock.rQshift16();2235 var redShift = this._sock.rQshift8();2236 var greenShift = this._sock.rQshift8();2237 var blueShift = this._sock.rQshift8();2238 this._sock.rQskipBytes(3); // padding22392240 // NB(directxman12): we don't want to call any callbacks or print messages until2241 // *after* we're past the point where we could backtrack22422243 /* Connection name/title */2244 var nameLength = this._sock.rQshift32();2245 if (this._sock.rQwait('server init name', nameLength, 24)) {2246 return false;2247 }2248 var name = this._sock.rQshiftStr(nameLength);2249 name = (0, _strings.decodeUTF8)(name, true);2250 if (this._rfbTightVNC) {2251 if (this._sock.rQwait('TightVNC extended server init header', 8, 24 + nameLength)) {2252 return false;2253 }2254 // In TightVNC mode, ServerInit message is extended2255 var numServerMessages = this._sock.rQshift16();2256 var numClientMessages = this._sock.rQshift16();2257 var numEncodings = this._sock.rQshift16();2258 this._sock.rQskipBytes(2); // padding22592260 var totalMessagesLength = (numServerMessages + numClientMessages + numEncodings) * 16;2261 if (this._sock.rQwait('TightVNC extended server init header', totalMessagesLength, 32 + nameLength)) {2262 return false;2263 }22642265 // we don't actually do anything with the capability information that TIGHT sends,2266 // so we just skip the all of this.22672268 // TIGHT server message capabilities2269 this._sock.rQskipBytes(16 * numServerMessages);22702271 // TIGHT client message capabilities2272 this._sock.rQskipBytes(16 * numClientMessages);22732274 // TIGHT encoding capabilities2275 this._sock.rQskipBytes(16 * numEncodings);2276 }22772278 // NB(directxman12): these are down here so that we don't run them multiple times2279 // if we backtrack2280 Log.Info("Screen: " + width + "x" + height + ", bpp: " + bpp + ", depth: " + depth + ", bigEndian: " + bigEndian + ", trueColor: " + trueColor + ", redMax: " + redMax + ", greenMax: " + greenMax + ", blueMax: " + blueMax + ", redShift: " + redShift + ", greenShift: " + greenShift + ", blueShift: " + blueShift);22812282 // we're past the point where we could backtrack, so it's safe to call this2283 this._setDesktopName(name);2284 this._resize(width, height);2285 if (!this._viewOnly) {2286 this._keyboard.grab();2287 }2288 this._fbDepth = 24;2289 if (this._fbName === "Intel(r) AMT KVM") {2290 Log.Warn("Intel AMT KVM only supports 8/16 bit depths. Using low color mode.");2291 this._fbDepth = 8;2292 }2293 RFB.messages.pixelFormat(this._sock, this._fbDepth, true);2294 this._sendEncodings();2295 RFB.messages.fbUpdateRequest(this._sock, false, 0, 0, this._fbWidth, this._fbHeight);2296 this._updateConnectionState('connected');2297 return true;2298 }2299 }, {2300 key: "_sendEncodings",2301 value: function _sendEncodings() {2302 var encs = [];23032304 // In preference order2305 encs.push(_encodings.encodings.encodingCopyRect);2306 // Only supported with full depth support2307 if (this._fbDepth == 24) {2308 if (_browser.supportsWebCodecsH264Decode) {2309 encs.push(_encodings.encodings.encodingH264);2310 }2311 encs.push(_encodings.encodings.encodingTight);2312 encs.push(_encodings.encodings.encodingTightPNG);2313 encs.push(_encodings.encodings.encodingZRLE);2314 encs.push(_encodings.encodings.encodingJPEG);2315 encs.push(_encodings.encodings.encodingHextile);2316 encs.push(_encodings.encodings.encodingRRE);2317 encs.push(_encodings.encodings.encodingZlib);2318 }2319 encs.push(_encodings.encodings.encodingRaw);23202321 // Psuedo-encoding settings2322 encs.push(_encodings.encodings.pseudoEncodingQualityLevel0 + this._qualityLevel);2323 encs.push(_encodings.encodings.pseudoEncodingCompressLevel0 + this._compressionLevel);2324 encs.push(_encodings.encodings.pseudoEncodingDesktopSize);2325 encs.push(_encodings.encodings.pseudoEncodingLastRect);2326 encs.push(_encodings.encodings.pseudoEncodingQEMUExtendedKeyEvent);2327 encs.push(_encodings.encodings.pseudoEncodingQEMULedEvent);2328 encs.push(_encodings.encodings.pseudoEncodingExtendedDesktopSize);2329 encs.push(_encodings.encodings.pseudoEncodingXvp);2330 encs.push(_encodings.encodings.pseudoEncodingFence);2331 encs.push(_encodings.encodings.pseudoEncodingContinuousUpdates);2332 encs.push(_encodings.encodings.pseudoEncodingDesktopName);2333 encs.push(_encodings.encodings.pseudoEncodingExtendedClipboard);2334 encs.push(_encodings.encodings.pseudoEncodingExtendedMouseButtons);2335 if (this._fbDepth == 24) {2336 encs.push(_encodings.encodings.pseudoEncodingVMwareCursor);2337 encs.push(_encodings.encodings.pseudoEncodingCursor);2338 }2339 RFB.messages.clientEncodings(this._sock, encs);2340 }23412342 /* RFB protocol initialization states:2343 * ProtocolVersion2344 * Security2345 * Authentication2346 * SecurityResult2347 * ClientInitialization - not triggered by server message2348 * ServerInitialization2349 */2350 }, {2351 key: "_initMsg",2352 value: function _initMsg() {2353 switch (this._rfbInitState) {2354 case 'ProtocolVersion':2355 return this._negotiateProtocolVersion();2356 case 'Security':2357 return this._negotiateSecurity();2358 case 'Authentication':2359 return this._negotiateAuthentication();2360 case 'SecurityResult':2361 return this._handleSecurityResult();2362 case 'SecurityReason':2363 return this._handleSecurityReason();2364 case 'ClientInitialisation':2365 this._sock.sQpush8(this._shared ? 1 : 0); // ClientInitialisation2366 this._sock.flush();2367 this._rfbInitState = 'ServerInitialisation';2368 return true;2369 case 'ServerInitialisation':2370 return this._negotiateServerInit();2371 default:2372 return this._fail("Unknown init state (state: " + this._rfbInitState + ")");2373 }2374 }23752376 // Resume authentication handshake after it was paused for some2377 // reason, e.g. waiting for a password from the user2378 }, {2379 key: "_resumeAuthentication",2380 value: function _resumeAuthentication() {2381 // We use setTimeout() so it's run in its own context, just like2382 // it originally did via the WebSocket's event handler2383 setTimeout(this._initMsg.bind(this), 0);2384 }2385 }, {2386 key: "_handleSetColourMapMsg",2387 value: function _handleSetColourMapMsg() {2388 Log.Debug("SetColorMapEntries");2389 return this._fail("Unexpected SetColorMapEntries message");2390 }2391 }, {2392 key: "_handleServerCutText",2393 value: function _handleServerCutText() {2394 Log.Debug("ServerCutText");2395 if (this._sock.rQwait("ServerCutText header", 7, 1)) {2396 return false;2397 }2398 this._sock.rQskipBytes(3); // Padding23992400 var length = this._sock.rQshift32();2401 length = (0, _int.toSigned32bit)(length);2402 if (this._sock.rQwait("ServerCutText content", Math.abs(length), 8)) {2403 return false;2404 }2405 if (length >= 0) {2406 //Standard msg2407 var text = this._sock.rQshiftStr(length);2408 if (this._viewOnly) {2409 return true;2410 }2411 this.dispatchEvent(new CustomEvent("clipboard", {2412 detail: {2413 text: text2414 }2415 }));2416 } else {2417 //Extended msg.2418 length = Math.abs(length);2419 var flags = this._sock.rQshift32();2420 var formats = flags & 0x0000FFFF;2421 var actions = flags & 0xFF000000;2422 var isCaps = !!(actions & extendedClipboardActionCaps);2423 if (isCaps) {2424 this._clipboardServerCapabilitiesFormats = {};2425 this._clipboardServerCapabilitiesActions = {};24262427 // Update our server capabilities for Formats2428 for (var i = 0; i <= 15; i++) {2429 var index = 1 << i;24302431 // Check if format flag is set.2432 if (formats & index) {2433 this._clipboardServerCapabilitiesFormats[index] = true;2434 // We don't send unsolicited clipboard, so we2435 // ignore the size2436 this._sock.rQshift32();2437 }2438 }24392440 // Update our server capabilities for Actions2441 for (var _i4 = 24; _i4 <= 31; _i4++) {2442 var _index = 1 << _i4;2443 this._clipboardServerCapabilitiesActions[_index] = !!(actions & _index);2444 }24452446 /* Caps handling done, send caps with the clients2447 capabilities set as a response */2448 var clientActions = [extendedClipboardActionCaps, extendedClipboardActionRequest, extendedClipboardActionPeek, extendedClipboardActionNotify, extendedClipboardActionProvide];2449 RFB.messages.extendedClipboardCaps(this._sock, clientActions, {2450 extendedClipboardFormatText: 02451 });2452 } else if (actions === extendedClipboardActionRequest) {2453 if (this._viewOnly) {2454 return true;2455 }24562457 // Check if server has told us it can handle Provide and there is clipboard data to send.2458 if (this._clipboardText != null && this._clipboardServerCapabilitiesActions[extendedClipboardActionProvide]) {2459 if (formats & extendedClipboardFormatText) {2460 RFB.messages.extendedClipboardProvide(this._sock, [extendedClipboardFormatText], [this._clipboardText]);2461 }2462 }2463 } else if (actions === extendedClipboardActionPeek) {2464 if (this._viewOnly) {2465 return true;2466 }2467 if (this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) {2468 if (this._clipboardText != null) {2469 RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);2470 } else {2471 RFB.messages.extendedClipboardNotify(this._sock, []);2472 }2473 }2474 } else if (actions === extendedClipboardActionNotify) {2475 if (this._viewOnly) {2476 return true;2477 }2478 if (this._clipboardServerCapabilitiesActions[extendedClipboardActionRequest]) {2479 if (formats & extendedClipboardFormatText) {2480 RFB.messages.extendedClipboardRequest(this._sock, [extendedClipboardFormatText]);2481 }2482 }2483 } else if (actions === extendedClipboardActionProvide) {2484 if (this._viewOnly) {2485 return true;2486 }2487 if (!(formats & extendedClipboardFormatText)) {2488 return true;2489 }2490 // Ignore what we had in our clipboard client side.2491 this._clipboardText = null;24922493 // FIXME: Should probably verify that this data was actually requested2494 var zlibStream = this._sock.rQshiftBytes(length - 4);2495 var streamInflator = new _inflator["default"]();2496 var textData = null;2497 streamInflator.setInput(zlibStream);2498 for (var _i5 = 0; _i5 <= 15; _i5++) {2499 var format = 1 << _i5;2500 if (formats & format) {2501 var size = 0x00;2502 var sizeArray = streamInflator.inflate(4);2503 size |= sizeArray[0] << 24;2504 size |= sizeArray[1] << 16;2505 size |= sizeArray[2] << 8;2506 size |= sizeArray[3];2507 var chunk = streamInflator.inflate(size);2508 if (format === extendedClipboardFormatText) {2509 textData = chunk;2510 }2511 }2512 }2513 streamInflator.setInput(null);2514 if (textData !== null) {2515 var tmpText = "";2516 for (var _i6 = 0; _i6 < textData.length; _i6++) {2517 tmpText += String.fromCharCode(textData[_i6]);2518 }2519 textData = tmpText;2520 textData = (0, _strings.decodeUTF8)(textData);2521 if (textData.length > 0 && "\0" === textData.charAt(textData.length - 1)) {2522 textData = textData.slice(0, -1);2523 }2524 textData = textData.replaceAll("\r\n", "\n");2525 this.dispatchEvent(new CustomEvent("clipboard", {2526 detail: {2527 text: textData2528 }2529 }));2530 }2531 } else {2532 return this._fail("Unexpected action in extended clipboard message: " + actions);2533 }2534 }2535 return true;2536 }2537 }, {2538 key: "_handleServerFenceMsg",2539 value: function _handleServerFenceMsg() {2540 if (this._sock.rQwait("ServerFence header", 8, 1)) {2541 return false;2542 }2543 this._sock.rQskipBytes(3); // Padding2544 var flags = this._sock.rQshift32();2545 var length = this._sock.rQshift8();2546 if (this._sock.rQwait("ServerFence payload", length, 9)) {2547 return false;2548 }2549 if (length > 64) {2550 Log.Warn("Bad payload length (" + length + ") in fence response");2551 length = 64;2552 }2553 var payload = this._sock.rQshiftStr(length);2554 this._supportsFence = true;25552556 /*2557 * Fence flags2558 *2559 * (1<<0) - BlockBefore2560 * (1<<1) - BlockAfter2561 * (1<<2) - SyncNext2562 * (1<<31) - Request2563 */25642565 if (!(flags & 1 << 31)) {2566 return this._fail("Unexpected fence response");2567 }25682569 // Filter out unsupported flags2570 // FIXME: support syncNext2571 flags &= 1 << 0 | 1 << 1;25722573 // BlockBefore and BlockAfter are automatically handled by2574 // the fact that we process each incoming message2575 // synchronuosly.2576 RFB.messages.clientFence(this._sock, flags, payload);2577 return true;2578 }2579 }, {2580 key: "_handleXvpMsg",2581 value: function _handleXvpMsg() {2582 if (this._sock.rQwait("XVP version and message", 3, 1)) {2583 return false;2584 }2585 this._sock.rQskipBytes(1); // Padding2586 var xvpVer = this._sock.rQshift8();2587 var xvpMsg = this._sock.rQshift8();2588 switch (xvpMsg) {2589 case 0:2590 // XVP_FAIL2591 Log.Error("XVP operation failed");2592 break;2593 case 1:2594 // XVP_INIT2595 this._rfbXvpVer = xvpVer;2596 Log.Info("XVP extensions enabled (version " + this._rfbXvpVer + ")");2597 this._setCapability("power", true);2598 break;2599 default:2600 this._fail("Illegal server XVP message (msg: " + xvpMsg + ")");2601 break;2602 }2603 return true;2604 }2605 }, {2606 key: "_normalMsg",2607 value: function _normalMsg() {2608 var msgType;2609 if (this._FBU.rects > 0) {2610 msgType = 0;2611 } else {2612 msgType = this._sock.rQshift8();2613 }2614 var first, ret;2615 switch (msgType) {2616 case 0:2617 // FramebufferUpdate2618 ret = this._framebufferUpdate();2619 if (ret && !this._enabledContinuousUpdates) {2620 RFB.messages.fbUpdateRequest(this._sock, true, 0, 0, this._fbWidth, this._fbHeight);2621 }2622 return ret;2623 case 1:2624 // SetColorMapEntries2625 return this._handleSetColourMapMsg();2626 case 2:2627 // Bell2628 Log.Debug("Bell");2629 this.dispatchEvent(new CustomEvent("bell", {2630 detail: {}2631 }));2632 return true;2633 case 3:2634 // ServerCutText2635 return this._handleServerCutText();2636 case 150:2637 // EndOfContinuousUpdates2638 first = !this._supportsContinuousUpdates;2639 this._supportsContinuousUpdates = true;2640 this._enabledContinuousUpdates = false;2641 if (first) {2642 this._enabledContinuousUpdates = true;2643 this._updateContinuousUpdates();2644 Log.Info("Enabling continuous updates.");2645 } else {2646 // FIXME: We need to send a framebufferupdaterequest here2647 // if we add support for turning off continuous updates2648 }2649 return true;2650 case 248:2651 // ServerFence2652 return this._handleServerFenceMsg();2653 case 250:2654 // XVP2655 return this._handleXvpMsg();2656 default:2657 this._fail("Unexpected server message (type " + msgType + ")");2658 Log.Debug("sock.rQpeekBytes(30): " + this._sock.rQpeekBytes(30));2659 return true;2660 }2661 }2662 }, {2663 key: "_framebufferUpdate",2664 value: function _framebufferUpdate() {2665 var _this6 = this;2666 if (this._FBU.rects === 0) {2667 if (this._sock.rQwait("FBU header", 3, 1)) {2668 return false;2669 }2670 this._sock.rQskipBytes(1); // Padding2671 this._FBU.rects = this._sock.rQshift16();26722673 // Make sure the previous frame is fully rendered first2674 // to avoid building up an excessive queue2675 if (this._display.pending()) {2676 this._flushing = true;2677 this._display.flush().then(function () {2678 _this6._flushing = false;2679 // Resume processing2680 if (!_this6._sock.rQwait("message", 1)) {2681 _this6._handleMessage();2682 }2683 });2684 return false;2685 }2686 }2687 while (this._FBU.rects > 0) {2688 if (this._FBU.encoding === null) {2689 if (this._sock.rQwait("rect header", 12)) {2690 return false;2691 }2692 /* New FramebufferUpdate */26932694 this._FBU.x = this._sock.rQshift16();2695 this._FBU.y = this._sock.rQshift16();2696 this._FBU.width = this._sock.rQshift16();2697 this._FBU.height = this._sock.rQshift16();2698 this._FBU.encoding = this._sock.rQshift32();2699 /* Encodings are signed */2700 this._FBU.encoding >>= 0;2701 }2702 if (!this._handleRect()) {2703 return false;2704 }2705 this._FBU.rects--;2706 this._FBU.encoding = null;2707 }2708 this._display.flip();2709 return true; // We finished this FBU2710 }2711 }, {2712 key: "_handleRect",2713 value: function _handleRect() {2714 switch (this._FBU.encoding) {2715 case _encodings.encodings.pseudoEncodingLastRect:2716 this._FBU.rects = 1; // Will be decreased when we return2717 return true;2718 case _encodings.encodings.pseudoEncodingVMwareCursor:2719 return this._handleVMwareCursor();2720 case _encodings.encodings.pseudoEncodingCursor:2721 return this._handleCursor();2722 case _encodings.encodings.pseudoEncodingQEMUExtendedKeyEvent:2723 this._qemuExtKeyEventSupported = true;2724 return true;2725 case _encodings.encodings.pseudoEncodingDesktopName:2726 return this._handleDesktopName();2727 case _encodings.encodings.pseudoEncodingDesktopSize:2728 this._resize(this._FBU.width, this._FBU.height);2729 return true;2730 case _encodings.encodings.pseudoEncodingExtendedDesktopSize:2731 return this._handleExtendedDesktopSize();2732 case _encodings.encodings.pseudoEncodingExtendedMouseButtons:2733 this._extendedPointerEventSupported = true;2734 return true;2735 case _encodings.encodings.pseudoEncodingQEMULedEvent:2736 return this._handleLedEvent();2737 default:2738 return this._handleDataRect();2739 }2740 }2741 }, {2742 key: "_handleVMwareCursor",2743 value: function _handleVMwareCursor() {2744 var hotx = this._FBU.x; // hotspot-x2745 var hoty = this._FBU.y; // hotspot-y2746 var w = this._FBU.width;2747 var h = this._FBU.height;2748 if (this._sock.rQwait("VMware cursor encoding", 1)) {2749 return false;2750 }2751 var cursorType = this._sock.rQshift8();2752 this._sock.rQshift8(); //Padding27532754 var rgba;2755 var bytesPerPixel = 4;27562757 //Classic cursor2758 if (cursorType == 0) {2759 //Used to filter away unimportant bits.2760 //OR is used for correct conversion in js.2761 var PIXEL_MASK = 0xffffff00 | 0;2762 rgba = new Array(w * h * bytesPerPixel);2763 if (this._sock.rQwait("VMware cursor classic encoding", w * h * bytesPerPixel * 2, 2)) {2764 return false;2765 }2766 var andMask = new Array(w * h);2767 for (var pixel = 0; pixel < w * h; pixel++) {2768 andMask[pixel] = this._sock.rQshift32();2769 }2770 var xorMask = new Array(w * h);2771 for (var _pixel = 0; _pixel < w * h; _pixel++) {2772 xorMask[_pixel] = this._sock.rQshift32();2773 }2774 for (var _pixel2 = 0; _pixel2 < w * h; _pixel2++) {2775 if (andMask[_pixel2] == 0) {2776 //Fully opaque pixel2777 var bgr = xorMask[_pixel2];2778 var r = bgr >> 8 & 0xff;2779 var g = bgr >> 16 & 0xff;2780 var b = bgr >> 24 & 0xff;2781 rgba[_pixel2 * bytesPerPixel] = r; //r2782 rgba[_pixel2 * bytesPerPixel + 1] = g; //g2783 rgba[_pixel2 * bytesPerPixel + 2] = b; //b2784 rgba[_pixel2 * bytesPerPixel + 3] = 0xff; //a2785 } else if ((andMask[_pixel2] & PIXEL_MASK) == PIXEL_MASK) {2786 //Only screen value matters, no mouse colouring2787 if (xorMask[_pixel2] == 0) {2788 //Transparent pixel2789 rgba[_pixel2 * bytesPerPixel] = 0x00;2790 rgba[_pixel2 * bytesPerPixel + 1] = 0x00;2791 rgba[_pixel2 * bytesPerPixel + 2] = 0x00;2792 rgba[_pixel2 * bytesPerPixel + 3] = 0x00;2793 } else if ((xorMask[_pixel2] & PIXEL_MASK) == PIXEL_MASK) {2794 //Inverted pixel, not supported in browsers.2795 //Fully opaque instead.2796 rgba[_pixel2 * bytesPerPixel] = 0x00;2797 rgba[_pixel2 * bytesPerPixel + 1] = 0x00;2798 rgba[_pixel2 * bytesPerPixel + 2] = 0x00;2799 rgba[_pixel2 * bytesPerPixel + 3] = 0xff;2800 } else {2801 //Unhandled xorMask2802 rgba[_pixel2 * bytesPerPixel] = 0x00;2803 rgba[_pixel2 * bytesPerPixel + 1] = 0x00;2804 rgba[_pixel2 * bytesPerPixel + 2] = 0x00;2805 rgba[_pixel2 * bytesPerPixel + 3] = 0xff;2806 }2807 } else {2808 //Unhandled andMask2809 rgba[_pixel2 * bytesPerPixel] = 0x00;2810 rgba[_pixel2 * bytesPerPixel + 1] = 0x00;2811 rgba[_pixel2 * bytesPerPixel + 2] = 0x00;2812 rgba[_pixel2 * bytesPerPixel + 3] = 0xff;2813 }2814 }28152816 //Alpha cursor.2817 } else if (cursorType == 1) {2818 if (this._sock.rQwait("VMware cursor alpha encoding", w * h * 4, 2)) {2819 return false;2820 }2821 rgba = new Array(w * h * bytesPerPixel);2822 for (var _pixel3 = 0; _pixel3 < w * h; _pixel3++) {2823 var data = this._sock.rQshift32();2824 rgba[_pixel3 * 4] = data >> 24 & 0xff; //r2825 rgba[_pixel3 * 4 + 1] = data >> 16 & 0xff; //g2826 rgba[_pixel3 * 4 + 2] = data >> 8 & 0xff; //b2827 rgba[_pixel3 * 4 + 3] = data & 0xff; //a2828 }2829 } else {2830 Log.Warn("The given cursor type is not supported: " + cursorType + " given.");2831 return false;2832 }2833 this._updateCursor(rgba, hotx, hoty, w, h);2834 return true;2835 }2836 }, {2837 key: "_handleCursor",2838 value: function _handleCursor() {2839 var hotx = this._FBU.x; // hotspot-x2840 var hoty = this._FBU.y; // hotspot-y2841 var w = this._FBU.width;2842 var h = this._FBU.height;2843 var pixelslength = w * h * 4;2844 var masklength = Math.ceil(w / 8) * h;2845 var bytes = pixelslength + masklength;2846 if (this._sock.rQwait("cursor encoding", bytes)) {2847 return false;2848 }28492850 // Decode from BGRX pixels + bit mask to RGBA2851 var pixels = this._sock.rQshiftBytes(pixelslength);2852 var mask = this._sock.rQshiftBytes(masklength);2853 var rgba = new Uint8Array(w * h * 4);2854 var pixIdx = 0;2855 for (var y = 0; y < h; y++) {2856 for (var x = 0; x < w; x++) {2857 var maskIdx = y * Math.ceil(w / 8) + Math.floor(x / 8);2858 var alpha = mask[maskIdx] << x % 8 & 0x80 ? 255 : 0;2859 rgba[pixIdx] = pixels[pixIdx + 2];2860 rgba[pixIdx + 1] = pixels[pixIdx + 1];2861 rgba[pixIdx + 2] = pixels[pixIdx];2862 rgba[pixIdx + 3] = alpha;2863 pixIdx += 4;2864 }2865 }2866 this._updateCursor(rgba, hotx, hoty, w, h);2867 return true;2868 }2869 }, {2870 key: "_handleDesktopName",2871 value: function _handleDesktopName() {2872 if (this._sock.rQwait("DesktopName", 4)) {2873 return false;2874 }2875 var length = this._sock.rQshift32();2876 if (this._sock.rQwait("DesktopName", length, 4)) {2877 return false;2878 }2879 var name = this._sock.rQshiftStr(length);2880 name = (0, _strings.decodeUTF8)(name, true);2881 this._setDesktopName(name);2882 return true;2883 }2884 }, {2885 key: "_handleLedEvent",2886 value: function _handleLedEvent() {2887 if (this._sock.rQwait("LED status", 1)) {2888 return false;2889 }2890 var data = this._sock.rQshift8();2891 // ScrollLock state can be retrieved with data & 1. This is currently not needed.2892 var numLock = data & 2 ? true : false;2893 var capsLock = data & 4 ? true : false;2894 this._remoteCapsLock = capsLock;2895 this._remoteNumLock = numLock;2896 return true;2897 }2898 }, {2899 key: "_handleExtendedDesktopSize",2900 value: function _handleExtendedDesktopSize() {2901 if (this._sock.rQwait("ExtendedDesktopSize", 4)) {2902 return false;2903 }2904 var numberOfScreens = this._sock.rQpeek8();2905 var bytes = 4 + numberOfScreens * 16;2906 if (this._sock.rQwait("ExtendedDesktopSize", bytes)) {2907 return false;2908 }2909 var firstUpdate = !this._supportsSetDesktopSize;2910 this._supportsSetDesktopSize = true;2911 this._sock.rQskipBytes(1); // number-of-screens2912 this._sock.rQskipBytes(3); // padding29132914 for (var i = 0; i < numberOfScreens; i += 1) {2915 // Save the id and flags of the first screen2916 if (i === 0) {2917 this._screenID = this._sock.rQshift32(); // id2918 this._sock.rQskipBytes(2); // x-position2919 this._sock.rQskipBytes(2); // y-position2920 this._sock.rQskipBytes(2); // width2921 this._sock.rQskipBytes(2); // height2922 this._screenFlags = this._sock.rQshift32(); // flags2923 } else {2924 this._sock.rQskipBytes(16);2925 }2926 }29272928 /*2929 * The x-position indicates the reason for the change:2930 *2931 * 0 - server resized on its own2932 * 1 - this client requested the resize2933 * 2 - another client requested the resize2934 */29352936 if (this._FBU.x === 1) {2937 this._pendingRemoteResize = false;2938 }29392940 // We need to handle errors when we requested the resize.2941 if (this._FBU.x === 1 && this._FBU.y !== 0) {2942 var msg = "";2943 // The y-position indicates the status code from the server2944 switch (this._FBU.y) {2945 case 1:2946 msg = "Resize is administratively prohibited";2947 break;2948 case 2:2949 msg = "Out of resources";2950 break;2951 case 3:2952 msg = "Invalid screen layout";2953 break;2954 default:2955 msg = "Unknown reason";2956 break;2957 }2958 Log.Warn("Server did not accept the resize request: " + msg);2959 } else {2960 this._resize(this._FBU.width, this._FBU.height);2961 }29622963 // Normally we only apply the current resize mode after a2964 // window resize event. However there is no such trigger on the2965 // initial connect. And we don't know if the server supports2966 // resizing until we've gotten here.2967 if (firstUpdate) {2968 this._requestRemoteResize();2969 }2970 if (this._FBU.x === 1 && this._FBU.y === 0) {2971 // We might have resized again whilst waiting for the2972 // previous request, so check if we are in sync2973 this._requestRemoteResize();2974 }2975 return true;2976 }2977 }, {2978 key: "_handleDataRect",2979 value: function _handleDataRect() {2980 var decoder = this._decoders[this._FBU.encoding];2981 if (!decoder) {2982 this._fail("Unsupported encoding (encoding: " + this._FBU.encoding + ")");2983 return false;2984 }2985 try {2986 return decoder.decodeRect(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, this._sock, this._display, this._fbDepth);2987 } catch (err) {2988 this._fail("Error decoding rect: " + err);2989 return false;2990 }2991 }2992 }, {2993 key: "_updateContinuousUpdates",2994 value: function _updateContinuousUpdates() {2995 if (!this._enabledContinuousUpdates) {2996 return;2997 }2998 RFB.messages.enableContinuousUpdates(this._sock, true, 0, 0, this._fbWidth, this._fbHeight);2999 }30003001 // Handle resize-messages from the server3002 }, {3003 key: "_resize",3004 value: function _resize(width, height) {3005 this._fbWidth = width;3006 this._fbHeight = height;3007 this._display.resize(this._fbWidth, this._fbHeight);30083009 // Adjust the visible viewport based on the new dimensions3010 this._updateClip();3011 this._updateScale();3012 this._updateContinuousUpdates();30133014 // Keep this size until browser client size changes3015 this._saveExpectedClientSize();3016 }3017 }, {3018 key: "_xvpOp",3019 value: function _xvpOp(ver, op) {3020 if (this._rfbXvpVer < ver) {3021 return;3022 }3023 Log.Info("Sending XVP operation " + op + " (version " + ver + ")");3024 RFB.messages.xvpOp(this._sock, ver, op);3025 }3026 }, {3027 key: "_updateCursor",3028 value: function _updateCursor(rgba, hotx, hoty, w, h) {3029 this._cursorImage = {3030 rgbaPixels: rgba,3031 hotx: hotx,3032 hoty: hoty,3033 w: w,3034 h: h3035 };3036 this._refreshCursor();3037 }3038 }, {3039 key: "_shouldShowDotCursor",3040 value: function _shouldShowDotCursor() {3041 // Called when this._cursorImage is updated3042 if (!this._showDotCursor) {3043 // User does not want to see the dot, so...3044 return false;3045 }30463047 // The dot should not be shown if the cursor is already visible,3048 // i.e. contains at least one not-fully-transparent pixel.3049 // So iterate through all alpha bytes in rgba and stop at the3050 // first non-zero.3051 for (var i = 3; i < this._cursorImage.rgbaPixels.length; i += 4) {3052 if (this._cursorImage.rgbaPixels[i]) {3053 return false;3054 }3055 }30563057 // At this point, we know that the cursor is fully transparent, and3058 // the user wants to see the dot instead of this.3059 return true;3060 }3061 }, {3062 key: "_refreshCursor",3063 value: function _refreshCursor() {3064 if (this._rfbConnectionState !== "connecting" && this._rfbConnectionState !== "connected") {3065 return;3066 }3067 var image = this._shouldShowDotCursor() ? RFB.cursors.dot : this._cursorImage;3068 this._cursor.change(image.rgbaPixels, image.hotx, image.hoty, image.w, image.h);3069 }3070 }], [{3071 key: "_convertButtonMask",3072 value: function _convertButtonMask(buttons) {3073 /* The bits in MouseEvent.buttons property correspond3074 * to the following mouse buttons:3075 * 0: Left3076 * 1: Right3077 * 2: Middle3078 * 3: Back3079 * 4: Forward3080 *3081 * These bits needs to be converted to what they are defined as3082 * in the RFB protocol.3083 */30843085 var buttonMaskMap = {3086 0: 1 << 0,3087 // Left3088 1: 1 << 2,3089 // Right3090 2: 1 << 1,3091 // Middle3092 3: 1 << 7,3093 // Back3094 4: 1 << 8 // Forward3095 };3096 var bmask = 0;3097 for (var i = 0; i < 5; i++) {3098 if (buttons & 1 << i) {3099 bmask |= buttonMaskMap[i];3100 }3101 }3102 return bmask;3103 }3104 }, {3105 key: "genDES",3106 value: function genDES(password, challenge) {3107 var passwordChars = password.split('').map(function (c) {3108 return c.charCodeAt(0);3109 });3110 var key = _crypto["default"].importKey("raw", passwordChars, {3111 name: "DES-ECB"3112 }, false, ["encrypt"]);3113 return _crypto["default"].encrypt({3114 name: "DES-ECB"3115 }, key, challenge);3116 }3117 }]);3118}(_eventtarget["default"]); // Class Methods3119RFB.messages = {3120 keyEvent: function keyEvent(sock, keysym, down) {3121 sock.sQpush8(4); // msg-type3122 sock.sQpush8(down);3123 sock.sQpush16(0);3124 sock.sQpush32(keysym);3125 sock.flush();3126 },3127 QEMUExtendedKeyEvent: function QEMUExtendedKeyEvent(sock, keysym, down, keycode) {3128 function getRFBkeycode(xtScanCode) {3129 var upperByte = keycode >> 8;3130 var lowerByte = keycode & 0x00ff;3131 if (upperByte === 0xe0 && lowerByte < 0x7f) {3132 return lowerByte | 0x80;3133 }3134 return xtScanCode;3135 }3136 sock.sQpush8(255); // msg-type3137 sock.sQpush8(0); // sub msg-type31383139 sock.sQpush16(down);3140 sock.sQpush32(keysym);3141 var RFBkeycode = getRFBkeycode(keycode);3142 sock.sQpush32(RFBkeycode);3143 sock.flush();3144 },3145 pointerEvent: function pointerEvent(sock, x, y, mask) {3146 sock.sQpush8(5); // msg-type31473148 // Marker bit must be set to 0, otherwise the server might3149 // confuse the marker bit with the highest bit in a normal3150 // PointerEvent message.3151 mask = mask & 0x7f;3152 sock.sQpush8(mask);3153 sock.sQpush16(x);3154 sock.sQpush16(y);3155 sock.flush();3156 },3157 extendedPointerEvent: function extendedPointerEvent(sock, x, y, mask) {3158 sock.sQpush8(5); // msg-type31593160 var higherBits = mask >> 7 & 0xff;31613162 // Bits 2-7 are reserved3163 if (higherBits & 0xfc) {3164 throw new Error("Invalid mouse button mask: " + mask);3165 }3166 var lowerBits = mask & 0x7f;3167 lowerBits |= 0x80; // Set marker bit to 131683169 sock.sQpush8(lowerBits);3170 sock.sQpush16(x);3171 sock.sQpush16(y);3172 sock.sQpush8(higherBits);3173 sock.flush();3174 },3175 // Used to build Notify and Request data.3176 _buildExtendedClipboardFlags: function _buildExtendedClipboardFlags(actions, formats) {3177 var data = new Uint8Array(4);3178 var formatFlag = 0x00000000;3179 var actionFlag = 0x00000000;3180 for (var i = 0; i < actions.length; i++) {3181 actionFlag |= actions[i];3182 }3183 for (var _i7 = 0; _i7 < formats.length; _i7++) {3184 formatFlag |= formats[_i7];3185 }3186 data[0] = actionFlag >> 24; // Actions3187 data[1] = 0x00; // Reserved3188 data[2] = 0x00; // Reserved3189 data[3] = formatFlag; // Formats31903191 return data;3192 },3193 extendedClipboardProvide: function extendedClipboardProvide(sock, formats, inData) {3194 // Deflate incomming data and their sizes3195 var deflator = new _deflator["default"]();3196 var dataToDeflate = [];3197 for (var i = 0; i < formats.length; i++) {3198 // We only support the format Text at this time3199 if (formats[i] != extendedClipboardFormatText) {3200 throw new Error("Unsupported extended clipboard format for Provide message.");3201 }32023203 // Change lone \r or \n into \r\n as defined in rfbproto3204 inData[i] = inData[i].replace(/\r\n|\r|\n/gm, "\r\n");32053206 // Check if it already has \03207 var text = (0, _strings.encodeUTF8)(inData[i] + "\0");3208 dataToDeflate.push(text.length >> 24 & 0xFF, text.length >> 16 & 0xFF, text.length >> 8 & 0xFF, text.length & 0xFF);3209 for (var j = 0; j < text.length; j++) {3210 dataToDeflate.push(text.charCodeAt(j));3211 }3212 }3213 var deflatedData = deflator.deflate(new Uint8Array(dataToDeflate));32143215 // Build data to send3216 var data = new Uint8Array(4 + deflatedData.length);3217 data.set(RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionProvide], formats));3218 data.set(deflatedData, 4);3219 RFB.messages.clientCutText(sock, data, true);3220 },3221 extendedClipboardNotify: function extendedClipboardNotify(sock, formats) {3222 var flags = RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionNotify], formats);3223 RFB.messages.clientCutText(sock, flags, true);3224 },3225 extendedClipboardRequest: function extendedClipboardRequest(sock, formats) {3226 var flags = RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionRequest], formats);3227 RFB.messages.clientCutText(sock, flags, true);3228 },3229 extendedClipboardCaps: function extendedClipboardCaps(sock, actions, formats) {3230 var formatKeys = Object.keys(formats);3231 var data = new Uint8Array(4 + 4 * formatKeys.length);3232 formatKeys.map(function (x) {3233 return parseInt(x);3234 });3235 formatKeys.sort(function (a, b) {3236 return a - b;3237 });3238 data.set(RFB.messages._buildExtendedClipboardFlags(actions, []));3239 var loopOffset = 4;3240 for (var i = 0; i < formatKeys.length; i++) {3241 data[loopOffset] = formats[formatKeys[i]] >> 24;3242 data[loopOffset + 1] = formats[formatKeys[i]] >> 16;3243 data[loopOffset + 2] = formats[formatKeys[i]] >> 8;3244 data[loopOffset + 3] = formats[formatKeys[i]] >> 0;3245 loopOffset += 4;3246 data[3] |= 1 << formatKeys[i]; // Update our format flags3247 }3248 RFB.messages.clientCutText(sock, data, true);3249 },3250 clientCutText: function clientCutText(sock, data) {3251 var extended = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;3252 sock.sQpush8(6); // msg-type32533254 sock.sQpush8(0); // padding3255 sock.sQpush8(0); // padding3256 sock.sQpush8(0); // padding32573258 var length;3259 if (extended) {3260 length = (0, _int.toUnsigned32bit)(-data.length);3261 } else {3262 length = data.length;3263 }3264 sock.sQpush32(length);3265 sock.sQpushBytes(data);3266 sock.flush();3267 },3268 setDesktopSize: function setDesktopSize(sock, width, height, id, flags) {3269 sock.sQpush8(251); // msg-type32703271 sock.sQpush8(0); // padding32723273 sock.sQpush16(width);3274 sock.sQpush16(height);3275 sock.sQpush8(1); // number-of-screens32763277 sock.sQpush8(0); // padding32783279 // screen array3280 sock.sQpush32(id);3281 sock.sQpush16(0); // x-position3282 sock.sQpush16(0); // y-position3283 sock.sQpush16(width);3284 sock.sQpush16(height);3285 sock.sQpush32(flags);3286 sock.flush();3287 },3288 clientFence: function clientFence(sock, flags, payload) {3289 sock.sQpush8(248); // msg-type32903291 sock.sQpush8(0); // padding3292 sock.sQpush8(0); // padding3293 sock.sQpush8(0); // padding32943295 sock.sQpush32(flags);3296 sock.sQpush8(payload.length);3297 sock.sQpushString(payload);3298 sock.flush();3299 },3300 enableContinuousUpdates: function enableContinuousUpdates(sock, enable, x, y, width, height) {3301 sock.sQpush8(150); // msg-type33023303 sock.sQpush8(enable);3304 sock.sQpush16(x);3305 sock.sQpush16(y);3306 sock.sQpush16(width);3307 sock.sQpush16(height);3308 sock.flush();3309 },3310 pixelFormat: function pixelFormat(sock, depth, trueColor) {3311 var bpp;3312 if (depth > 16) {3313 bpp = 32;3314 } else if (depth > 8) {3315 bpp = 16;3316 } else {3317 bpp = 8;3318 }3319 var bits = Math.floor(depth / 3);3320 sock.sQpush8(0); // msg-type33213322 sock.sQpush8(0); // padding3323 sock.sQpush8(0); // padding3324 sock.sQpush8(0); // padding33253326 sock.sQpush8(bpp);3327 sock.sQpush8(depth);3328 sock.sQpush8(0); // little-endian3329 sock.sQpush8(trueColor ? 1 : 0);3330 sock.sQpush16((1 << bits) - 1); // red-max3331 sock.sQpush16((1 << bits) - 1); // green-max3332 sock.sQpush16((1 << bits) - 1); // blue-max33333334 sock.sQpush8(bits * 0); // red-shift3335 sock.sQpush8(bits * 1); // green-shift3336 sock.sQpush8(bits * 2); // blue-shift33373338 sock.sQpush8(0); // padding3339 sock.sQpush8(0); // padding3340 sock.sQpush8(0); // padding33413342 sock.flush();3343 },3344 clientEncodings: function clientEncodings(sock, encodings) {3345 sock.sQpush8(2); // msg-type33463347 sock.sQpush8(0); // padding33483349 sock.sQpush16(encodings.length);3350 for (var i = 0; i < encodings.length; i++) {3351 sock.sQpush32(encodings[i]);3352 }3353 sock.flush();3354 },3355 fbUpdateRequest: function fbUpdateRequest(sock, incremental, x, y, w, h) {3356 if (typeof x === "undefined") {3357 x = 0;3358 }3359 if (typeof y === "undefined") {3360 y = 0;3361 }3362 sock.sQpush8(3); // msg-type33633364 sock.sQpush8(incremental ? 1 : 0);3365 sock.sQpush16(x);3366 sock.sQpush16(y);3367 sock.sQpush16(w);3368 sock.sQpush16(h);3369 sock.flush();3370 },3371 xvpOp: function xvpOp(sock, ver, op) {3372 sock.sQpush8(250); // msg-type33733374 sock.sQpush8(0); // padding33753376 sock.sQpush8(ver);3377 sock.sQpush8(op);3378 sock.flush();3379 }3380};3381RFB.cursors = {3382 none: {3383 rgbaPixels: new Uint8Array(),3384 w: 0,3385 h: 0,3386 hotx: 0,3387 hoty: 03388 },3389 dot: {3390 /* eslint-disable indent */3391 rgbaPixels: new Uint8Array([255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255]),3392 /* eslint-enable indent */3393 w: 3,3394 h: 3,3395 hotx: 1,3396 hoty: 13397 }3398};