@novnc/novnc 1.3.0-g42ec5f3 → 1.3.0-g58dfb7d
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 +174 -82
- package/docs/API.md +61 -0
- package/lib/decoders/tightpng.js +2 -2
- package/lib/display.js +15 -0
- package/lib/ra2.js +30 -28
- package/lib/rfb.js +201 -108
- package/package.json +1 -1
- package/core/util/bigint-mod-arith.js +0 -283
- package/lib/util/bigint-mod-arith.js +0 -339
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
|
@@ -27,7 +27,6 @@ import XtScancode from "./input/xtscancodes.js";
|
|
|
27
27
|
import { encodings } from "./encodings.js";
|
|
28
28
|
import RSAAESAuthenticationState from "./ra2.js";
|
|
29
29
|
import { MD5 } from "./util/md5.js";
|
|
30
|
-
import { modPow } from "./util/bigint-mod-arith.js";
|
|
31
30
|
|
|
32
31
|
import RawDecoder from "./decoders/raw.js";
|
|
33
32
|
import CopyRectDecoder from "./decoders/copyrect.js";
|
|
@@ -55,6 +54,21 @@ const GESTURE_SCRLSENS = 50;
|
|
|
55
54
|
const DOUBLE_TAP_TIMEOUT = 1000;
|
|
56
55
|
const DOUBLE_TAP_THRESHOLD = 50;
|
|
57
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
|
+
|
|
58
72
|
// Extended clipboard pseudo-encoding formats
|
|
59
73
|
const extendedClipboardFormatText = 1;
|
|
60
74
|
/*eslint-disable no-unused-vars */
|
|
@@ -80,6 +94,12 @@ export default class RFB extends EventTargetMixin {
|
|
|
80
94
|
throw new Error("Must specify URL, WebSocket or RTCDataChannel");
|
|
81
95
|
}
|
|
82
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
|
+
|
|
83
103
|
super();
|
|
84
104
|
|
|
85
105
|
this._target = target;
|
|
@@ -397,7 +417,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
397
417
|
|
|
398
418
|
sendCredentials(creds) {
|
|
399
419
|
this._rfbCredentials = creds;
|
|
400
|
-
|
|
420
|
+
this._resumeAuthentication();
|
|
401
421
|
}
|
|
402
422
|
|
|
403
423
|
sendCtrlAltDel() {
|
|
@@ -480,6 +500,18 @@ export default class RFB extends EventTargetMixin {
|
|
|
480
500
|
}
|
|
481
501
|
}
|
|
482
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
|
+
|
|
483
515
|
// ===== PRIVATE METHODS =====
|
|
484
516
|
|
|
485
517
|
_connect() {
|
|
@@ -917,8 +949,15 @@ export default class RFB extends EventTargetMixin {
|
|
|
917
949
|
}
|
|
918
950
|
}
|
|
919
951
|
break;
|
|
952
|
+
case 'connecting':
|
|
953
|
+
while (this._rfbConnectionState === 'connecting') {
|
|
954
|
+
if (!this._initMsg()) {
|
|
955
|
+
break;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
break;
|
|
920
959
|
default:
|
|
921
|
-
|
|
960
|
+
Log.Error("Got data while in an invalid state");
|
|
922
961
|
break;
|
|
923
962
|
}
|
|
924
963
|
}
|
|
@@ -1327,6 +1366,21 @@ export default class RFB extends EventTargetMixin {
|
|
|
1327
1366
|
this._rfbInitState = 'Security';
|
|
1328
1367
|
}
|
|
1329
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
|
+
|
|
1330
1384
|
_negotiateSecurity() {
|
|
1331
1385
|
if (this._rfbVersion >= 3.7) {
|
|
1332
1386
|
// Server sends supported list, client decides
|
|
@@ -1337,28 +1391,23 @@ export default class RFB extends EventTargetMixin {
|
|
|
1337
1391
|
this._rfbInitState = "SecurityReason";
|
|
1338
1392
|
this._securityContext = "no security types";
|
|
1339
1393
|
this._securityStatus = 1;
|
|
1340
|
-
return
|
|
1394
|
+
return true;
|
|
1341
1395
|
}
|
|
1342
1396
|
|
|
1343
1397
|
const types = this._sock.rQshiftBytes(numTypes);
|
|
1344
1398
|
Log.Debug("Server security types: " + types);
|
|
1345
1399
|
|
|
1346
|
-
// Look for
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
this.
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
} else if (types.includes(30)) {
|
|
1358
|
-
this._rfbAuthScheme = 30; // ARD Auth
|
|
1359
|
-
} else if (types.includes(19)) {
|
|
1360
|
-
this._rfbAuthScheme = 19; // VeNCrypt Auth
|
|
1361
|
-
} 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) {
|
|
1362
1411
|
return this._fail("Unsupported security types (types: " + types + ")");
|
|
1363
1412
|
}
|
|
1364
1413
|
|
|
@@ -1372,14 +1421,14 @@ export default class RFB extends EventTargetMixin {
|
|
|
1372
1421
|
this._rfbInitState = "SecurityReason";
|
|
1373
1422
|
this._securityContext = "authentication scheme";
|
|
1374
1423
|
this._securityStatus = 1;
|
|
1375
|
-
return
|
|
1424
|
+
return true;
|
|
1376
1425
|
}
|
|
1377
1426
|
}
|
|
1378
1427
|
|
|
1379
1428
|
this._rfbInitState = 'Authentication';
|
|
1380
1429
|
Log.Debug('Authenticating using scheme: ' + this._rfbAuthScheme);
|
|
1381
1430
|
|
|
1382
|
-
return
|
|
1431
|
+
return true;
|
|
1383
1432
|
}
|
|
1384
1433
|
|
|
1385
1434
|
_handleSecurityReason() {
|
|
@@ -1429,7 +1478,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1429
1478
|
this._rfbCredentials.username +
|
|
1430
1479
|
this._rfbCredentials.target;
|
|
1431
1480
|
this._sock.sendString(xvpAuthStr);
|
|
1432
|
-
this._rfbAuthScheme =
|
|
1481
|
+
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
1433
1482
|
return this._negotiateAuthentication();
|
|
1434
1483
|
}
|
|
1435
1484
|
|
|
@@ -1487,49 +1536,66 @@ export default class RFB extends EventTargetMixin {
|
|
|
1487
1536
|
subtypes.push(this._sock.rQshift32());
|
|
1488
1537
|
}
|
|
1489
1538
|
|
|
1490
|
-
//
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
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
|
+
}
|
|
1497
1552
|
}
|
|
1498
|
-
}
|
|
1499
1553
|
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
if (this._rfbCredentials.username === undefined ||
|
|
1503
|
-
this._rfbCredentials.password === undefined) {
|
|
1504
|
-
this.dispatchEvent(new CustomEvent(
|
|
1505
|
-
"credentialsrequired",
|
|
1506
|
-
{ detail: { types: ["username", "password"] } }));
|
|
1507
|
-
return false;
|
|
1554
|
+
if (this._rfbAuthScheme === -1) {
|
|
1555
|
+
return this._fail("Unsupported security types (types: " + subtypes + ")");
|
|
1508
1556
|
}
|
|
1509
1557
|
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
(user.length >> 24) & 0xFF,
|
|
1515
|
-
(user.length >> 16) & 0xFF,
|
|
1516
|
-
(user.length >> 8) & 0xFF,
|
|
1517
|
-
user.length & 0xFF
|
|
1518
|
-
]);
|
|
1519
|
-
this._sock.send([
|
|
1520
|
-
(pass.length >> 24) & 0xFF,
|
|
1521
|
-
(pass.length >> 16) & 0xFF,
|
|
1522
|
-
(pass.length >> 8) & 0xFF,
|
|
1523
|
-
pass.length & 0xFF
|
|
1524
|
-
]);
|
|
1525
|
-
this._sock.sendString(user);
|
|
1526
|
-
this._sock.sendString(pass);
|
|
1558
|
+
this._sock.send([this._rfbAuthScheme >> 24,
|
|
1559
|
+
this._rfbAuthScheme >> 16,
|
|
1560
|
+
this._rfbAuthScheme >> 8,
|
|
1561
|
+
this._rfbAuthScheme]);
|
|
1527
1562
|
|
|
1528
|
-
this.
|
|
1563
|
+
this._rfbVeNCryptState == 4;
|
|
1529
1564
|
return true;
|
|
1530
1565
|
}
|
|
1531
1566
|
}
|
|
1532
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
|
+
|
|
1533
1599
|
_negotiateStdVNCAuth() {
|
|
1534
1600
|
if (this._sock.rQwait("auth challenge", 16)) { return false; }
|
|
1535
1601
|
|
|
@@ -1595,7 +1661,19 @@ export default class RFB extends EventTargetMixin {
|
|
|
1595
1661
|
let exponentHex = "0x"+Array.from(exponent, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
|
|
1596
1662
|
let modulusHex = "0x"+Array.from(modulus, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
|
|
1597
1663
|
|
|
1598
|
-
let
|
|
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);
|
|
1599
1677
|
|
|
1600
1678
|
while (hexResult.length/2<exponent.length || (hexResult.length%2 != 0)) {
|
|
1601
1679
|
hexResult = "0"+hexResult;
|
|
@@ -1644,7 +1722,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1644
1722
|
this._rfbCredentials.ardCredentials = encrypted;
|
|
1645
1723
|
this._rfbCredentials.ardPublicKey = clientPublicKey;
|
|
1646
1724
|
|
|
1647
|
-
|
|
1725
|
+
this._resumeAuthentication();
|
|
1648
1726
|
}
|
|
1649
1727
|
|
|
1650
1728
|
_negotiateTightUnixAuth() {
|
|
@@ -1754,12 +1832,12 @@ export default class RFB extends EventTargetMixin {
|
|
|
1754
1832
|
case 'STDVNOAUTH__': // no auth
|
|
1755
1833
|
this._rfbInitState = 'SecurityResult';
|
|
1756
1834
|
return true;
|
|
1757
|
-
case 'STDVVNCAUTH_':
|
|
1758
|
-
this._rfbAuthScheme =
|
|
1759
|
-
return
|
|
1760
|
-
case 'TGHTULGNAUTH':
|
|
1761
|
-
this._rfbAuthScheme =
|
|
1762
|
-
return
|
|
1835
|
+
case 'STDVVNCAUTH_':
|
|
1836
|
+
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
1837
|
+
return true;
|
|
1838
|
+
case 'TGHTULGNAUTH':
|
|
1839
|
+
this._rfbAuthScheme = securityTypeUnixLogon;
|
|
1840
|
+
return true;
|
|
1763
1841
|
default:
|
|
1764
1842
|
return this._fail("Unsupported tiny auth scheme " +
|
|
1765
1843
|
"(scheme: " + authType + ")");
|
|
@@ -1796,7 +1874,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
1796
1874
|
}).then(() => {
|
|
1797
1875
|
this.dispatchEvent(new CustomEvent('securityresult'));
|
|
1798
1876
|
this._rfbInitState = "SecurityResult";
|
|
1799
|
-
|
|
1877
|
+
return true;
|
|
1800
1878
|
}).finally(() => {
|
|
1801
1879
|
this._rfbRSAAESAuthenticationState.removeEventListener(
|
|
1802
1880
|
"serververification", this._eventHandlers.handleRSAAESServerVerification);
|
|
@@ -1810,33 +1888,32 @@ export default class RFB extends EventTargetMixin {
|
|
|
1810
1888
|
|
|
1811
1889
|
_negotiateAuthentication() {
|
|
1812
1890
|
switch (this._rfbAuthScheme) {
|
|
1813
|
-
case
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
return true;
|
|
1817
|
-
}
|
|
1818
|
-
this._rfbInitState = 'ClientInitialisation';
|
|
1819
|
-
return this._initMsg();
|
|
1891
|
+
case securityTypeNone:
|
|
1892
|
+
this._rfbInitState = 'SecurityResult';
|
|
1893
|
+
return true;
|
|
1820
1894
|
|
|
1821
|
-
case
|
|
1895
|
+
case securityTypeXVP:
|
|
1822
1896
|
return this._negotiateXvpAuth();
|
|
1823
1897
|
|
|
1824
|
-
case
|
|
1898
|
+
case securityTypeARD:
|
|
1825
1899
|
return this._negotiateARDAuth();
|
|
1826
1900
|
|
|
1827
|
-
case
|
|
1901
|
+
case securityTypeVNCAuth:
|
|
1828
1902
|
return this._negotiateStdVNCAuth();
|
|
1829
1903
|
|
|
1830
|
-
case
|
|
1904
|
+
case securityTypeTight:
|
|
1831
1905
|
return this._negotiateTightAuth();
|
|
1832
1906
|
|
|
1833
|
-
case
|
|
1907
|
+
case securityTypeVeNCrypt:
|
|
1834
1908
|
return this._negotiateVeNCryptAuth();
|
|
1835
1909
|
|
|
1836
|
-
case
|
|
1910
|
+
case securityTypePlain:
|
|
1911
|
+
return this._negotiatePlainAuth();
|
|
1912
|
+
|
|
1913
|
+
case securityTypeUnixLogon:
|
|
1837
1914
|
return this._negotiateTightUnixAuth();
|
|
1838
1915
|
|
|
1839
|
-
case
|
|
1916
|
+
case securityTypeRA2ne:
|
|
1840
1917
|
return this._negotiateRA2neAuth();
|
|
1841
1918
|
|
|
1842
1919
|
default:
|
|
@@ -1846,6 +1923,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
1846
1923
|
}
|
|
1847
1924
|
|
|
1848
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
|
+
|
|
1849
1933
|
if (this._sock.rQwait('VNC auth response ', 4)) { return false; }
|
|
1850
1934
|
|
|
1851
1935
|
const status = this._sock.rQshift32();
|
|
@@ -1853,13 +1937,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
1853
1937
|
if (status === 0) { // OK
|
|
1854
1938
|
this._rfbInitState = 'ClientInitialisation';
|
|
1855
1939
|
Log.Debug('Authentication OK');
|
|
1856
|
-
return
|
|
1940
|
+
return true;
|
|
1857
1941
|
} else {
|
|
1858
1942
|
if (this._rfbVersion >= 3.8) {
|
|
1859
1943
|
this._rfbInitState = "SecurityReason";
|
|
1860
1944
|
this._securityContext = "security result";
|
|
1861
1945
|
this._securityStatus = status;
|
|
1862
|
-
return
|
|
1946
|
+
return true;
|
|
1863
1947
|
} else {
|
|
1864
1948
|
this.dispatchEvent(new CustomEvent(
|
|
1865
1949
|
"securityfailure",
|
|
@@ -2035,6 +2119,14 @@ export default class RFB extends EventTargetMixin {
|
|
|
2035
2119
|
}
|
|
2036
2120
|
}
|
|
2037
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
|
+
|
|
2038
2130
|
_handleSetColourMapMsg() {
|
|
2039
2131
|
Log.Debug("SetColorMapEntries");
|
|
2040
2132
|
|
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/decoders/tightpng.js
CHANGED
|
@@ -19,7 +19,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
|
|
|
19
19
|
|
|
20
20
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
|
|
21
21
|
|
|
22
|
-
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf
|
|
22
|
+
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
|
|
23
23
|
|
|
24
24
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
|
25
25
|
|
|
@@ -29,7 +29,7 @@ function _assertThisInitialized(self) { if (self === void 0) { throw new Referen
|
|
|
29
29
|
|
|
30
30
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
31
31
|
|
|
32
|
-
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
|
|
32
|
+
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
|
|
33
33
|
|
|
34
34
|
var TightPNGDecoder = /*#__PURE__*/function (_TightDecoder) {
|
|
35
35
|
_inherits(TightPNGDecoder, _TightDecoder);
|
package/lib/display.js
CHANGED
|
@@ -246,6 +246,21 @@ var Display = /*#__PURE__*/function () {
|
|
|
246
246
|
var vp = this._viewportLoc;
|
|
247
247
|
this.viewportChangeSize(vp.w, vp.h);
|
|
248
248
|
this.viewportChangePos(0, 0);
|
|
249
|
+
}
|
|
250
|
+
}, {
|
|
251
|
+
key: "getImageData",
|
|
252
|
+
value: function getImageData() {
|
|
253
|
+
return this._drawCtx.getImageData(0, 0, this.width, this.height);
|
|
254
|
+
}
|
|
255
|
+
}, {
|
|
256
|
+
key: "toDataURL",
|
|
257
|
+
value: function toDataURL(type, encoderOptions) {
|
|
258
|
+
return this._backbuffer.toDataURL(type, encoderOptions);
|
|
259
|
+
}
|
|
260
|
+
}, {
|
|
261
|
+
key: "toBlob",
|
|
262
|
+
value: function toBlob(callback, type, quality) {
|
|
263
|
+
return this._backbuffer.toBlob(callback, type, quality);
|
|
249
264
|
} // Track what parts of the visible canvas that need updating
|
|
250
265
|
|
|
251
266
|
}, {
|