@novnc/novnc 1.3.0-g1075cd8 → 1.3.0-g138df46
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 +182 -84
- package/docs/API.md +61 -0
- package/lib/base64.js +19 -33
- package/lib/decoders/copyrect.js +0 -10
- package/lib/decoders/hextile.js +12 -44
- package/lib/decoders/jpeg.js +0 -42
- package/lib/decoders/raw.js +4 -20
- package/lib/decoders/rre.js +0 -14
- package/lib/decoders/tight.js +8 -76
- package/lib/decoders/tightpng.js +2 -24
- package/lib/decoders/zrle.js +2 -51
- package/lib/deflator.js +4 -21
- package/lib/des.js +19 -35
- package/lib/display.js +57 -105
- package/lib/encodings.js +1 -10
- package/lib/inflator.js +1 -17
- package/lib/input/domkeytable.js +77 -48
- package/lib/input/fixedkeys.js +8 -3
- package/lib/input/gesturehandler.js +81 -151
- package/lib/input/keyboard.js +57 -88
- 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 +37 -261
- package/lib/rfb.js +453 -1005
- package/lib/util/browser.js +16 -25
- package/lib/util/cursor.js +20 -64
- package/lib/util/element.js +3 -5
- package/lib/util/events.js +23 -30
- package/lib/util/eventtarget.js +0 -12
- 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 +31 -84
- package/package.json +1 -1
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 */
|
|
@@ -79,6 +94,12 @@ export default class RFB extends EventTargetMixin {
|
|
|
79
94
|
throw new Error("Must specify URL, WebSocket or RTCDataChannel");
|
|
80
95
|
}
|
|
81
96
|
|
|
97
|
+
// We rely on modern APIs which might not be available in an
|
|
98
|
+
// insecure context
|
|
99
|
+
if (!window.isSecureContext) {
|
|
100
|
+
Log.Error("noVNC requires a secure context (TLS). Expect crashes!");
|
|
101
|
+
}
|
|
102
|
+
|
|
82
103
|
super();
|
|
83
104
|
|
|
84
105
|
this._target = target;
|
|
@@ -396,7 +417,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
396
417
|
|
|
397
418
|
sendCredentials(creds) {
|
|
398
419
|
this._rfbCredentials = creds;
|
|
399
|
-
|
|
420
|
+
this._resumeAuthentication();
|
|
400
421
|
}
|
|
401
422
|
|
|
402
423
|
sendCtrlAltDel() {
|
|
@@ -469,16 +490,45 @@ export default class RFB extends EventTargetMixin {
|
|
|
469
490
|
this._clipboardText = text;
|
|
470
491
|
RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);
|
|
471
492
|
} else {
|
|
472
|
-
let
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
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;
|
|
476
514
|
}
|
|
477
515
|
|
|
478
516
|
RFB.messages.clientCutText(this._sock, data);
|
|
479
517
|
}
|
|
480
518
|
}
|
|
481
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
|
+
|
|
482
532
|
// ===== PRIVATE METHODS =====
|
|
483
533
|
|
|
484
534
|
_connect() {
|
|
@@ -916,8 +966,15 @@ export default class RFB extends EventTargetMixin {
|
|
|
916
966
|
}
|
|
917
967
|
}
|
|
918
968
|
break;
|
|
969
|
+
case 'connecting':
|
|
970
|
+
while (this._rfbConnectionState === 'connecting') {
|
|
971
|
+
if (!this._initMsg()) {
|
|
972
|
+
break;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
break;
|
|
919
976
|
default:
|
|
920
|
-
|
|
977
|
+
Log.Error("Got data while in an invalid state");
|
|
921
978
|
break;
|
|
922
979
|
}
|
|
923
980
|
}
|
|
@@ -1326,6 +1383,21 @@ export default class RFB extends EventTargetMixin {
|
|
|
1326
1383
|
this._rfbInitState = 'Security';
|
|
1327
1384
|
}
|
|
1328
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
|
+
|
|
1329
1401
|
_negotiateSecurity() {
|
|
1330
1402
|
if (this._rfbVersion >= 3.7) {
|
|
1331
1403
|
// Server sends supported list, client decides
|
|
@@ -1336,28 +1408,23 @@ export default class RFB extends EventTargetMixin {
|
|
|
1336
1408
|
this._rfbInitState = "SecurityReason";
|
|
1337
1409
|
this._securityContext = "no security types";
|
|
1338
1410
|
this._securityStatus = 1;
|
|
1339
|
-
return
|
|
1411
|
+
return true;
|
|
1340
1412
|
}
|
|
1341
1413
|
|
|
1342
1414
|
const types = this._sock.rQshiftBytes(numTypes);
|
|
1343
1415
|
Log.Debug("Server security types: " + types);
|
|
1344
1416
|
|
|
1345
|
-
// Look for
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
this.
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
} else if (types.includes(30)) {
|
|
1357
|
-
this._rfbAuthScheme = 30; // ARD Auth
|
|
1358
|
-
} else if (types.includes(19)) {
|
|
1359
|
-
this._rfbAuthScheme = 19; // VeNCrypt Auth
|
|
1360
|
-
} 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) {
|
|
1361
1428
|
return this._fail("Unsupported security types (types: " + types + ")");
|
|
1362
1429
|
}
|
|
1363
1430
|
|
|
@@ -1371,14 +1438,14 @@ export default class RFB extends EventTargetMixin {
|
|
|
1371
1438
|
this._rfbInitState = "SecurityReason";
|
|
1372
1439
|
this._securityContext = "authentication scheme";
|
|
1373
1440
|
this._securityStatus = 1;
|
|
1374
|
-
return
|
|
1441
|
+
return true;
|
|
1375
1442
|
}
|
|
1376
1443
|
}
|
|
1377
1444
|
|
|
1378
1445
|
this._rfbInitState = 'Authentication';
|
|
1379
1446
|
Log.Debug('Authenticating using scheme: ' + this._rfbAuthScheme);
|
|
1380
1447
|
|
|
1381
|
-
return
|
|
1448
|
+
return true;
|
|
1382
1449
|
}
|
|
1383
1450
|
|
|
1384
1451
|
_handleSecurityReason() {
|
|
@@ -1428,7 +1495,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1428
1495
|
this._rfbCredentials.username +
|
|
1429
1496
|
this._rfbCredentials.target;
|
|
1430
1497
|
this._sock.sendString(xvpAuthStr);
|
|
1431
|
-
this._rfbAuthScheme =
|
|
1498
|
+
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
1432
1499
|
return this._negotiateAuthentication();
|
|
1433
1500
|
}
|
|
1434
1501
|
|
|
@@ -1486,49 +1553,66 @@ export default class RFB extends EventTargetMixin {
|
|
|
1486
1553
|
subtypes.push(this._sock.rQshift32());
|
|
1487
1554
|
}
|
|
1488
1555
|
|
|
1489
|
-
//
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
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
|
+
}
|
|
1496
1569
|
}
|
|
1497
|
-
}
|
|
1498
1570
|
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
if (this._rfbCredentials.username === undefined ||
|
|
1502
|
-
this._rfbCredentials.password === undefined) {
|
|
1503
|
-
this.dispatchEvent(new CustomEvent(
|
|
1504
|
-
"credentialsrequired",
|
|
1505
|
-
{ detail: { types: ["username", "password"] } }));
|
|
1506
|
-
return false;
|
|
1571
|
+
if (this._rfbAuthScheme === -1) {
|
|
1572
|
+
return this._fail("Unsupported security types (types: " + subtypes + ")");
|
|
1507
1573
|
}
|
|
1508
1574
|
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
(user.length >> 24) & 0xFF,
|
|
1514
|
-
(user.length >> 16) & 0xFF,
|
|
1515
|
-
(user.length >> 8) & 0xFF,
|
|
1516
|
-
user.length & 0xFF
|
|
1517
|
-
]);
|
|
1518
|
-
this._sock.send([
|
|
1519
|
-
(pass.length >> 24) & 0xFF,
|
|
1520
|
-
(pass.length >> 16) & 0xFF,
|
|
1521
|
-
(pass.length >> 8) & 0xFF,
|
|
1522
|
-
pass.length & 0xFF
|
|
1523
|
-
]);
|
|
1524
|
-
this._sock.sendString(user);
|
|
1525
|
-
this._sock.sendString(pass);
|
|
1575
|
+
this._sock.send([this._rfbAuthScheme >> 24,
|
|
1576
|
+
this._rfbAuthScheme >> 16,
|
|
1577
|
+
this._rfbAuthScheme >> 8,
|
|
1578
|
+
this._rfbAuthScheme]);
|
|
1526
1579
|
|
|
1527
|
-
this.
|
|
1580
|
+
this._rfbVeNCryptState == 4;
|
|
1528
1581
|
return true;
|
|
1529
1582
|
}
|
|
1530
1583
|
}
|
|
1531
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
|
+
|
|
1532
1616
|
_negotiateStdVNCAuth() {
|
|
1533
1617
|
if (this._sock.rQwait("auth challenge", 16)) { return false; }
|
|
1534
1618
|
|
|
@@ -1655,7 +1739,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1655
1739
|
this._rfbCredentials.ardCredentials = encrypted;
|
|
1656
1740
|
this._rfbCredentials.ardPublicKey = clientPublicKey;
|
|
1657
1741
|
|
|
1658
|
-
|
|
1742
|
+
this._resumeAuthentication();
|
|
1659
1743
|
}
|
|
1660
1744
|
|
|
1661
1745
|
_negotiateTightUnixAuth() {
|
|
@@ -1765,12 +1849,12 @@ export default class RFB extends EventTargetMixin {
|
|
|
1765
1849
|
case 'STDVNOAUTH__': // no auth
|
|
1766
1850
|
this._rfbInitState = 'SecurityResult';
|
|
1767
1851
|
return true;
|
|
1768
|
-
case 'STDVVNCAUTH_':
|
|
1769
|
-
this._rfbAuthScheme =
|
|
1770
|
-
return
|
|
1771
|
-
case 'TGHTULGNAUTH':
|
|
1772
|
-
this._rfbAuthScheme =
|
|
1773
|
-
return
|
|
1852
|
+
case 'STDVVNCAUTH_':
|
|
1853
|
+
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
1854
|
+
return true;
|
|
1855
|
+
case 'TGHTULGNAUTH':
|
|
1856
|
+
this._rfbAuthScheme = securityTypeUnixLogon;
|
|
1857
|
+
return true;
|
|
1774
1858
|
default:
|
|
1775
1859
|
return this._fail("Unsupported tiny auth scheme " +
|
|
1776
1860
|
"(scheme: " + authType + ")");
|
|
@@ -1807,7 +1891,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1807
1891
|
}).then(() => {
|
|
1808
1892
|
this.dispatchEvent(new CustomEvent('securityresult'));
|
|
1809
1893
|
this._rfbInitState = "SecurityResult";
|
|
1810
|
-
|
|
1894
|
+
return true;
|
|
1811
1895
|
}).finally(() => {
|
|
1812
1896
|
this._rfbRSAAESAuthenticationState.removeEventListener(
|
|
1813
1897
|
"serververification", this._eventHandlers.handleRSAAESServerVerification);
|
|
@@ -1821,33 +1905,32 @@ export default class RFB extends EventTargetMixin {
|
|
|
1821
1905
|
|
|
1822
1906
|
_negotiateAuthentication() {
|
|
1823
1907
|
switch (this._rfbAuthScheme) {
|
|
1824
|
-
case
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
return true;
|
|
1828
|
-
}
|
|
1829
|
-
this._rfbInitState = 'ClientInitialisation';
|
|
1830
|
-
return this._initMsg();
|
|
1908
|
+
case securityTypeNone:
|
|
1909
|
+
this._rfbInitState = 'SecurityResult';
|
|
1910
|
+
return true;
|
|
1831
1911
|
|
|
1832
|
-
case
|
|
1912
|
+
case securityTypeXVP:
|
|
1833
1913
|
return this._negotiateXvpAuth();
|
|
1834
1914
|
|
|
1835
|
-
case
|
|
1915
|
+
case securityTypeARD:
|
|
1836
1916
|
return this._negotiateARDAuth();
|
|
1837
1917
|
|
|
1838
|
-
case
|
|
1918
|
+
case securityTypeVNCAuth:
|
|
1839
1919
|
return this._negotiateStdVNCAuth();
|
|
1840
1920
|
|
|
1841
|
-
case
|
|
1921
|
+
case securityTypeTight:
|
|
1842
1922
|
return this._negotiateTightAuth();
|
|
1843
1923
|
|
|
1844
|
-
case
|
|
1924
|
+
case securityTypeVeNCrypt:
|
|
1845
1925
|
return this._negotiateVeNCryptAuth();
|
|
1846
1926
|
|
|
1847
|
-
case
|
|
1927
|
+
case securityTypePlain:
|
|
1928
|
+
return this._negotiatePlainAuth();
|
|
1929
|
+
|
|
1930
|
+
case securityTypeUnixLogon:
|
|
1848
1931
|
return this._negotiateTightUnixAuth();
|
|
1849
1932
|
|
|
1850
|
-
case
|
|
1933
|
+
case securityTypeRA2ne:
|
|
1851
1934
|
return this._negotiateRA2neAuth();
|
|
1852
1935
|
|
|
1853
1936
|
default:
|
|
@@ -1857,6 +1940,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
1857
1940
|
}
|
|
1858
1941
|
|
|
1859
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
|
+
|
|
1860
1950
|
if (this._sock.rQwait('VNC auth response ', 4)) { return false; }
|
|
1861
1951
|
|
|
1862
1952
|
const status = this._sock.rQshift32();
|
|
@@ -1864,13 +1954,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
1864
1954
|
if (status === 0) { // OK
|
|
1865
1955
|
this._rfbInitState = 'ClientInitialisation';
|
|
1866
1956
|
Log.Debug('Authentication OK');
|
|
1867
|
-
return
|
|
1957
|
+
return true;
|
|
1868
1958
|
} else {
|
|
1869
1959
|
if (this._rfbVersion >= 3.8) {
|
|
1870
1960
|
this._rfbInitState = "SecurityReason";
|
|
1871
1961
|
this._securityContext = "security result";
|
|
1872
1962
|
this._securityStatus = status;
|
|
1873
|
-
return
|
|
1963
|
+
return true;
|
|
1874
1964
|
} else {
|
|
1875
1965
|
this.dispatchEvent(new CustomEvent(
|
|
1876
1966
|
"securityfailure",
|
|
@@ -2046,6 +2136,14 @@ export default class RFB extends EventTargetMixin {
|
|
|
2046
2136
|
}
|
|
2047
2137
|
}
|
|
2048
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
|
+
|
|
2049
2147
|
_handleSetColourMapMsg() {
|
|
2050
2148
|
Log.Debug("SetColorMapEntries");
|
|
2051
2149
|
|
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;
|