1import { E as EnumOf, c as concatBuffer, a as fromByteArray, e as encodeUTF16LE, s as stringToArrayBuffer, t as toByteArray, b as arrayBufferToString, d as digestToHex, g as decodeUTF16LE } from './utils-CRB9uaPI.js'; 2 3const newLine = "\n"; 4const ActionType = EnumOf({ 5 Health: "health", 6 Message: "message" 7}); 8const MessageType = EnumOf({ 9 Command: "command", 10 Connection: "connection", 11 Download: "download", 12 Get: "get", 13 Put: "put", 14 Response: "response", 15 ResponseAck: "response_ack", 16 Sandbox: "sandbox", 17 Signal: "signal", 18 TransferComplete: "transfer_completed", 19 Upload: "upload" 20}); 21const SpecialMessage = EnumOf({ 22 CTRL_C: "ctrl_c", 23 Quit: "quit" 24}); 25 26const endSessionString = "--- SESSION TERMINATED ---"; 27const maxDurationString = "Remote Session duration limit reached (1 hour)"; 28const maxWaitingTimeString = "Client connection timeout"; 29const healthInterval = 2e3; 30const maxWaitingTime = 3e5; 31const maxSessionTime = 36e5; 32const maxUploadSize = 67108864; 33const BUFFER_CHANGE_EVENT = "buffer-change"; 34const INPUT_CHANGE_EVENT = "input-change"; 35const CURRENT_FOLDER_CHANGE_EVENT = "current-folder-change"; 36const CONNECTED_CHANGE_EVENT = "connected-change"; 37const CONNECTING_CHANGE_EVENT = "connecting-change"; 38const UPLOADING_CHANGE_EVENT = "uploading-change"; 39const DOWNLOADING_CHANGE_EVENT = "downloading-change"; 40const CONNECTION_ESTABLISHED_EVENT = "connection-established-change"; 41const RESPONSE_FINISHED_EVENT = "response-finished"; 42class RemoteShellHandler { 43 authToken; 44 arsBaseUrl; 45 accountId; 46 machineId; 47 machineName; 48 sessionId; 49 userInfo; 50 rsaKeyPair = null; 51 aesKey = null; 52 healthLoop = null; 53 sessionTimeout = null; 54 waitingTimeout = null; 55 ws = null; 56 connected = false; 57 downloading = false; 58 uploading = false; 59 connecting = false; 60 connectionEstablished = false; 61 buffer = ""; 62 currentFolder = ""; 63 callBacks = null; 64 lastCommand = null; 65 enableCmdInput = true; 66 isInsideAnExecCmd = false; 67 progressLoop = null; 68 progressBaseMessage = ""; 69 progressDots = 0; 70 staticBufferSnapshot = ""; 71 constructor(arsBaseUrl, accountId, machineId, machineName, userInfo, callbacks) { 72 this.arsBaseUrl = arsBaseUrl; 73 this.accountId = accountId; 74 this.machineId = machineId; 75 this.machineName = machineName; 76 this.userInfo = userInfo; 77 this.callBacks = callbacks; 78 } 79 listeners = {}; 80 on(event, callback) { 81 if (!this.listeners[event]) { 82 this.listeners[event] = []; 83 } 84 this.listeners[event].push(callback); 85 } 86 off(event, callback) { 87 if (!this.listeners[event]) return; 88 this.listeners[event] = this.listeners[event].filter((cb) => cb !== callback); 89 } 90 emit(event, data) { 91 if (this.listeners[event]) { 92 this.listeners[event].forEach((callback) => callback(data)); 93 } 94 } 95 getMachineName() { 96 return this.machineName; 97 } 98 getMachineId() { 99 return this.machineId; 100 } 101 getUserInfo() { 102 return this.userInfo; 103 } 104 getAccountId() { 105 return this.accountId; 106 } 107 setLastCommand(cmd) { 108 this.lastCommand = cmd; 109 } 110 isInExecMode() { 111 return this.isInsideAnExecCmd; 112 } 113 setCmdInputEnabled(enable) { 114 this.enableCmdInput = enable; 115 } 116 getAESKey() { 117 return this.aesKey; 118 } 119 getSessionId() { 120 return this.sessionId; 121 } 122 isConnected() { 123 return this.connected; 124 } 125 isConnecting() { 126 return this.connecting; 127 } 128 isUploadingFile() { 129 return this.uploading; 130 } 131 isDownloadingFile() { 132 return this.downloading; 133 } 134 getBuffer() { 135 return this.buffer; 136 } 137 getCurrentDirectory() { 138 return this.currentFolder; 139 } 140 updateInputValue(value) { 141 this.emit(INPUT_CHANGE_EVENT, value); 142 } 143 quitArsSession(reason) { 144 this.stopProgress(); 145 if (reason) { 146 this.updateBuffer(reason); 147 } 148 this.callBacks?.quitArsSession(); 149 this.ws?.close(); 150 this.connected = false; 151 this.emit(CONNECTED_CHANGE_EVENT, this.connected); 152 this.connectionEstablished = false; 153 this.emit(CONNECTION_ESTABLISHED_EVENT, this.connectionEstablished); 154 this.emit(CURRENT_FOLDER_CHANGE_EVENT, ""); 155 } 156 sendFeedbackToBuffer = (message) => { 157 if (message.public_key) { 158 this.updateProgress("receiving public key"); 159 } 160 if (message.handshake_completed) { 161 this.stopProgress("");
162 this.emit(BUFFER_CHANGE_EVENT, "clear"); 163 if (!this.connectionEstablished) { 164 this.connectionEstablished = true; 165 this.emit(CONNECTION_ESTABLISHED_EVENT, this.connectionEstablished); 166 } 167 } 168 }; 169 sendJsonMessage = (message) => { 170 if (this.ws && this.ws.readyState === WebSocket.OPEN) { 171 this.sendFeedbackToBuffer(message); 172 const msg = JSON.stringify(message); 173 this.uploading = true; 174 this.emit(UPLOADING_CHANGE_EVENT, this.uploading); 175 this.ws.send(msg); 176 this.uploading = false; 177 this.emit(UPLOADING_CHANGE_EVENT, this.uploading); 178 } else { 179 console.warn("Socket not open. Message not sent."); 180 } 181 }; 182 showError = (title, errors) => { 183 this.callBacks?.showError(title, errors); 184 }; 185 showNotification = (notification) => { 186 this.callBacks?.showNotification(notification); 187 }; 188 sendAuditLog = (auditObj) => { 189 this.callBacks?.sendAuditLog(auditObj); 190 }; 191 updateBuffer = (value) => { 192 this.buffer = value; 193 this.emit(BUFFER_CHANGE_EVENT, this.buffer); 194 const prompt = this.currentFolder ? this.currentFolder : "> "; 195 this.emit(CURRENT_FOLDER_CHANGE_EVENT, prompt); 196 }; 197 setDownloadStarted = (isDownloading) => { 198 this.downloading = isDownloading; 199 }; 200 setUploadingStarted = (isUploading) => { 201 this.uploading = isUploading; 202 }; 203 startProgress(msg) { 204 this.progressBaseMessage = msg; 205 this.progressDots = 0; 206 if (!this.progressLoop) { 207 this.staticBufferSnapshot = this.buffer; 208 this.progressLoop = setInterval(() => { 209 this.progressDots = (this.progressDots + 1) % 4; 210 const dots = ".".repeat(this.progressDots); 211 this.buffer = this.staticBufferSnapshot + newLine + this.progressBaseMessage + dots; 212 this.emit(BUFFER_CHANGE_EVENT, this.buffer); 213 }, 500); 214 } 215 } 216 updateProgress(msg) { 217 if (this.progressLoop) { 218 this.progressBaseMessage = msg; 219 this.progressDots = 0; 220 this.buffer = this.staticBufferSnapshot + newLine + this.progressBaseMessage; 221 this.emit(BUFFER_CHANGE_EVENT, this.buffer); 222 } else { 223 this.startProgress(msg); 224 } 225 } 226 stopProgress(finalMsg) { 227 if (this.progressLoop) { 228 clearInterval(this.progressLoop); 229 this.progressLoop = null; 230 this.buffer = this.staticBufferSnapshot + (finalMsg ? newLine + finalMsg + newLine : ""); 231 this.staticBufferSnapshot = ""; 232 this.emit(BUFFER_CHANGE_EVENT, this.buffer); 233 } 234 } 235 downloadUrl = (url, fileName) => { 236 const a = document.createElement("a"); 237 document.body.appendChild(a); 238 a.style.display = "none"; 239 a.href = url; 240 a.download = fileName || ""; 241 a.click(); 242 window.URL.revokeObjectURL(url); 243 }; 244 handleTimeoutsAndIntervals = () => { 245 if (this.connected && this.ws) { 246 if (this.healthLoop) { 247 clearInterval(this.healthLoop); 248 this.healthLoop = setInterval(() => { 249 this.sendJsonMessage({ 250 action: ActionType.Health, 251 session_id: this.sessionId, 252 timestamp: Date.now() 253 }); 254 }, healthInterval); 255 } 256 if (this.sessionTimeout) { 257 clearTimeout(this.sessionTimeout); 258 this.sessionTimeout = setTimeout(() => { 259 console.log(maxDurationString); 260 }, maxSessionTime); 261 } 262 if (this.waitingTimeout) { 263 clearTimeout(this.waitingTimeout); 264 this.waitingTimeout = setTimeout(() => { 265 console.log(maxWaitingTimeString); 266 }, maxWaitingTime); 267 } 268 } else { 269 if (this.healthLoop) { 270 clearInterval(this.healthLoop); 271 } 272 if (this.sessionTimeout) { 273 clearTimeout(this.sessionTimeout); 274 } 275 if (this.waitingTimeout) { 276 clearTimeout(this.waitingTimeout); 277 } 278 } 279 }; 280 handleConnectedSocket = async () => { 281 if (this.ws && this.sessionId) { 282 if (this.waitingTimeout) { 283 clearTimeout(this.waitingTimeout); 284 } 285 const keyPair = await window.crypto.subtle.generateKey( 286 { 287 hash: "SHA-256", 288 modulusLength: 4096, 289 name: "RSA-OAEP", 290 publicExponent: new Uint8Array([1, 0, 1]) 291 }, 292 false, 293 ["encrypt", "decrypt"] 294 ); 295 this.rsaKeyPair = keyPair; 296 if (keyPair.publicKey) { 297 try { 298 const publicKey = await crypto.subtle.exportKey( 299 "spki", 300 keyPair.publicKey 301 ); 302 let body = btoa( 303 String.fromCharCode(...new Uint8Array(publicKey)) 304 ); 305 body = body.match(/.{1,64}/g).join("\n"); 306 this.sendJsonMessage({ 307 action: ActionType.Message, 308 public_key: `-----BEGIN PUBLIC KEY----- 309${body} 310-----END PUBLIC KEY-----`, 311 session_id: this.sessionId 312 }); 313 } catch (err) { 314 this.showError("Connection error", [ 315 { error: { message: `Something went wrong. (${err.message})` } } 316 ]); 317 } 318 } 319 } 320 }; 321 putFileRemoteShell = async (url, fileToSend, fileName) => { 322 const headers = new Headers(); 323 headers.append("Content-Type", "application/x-binary"); 324 headers.append("Content-Disposition", "attachment"); 325 const formData = new FormData(); 326 formData.append("data", new Blob([fileToSend]), fileName); 327 const response = await fetch(url, { 328 method: "PUT", 329 headers, 330 body: formData 331 }); 332 if (response.ok) { 333 return true; 334 } 335 return null; 336 }; 337 fetchFile = (url) => fetch(url, { 338 headers: { "Content-Type": "application/x-binary" }, 339 method: "GET" 340 }); 341 fileTransferRemoteShell = async (param) => { 342 const { 343 authToken, 344 account_id, 345 client_method, 346 client_type, 347 file_name, 348 machine_id, 349 session_id, 350 user_id 351 } = param; 352 const response = await fetch(`${this.arsBaseUrl}/signedurl?client_type=${client_type}`, { 353 method: "POST", 354 headers: { 355 authorization: `Bearer ${authToken}`, 356 "Content-type": "application/json" 357 }, 358 body: JSON.stringify({ 359 account_id, 360 client_method, 361 file_name, 362 machine_id, 363 session_id, 364 user_id 365 }) 366 }); 367 if (response.ok) { 368 return await response.json(); 369 } 370 return null; 371 }; 372 handleFileUpload = async (event) => { 373 const target = event.target; 374 if (target.files?.length && this.aesKey) { 375 this.uploading = true; 376 const currentFile = target.files[0]; 377 target.files = null; 378 target.value = ""; 379 if (!currentFile) { 380 this.showNotification({ 381 message: "File size limit exceeded (64MB).", 382 title: "Error uploading file", 383 type: "critical" 384 }); 385 this.uploading = false;
386 return; 387 } 388 const uploadMessage = `${MessageType.Put} "${currentFile?.name}"`; 389 this.updateBuffer( 390 this.buffer + newLine + this.currentFolder + " " + uploadMessage + newLine 391 ); 392 this.updateInputValue(""); 393 this.sendAuditLog({ 394 message: uploadMessage, 395 account_id: this.accountId, 396 connection_start: false, 397 machine_id: this.machineId, 398 pc_hostname: this.machineName, 399 session_id: this.sessionId, 400 user_id: this.userInfo.id || "" 401 }); 402 if (currentFile.size > maxUploadSize) { 403 this.showNotification({ 404 message: "File size limit exceeded (64MB).", 405 title: "Error uploading file", 406 type: "critical" 407 }); 408 this.uploading = false; 409 } else { 410 const params = { 411 authToken: this.authToken || "", 412 account_id: this.accountId, 413 client_method: "put_object", 414 client_type: "web", 415 file_name: currentFile.name, 416 machine_id: this.machineId || "", 417 session_id: this.sessionId || "", 418 user_id: this.userInfo.id 419 }; 420 const { presigned_url: presignedUrl } = await this.fileTransferRemoteShell(params); 421 if (!presignedUrl) { 422 this.showNotification({ 423 message: "Error during the upload.", 424 title: "Error uploading file", 425 type: "critical" 426 }); 427 this.uploading = false; 428 return; 429 } 430 const fileArrayBuffer = await currentFile.arrayBuffer(); 431 const digest = await crypto.subtle.digest("SHA-1", fileArrayBuffer); 432 const fileToCrypt = concatBuffer(fileArrayBuffer, digest); 433 const iv = window.crypto.getRandomValues(new Uint8Array(12)); 434 const cryptedFile = await window.crypto.subtle.encrypt( 435 { 436 iv, 437 name: "AES-GCM" 438 }, 439 this.aesKey, 440 fileToCrypt 441 ); 442 const fileToSend = concatBuffer(cryptedFile, iv.buffer); 443 const putFile = await this.putFileRemoteShell( 444 presignedUrl, 445 fileToSend, 446 currentFile.name 447 ); 448 this.updateBuffer(this.buffer + newLine + "upload in progress..."); 449 if (putFile) { 450 const payloadToCrypt = JSON.stringify({ 451 data: fromByteArray(encodeUTF16LE(uploadMessage)), 452 type: MessageType.Upload 453 }); 454 const putFileIv = window.crypto.getRandomValues(new Uint8Array(12)); 455 const res = await window.crypto.subtle.encrypt( 456 { 457 iv: putFileIv, 458 name: "AES-GCM" 459 }, 460 this.aesKey, 461 stringToArrayBuffer(payloadToCrypt) 462 ); 463 const encryptedPayload = fromByteArray( 464 new Uint8Array(res.slice(0, -16)) 465 ); 466 const gcm_tag = fromByteArray( 467 new Uint8Array(res.slice(-16)) 468 ); 469 this.sendJsonMessage({ 470 action: ActionType.Message, 471 body: { 472 gcm_tag, 473 iv: fromByteArray(new Uint8Array(putFileIv)), 474 payload: encryptedPayload 475 }, 476 session_id: this.sessionId 477 }); 478 } 479 } 480 } 481 }; 482 handleMessage = async (messageObj) => { 483 if (!this.aesKey || !messageObj.body) { 484 return; 485 } 486 try { 487 const payloadArray = new Uint8Array(toByteArray(messageObj.body.payload)); 488 const tagArray = new Uint8Array(toByteArray(messageObj.body.gcm_tag)); 489 const cyphered = new Uint8Array([...payloadArray, ...tagArray]); 490 const decrypted = await crypto.subtle.decrypt( 491 { 492 iv: toByteArray(messageObj.body.iv), 493 name: "AES-GCM", 494 tagLength: 128 495 }, 496 this.aesKey, 497 cyphered 498 ); 499 const res = await arrayBufferToString(decrypted); 500 const parsedData = JSON.parse(res); 501 const { 502 error, 503 file_name, 504 sandbox_hash, 505 sandbox_information, 506 sandbox_status, 507 success 508 } = parsedData.data; 509 if (parsedData.type === MessageType.TransferComplete) { 510 if (this.downloading) { 511 this.downloading = false;
512 this.emit(DOWNLOADING_CHANGE_EVENT, this.downloading); 513 this.updateInputValue(""); 514 if (error) { 515 this.updateBuffer( 516 `${this.buffer}${newLine}Error transferring file${newLine}` 517 ); 518 this.showError("Error transferring file", [ 519 { error: { message: error || "Something went wrong." } } 520 ]); 521 return; 522 } 523 const params = { 524 authToken: this.authToken || "", 525 account_id: this.accountId, 526 client_method: "get_object", 527 client_type: "web", 528 file_name, 529 machine_id: this.machineId, 530 session_id: this.sessionId || "", 531 user_id: this.userInfo.id 532 }; 533 if (file_name) { 534 try { 535 const transferRequest = await this.fileTransferRemoteShell(params); 536 if (!transferRequest || !transferRequest.presigned_url) { 537 this.showError("Error downloading file", [ 538 { error: { message: "Error during the download." } } 539 ]); 540 return; 541 } 542 const { presigned_url: presignedUrl } = transferRequest; 543 const file = await this.fetchFile(presignedUrl); 544 if (!file.ok) { 545 this.updateBuffer( 546 `${this.buffer}${newLine}Error transferring file${newLine}` 547 ); 548 this.showError("Error transferring file", [ 549 { error: { message: "Error during the download." } } 550 ]); 551 return; 552 } 553 const fileAB = await file.arrayBuffer(); 554 const currentBuffer = fileAB.slice(0, -12); 555 const currentIv = fileAB.slice(-12); 556 if (this.aesKey) { 557 const decryptedFile = await window.crypto.subtle.decrypt( 558 { 559 iv: currentIv, 560 name: "AES-GCM", 561 tagLength: 128 562 }, 563 this.aesKey, 564 currentBuffer 565 ); 566 const currentFile = decryptedFile.slice(0, -20); 567 const receivedDigest = decryptedFile.slice(-20); 568 const currentDigest = await crypto.subtle.digest( 569 "SHA-1", 570 currentFile 571 ); 572 if (digestToHex(currentDigest) === digestToHex(receivedDigest)) { 573 const href = window.URL.createObjectURL(new Blob([currentFile])); 574 this.downloadUrl(href, file_name); 575 } else { 576 this.updateBuffer( 577 `${this.buffer}${newLine}Error transferring file${newLine}` 578 ); 579 this.showError("Error transferring file", [ 580 { error: { message: "Hashes don't match." } } 581 ]); 582 } 583 } 584 } catch (err) { 585 this.showError("Error downloading/transferring file", [ 586 { 587 error: { 588 message: `Error during the download. (${err.message})` 589 } 590 } 591 ]); 592 } 593 } 594 } 595 if (sandbox_hash || sandbox_information || sandbox_status) { 596 this.updateBuffer( 597 `${this.buffer}${newLine}${sandbox_status}${newLine}${sandbox_information}${newLine}${sandbox_hash}` 598 ); 599 } 600 if (success) { 601 if (!file_name) { 602 this.updateBuffer( 603 `${this.buffer}${newLine}File successfully uploaded ${newLine}` 604 ); 605 this.showNotification({ 606 title: `File successfully uploaded`, 607 type: "success" 608 }); 609 } else { 610 this.updateBuffer( 611 `${this.buffer}${newLine}File ${file_name} successfully downloaded ${newLine}` 612 ); 613 this.showNotification({ 614 title: `File ${file_name} successfully downloaded`, 615 type: "success" 616 }); 617 } 618 } else { 619 this.updateBuffer( 620 `${this.buffer}${newLine}Error transferring file${newLine}` 621 ); 622 this.showError("Error transferring file", [ 623 { error: { message: error || "Something went wrong." } } 624 ]); 625 } 626 this.enableCmdInput = true;
627 this.emit(RESPONSE_FINISHED_EVENT, this.enableCmdInput); 628 } else if (parsedData.type === MessageType.Response) { 629 const decodedMessage = decodeUTF16LE( 630 toByteArray(parsedData.data.message) 631 ); 632 this.currentFolder = parsedData.data.cwd ? decodeUTF16LE(toByteArray(parsedData.data.cwd)) + ">" : ""; 633 this.emit(CURRENT_FOLDER_CHANGE_EVENT, this.currentFolder); 634 this.updateBuffer(this.buffer + decodedMessage); 635 const hasCwd = !!parsedData?.data?.cwd; 636 if (hasCwd) { 637 this.isInsideAnExecCmd = false; 638 this.enableCmdInput = true; 639 } else { 640 if (this.lastCommand?.startsWith("exec") || this.lastCommand?.startsWith("put") || this.lastCommand?.startsWith("get") || this.lastCommand?.startsWith("del") || this.lastCommand?.startsWith("cat") || this.lastCommand?.startsWith("move") || this.lastCommand?.startsWith("reg") || this.lastCommand?.startsWith("sc")) { 641 this.isInsideAnExecCmd = true; 642 } 643 this.enableCmdInput = this.isInsideAnExecCmd; 644 } 645 this.emit(RESPONSE_FINISHED_EVENT, this.enableCmdInput); 646 const payload = JSON.stringify({ 647 data: { 648 id: messageObj.id 649 }, 650 type: MessageType.ResponseAck 651 }); 652 const iv = window.crypto.getRandomValues(new Uint8Array(12)); 653 if (this.aesKey) { 654 const encrypted = await window.crypto.subtle.encrypt( 655 { 656 iv, 657 name: "AES-GCM" 658 }, 659 this.aesKey, 660 stringToArrayBuffer(payload) 661 ); 662 const encryptedPayload = fromByteArray( 663 new Uint8Array(encrypted.slice(0, -16)) 664 ); 665 const gcm_tag = fromByteArray( 666 new Uint8Array(encrypted.slice(-16)) 667 ); 668 this.sendJsonMessage({ 669 action: ActionType.Message, 670 body: { 671 gcm_tag, 672 iv: fromByteArray(new Uint8Array(iv)), 673 payload: encryptedPayload 674 }, 675 session_id: this.sessionId 676 }); 677 } 678 } 679 } catch (err) { 680 this.showError("Error in decrypt", err); 681 } 682 }; 683 handleSymmetricalKeyDecryption = async (symmetricalKey) => { 684 if (this.rsaKeyPair?.privateKey) { 685 const decrypted = await window.crypto.subtle.decrypt( 686 { 687 name: "RSA-OAEP" 688 }, 689 this.rsaKeyPair?.privateKey, 690 toByteArray(symmetricalKey) 691 ); 692 const str = await arrayBufferToString(decrypted); 693 const k = str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); 694 try { 695 const key = await crypto.subtle.importKey( 696 "jwk", 697 { 698 alg: "A256GCM", 699 ext: false, 700 k, 701 kty: "oct" 702 }, 703 { name: "AES-GCM" }, 704 false, 705 ["encrypt", "decrypt"] 706 ); 707 this.sendJsonMessage({ 708 action: ActionType.Message, 709 handshake_completed: { 710 success: true, 711 user_email: this.userInfo.email, 712 user_id: this.userInfo.id, 713 user_name: this.userInfo.name 714 }, 715 session_id: this.sessionId 716 }); 717 this.aesKey = key; 718 this.sendAuditLog({ 719 message: "handleSymmetricalKeyDecryption done", 720 account_id: this.accountId, 721 connection_start: true, 722 machine_id: this.machineId, 723 pc_hostname: this.machineName, 724 session_id: this.sessionId, 725 user_id: this.userInfo.id || "" 726 }); 727 } catch (err) { 728 this.showError("Description error", [ 729 { error: { message: "Error importing key." } } 730 ]); 731 } 732 } 733 }; 734 startARSSession = async (authToken) => { 735 const url = `${this.arsBaseUrl}/start?client_type=web`; 736 this.authToken = authToken; 737 this.connecting = true; 738 this.emit(CONNECTING_CHANGE_EVENT, this.connecting); 739 this.startProgress("connection in progress"); 740 try { 741 const response = await fetch(url, { 742 method: "POST", 743 headers: { 744 "Content-type": "application/json; charset=UTF-8", 745 accept: "application/json", 746 authorization: `Bearer ${this.authToken}` 747 }, 748 body: JSON.stringify({ 749 "account_id": this.accountId, 750 "machine_id": this.machineId 751 }) 752 }); 753 if (!response.ok) { 754 const errorPayload = await response.json(); 755 console.error(`Error! status: ${response.status} ${JSON.stringify(errorPayload)}`); 756 this.connecting = false;
757 this.emit(CONNECTING_CHANGE_EVENT, this.connecting); 758 this.connected = false; 759 this.emit(CONNECTED_CHANGE_EVENT, this.connected); 760 return { 761 error: { message: `${response.status} ${JSON.stringify(errorPayload)}`, code: response.status } 762 }; 763 } 764 const result = await response.json(); 765 const wsUrl = result["ws_url"]; 766 this.sessionId = result["session_id"]; 767 this.ws = new WebSocket(encodeURI(`${wsUrl}?client_type=web&session_id=${this.sessionId}`), authToken); 768 await this.startRemoteShell(); 769 this.connecting = false; 770 this.emit(CONNECTING_CHANGE_EVENT, this.connecting); 771 this.connected = true; 772 this.emit(CONNECTED_CHANGE_EVENT, this.connected); 773 this.updateProgress("web socket connected"); 774 return this.ws; 775 } catch (error) { 776 if (error instanceof Error) { 777 this.connected = false; 778 this.emit(CONNECTED_CHANGE_EVENT, this.connected); 779 this.connecting = false; 780 this.emit(CONNECTING_CHANGE_EVENT, this.connecting); 781 console.error("error during startARSSession: ", error.message); 782 return { 783 error: { message: error.message } 784 }; 785 } else { 786 this.connected = false; 787 this.emit(CONNECTED_CHANGE_EVENT, this.connected); 788 this.connecting = false; 789 this.emit(CONNECTING_CHANGE_EVENT, this.connecting); 790 console.error("unexpected error: ", error); 791 return null; 792 } 793 } 794 }; 795 startRemoteShell = async () => { 796 const instance = this; 797 try { 798 if (!instance.ws) { 799 return; 800 } 801 instance.ws.onclose = function() { 802 instance.quitArsSession("web socket has been closed!"); 803 }; 804 instance.ws.onerror = function(event) { 805 instance.quitArsSession(`web socket has been closed due to an error: ${event}`); 806 }; 807 instance.ws.onmessage = async function(message) { 808 instance.downloading = true; 809 instance.emit(DOWNLOADING_CHANGE_EVENT, instance.downloading); 810 const messageObj = JSON.parse(message.data); 811 if (messageObj) { 812 if (messageObj.connection) { 813 instance.connecting = false; 814 instance.emit(CONNECTING_CHANGE_EVENT, instance.connecting); 815 instance.updateProgress("initiating handshake"); 816 await instance.handleConnectedSocket(); 817 instance.connected = true; 818 instance.emit(CONNECTED_CHANGE_EVENT, instance.connected); 819 } else if (messageObj.symmetrical_key) { 820 instance.updateProgress("handling keys"); 821 await instance.handleSymmetricalKeyDecryption(messageObj.symmetrical_key); 822 } else if (messageObj.action === "health") { 823 instance.stopProgress(); 824 instance.quitArsSession(endSessionString); 825 } else if (messageObj.body) { 826 await instance.handleMessage(messageObj); 827 } 828 } 829 instance.downloading = false; 830 instance.emit(DOWNLOADING_CHANGE_EVENT, instance.downloading); 831 }; 832 instance.ws.onopen = function() { 833 instance.handleTimeoutsAndIntervals(); 834 }; 835 } catch (error) { 836 instance.showError("problem starting Remote Shell", []); 837 } 838 }; 839} 840 841const RemoteShellHandler$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({ 842 __proto__: null, 843 BUFFER_CHANGE_EVENT, 844 CONNECTED_CHANGE_EVENT, 845 CONNECTING_CHANGE_EVENT, 846 CONNECTION_ESTABLISHED_EVENT, 847 CURRENT_FOLDER_CHANGE_EVENT, 848 DOWNLOADING_CHANGE_EVENT, 849 INPUT_CHANGE_EVENT, 850 RESPONSE_FINISHED_EVENT, 851 RemoteShellHandler, 852 UPLOADING_CHANGE_EVENT 853}, Symbol.toStringTag, { value: 'Module' })); 854 855export { ActionType as A, BUFFER_CHANGE_EVENT as B, CONNECTED_CHANGE_EVENT as C, DOWNLOADING_CHANGE_EVENT as D, INPUT_CHANGE_EVENT as I, MessageType as M, RESPONSE_FINISHED_EVENT as R, SpecialMessage as S, UPLOADING_CHANGE_EVENT as U, CONNECTING_CHANGE_EVENT as a, CURRENT_FOLDER_CHANGE_EVENT as b, CONNECTION_ESTABLISHED_EVENT as c, RemoteShellHandler$1 as d, newLine as n };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.