@novnc/novnc 1.6.0 → 1.7.0

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.
Files changed (103) hide show
  1. package/core/base64.js +104 -0
  2. package/core/crypto/aes.js +178 -0
  3. package/core/crypto/bigint.js +34 -0
  4. package/core/crypto/crypto.js +90 -0
  5. package/core/crypto/des.js +330 -0
  6. package/core/crypto/dh.js +55 -0
  7. package/core/crypto/md5.js +82 -0
  8. package/core/crypto/rsa.js +132 -0
  9. package/core/decoders/copyrect.js +27 -0
  10. package/core/decoders/h264.js +321 -0
  11. package/core/decoders/hextile.js +181 -0
  12. package/core/decoders/jpeg.js +161 -0
  13. package/core/decoders/raw.js +59 -0
  14. package/core/decoders/rre.js +44 -0
  15. package/core/decoders/tight.js +393 -0
  16. package/core/decoders/tightpng.js +27 -0
  17. package/core/decoders/zlib.js +51 -0
  18. package/core/decoders/zrle.js +185 -0
  19. package/core/deflator.js +84 -0
  20. package/core/display.js +578 -0
  21. package/core/encodings.js +54 -0
  22. package/core/inflator.js +65 -0
  23. package/core/input/domkeytable.js +311 -0
  24. package/core/input/fixedkeys.js +129 -0
  25. package/core/input/gesturehandler.js +567 -0
  26. package/core/input/keyboard.js +294 -0
  27. package/core/input/keysym.js +616 -0
  28. package/core/input/keysymdef.js +688 -0
  29. package/core/input/util.js +191 -0
  30. package/core/input/vkeys.js +116 -0
  31. package/core/input/xtscancodes.js +173 -0
  32. package/core/ra2.js +312 -0
  33. package/core/rfb.js +3411 -0
  34. package/core/util/browser.js +233 -0
  35. package/core/util/cursor.js +249 -0
  36. package/core/util/element.js +32 -0
  37. package/core/util/events.js +138 -0
  38. package/core/util/eventtarget.js +35 -0
  39. package/core/util/int.js +15 -0
  40. package/core/util/logging.js +56 -0
  41. package/core/util/strings.js +28 -0
  42. package/core/websock.js +369 -0
  43. package/docs/API.md +0 -5
  44. package/package.json +6 -10
  45. package/vendor/pako/LICENSE +21 -0
  46. package/vendor/pako/README.md +6 -0
  47. package/{lib/vendor → vendor}/pako/lib/utils/common.js +13 -23
  48. package/{lib/vendor → vendor}/pako/lib/zlib/adler32.js +12 -14
  49. package/vendor/pako/lib/zlib/constants.js +47 -0
  50. package/{lib/vendor → vendor}/pako/lib/zlib/crc32.js +15 -14
  51. package/{lib/vendor → vendor}/pako/lib/zlib/deflate.js +459 -334
  52. package/{lib/vendor → vendor}/pako/lib/zlib/gzheader.js +13 -19
  53. package/{lib/vendor → vendor}/pako/lib/zlib/inffast.js +116 -119
  54. package/vendor/pako/lib/zlib/inflate.js +1527 -0
  55. package/{lib/vendor → vendor}/pako/lib/zlib/inftrees.js +103 -91
  56. package/vendor/pako/lib/zlib/messages.js +11 -0
  57. package/{lib/vendor → vendor}/pako/lib/zlib/trees.js +313 -268
  58. package/{lib/vendor → vendor}/pako/lib/zlib/zstream.js +4 -10
  59. package/lib/base64.js +0 -100
  60. package/lib/crypto/aes.js +0 -481
  61. package/lib/crypto/bigint.js +0 -41
  62. package/lib/crypto/crypto.js +0 -109
  63. package/lib/crypto/des.js +0 -374
  64. package/lib/crypto/dh.js +0 -81
  65. package/lib/crypto/md5.js +0 -97
  66. package/lib/crypto/rsa.js +0 -312
  67. package/lib/decoders/copyrect.js +0 -40
  68. package/lib/decoders/h264.js +0 -349
  69. package/lib/decoders/hextile.js +0 -195
  70. package/lib/decoders/jpeg.js +0 -175
  71. package/lib/decoders/raw.js +0 -66
  72. package/lib/decoders/rre.js +0 -52
  73. package/lib/decoders/tight.js +0 -363
  74. package/lib/decoders/tightpng.js +0 -51
  75. package/lib/decoders/zlib.js +0 -57
  76. package/lib/decoders/zrle.js +0 -192
  77. package/lib/deflator.js +0 -88
  78. package/lib/display.js +0 -588
  79. package/lib/encodings.js +0 -70
  80. package/lib/inflator.js +0 -77
  81. package/lib/input/domkeytable.js +0 -313
  82. package/lib/input/fixedkeys.js +0 -127
  83. package/lib/input/gesturehandler.js +0 -573
  84. package/lib/input/keyboard.js +0 -293
  85. package/lib/input/keysym.js +0 -878
  86. package/lib/input/keysymdef.js +0 -1351
  87. package/lib/input/util.js +0 -217
  88. package/lib/input/vkeys.js +0 -121
  89. package/lib/input/xtscancodes.js +0 -343
  90. package/lib/ra2.js +0 -535
  91. package/lib/rfb.js +0 -3398
  92. package/lib/util/browser.js +0 -239
  93. package/lib/util/cursor.js +0 -269
  94. package/lib/util/element.js +0 -41
  95. package/lib/util/events.js +0 -133
  96. package/lib/util/eventtarget.js +0 -53
  97. package/lib/util/int.js +0 -21
  98. package/lib/util/logging.js +0 -56
  99. package/lib/util/strings.js +0 -36
  100. package/lib/vendor/pako/lib/zlib/constants.js +0 -47
  101. package/lib/vendor/pako/lib/zlib/inflate.js +0 -1602
  102. package/lib/vendor/pako/lib/zlib/messages.js +0 -25
  103. package/lib/websock.js +0 -395
