@novnc/novnc 1.3.0-g98664c7 → 1.3.0-gbdc0bbb
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/rfb.js +275 -77
- package/core/util/md5.js +79 -0
- package/docs/API.md +61 -0
- package/lib/base64.js +20 -35
- package/lib/decoders/copyrect.js +1 -12
- package/lib/decoders/hextile.js +12 -44
- package/lib/decoders/jpeg.js +1 -44
- package/lib/decoders/raw.js +5 -22
- package/lib/decoders/rre.js +1 -16
- 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 +48 -88
- package/lib/input/keysym.js +15 -272
- 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 +2 -170
- package/lib/ra2.js +37 -261
- package/lib/rfb.js +578 -947
- 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 +1 -14
- package/lib/util/int.js +1 -2
- package/lib/util/logging.js +1 -19
- package/lib/util/md5.js +83 -0
- 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/rfb.js
CHANGED
|
@@ -26,6 +26,7 @@ import KeyTable from "./input/keysym.js";
|
|
|
26
26
|
import XtScancode from "./input/xtscancodes.js";
|
|
27
27
|
import { encodings } from "./encodings.js";
|
|
28
28
|
import RSAAESAuthenticationState from "./ra2.js";
|
|
29
|
+
import { MD5 } from "./util/md5.js";
|
|
29
30
|
|
|
30
31
|
import RawDecoder from "./decoders/raw.js";
|
|
31
32
|
import CopyRectDecoder from "./decoders/copyrect.js";
|
|
@@ -53,6 +54,21 @@ const GESTURE_SCRLSENS = 50;
|
|
|
53
54
|
const DOUBLE_TAP_TIMEOUT = 1000;
|
|
54
55
|
const DOUBLE_TAP_THRESHOLD = 50;
|
|
55
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
|
+
|
|
56
72
|
// Extended clipboard pseudo-encoding formats
|
|
57
73
|
const extendedClipboardFormatText = 1;
|
|
58
74
|
/*eslint-disable no-unused-vars */
|
|
@@ -78,6 +94,12 @@ export default class RFB extends EventTargetMixin {
|
|
|
78
94
|
throw new Error("Must specify URL, WebSocket or RTCDataChannel");
|
|
79
95
|
}
|
|
80
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
|
+
|
|
81
103
|
super();
|
|
82
104
|
|
|
83
105
|
this._target = target;
|
|
@@ -395,7 +417,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
395
417
|
|
|
396
418
|
sendCredentials(creds) {
|
|
397
419
|
this._rfbCredentials = creds;
|
|
398
|
-
|
|
420
|
+
this._resumeAuthentication();
|
|
399
421
|
}
|
|
400
422
|
|
|
401
423
|
sendCtrlAltDel() {
|
|
@@ -478,6 +500,18 @@ export default class RFB extends EventTargetMixin {
|
|
|
478
500
|
}
|
|
479
501
|
}
|
|
480
502
|
|
|
503
|
+
getImageData() {
|
|
504
|
+
return this._display.getImageData();
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
toDataURL(type, encoderOptions) {
|
|
508
|
+
return this._display.toDataURL(type, encoderOptions);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
toBlob(callback, type, quality) {
|
|
512
|
+
return this._display.toBlob(callback, type, quality);
|
|
513
|
+
}
|
|
514
|
+
|
|
481
515
|
// ===== PRIVATE METHODS =====
|
|
482
516
|
|
|
483
517
|
_connect() {
|
|
@@ -915,8 +949,15 @@ export default class RFB extends EventTargetMixin {
|
|
|
915
949
|
}
|
|
916
950
|
}
|
|
917
951
|
break;
|
|
952
|
+
case 'connecting':
|
|
953
|
+
while (this._rfbConnectionState === 'connecting') {
|
|
954
|
+
if (!this._initMsg()) {
|
|
955
|
+
break;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
break;
|
|
918
959
|
default:
|
|
919
|
-
|
|
960
|
+
Log.Error("Got data while in an invalid state");
|
|
920
961
|
break;
|
|
921
962
|
}
|
|
922
963
|
}
|
|
@@ -1288,13 +1329,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
1288
1329
|
break;
|
|
1289
1330
|
case "003.003":
|
|
1290
1331
|
case "003.006": // UltraVNC
|
|
1291
|
-
case "003.889": // Apple Remote Desktop
|
|
1292
1332
|
this._rfbVersion = 3.3;
|
|
1293
1333
|
break;
|
|
1294
1334
|
case "003.007":
|
|
1295
1335
|
this._rfbVersion = 3.7;
|
|
1296
1336
|
break;
|
|
1297
1337
|
case "003.008":
|
|
1338
|
+
case "003.889": // Apple Remote Desktop
|
|
1298
1339
|
case "004.000": // Intel AMT KVM
|
|
1299
1340
|
case "004.001": // RealVNC 4.6
|
|
1300
1341
|
case "005.000": // RealVNC 5.3
|
|
@@ -1325,6 +1366,21 @@ export default class RFB extends EventTargetMixin {
|
|
|
1325
1366
|
this._rfbInitState = 'Security';
|
|
1326
1367
|
}
|
|
1327
1368
|
|
|
1369
|
+
_isSupportedSecurityType(type) {
|
|
1370
|
+
const clientTypes = [
|
|
1371
|
+
securityTypeNone,
|
|
1372
|
+
securityTypeVNCAuth,
|
|
1373
|
+
securityTypeRA2ne,
|
|
1374
|
+
securityTypeTight,
|
|
1375
|
+
securityTypeVeNCrypt,
|
|
1376
|
+
securityTypeXVP,
|
|
1377
|
+
securityTypeARD,
|
|
1378
|
+
securityTypePlain,
|
|
1379
|
+
];
|
|
1380
|
+
|
|
1381
|
+
return clientTypes.includes(type);
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1328
1384
|
_negotiateSecurity() {
|
|
1329
1385
|
if (this._rfbVersion >= 3.7) {
|
|
1330
1386
|
// Server sends supported list, client decides
|
|
@@ -1335,26 +1391,23 @@ export default class RFB extends EventTargetMixin {
|
|
|
1335
1391
|
this._rfbInitState = "SecurityReason";
|
|
1336
1392
|
this._securityContext = "no security types";
|
|
1337
1393
|
this._securityStatus = 1;
|
|
1338
|
-
return
|
|
1394
|
+
return true;
|
|
1339
1395
|
}
|
|
1340
1396
|
|
|
1341
1397
|
const types = this._sock.rQshiftBytes(numTypes);
|
|
1342
1398
|
Log.Debug("Server security types: " + types);
|
|
1343
1399
|
|
|
1344
|
-
// Look for
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
this.
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
} else if (types.includes(19)) {
|
|
1356
|
-
this._rfbAuthScheme = 19; // VeNCrypt Auth
|
|
1357
|
-
} else {
|
|
1400
|
+
// Look for a matching security type in the order that the
|
|
1401
|
+
// server prefers
|
|
1402
|
+
this._rfbAuthScheme = -1;
|
|
1403
|
+
for (let type of types) {
|
|
1404
|
+
if (this._isSupportedSecurityType(type)) {
|
|
1405
|
+
this._rfbAuthScheme = type;
|
|
1406
|
+
break;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
if (this._rfbAuthScheme === -1) {
|
|
1358
1411
|
return this._fail("Unsupported security types (types: " + types + ")");
|
|
1359
1412
|
}
|
|
1360
1413
|
|
|
@@ -1368,14 +1421,14 @@ export default class RFB extends EventTargetMixin {
|
|
|
1368
1421
|
this._rfbInitState = "SecurityReason";
|
|
1369
1422
|
this._securityContext = "authentication scheme";
|
|
1370
1423
|
this._securityStatus = 1;
|
|
1371
|
-
return
|
|
1424
|
+
return true;
|
|
1372
1425
|
}
|
|
1373
1426
|
}
|
|
1374
1427
|
|
|
1375
1428
|
this._rfbInitState = 'Authentication';
|
|
1376
1429
|
Log.Debug('Authenticating using scheme: ' + this._rfbAuthScheme);
|
|
1377
1430
|
|
|
1378
|
-
return
|
|
1431
|
+
return true;
|
|
1379
1432
|
}
|
|
1380
1433
|
|
|
1381
1434
|
_handleSecurityReason() {
|
|
@@ -1425,7 +1478,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1425
1478
|
this._rfbCredentials.username +
|
|
1426
1479
|
this._rfbCredentials.target;
|
|
1427
1480
|
this._sock.sendString(xvpAuthStr);
|
|
1428
|
-
this._rfbAuthScheme =
|
|
1481
|
+
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
1429
1482
|
return this._negotiateAuthentication();
|
|
1430
1483
|
}
|
|
1431
1484
|
|
|
@@ -1483,49 +1536,66 @@ export default class RFB extends EventTargetMixin {
|
|
|
1483
1536
|
subtypes.push(this._sock.rQshift32());
|
|
1484
1537
|
}
|
|
1485
1538
|
|
|
1486
|
-
//
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1539
|
+
// Look for a matching security type in the order that the
|
|
1540
|
+
// server prefers
|
|
1541
|
+
this._rfbAuthScheme = -1;
|
|
1542
|
+
for (let type of subtypes) {
|
|
1543
|
+
// Avoid getting in to a loop
|
|
1544
|
+
if (type === securityTypeVeNCrypt) {
|
|
1545
|
+
continue;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
if (this._isSupportedSecurityType(type)) {
|
|
1549
|
+
this._rfbAuthScheme = type;
|
|
1550
|
+
break;
|
|
1551
|
+
}
|
|
1493
1552
|
}
|
|
1494
|
-
}
|
|
1495
1553
|
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
if (this._rfbCredentials.username === undefined ||
|
|
1499
|
-
this._rfbCredentials.password === undefined) {
|
|
1500
|
-
this.dispatchEvent(new CustomEvent(
|
|
1501
|
-
"credentialsrequired",
|
|
1502
|
-
{ detail: { types: ["username", "password"] } }));
|
|
1503
|
-
return false;
|
|
1554
|
+
if (this._rfbAuthScheme === -1) {
|
|
1555
|
+
return this._fail("Unsupported security types (types: " + subtypes + ")");
|
|
1504
1556
|
}
|
|
1505
1557
|
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
(user.length >> 24) & 0xFF,
|
|
1511
|
-
(user.length >> 16) & 0xFF,
|
|
1512
|
-
(user.length >> 8) & 0xFF,
|
|
1513
|
-
user.length & 0xFF
|
|
1514
|
-
]);
|
|
1515
|
-
this._sock.send([
|
|
1516
|
-
(pass.length >> 24) & 0xFF,
|
|
1517
|
-
(pass.length >> 16) & 0xFF,
|
|
1518
|
-
(pass.length >> 8) & 0xFF,
|
|
1519
|
-
pass.length & 0xFF
|
|
1520
|
-
]);
|
|
1521
|
-
this._sock.sendString(user);
|
|
1522
|
-
this._sock.sendString(pass);
|
|
1558
|
+
this._sock.send([this._rfbAuthScheme >> 24,
|
|
1559
|
+
this._rfbAuthScheme >> 16,
|
|
1560
|
+
this._rfbAuthScheme >> 8,
|
|
1561
|
+
this._rfbAuthScheme]);
|
|
1523
1562
|
|
|
1524
|
-
this.
|
|
1563
|
+
this._rfbVeNCryptState == 4;
|
|
1525
1564
|
return true;
|
|
1526
1565
|
}
|
|
1527
1566
|
}
|
|
1528
1567
|
|
|
1568
|
+
_negotiatePlainAuth() {
|
|
1569
|
+
if (this._rfbCredentials.username === undefined ||
|
|
1570
|
+
this._rfbCredentials.password === undefined) {
|
|
1571
|
+
this.dispatchEvent(new CustomEvent(
|
|
1572
|
+
"credentialsrequired",
|
|
1573
|
+
{ detail: { types: ["username", "password"] } }));
|
|
1574
|
+
return false;
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
const user = encodeUTF8(this._rfbCredentials.username);
|
|
1578
|
+
const pass = encodeUTF8(this._rfbCredentials.password);
|
|
1579
|
+
|
|
1580
|
+
this._sock.send([
|
|
1581
|
+
(user.length >> 24) & 0xFF,
|
|
1582
|
+
(user.length >> 16) & 0xFF,
|
|
1583
|
+
(user.length >> 8) & 0xFF,
|
|
1584
|
+
user.length & 0xFF
|
|
1585
|
+
]);
|
|
1586
|
+
this._sock.send([
|
|
1587
|
+
(pass.length >> 24) & 0xFF,
|
|
1588
|
+
(pass.length >> 16) & 0xFF,
|
|
1589
|
+
(pass.length >> 8) & 0xFF,
|
|
1590
|
+
pass.length & 0xFF
|
|
1591
|
+
]);
|
|
1592
|
+
this._sock.sendString(user);
|
|
1593
|
+
this._sock.sendString(pass);
|
|
1594
|
+
|
|
1595
|
+
this._rfbInitState = "SecurityResult";
|
|
1596
|
+
return true;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1529
1599
|
_negotiateStdVNCAuth() {
|
|
1530
1600
|
if (this._sock.rQwait("auth challenge", 16)) { return false; }
|
|
1531
1601
|
|
|
@@ -1544,6 +1614,117 @@ export default class RFB extends EventTargetMixin {
|
|
|
1544
1614
|
return true;
|
|
1545
1615
|
}
|
|
1546
1616
|
|
|
1617
|
+
_negotiateARDAuth() {
|
|
1618
|
+
|
|
1619
|
+
if (this._rfbCredentials.username === undefined ||
|
|
1620
|
+
this._rfbCredentials.password === undefined) {
|
|
1621
|
+
this.dispatchEvent(new CustomEvent(
|
|
1622
|
+
"credentialsrequired",
|
|
1623
|
+
{ detail: { types: ["username", "password"] } }));
|
|
1624
|
+
return false;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
if (this._rfbCredentials.ardPublicKey != undefined &&
|
|
1628
|
+
this._rfbCredentials.ardCredentials != undefined) {
|
|
1629
|
+
// if the async web crypto is done return the results
|
|
1630
|
+
this._sock.send(this._rfbCredentials.ardCredentials);
|
|
1631
|
+
this._sock.send(this._rfbCredentials.ardPublicKey);
|
|
1632
|
+
this._rfbCredentials.ardCredentials = null;
|
|
1633
|
+
this._rfbCredentials.ardPublicKey = null;
|
|
1634
|
+
this._rfbInitState = "SecurityResult";
|
|
1635
|
+
return true;
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
if (this._sock.rQwait("read ard", 4)) { return false; }
|
|
1639
|
+
|
|
1640
|
+
let generator = this._sock.rQshiftBytes(2); // DH base generator value
|
|
1641
|
+
|
|
1642
|
+
let keyLength = this._sock.rQshift16();
|
|
1643
|
+
|
|
1644
|
+
if (this._sock.rQwait("read ard keylength", keyLength*2, 4)) { return false; }
|
|
1645
|
+
|
|
1646
|
+
// read the server values
|
|
1647
|
+
let prime = this._sock.rQshiftBytes(keyLength); // predetermined prime modulus
|
|
1648
|
+
let serverPublicKey = this._sock.rQshiftBytes(keyLength); // other party's public key
|
|
1649
|
+
|
|
1650
|
+
let clientPrivateKey = window.crypto.getRandomValues(new Uint8Array(keyLength));
|
|
1651
|
+
let padding = Array.from(window.crypto.getRandomValues(new Uint8Array(64)), byte => String.fromCharCode(65+byte%26)).join('');
|
|
1652
|
+
|
|
1653
|
+
this._negotiateARDAuthAsync(generator, keyLength, prime, serverPublicKey, clientPrivateKey, padding);
|
|
1654
|
+
|
|
1655
|
+
return false;
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
_modPow(base, exponent, modulus) {
|
|
1659
|
+
|
|
1660
|
+
let baseHex = "0x"+Array.from(base, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
|
|
1661
|
+
let exponentHex = "0x"+Array.from(exponent, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
|
|
1662
|
+
let modulusHex = "0x"+Array.from(modulus, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
|
|
1663
|
+
|
|
1664
|
+
let b = BigInt(baseHex);
|
|
1665
|
+
let e = BigInt(exponentHex);
|
|
1666
|
+
let m = BigInt(modulusHex);
|
|
1667
|
+
let r = 1n;
|
|
1668
|
+
b = b % m;
|
|
1669
|
+
while (e > 0) {
|
|
1670
|
+
if (e % 2n === 1n) {
|
|
1671
|
+
r = (r * b) % m;
|
|
1672
|
+
}
|
|
1673
|
+
e = e / 2n;
|
|
1674
|
+
b = (b * b) % m;
|
|
1675
|
+
}
|
|
1676
|
+
let hexResult = r.toString(16);
|
|
1677
|
+
|
|
1678
|
+
while (hexResult.length/2<exponent.length || (hexResult.length%2 != 0)) {
|
|
1679
|
+
hexResult = "0"+hexResult;
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
let bytesResult = [];
|
|
1683
|
+
for (let c = 0; c < hexResult.length; c += 2) {
|
|
1684
|
+
bytesResult.push(parseInt(hexResult.substr(c, 2), 16));
|
|
1685
|
+
}
|
|
1686
|
+
return bytesResult;
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
async _aesEcbEncrypt(string, key) {
|
|
1690
|
+
// perform AES-ECB blocks
|
|
1691
|
+
let keyString = Array.from(key, byte => String.fromCharCode(byte)).join('');
|
|
1692
|
+
let aesKey = await window.crypto.subtle.importKey("raw", MD5(keyString), {name: "AES-CBC"}, false, ["encrypt"]);
|
|
1693
|
+
let data = new Uint8Array(string.length);
|
|
1694
|
+
for (let i = 0; i < string.length; ++i) {
|
|
1695
|
+
data[i] = string.charCodeAt(i);
|
|
1696
|
+
}
|
|
1697
|
+
let encrypted = new Uint8Array(data.length);
|
|
1698
|
+
for (let i=0;i<data.length;i+=16) {
|
|
1699
|
+
let block = data.slice(i, i+16);
|
|
1700
|
+
let encryptedBlock = await window.crypto.subtle.encrypt({name: "AES-CBC", iv: block},
|
|
1701
|
+
aesKey, new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
|
1702
|
+
);
|
|
1703
|
+
encrypted.set((new Uint8Array(encryptedBlock)).slice(0, 16), i);
|
|
1704
|
+
}
|
|
1705
|
+
return encrypted;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
async _negotiateARDAuthAsync(generator, keyLength, prime, serverPublicKey, clientPrivateKey, padding) {
|
|
1709
|
+
// calculate the DH keys
|
|
1710
|
+
let clientPublicKey = this._modPow(generator, clientPrivateKey, prime);
|
|
1711
|
+
let sharedKey = this._modPow(serverPublicKey, clientPrivateKey, prime);
|
|
1712
|
+
|
|
1713
|
+
let username = encodeUTF8(this._rfbCredentials.username).substring(0, 63);
|
|
1714
|
+
let password = encodeUTF8(this._rfbCredentials.password).substring(0, 63);
|
|
1715
|
+
|
|
1716
|
+
let paddedUsername = username + '\0' + padding.substring(0, 63);
|
|
1717
|
+
let paddedPassword = password + '\0' + padding.substring(0, 63);
|
|
1718
|
+
let credentials = paddedUsername.substring(0, 64) + paddedPassword.substring(0, 64);
|
|
1719
|
+
|
|
1720
|
+
let encrypted = await this._aesEcbEncrypt(credentials, sharedKey);
|
|
1721
|
+
|
|
1722
|
+
this._rfbCredentials.ardCredentials = encrypted;
|
|
1723
|
+
this._rfbCredentials.ardPublicKey = clientPublicKey;
|
|
1724
|
+
|
|
1725
|
+
this._resumeAuthentication();
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1547
1728
|
_negotiateTightUnixAuth() {
|
|
1548
1729
|
if (this._rfbCredentials.username === undefined ||
|
|
1549
1730
|
this._rfbCredentials.password === undefined) {
|
|
@@ -1651,12 +1832,12 @@ export default class RFB extends EventTargetMixin {
|
|
|
1651
1832
|
case 'STDVNOAUTH__': // no auth
|
|
1652
1833
|
this._rfbInitState = 'SecurityResult';
|
|
1653
1834
|
return true;
|
|
1654
|
-
case 'STDVVNCAUTH_':
|
|
1655
|
-
this._rfbAuthScheme =
|
|
1656
|
-
return
|
|
1657
|
-
case 'TGHTULGNAUTH':
|
|
1658
|
-
this._rfbAuthScheme =
|
|
1659
|
-
return
|
|
1835
|
+
case 'STDVVNCAUTH_':
|
|
1836
|
+
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
1837
|
+
return true;
|
|
1838
|
+
case 'TGHTULGNAUTH':
|
|
1839
|
+
this._rfbAuthScheme = securityTypeUnixLogon;
|
|
1840
|
+
return true;
|
|
1660
1841
|
default:
|
|
1661
1842
|
return this._fail("Unsupported tiny auth scheme " +
|
|
1662
1843
|
"(scheme: " + authType + ")");
|
|
@@ -1693,7 +1874,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1693
1874
|
}).then(() => {
|
|
1694
1875
|
this.dispatchEvent(new CustomEvent('securityresult'));
|
|
1695
1876
|
this._rfbInitState = "SecurityResult";
|
|
1696
|
-
|
|
1877
|
+
return true;
|
|
1697
1878
|
}).finally(() => {
|
|
1698
1879
|
this._rfbRSAAESAuthenticationState.removeEventListener(
|
|
1699
1880
|
"serververification", this._eventHandlers.handleRSAAESServerVerification);
|
|
@@ -1707,30 +1888,32 @@ export default class RFB extends EventTargetMixin {
|
|
|
1707
1888
|
|
|
1708
1889
|
_negotiateAuthentication() {
|
|
1709
1890
|
switch (this._rfbAuthScheme) {
|
|
1710
|
-
case
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
return true;
|
|
1714
|
-
}
|
|
1715
|
-
this._rfbInitState = 'ClientInitialisation';
|
|
1716
|
-
return this._initMsg();
|
|
1891
|
+
case securityTypeNone:
|
|
1892
|
+
this._rfbInitState = 'SecurityResult';
|
|
1893
|
+
return true;
|
|
1717
1894
|
|
|
1718
|
-
case
|
|
1895
|
+
case securityTypeXVP:
|
|
1719
1896
|
return this._negotiateXvpAuth();
|
|
1720
1897
|
|
|
1721
|
-
case
|
|
1898
|
+
case securityTypeARD:
|
|
1899
|
+
return this._negotiateARDAuth();
|
|
1900
|
+
|
|
1901
|
+
case securityTypeVNCAuth:
|
|
1722
1902
|
return this._negotiateStdVNCAuth();
|
|
1723
1903
|
|
|
1724
|
-
case
|
|
1904
|
+
case securityTypeTight:
|
|
1725
1905
|
return this._negotiateTightAuth();
|
|
1726
1906
|
|
|
1727
|
-
case
|
|
1907
|
+
case securityTypeVeNCrypt:
|
|
1728
1908
|
return this._negotiateVeNCryptAuth();
|
|
1729
1909
|
|
|
1730
|
-
case
|
|
1910
|
+
case securityTypePlain:
|
|
1911
|
+
return this._negotiatePlainAuth();
|
|
1912
|
+
|
|
1913
|
+
case securityTypeUnixLogon:
|
|
1731
1914
|
return this._negotiateTightUnixAuth();
|
|
1732
1915
|
|
|
1733
|
-
case
|
|
1916
|
+
case securityTypeRA2ne:
|
|
1734
1917
|
return this._negotiateRA2neAuth();
|
|
1735
1918
|
|
|
1736
1919
|
default:
|
|
@@ -1740,6 +1923,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
1740
1923
|
}
|
|
1741
1924
|
|
|
1742
1925
|
_handleSecurityResult() {
|
|
1926
|
+
// There is no security choice, and hence no security result
|
|
1927
|
+
// until RFB 3.7
|
|
1928
|
+
if (this._rfbVersion < 3.7) {
|
|
1929
|
+
this._rfbInitState = 'ClientInitialisation';
|
|
1930
|
+
return true;
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1743
1933
|
if (this._sock.rQwait('VNC auth response ', 4)) { return false; }
|
|
1744
1934
|
|
|
1745
1935
|
const status = this._sock.rQshift32();
|
|
@@ -1747,13 +1937,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
1747
1937
|
if (status === 0) { // OK
|
|
1748
1938
|
this._rfbInitState = 'ClientInitialisation';
|
|
1749
1939
|
Log.Debug('Authentication OK');
|
|
1750
|
-
return
|
|
1940
|
+
return true;
|
|
1751
1941
|
} else {
|
|
1752
1942
|
if (this._rfbVersion >= 3.8) {
|
|
1753
1943
|
this._rfbInitState = "SecurityReason";
|
|
1754
1944
|
this._securityContext = "security result";
|
|
1755
1945
|
this._securityStatus = status;
|
|
1756
|
-
return
|
|
1946
|
+
return true;
|
|
1757
1947
|
} else {
|
|
1758
1948
|
this.dispatchEvent(new CustomEvent(
|
|
1759
1949
|
"securityfailure",
|
|
@@ -1929,6 +2119,14 @@ export default class RFB extends EventTargetMixin {
|
|
|
1929
2119
|
}
|
|
1930
2120
|
}
|
|
1931
2121
|
|
|
2122
|
+
// Resume authentication handshake after it was paused for some
|
|
2123
|
+
// reason, e.g. waiting for a password from the user
|
|
2124
|
+
_resumeAuthentication() {
|
|
2125
|
+
// We use setTimeout() so it's run in its own context, just like
|
|
2126
|
+
// it originally did via the WebSocket's event handler
|
|
2127
|
+
setTimeout(this._initMsg.bind(this), 0);
|
|
2128
|
+
}
|
|
2129
|
+
|
|
1932
2130
|
_handleSetColourMapMsg() {
|
|
1933
2131
|
Log.Debug("SetColorMapEntries");
|
|
1934
2132
|
|
package/core/util/md5.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* noVNC: HTML5 VNC client
|
|
3
|
+
* Copyright (C) 2021 The noVNC Authors
|
|
4
|
+
* Licensed under MPL 2.0 (see LICENSE.txt)
|
|
5
|
+
*
|
|
6
|
+
* See README.md for usage and integration instructions.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* Performs MD5 hashing on a string of binary characters, returns an array of bytes
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export function MD5(d) {
|
|
14
|
+
let r = M(V(Y(X(d), 8 * d.length)));
|
|
15
|
+
return r;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function M(d) {
|
|
19
|
+
let f = new Uint8Array(d.length);
|
|
20
|
+
for (let i=0;i<d.length;i++) {
|
|
21
|
+
f[i] = d.charCodeAt(i);
|
|
22
|
+
}
|
|
23
|
+
return f;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function X(d) {
|
|
27
|
+
let r = Array(d.length >> 2);
|
|
28
|
+
for (let m = 0; m < r.length; m++) r[m] = 0;
|
|
29
|
+
for (let m = 0; m < 8 * d.length; m += 8) r[m >> 5] |= (255 & d.charCodeAt(m / 8)) << m % 32;
|
|
30
|
+
return r;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function V(d) {
|
|
34
|
+
let r = "";
|
|
35
|
+
for (let m = 0; m < 32 * d.length; m += 8) r += String.fromCharCode(d[m >> 5] >>> m % 32 & 255);
|
|
36
|
+
return r;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function Y(d, g) {
|
|
40
|
+
d[g >> 5] |= 128 << g % 32, d[14 + (g + 64 >>> 9 << 4)] = g;
|
|
41
|
+
let m = 1732584193, f = -271733879, r = -1732584194, i = 271733878;
|
|
42
|
+
for (let n = 0; n < d.length; n += 16) {
|
|
43
|
+
let h = m,
|
|
44
|
+
t = f,
|
|
45
|
+
g = r,
|
|
46
|
+
e = i;
|
|
47
|
+
f = ii(f = ii(f = ii(f = ii(f = hh(f = hh(f = hh(f = hh(f = gg(f = gg(f = gg(f = gg(f = ff(f = ff(f = ff(f = ff(f, r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 0], 7, -680876936), f, r, d[n + 1], 12, -389564586), m, f, d[n + 2], 17, 606105819), i, m, d[n + 3], 22, -1044525330), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 4], 7, -176418897), f, r, d[n + 5], 12, 1200080426), m, f, d[n + 6], 17, -1473231341), i, m, d[n + 7], 22, -45705983), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 8], 7, 1770035416), f, r, d[n + 9], 12, -1958414417), m, f, d[n + 10], 17, -42063), i, m, d[n + 11], 22, -1990404162), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 12], 7, 1804603682), f, r, d[n + 13], 12, -40341101), m, f, d[n + 14], 17, -1502002290), i, m, d[n + 15], 22, 1236535329), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 1], 5, -165796510), f, r, d[n + 6], 9, -1069501632), m, f, d[n + 11], 14, 643717713), i, m, d[n + 0], 20, -373897302), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 5], 5, -701558691), f, r, d[n + 10], 9, 38016083), m, f, d[n + 15], 14, -660478335), i, m, d[n + 4], 20, -405537848), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 9], 5, 568446438), f, r, d[n + 14], 9, -1019803690), m, f, d[n + 3], 14, -187363961), i, m, d[n + 8], 20, 1163531501), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 13], 5, -1444681467), f, r, d[n + 2], 9, -51403784), m, f, d[n + 7], 14, 1735328473), i, m, d[n + 12], 20, -1926607734), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 5], 4, -378558), f, r, d[n + 8], 11, -2022574463), m, f, d[n + 11], 16, 1839030562), i, m, d[n + 14], 23, -35309556), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 1], 4, -1530992060), f, r, d[n + 4], 11, 1272893353), m, f, d[n + 7], 16, -155497632), i, m, d[n + 10], 23, -1094730640), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 13], 4, 681279174), f, r, d[n + 0], 11, -358537222), m, f, d[n + 3], 16, -722521979), i, m, d[n + 6], 23, 76029189), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 9], 4, -640364487), f, r, d[n + 12], 11, -421815835), m, f, d[n + 15], 16, 530742520), i, m, d[n + 2], 23, -995338651), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 0], 6, -198630844), f, r, d[n + 7], 10, 1126891415), m, f, d[n + 14], 15, -1416354905), i, m, d[n + 5], 21, -57434055), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 12], 6, 1700485571), f, r, d[n + 3], 10, -1894986606), m, f, d[n + 10], 15, -1051523), i, m, d[n + 1], 21, -2054922799), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 8], 6, 1873313359), f, r, d[n + 15], 10, -30611744), m, f, d[n + 6], 15, -1560198380), i, m, d[n + 13], 21, 1309151649), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 4], 6, -145523070), f, r, d[n + 11], 10, -1120210379), m, f, d[n + 2], 15, 718787259), i, m, d[n + 9], 21, -343485551), m = add(m, h), f = add(f, t), r = add(r, g), i = add(i, e);
|
|
48
|
+
}
|
|
49
|
+
return Array(m, f, r, i);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function cmn(d, g, m, f, r, i) {
|
|
53
|
+
return add(rol(add(add(g, d), add(f, i)), r), m);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function ff(d, g, m, f, r, i, n) {
|
|
57
|
+
return cmn(g & m | ~g & f, d, g, r, i, n);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function gg(d, g, m, f, r, i, n) {
|
|
61
|
+
return cmn(g & f | m & ~f, d, g, r, i, n);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function hh(d, g, m, f, r, i, n) {
|
|
65
|
+
return cmn(g ^ m ^ f, d, g, r, i, n);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function ii(d, g, m, f, r, i, n) {
|
|
69
|
+
return cmn(m ^ (g | ~f), d, g, r, i, n);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function add(d, g) {
|
|
73
|
+
let m = (65535 & d) + (65535 & g);
|
|
74
|
+
return (d >> 16) + (g >> 16) + (m >> 16) << 16 | 65535 & m;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function rol(d, g) {
|
|
78
|
+
return d << g | d >>> 32 - g;
|
|
79
|
+
}
|