@novnc/novnc 1.3.0-gcdfb336 → 1.3.0-gd8b3ec9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/display.js +12 -0
- package/core/input/keyboard.js +10 -0
- package/core/rfb.js +176 -84
- package/core/util/cursor.js +4 -0
- package/docs/API.md +61 -0
- package/lib/base64.js +19 -33
- package/lib/decoders/copyrect.js +4 -11
- package/lib/decoders/hextile.js +16 -46
- package/lib/decoders/jpeg.js +4 -43
- package/lib/decoders/raw.js +8 -21
- package/lib/decoders/rre.js +4 -15
- package/lib/decoders/tight.js +12 -78
- package/lib/decoders/tightpng.js +5 -25
- package/lib/decoders/zrle.js +6 -52
- package/lib/deflator.js +8 -22
- package/lib/des.js +23 -36
- package/lib/display.js +61 -107
- package/lib/encodings.js +1 -10
- package/lib/inflator.js +5 -18
- package/lib/input/domkeytable.js +77 -48
- package/lib/input/fixedkeys.js +8 -3
- package/lib/input/gesturehandler.js +85 -152
- package/lib/input/keyboard.js +61 -90
- package/lib/input/keysym.js +14 -270
- package/lib/input/keysymdef.js +5 -7
- package/lib/input/util.js +42 -84
- package/lib/input/vkeys.js +0 -3
- package/lib/input/xtscancodes.js +1 -168
- package/lib/ra2.js +41 -263
- package/lib/rfb.js +456 -1012
- package/lib/util/browser.js +16 -25
- package/lib/util/cursor.js +28 -65
- package/lib/util/element.js +3 -5
- package/lib/util/events.js +23 -30
- package/lib/util/eventtarget.js +4 -13
- package/lib/util/int.js +1 -2
- package/lib/util/logging.js +1 -19
- package/lib/util/md5.js +7 -27
- package/lib/util/strings.js +3 -5
- package/lib/vendor/pako/lib/utils/common.js +8 -17
- package/lib/vendor/pako/lib/zlib/adler32.js +3 -7
- package/lib/vendor/pako/lib/zlib/constants.js +2 -5
- package/lib/vendor/pako/lib/zlib/crc32.js +5 -12
- package/lib/vendor/pako/lib/zlib/deflate.js +212 -617
- package/lib/vendor/pako/lib/zlib/gzheader.js +1 -13
- package/lib/vendor/pako/lib/zlib/inffast.js +60 -176
- package/lib/vendor/pako/lib/zlib/inflate.js +397 -887
- package/lib/vendor/pako/lib/zlib/inftrees.js +62 -168
- package/lib/vendor/pako/lib/zlib/messages.js +1 -11
- package/lib/vendor/pako/lib/zlib/trees.js +245 -587
- package/lib/vendor/pako/lib/zlib/zstream.js +2 -18
- package/lib/websock.js +35 -86
- package/package.json +31 -31
package/core/display.js
CHANGED
|
@@ -224,6 +224,18 @@ export default class Display {
|
|
|
224
224
|
this.viewportChangePos(0, 0);
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
getImageData() {
|
|
228
|
+
return this._drawCtx.getImageData(0, 0, this.width, this.height);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
toDataURL(type, encoderOptions) {
|
|
232
|
+
return this._backbuffer.toDataURL(type, encoderOptions);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
toBlob(callback, type, quality) {
|
|
236
|
+
return this._backbuffer.toBlob(callback, type, quality);
|
|
237
|
+
}
|
|
238
|
+
|
|
227
239
|
// Track what parts of the visible canvas that need updating
|
|
228
240
|
_damage(x, y, w, h) {
|
|
229
241
|
if (x < this._damageBounds.left) {
|
package/core/input/keyboard.js
CHANGED
|
@@ -153,6 +153,16 @@ export default class Keyboard {
|
|
|
153
153
|
keysym = this._keyDownList[code];
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
// macOS doesn't send proper key releases if a key is pressed
|
|
157
|
+
// while meta is held down
|
|
158
|
+
if ((browser.isMac() || browser.isIOS()) &&
|
|
159
|
+
(e.metaKey && code !== 'MetaLeft' && code !== 'MetaRight')) {
|
|
160
|
+
this._sendKeyEvent(keysym, code, true);
|
|
161
|
+
this._sendKeyEvent(keysym, code, false);
|
|
162
|
+
stopEvent(e);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
156
166
|
// macOS doesn't send proper key events for modifiers, only
|
|
157
167
|
// state change events. That gets extra confusing for CapsLock
|
|
158
168
|
// which toggles on each press, but not on release. So pretend
|
package/core/rfb.js
CHANGED
|
@@ -54,6 +54,21 @@ const GESTURE_SCRLSENS = 50;
|
|
|
54
54
|
const DOUBLE_TAP_TIMEOUT = 1000;
|
|
55
55
|
const DOUBLE_TAP_THRESHOLD = 50;
|
|
56
56
|
|
|
57
|
+
// Security types
|
|
58
|
+
const securityTypeNone = 1;
|
|
59
|
+
const securityTypeVNCAuth = 2;
|
|
60
|
+
const securityTypeRA2ne = 6;
|
|
61
|
+
const securityTypeTight = 16;
|
|
62
|
+
const securityTypeVeNCrypt = 19;
|
|
63
|
+
const securityTypeXVP = 22;
|
|
64
|
+
const securityTypeARD = 30;
|
|
65
|
+
|
|
66
|
+
// Special Tight security types
|
|
67
|
+
const securityTypeUnixLogon = 129;
|
|
68
|
+
|
|
69
|
+
// VeNCrypt security types
|
|
70
|
+
const securityTypePlain = 256;
|
|
71
|
+
|
|
57
72
|
// Extended clipboard pseudo-encoding formats
|
|
58
73
|
const extendedClipboardFormatText = 1;
|
|
59
74
|
/*eslint-disable no-unused-vars */
|
|
@@ -402,7 +417,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
402
417
|
|
|
403
418
|
sendCredentials(creds) {
|
|
404
419
|
this._rfbCredentials = creds;
|
|
405
|
-
|
|
420
|
+
this._resumeAuthentication();
|
|
406
421
|
}
|
|
407
422
|
|
|
408
423
|
sendCtrlAltDel() {
|
|
@@ -475,16 +490,45 @@ export default class RFB extends EventTargetMixin {
|
|
|
475
490
|
this._clipboardText = text;
|
|
476
491
|
RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);
|
|
477
492
|
} else {
|
|
478
|
-
let
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
493
|
+
let length, i;
|
|
494
|
+
let data;
|
|
495
|
+
|
|
496
|
+
length = 0;
|
|
497
|
+
// eslint-disable-next-line no-unused-vars
|
|
498
|
+
for (let codePoint of text) {
|
|
499
|
+
length++;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
data = new Uint8Array(length);
|
|
503
|
+
|
|
504
|
+
i = 0;
|
|
505
|
+
for (let codePoint of text) {
|
|
506
|
+
let code = codePoint.codePointAt(0);
|
|
507
|
+
|
|
508
|
+
/* Only ISO 8859-1 is supported */
|
|
509
|
+
if (code > 0xff) {
|
|
510
|
+
code = 0x3f; // '?'
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
data[i++] = code;
|
|
482
514
|
}
|
|
483
515
|
|
|
484
516
|
RFB.messages.clientCutText(this._sock, data);
|
|
485
517
|
}
|
|
486
518
|
}
|
|
487
519
|
|
|
520
|
+
getImageData() {
|
|
521
|
+
return this._display.getImageData();
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
toDataURL(type, encoderOptions) {
|
|
525
|
+
return this._display.toDataURL(type, encoderOptions);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
toBlob(callback, type, quality) {
|
|
529
|
+
return this._display.toBlob(callback, type, quality);
|
|
530
|
+
}
|
|
531
|
+
|
|
488
532
|
// ===== PRIVATE METHODS =====
|
|
489
533
|
|
|
490
534
|
_connect() {
|
|
@@ -922,8 +966,15 @@ export default class RFB extends EventTargetMixin {
|
|
|
922
966
|
}
|
|
923
967
|
}
|
|
924
968
|
break;
|
|
969
|
+
case 'connecting':
|
|
970
|
+
while (this._rfbConnectionState === 'connecting') {
|
|
971
|
+
if (!this._initMsg()) {
|
|
972
|
+
break;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
break;
|
|
925
976
|
default:
|
|
926
|
-
|
|
977
|
+
Log.Error("Got data while in an invalid state");
|
|
927
978
|
break;
|
|
928
979
|
}
|
|
929
980
|
}
|
|
@@ -1332,6 +1383,21 @@ export default class RFB extends EventTargetMixin {
|
|
|
1332
1383
|
this._rfbInitState = 'Security';
|
|
1333
1384
|
}
|
|
1334
1385
|
|
|
1386
|
+
_isSupportedSecurityType(type) {
|
|
1387
|
+
const clientTypes = [
|
|
1388
|
+
securityTypeNone,
|
|
1389
|
+
securityTypeVNCAuth,
|
|
1390
|
+
securityTypeRA2ne,
|
|
1391
|
+
securityTypeTight,
|
|
1392
|
+
securityTypeVeNCrypt,
|
|
1393
|
+
securityTypeXVP,
|
|
1394
|
+
securityTypeARD,
|
|
1395
|
+
securityTypePlain,
|
|
1396
|
+
];
|
|
1397
|
+
|
|
1398
|
+
return clientTypes.includes(type);
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1335
1401
|
_negotiateSecurity() {
|
|
1336
1402
|
if (this._rfbVersion >= 3.7) {
|
|
1337
1403
|
// Server sends supported list, client decides
|
|
@@ -1342,28 +1408,23 @@ export default class RFB extends EventTargetMixin {
|
|
|
1342
1408
|
this._rfbInitState = "SecurityReason";
|
|
1343
1409
|
this._securityContext = "no security types";
|
|
1344
1410
|
this._securityStatus = 1;
|
|
1345
|
-
return
|
|
1411
|
+
return true;
|
|
1346
1412
|
}
|
|
1347
1413
|
|
|
1348
1414
|
const types = this._sock.rQshiftBytes(numTypes);
|
|
1349
1415
|
Log.Debug("Server security types: " + types);
|
|
1350
1416
|
|
|
1351
|
-
// Look for
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
this.
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
} else if (types.includes(30)) {
|
|
1363
|
-
this._rfbAuthScheme = 30; // ARD Auth
|
|
1364
|
-
} else if (types.includes(19)) {
|
|
1365
|
-
this._rfbAuthScheme = 19; // VeNCrypt Auth
|
|
1366
|
-
} else {
|
|
1417
|
+
// Look for a matching security type in the order that the
|
|
1418
|
+
// server prefers
|
|
1419
|
+
this._rfbAuthScheme = -1;
|
|
1420
|
+
for (let type of types) {
|
|
1421
|
+
if (this._isSupportedSecurityType(type)) {
|
|
1422
|
+
this._rfbAuthScheme = type;
|
|
1423
|
+
break;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
if (this._rfbAuthScheme === -1) {
|
|
1367
1428
|
return this._fail("Unsupported security types (types: " + types + ")");
|
|
1368
1429
|
}
|
|
1369
1430
|
|
|
@@ -1377,14 +1438,14 @@ export default class RFB extends EventTargetMixin {
|
|
|
1377
1438
|
this._rfbInitState = "SecurityReason";
|
|
1378
1439
|
this._securityContext = "authentication scheme";
|
|
1379
1440
|
this._securityStatus = 1;
|
|
1380
|
-
return
|
|
1441
|
+
return true;
|
|
1381
1442
|
}
|
|
1382
1443
|
}
|
|
1383
1444
|
|
|
1384
1445
|
this._rfbInitState = 'Authentication';
|
|
1385
1446
|
Log.Debug('Authenticating using scheme: ' + this._rfbAuthScheme);
|
|
1386
1447
|
|
|
1387
|
-
return
|
|
1448
|
+
return true;
|
|
1388
1449
|
}
|
|
1389
1450
|
|
|
1390
1451
|
_handleSecurityReason() {
|
|
@@ -1434,7 +1495,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1434
1495
|
this._rfbCredentials.username +
|
|
1435
1496
|
this._rfbCredentials.target;
|
|
1436
1497
|
this._sock.sendString(xvpAuthStr);
|
|
1437
|
-
this._rfbAuthScheme =
|
|
1498
|
+
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
1438
1499
|
return this._negotiateAuthentication();
|
|
1439
1500
|
}
|
|
1440
1501
|
|
|
@@ -1492,49 +1553,66 @@ export default class RFB extends EventTargetMixin {
|
|
|
1492
1553
|
subtypes.push(this._sock.rQshift32());
|
|
1493
1554
|
}
|
|
1494
1555
|
|
|
1495
|
-
//
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1556
|
+
// Look for a matching security type in the order that the
|
|
1557
|
+
// server prefers
|
|
1558
|
+
this._rfbAuthScheme = -1;
|
|
1559
|
+
for (let type of subtypes) {
|
|
1560
|
+
// Avoid getting in to a loop
|
|
1561
|
+
if (type === securityTypeVeNCrypt) {
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
if (this._isSupportedSecurityType(type)) {
|
|
1566
|
+
this._rfbAuthScheme = type;
|
|
1567
|
+
break;
|
|
1568
|
+
}
|
|
1502
1569
|
}
|
|
1503
|
-
}
|
|
1504
1570
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
if (this._rfbCredentials.username === undefined ||
|
|
1508
|
-
this._rfbCredentials.password === undefined) {
|
|
1509
|
-
this.dispatchEvent(new CustomEvent(
|
|
1510
|
-
"credentialsrequired",
|
|
1511
|
-
{ detail: { types: ["username", "password"] } }));
|
|
1512
|
-
return false;
|
|
1571
|
+
if (this._rfbAuthScheme === -1) {
|
|
1572
|
+
return this._fail("Unsupported security types (types: " + subtypes + ")");
|
|
1513
1573
|
}
|
|
1514
1574
|
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
(user.length >> 24) & 0xFF,
|
|
1520
|
-
(user.length >> 16) & 0xFF,
|
|
1521
|
-
(user.length >> 8) & 0xFF,
|
|
1522
|
-
user.length & 0xFF
|
|
1523
|
-
]);
|
|
1524
|
-
this._sock.send([
|
|
1525
|
-
(pass.length >> 24) & 0xFF,
|
|
1526
|
-
(pass.length >> 16) & 0xFF,
|
|
1527
|
-
(pass.length >> 8) & 0xFF,
|
|
1528
|
-
pass.length & 0xFF
|
|
1529
|
-
]);
|
|
1530
|
-
this._sock.sendString(user);
|
|
1531
|
-
this._sock.sendString(pass);
|
|
1575
|
+
this._sock.send([this._rfbAuthScheme >> 24,
|
|
1576
|
+
this._rfbAuthScheme >> 16,
|
|
1577
|
+
this._rfbAuthScheme >> 8,
|
|
1578
|
+
this._rfbAuthScheme]);
|
|
1532
1579
|
|
|
1533
|
-
this.
|
|
1580
|
+
this._rfbVeNCryptState == 4;
|
|
1534
1581
|
return true;
|
|
1535
1582
|
}
|
|
1536
1583
|
}
|
|
1537
1584
|
|
|
1585
|
+
_negotiatePlainAuth() {
|
|
1586
|
+
if (this._rfbCredentials.username === undefined ||
|
|
1587
|
+
this._rfbCredentials.password === undefined) {
|
|
1588
|
+
this.dispatchEvent(new CustomEvent(
|
|
1589
|
+
"credentialsrequired",
|
|
1590
|
+
{ detail: { types: ["username", "password"] } }));
|
|
1591
|
+
return false;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
const user = encodeUTF8(this._rfbCredentials.username);
|
|
1595
|
+
const pass = encodeUTF8(this._rfbCredentials.password);
|
|
1596
|
+
|
|
1597
|
+
this._sock.send([
|
|
1598
|
+
(user.length >> 24) & 0xFF,
|
|
1599
|
+
(user.length >> 16) & 0xFF,
|
|
1600
|
+
(user.length >> 8) & 0xFF,
|
|
1601
|
+
user.length & 0xFF
|
|
1602
|
+
]);
|
|
1603
|
+
this._sock.send([
|
|
1604
|
+
(pass.length >> 24) & 0xFF,
|
|
1605
|
+
(pass.length >> 16) & 0xFF,
|
|
1606
|
+
(pass.length >> 8) & 0xFF,
|
|
1607
|
+
pass.length & 0xFF
|
|
1608
|
+
]);
|
|
1609
|
+
this._sock.sendString(user);
|
|
1610
|
+
this._sock.sendString(pass);
|
|
1611
|
+
|
|
1612
|
+
this._rfbInitState = "SecurityResult";
|
|
1613
|
+
return true;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1538
1616
|
_negotiateStdVNCAuth() {
|
|
1539
1617
|
if (this._sock.rQwait("auth challenge", 16)) { return false; }
|
|
1540
1618
|
|
|
@@ -1661,7 +1739,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1661
1739
|
this._rfbCredentials.ardCredentials = encrypted;
|
|
1662
1740
|
this._rfbCredentials.ardPublicKey = clientPublicKey;
|
|
1663
1741
|
|
|
1664
|
-
|
|
1742
|
+
this._resumeAuthentication();
|
|
1665
1743
|
}
|
|
1666
1744
|
|
|
1667
1745
|
_negotiateTightUnixAuth() {
|
|
@@ -1771,12 +1849,12 @@ export default class RFB extends EventTargetMixin {
|
|
|
1771
1849
|
case 'STDVNOAUTH__': // no auth
|
|
1772
1850
|
this._rfbInitState = 'SecurityResult';
|
|
1773
1851
|
return true;
|
|
1774
|
-
case 'STDVVNCAUTH_':
|
|
1775
|
-
this._rfbAuthScheme =
|
|
1776
|
-
return
|
|
1777
|
-
case 'TGHTULGNAUTH':
|
|
1778
|
-
this._rfbAuthScheme =
|
|
1779
|
-
return
|
|
1852
|
+
case 'STDVVNCAUTH_':
|
|
1853
|
+
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
1854
|
+
return true;
|
|
1855
|
+
case 'TGHTULGNAUTH':
|
|
1856
|
+
this._rfbAuthScheme = securityTypeUnixLogon;
|
|
1857
|
+
return true;
|
|
1780
1858
|
default:
|
|
1781
1859
|
return this._fail("Unsupported tiny auth scheme " +
|
|
1782
1860
|
"(scheme: " + authType + ")");
|
|
@@ -1813,7 +1891,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1813
1891
|
}).then(() => {
|
|
1814
1892
|
this.dispatchEvent(new CustomEvent('securityresult'));
|
|
1815
1893
|
this._rfbInitState = "SecurityResult";
|
|
1816
|
-
|
|
1894
|
+
return true;
|
|
1817
1895
|
}).finally(() => {
|
|
1818
1896
|
this._rfbRSAAESAuthenticationState.removeEventListener(
|
|
1819
1897
|
"serververification", this._eventHandlers.handleRSAAESServerVerification);
|
|
@@ -1827,33 +1905,32 @@ export default class RFB extends EventTargetMixin {
|
|
|
1827
1905
|
|
|
1828
1906
|
_negotiateAuthentication() {
|
|
1829
1907
|
switch (this._rfbAuthScheme) {
|
|
1830
|
-
case
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
return true;
|
|
1834
|
-
}
|
|
1835
|
-
this._rfbInitState = 'ClientInitialisation';
|
|
1836
|
-
return this._initMsg();
|
|
1908
|
+
case securityTypeNone:
|
|
1909
|
+
this._rfbInitState = 'SecurityResult';
|
|
1910
|
+
return true;
|
|
1837
1911
|
|
|
1838
|
-
case
|
|
1912
|
+
case securityTypeXVP:
|
|
1839
1913
|
return this._negotiateXvpAuth();
|
|
1840
1914
|
|
|
1841
|
-
case
|
|
1915
|
+
case securityTypeARD:
|
|
1842
1916
|
return this._negotiateARDAuth();
|
|
1843
1917
|
|
|
1844
|
-
case
|
|
1918
|
+
case securityTypeVNCAuth:
|
|
1845
1919
|
return this._negotiateStdVNCAuth();
|
|
1846
1920
|
|
|
1847
|
-
case
|
|
1921
|
+
case securityTypeTight:
|
|
1848
1922
|
return this._negotiateTightAuth();
|
|
1849
1923
|
|
|
1850
|
-
case
|
|
1924
|
+
case securityTypeVeNCrypt:
|
|
1851
1925
|
return this._negotiateVeNCryptAuth();
|
|
1852
1926
|
|
|
1853
|
-
case
|
|
1927
|
+
case securityTypePlain:
|
|
1928
|
+
return this._negotiatePlainAuth();
|
|
1929
|
+
|
|
1930
|
+
case securityTypeUnixLogon:
|
|
1854
1931
|
return this._negotiateTightUnixAuth();
|
|
1855
1932
|
|
|
1856
|
-
case
|
|
1933
|
+
case securityTypeRA2ne:
|
|
1857
1934
|
return this._negotiateRA2neAuth();
|
|
1858
1935
|
|
|
1859
1936
|
default:
|
|
@@ -1863,6 +1940,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
1863
1940
|
}
|
|
1864
1941
|
|
|
1865
1942
|
_handleSecurityResult() {
|
|
1943
|
+
// There is no security choice, and hence no security result
|
|
1944
|
+
// until RFB 3.7
|
|
1945
|
+
if (this._rfbVersion < 3.7) {
|
|
1946
|
+
this._rfbInitState = 'ClientInitialisation';
|
|
1947
|
+
return true;
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1866
1950
|
if (this._sock.rQwait('VNC auth response ', 4)) { return false; }
|
|
1867
1951
|
|
|
1868
1952
|
const status = this._sock.rQshift32();
|
|
@@ -1870,13 +1954,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
1870
1954
|
if (status === 0) { // OK
|
|
1871
1955
|
this._rfbInitState = 'ClientInitialisation';
|
|
1872
1956
|
Log.Debug('Authentication OK');
|
|
1873
|
-
return
|
|
1957
|
+
return true;
|
|
1874
1958
|
} else {
|
|
1875
1959
|
if (this._rfbVersion >= 3.8) {
|
|
1876
1960
|
this._rfbInitState = "SecurityReason";
|
|
1877
1961
|
this._securityContext = "security result";
|
|
1878
1962
|
this._securityStatus = status;
|
|
1879
|
-
return
|
|
1963
|
+
return true;
|
|
1880
1964
|
} else {
|
|
1881
1965
|
this.dispatchEvent(new CustomEvent(
|
|
1882
1966
|
"securityfailure",
|
|
@@ -2052,6 +2136,14 @@ export default class RFB extends EventTargetMixin {
|
|
|
2052
2136
|
}
|
|
2053
2137
|
}
|
|
2054
2138
|
|
|
2139
|
+
// Resume authentication handshake after it was paused for some
|
|
2140
|
+
// reason, e.g. waiting for a password from the user
|
|
2141
|
+
_resumeAuthentication() {
|
|
2142
|
+
// We use setTimeout() so it's run in its own context, just like
|
|
2143
|
+
// it originally did via the WebSocket's event handler
|
|
2144
|
+
setTimeout(this._initMsg.bind(this), 0);
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2055
2147
|
_handleSetColourMapMsg() {
|
|
2056
2148
|
Log.Debug("SetColorMapEntries");
|
|
2057
2149
|
|
package/core/util/cursor.js
CHANGED
|
@@ -18,6 +18,10 @@ export default class Cursor {
|
|
|
18
18
|
this._canvas.style.position = 'fixed';
|
|
19
19
|
this._canvas.style.zIndex = '65535';
|
|
20
20
|
this._canvas.style.pointerEvents = 'none';
|
|
21
|
+
// Safari on iOS can select the cursor image
|
|
22
|
+
// https://bugs.webkit.org/show_bug.cgi?id=249223
|
|
23
|
+
this._canvas.style.userSelect = 'none';
|
|
24
|
+
this._canvas.style.WebkitUserSelect = 'none';
|
|
21
25
|
// Can't use "display" because of Firefox bug #1445997
|
|
22
26
|
this._canvas.style.visibility = 'hidden';
|
|
23
27
|
}
|
package/docs/API.md
CHANGED
|
@@ -155,6 +155,15 @@ protocol stream.
|
|
|
155
155
|
[`RFB.clipboardPasteFrom()`](#rfbclipboardpastefrom)
|
|
156
156
|
- Send clipboard contents to server.
|
|
157
157
|
|
|
158
|
+
[`RFB.getImageData()`](#rfbgetimagedata)
|
|
159
|
+
- Return the current content of the screen as an ImageData array.
|
|
160
|
+
|
|
161
|
+
[`RFB.toDataURL()`](#rfbtodataurl)
|
|
162
|
+
- Return the current content of the screen as data-url encoded image file.
|
|
163
|
+
|
|
164
|
+
[`RFB.toBlob()`](#rfbtoblob)
|
|
165
|
+
- Return the current content of the screen as Blob encoded image file.
|
|
166
|
+
|
|
158
167
|
### Details
|
|
159
168
|
|
|
160
169
|
#### RFB()
|
|
@@ -423,3 +432,55 @@ to the remote server.
|
|
|
423
432
|
|
|
424
433
|
**`text`**
|
|
425
434
|
- A `DOMString` specifying the clipboard data to send.
|
|
435
|
+
|
|
436
|
+
#### RFB.getImageData()
|
|
437
|
+
|
|
438
|
+
The `RFB.getImageData()` method is used to return the current content of the
|
|
439
|
+
screen encoded as [`ImageData`](https://developer.mozilla.org/en-US/docs/Web/API/ImageData).
|
|
440
|
+
|
|
441
|
+
##### Syntax
|
|
442
|
+
|
|
443
|
+
RFB.getImageData();
|
|
444
|
+
|
|
445
|
+
#### RFB.toDataURL()
|
|
446
|
+
|
|
447
|
+
The `RFB.toDataURL()` method is used to return the current content of the
|
|
448
|
+
screen encoded as a data URL that could for example be put in the `src` attribute
|
|
449
|
+
of an `img` tag.
|
|
450
|
+
|
|
451
|
+
##### Syntax
|
|
452
|
+
|
|
453
|
+
RFB.toDataURL();
|
|
454
|
+
RFB.toDataURL(type);
|
|
455
|
+
RFB.toDataURL(type, encoderOptions);
|
|
456
|
+
|
|
457
|
+
###### Parameters
|
|
458
|
+
|
|
459
|
+
**`type`** *Optional*
|
|
460
|
+
- A string indicating the requested MIME type of the image
|
|
461
|
+
|
|
462
|
+
**`encoderOptions`** *Optional*
|
|
463
|
+
- A number between 0 and 1 indicating the image quality.
|
|
464
|
+
|
|
465
|
+
#### RFB.toBlob()
|
|
466
|
+
|
|
467
|
+
The `RFB.toBlob()` method is used to return the current content of the
|
|
468
|
+
screen encoded as [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
|
|
469
|
+
|
|
470
|
+
##### Syntax
|
|
471
|
+
|
|
472
|
+
RFB.toDataURL(callback);
|
|
473
|
+
RFB.toDataURL(callback, type);
|
|
474
|
+
RFB.toDataURL(callback, type, quality);
|
|
475
|
+
|
|
476
|
+
###### Parameters
|
|
477
|
+
|
|
478
|
+
**`callback`**
|
|
479
|
+
- A callback function which will receive the resulting [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
|
|
480
|
+
as the single argument
|
|
481
|
+
|
|
482
|
+
**`type`** *Optional*
|
|
483
|
+
- A string indicating the requested MIME type of the image
|
|
484
|
+
|
|
485
|
+
**`encoderOptions`** *Optional*
|
|
486
|
+
- A number between 0 and 1 indicating the image quality.
|
package/lib/base64.js
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
|
|
4
|
-
|
|
5
4
|
Object.defineProperty(exports, "__esModule", {
|
|
6
5
|
value: true
|
|
7
6
|
});
|
|
8
7
|
exports["default"] = void 0;
|
|
9
|
-
|
|
10
8
|
var Log = _interopRequireWildcard(require("./util/logging.js"));
|
|
11
|
-
|
|
12
9
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
13
|
-
|
|
14
10
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
15
|
-
|
|
16
11
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
17
12
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
18
13
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
@@ -26,18 +21,18 @@ var _default = {
|
|
|
26
21
|
|
|
27
22
|
var result = '';
|
|
28
23
|
var length = data.length;
|
|
29
|
-
var lengthpad = length % 3;
|
|
24
|
+
var lengthpad = length % 3;
|
|
25
|
+
// Convert every three bytes to 4 ascii characters.
|
|
30
26
|
|
|
31
27
|
for (var i = 0; i < length - 2; i += 3) {
|
|
32
28
|
result += this.toBase64Table[data[i] >> 2];
|
|
33
29
|
result += this.toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
|
|
34
30
|
result += this.toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
|
|
35
31
|
result += this.toBase64Table[data[i + 2] & 0x3f];
|
|
36
|
-
}
|
|
37
|
-
|
|
32
|
+
}
|
|
38
33
|
|
|
34
|
+
// Convert the remaining 1 or 2 bytes, pad out to 4 characters.
|
|
39
35
|
var j = length - lengthpad;
|
|
40
|
-
|
|
41
36
|
if (lengthpad === 2) {
|
|
42
37
|
result += this.toBase64Table[data[j] >> 2];
|
|
43
38
|
result += this.toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)];
|
|
@@ -49,67 +44,58 @@ var _default = {
|
|
|
49
44
|
result += this.toBase64Table[64];
|
|
50
45
|
result += this.toBase64Table[64];
|
|
51
46
|
}
|
|
52
|
-
|
|
53
47
|
return result;
|
|
54
48
|
},
|
|
55
|
-
|
|
56
49
|
/* Convert Base64 data to a string */
|
|
57
|
-
|
|
58
50
|
/* eslint-disable comma-spacing */
|
|
59
51
|
toBinaryTable: [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1],
|
|
60
|
-
|
|
61
|
-
/* eslint-enable comma-spacing */
|
|
62
|
-
decode: function decode(data) {
|
|
52
|
+
/* eslint-enable comma-spacing */decode: function decode(data) {
|
|
63
53
|
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
64
54
|
var dataLength = data.indexOf('=') - offset;
|
|
65
|
-
|
|
66
55
|
if (dataLength < 0) {
|
|
67
56
|
dataLength = data.length - offset;
|
|
68
57
|
}
|
|
69
|
-
/* Every four characters is 3 resulting numbers */
|
|
70
|
-
|
|
71
58
|
|
|
59
|
+
/* Every four characters is 3 resulting numbers */
|
|
72
60
|
var resultLength = (dataLength >> 2) * 3 + Math.floor(dataLength % 4 / 1.5);
|
|
73
|
-
var result = new Array(resultLength);
|
|
61
|
+
var result = new Array(resultLength);
|
|
74
62
|
|
|
75
|
-
|
|
63
|
+
// Convert one by one.
|
|
76
64
|
|
|
65
|
+
var leftbits = 0; // number of bits decoded, but yet to be appended
|
|
77
66
|
var leftdata = 0; // bits decoded, but yet to be appended
|
|
78
|
-
|
|
79
67
|
for (var idx = 0, i = offset; i < data.length; i++) {
|
|
80
68
|
var c = this.toBinaryTable[data.charCodeAt(i) & 0x7f];
|
|
81
|
-
var padding = data.charAt(i) === this.base64Pad;
|
|
82
|
-
|
|
69
|
+
var padding = data.charAt(i) === this.base64Pad;
|
|
70
|
+
// Skip illegal characters and whitespace
|
|
83
71
|
if (c === -1) {
|
|
84
72
|
Log.Error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
|
|
85
73
|
continue;
|
|
86
|
-
}
|
|
87
|
-
|
|
74
|
+
}
|
|
88
75
|
|
|
76
|
+
// Collect data into leftdata, update bitcount
|
|
89
77
|
leftdata = leftdata << 6 | c;
|
|
90
|
-
leftbits += 6;
|
|
78
|
+
leftbits += 6;
|
|
91
79
|
|
|
80
|
+
// If we have 8 or more bits, append 8 bits to the result
|
|
92
81
|
if (leftbits >= 8) {
|
|
93
|
-
leftbits -= 8;
|
|
94
|
-
|
|
82
|
+
leftbits -= 8;
|
|
83
|
+
// Append if not padding.
|
|
95
84
|
if (!padding) {
|
|
96
85
|
result[idx++] = leftdata >> leftbits & 0xff;
|
|
97
86
|
}
|
|
98
|
-
|
|
99
87
|
leftdata &= (1 << leftbits) - 1;
|
|
100
88
|
}
|
|
101
|
-
}
|
|
102
|
-
|
|
89
|
+
}
|
|
103
90
|
|
|
91
|
+
// If there are any bits left, the base64 string was corrupted
|
|
104
92
|
if (leftbits) {
|
|
105
93
|
var err = new Error('Corrupted base64 string');
|
|
106
94
|
err.name = 'Base64-Error';
|
|
107
95
|
throw err;
|
|
108
96
|
}
|
|
109
|
-
|
|
110
97
|
return result;
|
|
111
98
|
}
|
|
112
99
|
};
|
|
113
100
|
/* End of Base64 namespace */
|
|
114
|
-
|
|
115
101
|
exports["default"] = _default;
|