package/core/ra2.js ADDED
@@ -0,0 +1,312 @@
1
+ import { encodeUTF8 } from './util/strings.js';
2
+ import EventTargetMixin from './util/eventtarget.js';
3
+ import legacyCrypto from './crypto/crypto.js';
4
+
5
+ class RA2Cipher {
6
+ constructor() {
7
+ this._cipher = null;
8
+ this._counter = new Uint8Array(16);
9
+ }
10
+
11
+ async setKey(key) {
12
+ this._cipher = await legacyCrypto.importKey(
13
+ "raw", key, { name: "AES-EAX" }, false, ["encrypt, decrypt"]);
14
+ }
15
+
16
+ async makeMessage(message) {
17
+ const ad = new Uint8Array([(message.length & 0xff00) >>> 8, message.length & 0xff]);
18
+ const encrypted = await legacyCrypto.encrypt({
19
+ name: "AES-EAX",
20
+ iv: this._counter,
21
+ additionalData: ad,
22
+ }, this._cipher, message);
23
+ for (let i = 0; i < 16 && this._counter[i]++ === 255; i++);
24
+ const res = new Uint8Array(message.length + 2 + 16);
25
+ res.set(ad);
26
+ res.set(encrypted, 2);
27
+ return res;
28
+ }
29
+
30
+ async receiveMessage(length, encrypted) {
31
+ const ad = new Uint8Array([(length & 0xff00) >>> 8, length & 0xff]);
32
+ const res = await legacyCrypto.decrypt({
33
+ name: "AES-EAX",
34
+ iv: this._counter,
35
+ additionalData: ad,
36
+ }, this._cipher, encrypted);
37
+ for (let i = 0; i < 16 && this._counter[i]++ === 255; i++);
38
+ return res;
39
+ }
40
+ }
41
+
42
+ export default class RSAAESAuthenticationState extends EventTargetMixin {
43
+ constructor(sock, getCredentials) {
44
+ super();
45
+ this._hasStarted = false;
46
+ this._checkSock = null;
47
+ this._checkCredentials = null;
48
+ this._approveServerResolve = null;
49
+ this._sockReject = null;
50
+ this._credentialsReject = null;
51
+ this._approveServerReject = null;
52
+ this._sock = sock;
53
+ this._getCredentials = getCredentials;
54
+ }
55
+
56
+ _waitSockAsync(len) {
57
+ return new Promise((resolve, reject) => {
58
+ const hasData = () => !this._sock.rQwait('RA2', len);
59
+ if (hasData()) {
60
+ resolve();
61
+ } else {
62
+ this._checkSock = () => {
63
+ if (hasData()) {
64
+ resolve();
65
+ this._checkSock = null;
66
+ this._sockReject = null;
67
+ }
68
+ };
69
+ this._sockReject = reject;
70
+ }
71
+ });
72
+ }
73
+
74
+ _waitApproveKeyAsync() {
75
+ return new Promise((resolve, reject) => {
76
+ this._approveServerResolve = resolve;
77
+ this._approveServerReject = reject;
78
+ });
79
+ }
80
+
81
+ _waitCredentialsAsync(subtype) {
82
+ const hasCredentials = () => {
83
+ if (subtype === 1 && this._getCredentials().username !== undefined &&
84
+ this._getCredentials().password !== undefined) {
85
+ return true;
86
+ } else if (subtype === 2 && this._getCredentials().password !== undefined) {
87
+ return true;
88
+ }
89
+ return false;
90
+ };
91
+ return new Promise((resolve, reject) => {
92
+ if (hasCredentials()) {
93
+ resolve();
94
+ } else {
95
+ this._checkCredentials = () => {
96
+ if (hasCredentials()) {
97
+ resolve();
98
+ this._checkCredentials = null;
99
+ this._credentialsReject = null;
100
+ }
101
+ };
102
+ this._credentialsReject = reject;
103
+ }
104
+ });
105
+ }
106
+
107
+ checkInternalEvents() {
108
+ if (this._checkSock !== null) {
109
+ this._checkSock();
110
+ }
111
+ if (this._checkCredentials !== null) {
112
+ this._checkCredentials();
113
+ }
114
+ }
115
+
116
+ approveServer() {
117
+ if (this._approveServerResolve !== null) {
118
+ this._approveServerResolve();
119
+ this._approveServerResolve = null;
120
+ }
121
+ }
122
+
123
+ disconnect() {
124
+ if (this._sockReject !== null) {
125
+ this._sockReject(new Error("disconnect normally"));
126
+ this._sockReject = null;
127
+ }
128
+ if (this._credentialsReject !== null) {
129
+ this._credentialsReject(new Error("disconnect normally"));
130
+ this._credentialsReject = null;
131
+ }
132
+ if (this._approveServerReject !== null) {
133
+ this._approveServerReject(new Error("disconnect normally"));
134
+ this._approveServerReject = null;
135
+ }
136
+ }
137
+
138
+ async negotiateRA2neAuthAsync() {
139
+ this._hasStarted = true;
140
+ // 1: Receive server public key
141
+ await this._waitSockAsync(4);
142
+ const serverKeyLengthBuffer = this._sock.rQpeekBytes(4);
143
+ const serverKeyLength = this._sock.rQshift32();
144
+ if (serverKeyLength < 1024) {
145
+ throw new Error("RA2: server public key is too short: " + serverKeyLength);
146
+ } else if (serverKeyLength > 8192) {
147
+ throw new Error("RA2: server public key is too long: " + serverKeyLength);
148
+ }
149
+ const serverKeyBytes = Math.ceil(serverKeyLength / 8);
150
+ await this._waitSockAsync(serverKeyBytes * 2);
151
+ const serverN = this._sock.rQshiftBytes(serverKeyBytes);
152
+ const serverE = this._sock.rQshiftBytes(serverKeyBytes);
153
+ const serverRSACipher = await legacyCrypto.importKey(
154
+ "raw", { n: serverN, e: serverE }, { name: "RSA-PKCS1-v1_5" }, false, ["encrypt"]);
155
+ const serverPublickey = new Uint8Array(4 + serverKeyBytes * 2);
156
+ serverPublickey.set(serverKeyLengthBuffer);
157
+ serverPublickey.set(serverN, 4);
158
+ serverPublickey.set(serverE, 4 + serverKeyBytes);
159
+
160
+ // verify server public key
161
+ let approveKey = this._waitApproveKeyAsync();
162
+ this.dispatchEvent(new CustomEvent("serververification", {
163
+ detail: { type: "RSA", publickey: serverPublickey }
164
+ }));
165
+ await approveKey;
166
+
167
+ // 2: Send client public key
168
+ const clientKeyLength = 2048;
169
+ const clientKeyBytes = Math.ceil(clientKeyLength / 8);
170
+ const clientRSACipher = (await legacyCrypto.generateKey({
171
+ name: "RSA-PKCS1-v1_5",
172
+ modulusLength: clientKeyLength,
173
+ publicExponent: new Uint8Array([1, 0, 1]),
174
+ }, true, ["encrypt"])).privateKey;
175
+ const clientExportedRSAKey = await legacyCrypto.exportKey("raw", clientRSACipher);
176
+ const clientN = clientExportedRSAKey.n;
177
+ const clientE = clientExportedRSAKey.e;
178
+ const clientPublicKey = new Uint8Array(4 + clientKeyBytes * 2);
179
+ clientPublicKey[0] = (clientKeyLength & 0xff000000) >>> 24;
180
+ clientPublicKey[1] = (clientKeyLength & 0xff0000) >>> 16;
181
+ clientPublicKey[2] = (clientKeyLength & 0xff00) >>> 8;
182
+ clientPublicKey[3] = clientKeyLength & 0xff;
183
+ clientPublicKey.set(clientN, 4);
184
+ clientPublicKey.set(clientE, 4 + clientKeyBytes);
185
+ this._sock.sQpushBytes(clientPublicKey);
186
+ this._sock.flush();
187
+
188
+ // 3: Send client random
189
+ const clientRandom = new Uint8Array(16);
190
+ window.crypto.getRandomValues(clientRandom);
191
+ const clientEncryptedRandom = await legacyCrypto.encrypt(
192
+ { name: "RSA-PKCS1-v1_5" }, serverRSACipher, clientRandom);
193
+ const clientRandomMessage = new Uint8Array(2 + serverKeyBytes);
194
+ clientRandomMessage[0] = (serverKeyBytes & 0xff00) >>> 8;
195
+ clientRandomMessage[1] = serverKeyBytes & 0xff;
196
+ clientRandomMessage.set(clientEncryptedRandom, 2);
197
+ this._sock.sQpushBytes(clientRandomMessage);
198
+ this._sock.flush();
199
+
200
+ // 4: Receive server random
201
+ await this._waitSockAsync(2);
202
+ if (this._sock.rQshift16() !== clientKeyBytes) {
203
+ throw new Error("RA2: wrong encrypted message length");
204
+ }
205
+ const serverEncryptedRandom = this._sock.rQshiftBytes(clientKeyBytes);
206
+ const serverRandom = await legacyCrypto.decrypt(
207
+ { name: "RSA-PKCS1-v1_5" }, clientRSACipher, serverEncryptedRandom);
208
+ if (serverRandom === null || serverRandom.length !== 16) {
209
+ throw new Error("RA2: corrupted server encrypted random");
210
+ }
211
+
212
+ // 5: Compute session keys and set ciphers
213
+ let clientSessionKey = new Uint8Array(32);
214
+ let serverSessionKey = new Uint8Array(32);
215
+ clientSessionKey.set(serverRandom);
216
+ clientSessionKey.set(clientRandom, 16);
217
+ serverSessionKey.set(clientRandom);
218
+ serverSessionKey.set(serverRandom, 16);
219
+ clientSessionKey = await window.crypto.subtle.digest("SHA-1", clientSessionKey);
220
+ clientSessionKey = new Uint8Array(clientSessionKey).slice(0, 16);
221
+ serverSessionKey = await window.crypto.subtle.digest("SHA-1", serverSessionKey);
222
+ serverSessionKey = new Uint8Array(serverSessionKey).slice(0, 16);
223
+ const clientCipher = new RA2Cipher();
224
+ await clientCipher.setKey(clientSessionKey);
225
+ const serverCipher = new RA2Cipher();
226
+ await serverCipher.setKey(serverSessionKey);
227
+
228
+ // 6: Compute and exchange hashes
229
+ let serverHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2);
230
+ let clientHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2);
231
+ serverHash.set(serverPublickey);
232
+ serverHash.set(clientPublicKey, 4 + serverKeyBytes * 2);
233
+ clientHash.set(clientPublicKey);
234
+ clientHash.set(serverPublickey, 4 + clientKeyBytes * 2);
235
+ serverHash = await window.crypto.subtle.digest("SHA-1", serverHash);
236
+ clientHash = await window.crypto.subtle.digest("SHA-1", clientHash);
237
+ serverHash = new Uint8Array(serverHash);
238
+ clientHash = new Uint8Array(clientHash);
239
+ this._sock.sQpushBytes(await clientCipher.makeMessage(clientHash));
240
+ this._sock.flush();
241
+ await this._waitSockAsync(2 + 20 + 16);
242
+ if (this._sock.rQshift16() !== 20) {
243
+ throw new Error("RA2: wrong server hash");
244
+ }
245
+ const serverHashReceived = await serverCipher.receiveMessage(
246
+ 20, this._sock.rQshiftBytes(20 + 16));
247
+ if (serverHashReceived === null) {
248
+ throw new Error("RA2: failed to authenticate the message");
249
+ }
250
+ for (let i = 0; i < 20; i++) {
251
+ if (serverHashReceived[i] !== serverHash[i]) {
252
+ throw new Error("RA2: wrong server hash");
253
+ }
254
+ }
255
+
256
+ // 7: Receive subtype
257
+ await this._waitSockAsync(2 + 1 + 16);
258
+ if (this._sock.rQshift16() !== 1) {
259
+ throw new Error("RA2: wrong subtype");
260
+ }
261
+ let subtype = (await serverCipher.receiveMessage(
262
+ 1, this._sock.rQshiftBytes(1 + 16)));
263
+ if (subtype === null) {
264
+ throw new Error("RA2: failed to authenticate the message");
265
+ }
266
+ subtype = subtype[0];
267
+ let waitCredentials = this._waitCredentialsAsync(subtype);
268
+ if (subtype === 1) {
269
+ if (this._getCredentials().username === undefined ||
270
+ this._getCredentials().password === undefined) {
271
+ this.dispatchEvent(new CustomEvent(
272
+ "credentialsrequired",
273
+ { detail: { types: ["username", "password"] } }));
274
+ }
275
+ } else if (subtype === 2) {
276
+ if (this._getCredentials().password === undefined) {
277
+ this.dispatchEvent(new CustomEvent(
278
+ "credentialsrequired",
279
+ { detail: { types: ["password"] } }));
280
+ }
281
+ } else {
282
+ throw new Error("RA2: wrong subtype");
283
+ }
284
+ await waitCredentials;
285
+ let username;
286
+ if (subtype === 1) {
287
+ username = encodeUTF8(this._getCredentials().username).slice(0, 255);
288
+ } else {
289
+ username = "";
290
+ }
291
+ const password = encodeUTF8(this._getCredentials().password).slice(0, 255);
292
+ const credentials = new Uint8Array(username.length + password.length + 2);
293
+ credentials[0] = username.length;
294
+ credentials[username.length + 1] = password.length;
295
+ for (let i = 0; i < username.length; i++) {
296
+ credentials[i + 1] = username.charCodeAt(i);
297
+ }
298
+ for (let i = 0; i < password.length; i++) {
299
+ credentials[username.length + 2 + i] = password.charCodeAt(i);
300
+ }
301
+ this._sock.sQpushBytes(await clientCipher.makeMessage(credentials));
302
+ this._sock.flush();
303
+ }
304
+
305
+ get hasStarted() {
306
+ return this._hasStarted;
307
+ }
308
+
309
+ set hasStarted(s) {
310
+ this._hasStarted = s;
311
+ }
312
+ }