| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  | import Websock from "./websock"; | 
					
						
							|  |  |  | import * as message from "./message.js"; | 
					
						
							|  |  |  | import * as rendezvous from "./rendezvous.js"; | 
					
						
							| 
									
										
										
										
											2022-02-06 03:13:41 +08:00
										 |  |  | import { loadVp9 } from "./codec"; | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  | import * as sha256 from "fast-sha256"; | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  | import * as globals from "./globals"; | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  | import { decompress, mapKey, sleep } from "./common"; | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 02:27:49 +08:00
										 |  |  | const PORT = 21116; | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  | const HOSTS = [ | 
					
						
							|  |  |  |   "rs-sg.rustdesk.com", | 
					
						
							|  |  |  |   "rs-cn.rustdesk.com", | 
					
						
							|  |  |  |   "rs-us.rustdesk.com", | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | let HOST = localStorage.getItem("rendezvous-server") || HOSTS[0]; | 
					
						
							| 
									
										
										
										
											2022-01-27 01:30:29 +08:00
										 |  |  | const SCHEMA = "ws://"; | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  | type MsgboxCallback = (type: string, title: string, text: string) => void; | 
					
						
							| 
									
										
										
										
											2022-01-21 00:42:33 +08:00
										 |  |  | type DrawCallback = (data: Uint8Array) => void; | 
					
						
							| 
									
										
										
										
											2022-04-07 15:00:06 +08:00
										 |  |  | //const cursorCanvas = document.createElement("canvas");
 | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 02:27:49 +08:00
										 |  |  | export default class Connection { | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |   _msgs: any[]; | 
					
						
							|  |  |  |   _ws: Websock | undefined; | 
					
						
							|  |  |  |   _interval: any; | 
					
						
							|  |  |  |   _id: string; | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |   _hash: message.Hash | undefined; | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |   _msgbox: MsgboxCallback; | 
					
						
							|  |  |  |   _draw: DrawCallback; | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |   _peerInfo: message.PeerInfo | undefined; | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |   _firstFrame: Boolean | undefined; | 
					
						
							|  |  |  |   _videoDecoder: any; | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |   _password: Uint8Array | undefined; | 
					
						
							| 
									
										
										
										
											2022-01-26 18:58:55 +08:00
										 |  |  |   _options: any; | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |   _videoTestSpeed: number[]; | 
					
						
							| 
									
										
										
										
											2022-04-07 15:00:06 +08:00
										 |  |  |   //_cursors: { [name: number]: any };
 | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   constructor() { | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |     this._msgbox = globals.msgbox; | 
					
						
							|  |  |  |     this._draw = globals.draw; | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     this._msgs = []; | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |     this._id = ""; | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |     this._videoTestSpeed = [0, 0]; | 
					
						
							| 
									
										
										
										
											2022-04-07 15:00:06 +08:00
										 |  |  |     //this._cursors = {};
 | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async start(id: string) { | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       await this._start(id); | 
					
						
							|  |  |  |     } catch (e: any) { | 
					
						
							|  |  |  |       this.msgbox( | 
					
						
							|  |  |  |         "error", | 
					
						
							|  |  |  |         "Connection Error", | 
					
						
							|  |  |  |         e.type == "close" ? "Reset by the peer" : String(e) | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async _start(id: string) { | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |     if (!this._options) { | 
					
						
							|  |  |  |       this._options = globals.getPeers()[id] || {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!this._password) { | 
					
						
							|  |  |  |       const p = this.getOption("password"); | 
					
						
							|  |  |  |       if (p) { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           this._password = Uint8Array.from(JSON.parse("[" + p + "]")); | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           console.error(e); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-01-26 18:58:55 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     this._interval = setInterval(() => { | 
					
						
							|  |  |  |       while (this._msgs.length) { | 
					
						
							|  |  |  |         this._ws?.sendMessage(this._msgs[0]); | 
					
						
							|  |  |  |         this._msgs.splice(0, 1); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, 1); | 
					
						
							| 
									
										
										
										
											2022-01-31 00:34:45 +08:00
										 |  |  |     this.loadVideoDecoder(); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |     const uri = getDefaultUri(); | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |     const ws = new Websock(uri, true); | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     this._ws = ws; | 
					
						
							|  |  |  |     this._id = id; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |     console.log( | 
					
						
							| 
									
										
										
										
											2023-01-09 02:30:34 -05:00
										 |  |  |       new Date() + ": Connecting to rendezvous server: " + uri + ", for " + id | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     await ws.open(); | 
					
						
							| 
									
										
										
										
											2023-01-09 02:30:34 -05:00
										 |  |  |     console.log(new Date() + ": Connected to rendezvous server"); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     const conn_type = rendezvous.ConnType.DEFAULT_CONN; | 
					
						
							|  |  |  |     const nat_type = rendezvous.NatType.SYMMETRIC; | 
					
						
							|  |  |  |     const punch_hole_request = rendezvous.PunchHoleRequest.fromPartial({ | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |       id, | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       licence_key: localStorage.getItem("key") || undefined, | 
					
						
							|  |  |  |       conn_type, | 
					
						
							|  |  |  |       nat_type, | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |       token: localStorage.getItem("access_token") || undefined, | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     ws.sendRendezvous({ punch_hole_request }); | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |     const msg = (await ws.next()) as rendezvous.RendezvousMessage; | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |     ws.close(); | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |     console.log(new Date() + ": Got relay response"); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     const phr = msg.punch_hole_response; | 
					
						
							|  |  |  |     const rr = msg.relay_response; | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     if (phr) { | 
					
						
							| 
									
										
										
										
											2022-03-25 18:56:55 +08:00
										 |  |  |       if (phr?.other_failure) { | 
					
						
							|  |  |  |         this.msgbox("error", "Error", phr?.other_failure); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |       if (phr.failure != rendezvous.PunchHoleResponse_Failure.UNRECOGNIZED) { | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |         switch (phr?.failure) { | 
					
						
							|  |  |  |           case rendezvous.PunchHoleResponse_Failure.ID_NOT_EXIST: | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |             this.msgbox("error", "Error", "ID does not exist"); | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |           case rendezvous.PunchHoleResponse_Failure.OFFLINE: | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |             this.msgbox("error", "Error", "Remote desktop is offline"); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |             break; | 
					
						
							|  |  |  |           case rendezvous.PunchHoleResponse_Failure.LICENSE_MISMATCH: | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |             this.msgbox("error", "Error", "Key mismatch"); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2022-03-25 18:56:55 +08:00
										 |  |  |           case rendezvous.PunchHoleResponse_Failure.LICENSE_OVERUSE: | 
					
						
							|  |  |  |             this.msgbox("error", "Error", "Key overuse"); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else if (rr) { | 
					
						
							| 
									
										
										
										
											2022-03-25 18:56:55 +08:00
										 |  |  |       if (!rr.version) { | 
					
						
							|  |  |  |         this.msgbox("error", "Error", "Remote version is low, not support web"); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |       await this.connectRelay(rr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async connectRelay(rr: rendezvous.RelayResponse) { | 
					
						
							|  |  |  |     const pk = rr.pk; | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     let uri = rr.relay_server; | 
					
						
							| 
									
										
										
										
											2022-01-20 02:27:49 +08:00
										 |  |  |     if (uri) { | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |       uri = getrUriFromRs(uri, true, 2); | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-01-20 02:27:49 +08:00
										 |  |  |       uri = getDefaultUri(true); | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     const uuid = rr.uuid; | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |     console.log(new Date() + ": Connecting to relay server: " + uri); | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |     const ws = new Websock(uri, false); | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     await ws.open(); | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |     console.log(new Date() + ": Connected to relay server"); | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |     this._ws = ws; | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     const request_relay = rendezvous.RequestRelay.fromPartial({ | 
					
						
							|  |  |  |       licence_key: localStorage.getItem("key") || undefined, | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |       uuid, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     ws.sendRendezvous({ request_relay }); | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |     const secure = (await this.secure(pk)) || false; | 
					
						
							|  |  |  |     globals.pushEvent("connection_ready", { secure, direct: false }); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |     await this.msgLoop(); | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async secure(pk: Uint8Array | undefined) { | 
					
						
							| 
									
										
										
										
											2022-01-20 12:49:57 +08:00
										 |  |  |     if (pk) { | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |       const RS_PK = "OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw="; | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |       try { | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |         pk = await globals.verify(pk, localStorage.getItem("key") || RS_PK); | 
					
						
							|  |  |  |         if (pk) { | 
					
						
							|  |  |  |           const idpk = message.IdPk.decode(pk); | 
					
						
							|  |  |  |           if (idpk.id == this._id) { | 
					
						
							|  |  |  |             pk = idpk.pk; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |         if (pk?.length != 32) { | 
					
						
							|  |  |  |           pk = undefined; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         console.error(e); | 
					
						
							|  |  |  |         pk = undefined; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |       if (!pk) | 
					
						
							|  |  |  |         console.error( | 
					
						
							|  |  |  |           "Handshake failed: invalid public key from rendezvous server" | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (!pk) { | 
					
						
							|  |  |  |       // send an empty message out in case server is setting up secure and waiting for first message
 | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |       const public_key = message.PublicKey.fromPartial({}); | 
					
						
							|  |  |  |       this._ws?.sendMessage({ public_key }); | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |     const msg = (await this._ws?.next()) as message.Message; | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     let signedId: any = msg?.signed_id; | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |     if (!signedId) { | 
					
						
							|  |  |  |       console.error("Handshake failed: invalid message type"); | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |       const public_key = message.PublicKey.fromPartial({}); | 
					
						
							|  |  |  |       this._ws?.sendMessage({ public_key }); | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       signedId = await globals.verify(signedId.id, Uint8Array.from(pk!)); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       console.error(e); | 
					
						
							|  |  |  |       // fall back to non-secure connection in case pk mismatch
 | 
					
						
							|  |  |  |       console.error("pk mismatch, fall back to non-secure"); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       const public_key = message.PublicKey.fromPartial({}); | 
					
						
							|  |  |  |       this._ws?.sendMessage({ public_key }); | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |     const idpk = message.IdPk.decode(signedId); | 
					
						
							|  |  |  |     const id = idpk.id; | 
					
						
							|  |  |  |     const theirPk = idpk.pk; | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |     if (id != this._id!) { | 
					
						
							|  |  |  |       console.error("Handshake failed: sign failure"); | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |       const public_key = message.PublicKey.fromPartial({}); | 
					
						
							|  |  |  |       this._ws?.sendMessage({ public_key }); | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (theirPk.length != 32) { | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |       console.error( | 
					
						
							|  |  |  |         "Handshake failed: invalid public box key length from peer" | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |       const public_key = message.PublicKey.fromPartial({}); | 
					
						
							|  |  |  |       this._ws?.sendMessage({ public_key }); | 
					
						
							| 
									
										
										
										
											2022-01-20 15:41:11 +08:00
										 |  |  |       return; | 
					
						
							| 
									
										
										
										
											2022-01-20 12:49:57 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     const [mySk, asymmetric_value] = globals.genBoxKeyPair(); | 
					
						
							|  |  |  |     const secret_key = globals.genSecretKey(); | 
					
						
							|  |  |  |     const symmetric_value = globals.seal(secret_key, theirPk, mySk); | 
					
						
							|  |  |  |     const public_key = message.PublicKey.fromPartial({ | 
					
						
							|  |  |  |       asymmetric_value, | 
					
						
							|  |  |  |       symmetric_value, | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     this._ws?.sendMessage({ public_key }); | 
					
						
							|  |  |  |     this._ws?.setSecretKey(secret_key); | 
					
						
							|  |  |  |     console.log("secured"); | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   async msgLoop() { | 
					
						
							|  |  |  |     while (true) { | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |       const msg = (await this._ws?.next()) as message.Message; | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |       if (msg?.hash) { | 
					
						
							|  |  |  |         this._hash = msg?.hash; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |         if (!this._password) | 
					
						
							|  |  |  |           this.msgbox("input-password", "Password Required", ""); | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |         this.login(); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       } else if (msg?.test_delay) { | 
					
						
							|  |  |  |         const test_delay = msg?.test_delay; | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |         console.log(test_delay); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         if (!test_delay.from_client) { | 
					
						
							|  |  |  |           this._ws?.sendMessage({ test_delay }); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       } else if (msg?.login_response) { | 
					
						
							|  |  |  |         const r = msg?.login_response; | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |         if (r.error) { | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |           if (r.error == "Wrong Password") { | 
					
						
							|  |  |  |             this._password = undefined; | 
					
						
							|  |  |  |             this.msgbox( | 
					
						
							|  |  |  |               "re-input-password", | 
					
						
							|  |  |  |               r.error, | 
					
						
							|  |  |  |               "Do you want to enter again?" | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             this.msgbox("error", "Login Error", r.error); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         } else if (r.peer_info) { | 
					
						
							|  |  |  |           this.handlePeerInfo(r.peer_info); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       } else if (msg?.video_frame) { | 
					
						
							|  |  |  |         this.handleVideoFrame(msg?.video_frame!); | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |       } else if (msg?.clipboard) { | 
					
						
							|  |  |  |         const cb = msg?.clipboard; | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         if (cb.compress) { | 
					
						
							|  |  |  |           const c = await decompress(cb.content); | 
					
						
							|  |  |  |           if (!c) continue; | 
					
						
							|  |  |  |           cb.content = c; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-03-26 18:04:42 +08:00
										 |  |  |         try { | 
					
						
							| 
									
										
										
										
											2022-04-07 15:00:06 +08:00
										 |  |  |           globals.copyToClipboard(new TextDecoder().decode(cb.content)); | 
					
						
							| 
									
										
										
										
											2022-03-26 18:04:42 +08:00
										 |  |  |         } catch (e) { | 
					
						
							|  |  |  |           console.error(e); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // globals.pushEvent("clipboard", cb);
 | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       } else if (msg?.cursor_data) { | 
					
						
							|  |  |  |         const cd = msg?.cursor_data; | 
					
						
							|  |  |  |         const c = await decompress(cd.colors); | 
					
						
							|  |  |  |         if (!c) continue; | 
					
						
							|  |  |  |         cd.colors = c; | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |         globals.pushEvent("cursor_data", cd); | 
					
						
							| 
									
										
										
										
											2022-04-07 15:00:06 +08:00
										 |  |  |         /* | 
					
						
							|  |  |  |         let ctx = cursorCanvas.getContext("2d"); | 
					
						
							|  |  |  |         cursorCanvas.width = cd.width; | 
					
						
							|  |  |  |         cursorCanvas.height = cd.height; | 
					
						
							|  |  |  |         let imgData = new ImageData( | 
					
						
							|  |  |  |           new Uint8ClampedArray(c), | 
					
						
							|  |  |  |           cd.width, | 
					
						
							|  |  |  |           cd.height | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         ctx?.clearRect(0, 0, cd.width, cd.height); | 
					
						
							|  |  |  |         ctx?.putImageData(imgData, 0, 0); | 
					
						
							|  |  |  |         let url = cursorCanvas.toDataURL(); | 
					
						
							|  |  |  |         const img = document.createElement("img"); | 
					
						
							|  |  |  |         img.src = url; | 
					
						
							|  |  |  |         this._cursors[cd.id] = img; | 
					
						
							|  |  |  |         //cursorCanvas.width /= 2.;
 | 
					
						
							|  |  |  |         //cursorCanvas.height /= 2.;
 | 
					
						
							|  |  |  |         //ctx?.drawImage(img, cursorCanvas.width, cursorCanvas.height);
 | 
					
						
							|  |  |  |         url = cursorCanvas.toDataURL(); | 
					
						
							|  |  |  |         document.body.style.cursor = | 
					
						
							|  |  |  |           "url(" + url + ")" + cd.hotx + " " + cd.hoty + ", default"; | 
					
						
							|  |  |  |         console.log(document.body.style.cursor); | 
					
						
							|  |  |  |         */ | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       } else if (msg?.cursor_id) { | 
					
						
							|  |  |  |         globals.pushEvent("cursor_id", { id: msg?.cursor_id }); | 
					
						
							|  |  |  |       } else if (msg?.cursor_position) { | 
					
						
							|  |  |  |         globals.pushEvent("cursor_position", msg?.cursor_position); | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |       } else if (msg?.misc) { | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |         if (!this.handleMisc(msg?.misc)) break; | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       } else if (msg?.audio_frame) { | 
					
						
							| 
									
										
										
										
											2022-02-06 03:13:41 +08:00
										 |  |  |         globals.playAudio(msg?.audio_frame.data); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   msgbox(type_: string, title: string, text: string) { | 
					
						
							|  |  |  |     this._msgbox?.(type_, title, text); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-27 23:32:51 +08:00
										 |  |  |   draw(frame: any) { | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |     this._draw?.(frame); | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |     globals.draw(frame); | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |   close() { | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |     this._msgs = []; | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |     clearInterval(this._interval); | 
					
						
							|  |  |  |     this._ws?.close(); | 
					
						
							| 
									
										
										
										
											2022-01-21 00:41:02 +08:00
										 |  |  |     this._videoDecoder?.close(); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-27 23:32:51 +08:00
										 |  |  |   refresh() { | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |     const misc = message.Misc.fromPartial({ refresh_video: true }); | 
					
						
							| 
									
										
										
										
											2022-01-27 23:32:51 +08:00
										 |  |  |     this._ws?.sendMessage({ misc }); | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |   setMsgbox(callback: MsgboxCallback) { | 
					
						
							|  |  |  |     this._msgbox = callback; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |   setDraw(callback: DrawCallback) { | 
					
						
							|  |  |  |     this._draw = callback; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |   login(password: string | undefined = undefined) { | 
					
						
							| 
									
										
										
										
											2022-01-27 13:24:40 +08:00
										 |  |  |     if (password) { | 
					
						
							|  |  |  |       const salt = this._hash?.salt; | 
					
						
							|  |  |  |       let p = hash([password, salt!]); | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |       this._password = p; | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |       const challenge = this._hash?.challenge; | 
					
						
							| 
									
										
										
										
											2022-01-27 13:24:40 +08:00
										 |  |  |       p = hash([p, challenge!]); | 
					
						
							|  |  |  |       this.msgbox("connecting", "Connecting...", "Logging in..."); | 
					
						
							| 
									
										
										
										
											2022-01-27 23:32:51 +08:00
										 |  |  |       this._sendLoginMessage(p); | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |       let p = this._password; | 
					
						
							|  |  |  |       if (p) { | 
					
						
							|  |  |  |         const challenge = this._hash?.challenge; | 
					
						
							|  |  |  |         p = hash([p, challenge!]); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this._sendLoginMessage(p); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |   async reconnect() { | 
					
						
							|  |  |  |     this.close(); | 
					
						
							|  |  |  |     await this.start(this._id); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-27 23:32:51 +08:00
										 |  |  |   _sendLoginMessage(password: Uint8Array | undefined = undefined) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     const login_request = message.LoginRequest.fromPartial({ | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |       username: this._id!, | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       my_id: "web", // to-do
 | 
					
						
							|  |  |  |       my_name: "web", // to-do
 | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |       password, | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       option: this.getOptionMessage(), | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |       video_ack_required: true, | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     this._ws?.sendMessage({ login_request }); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-20 18:44:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |   getOptionMessage(): message.OptionMessage | undefined { | 
					
						
							|  |  |  |     let n = 0; | 
					
						
							|  |  |  |     const msg = message.OptionMessage.fromPartial({}); | 
					
						
							| 
									
										
										
										
											2022-01-31 00:34:45 +08:00
										 |  |  |     const q = this.getImageQualityEnum(this.getImageQuality(), true); | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |     const yes = message.OptionMessage_BoolOption.Yes; | 
					
						
							|  |  |  |     if (q != undefined) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       msg.image_quality = q; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       n += 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (this._options["show-remote-cursor"]) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       msg.show_remote_cursor = yes; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       n += 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (this._options["lock-after-session-end"]) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       msg.lock_after_session_end = yes; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       n += 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (this._options["privacy-mode"]) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       msg.privacy_mode = yes; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       n += 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (this._options["disable-audio"]) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       msg.disable_audio = yes; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       n += 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (this._options["disable-clipboard"]) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       msg.disable_clipboard = yes; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       n += 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return n > 0 ? msg : undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |   sendVideoReceived() { | 
					
						
							|  |  |  |     const misc = message.Misc.fromPartial({ video_received: true }); | 
					
						
							|  |  |  |     this._ws?.sendMessage({ misc }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |   handleVideoFrame(vf: message.VideoFrame) { | 
					
						
							| 
									
										
										
										
											2022-01-20 18:44:28 +08:00
										 |  |  |     if (!this._firstFrame) { | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |       this.msgbox("", "", ""); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:44:28 +08:00
										 |  |  |       this._firstFrame = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |     if (vf.vp9s) { | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |       const dec = this._videoDecoder; | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |       var tm = new Date().getTime(); | 
					
						
							|  |  |  |       var i = 0; | 
					
						
							|  |  |  |       const n = vf.vp9s?.frames.length; | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |       vf.vp9s.frames.forEach((f) => { | 
					
						
							| 
									
										
										
										
											2022-01-21 00:41:02 +08:00
										 |  |  |         dec.processFrame(f.data.slice(0).buffer, (ok: any) => { | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |           i++; | 
					
						
							|  |  |  |           if (i == n) this.sendVideoReceived(); | 
					
						
							|  |  |  |           if (ok && dec.frameBuffer && n == i) { | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |             this.draw(dec.frameBuffer); | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |             const now = new Date().getTime(); | 
					
						
							|  |  |  |             var elapsed = now - tm; | 
					
						
							|  |  |  |             this._videoTestSpeed[1] += elapsed; | 
					
						
							|  |  |  |             this._videoTestSpeed[0] += 1; | 
					
						
							|  |  |  |             if (this._videoTestSpeed[0] >= 30) { | 
					
						
							|  |  |  |               console.log( | 
					
						
							|  |  |  |                 "video decoder: " + | 
					
						
							|  |  |  |                   parseInt( | 
					
						
							|  |  |  |                     "" + this._videoTestSpeed[1] / this._videoTestSpeed[0] | 
					
						
							|  |  |  |                   ) | 
					
						
							|  |  |  |               ); | 
					
						
							|  |  |  |               this._videoTestSpeed = [0, 0]; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-20 18:44:28 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   handlePeerInfo(pi: message.PeerInfo) { | 
					
						
							|  |  |  |     this._peerInfo = pi; | 
					
						
							|  |  |  |     if (pi.displays.length == 0) { | 
					
						
							|  |  |  |       this.msgbox("error", "Remote Error", "No Display"); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.msgbox("success", "Successful", "Connected, waiting for image..."); | 
					
						
							|  |  |  |     globals.pushEvent("peer_info", pi); | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |     const p = this.shouldAutoLogin(); | 
					
						
							|  |  |  |     if (p) this.inputOsPassword(p); | 
					
						
							|  |  |  |     const username = this.getOption("info")?.username; | 
					
						
							|  |  |  |     if (username && !pi.username) pi.username = username; | 
					
						
							|  |  |  |     this.setOption("info", pi); | 
					
						
							|  |  |  |     if (this.getRemember()) { | 
					
						
							|  |  |  |       if (this._password?.length) { | 
					
						
							|  |  |  |         const p = this._password.toString(); | 
					
						
							|  |  |  |         if (p != this.getOption("password")) { | 
					
						
							|  |  |  |           this.setOption("password", p); | 
					
						
							|  |  |  |           console.log("remember password of " + this._id); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       this.setOption("password", undefined); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   shouldAutoLogin(): string { | 
					
						
							|  |  |  |     const l = this.getOption("lock-after-session-end"); | 
					
						
							|  |  |  |     const a = !!this.getOption("auto-login"); | 
					
						
							|  |  |  |     const p = this.getOption("os-password"); | 
					
						
							|  |  |  |     if (p && l && a) { | 
					
						
							|  |  |  |       return p; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ""; | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   handleMisc(misc: message.Misc) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     if (misc.audio_format) { | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |       globals.initAudio( | 
					
						
							|  |  |  |         misc.audio_format.channels, | 
					
						
							|  |  |  |         misc.audio_format.sample_rate | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |     } else if (misc.chat_message) { | 
					
						
							| 
									
										
										
										
											2022-02-10 00:07:04 +08:00
										 |  |  |       globals.pushEvent("chat", { text: misc.chat_message.text }); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     } else if (misc.permission_info) { | 
					
						
							|  |  |  |       const p = misc.permission_info; | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |       console.info("Change permission " + p.permission + " -> " + p.enabled); | 
					
						
							|  |  |  |       let name; | 
					
						
							|  |  |  |       switch (p.permission) { | 
					
						
							|  |  |  |         case message.PermissionInfo_Permission.Keyboard: | 
					
						
							|  |  |  |           name = "keyboard"; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         case message.PermissionInfo_Permission.Clipboard: | 
					
						
							|  |  |  |           name = "clipboard"; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         case message.PermissionInfo_Permission.Audio: | 
					
						
							|  |  |  |           name = "audio"; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       globals.pushEvent("permission", { [name]: p.enabled }); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     } else if (misc.switch_display) { | 
					
						
							| 
									
										
										
										
											2022-01-31 00:34:45 +08:00
										 |  |  |       this.loadVideoDecoder(); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |       globals.pushEvent("switch_display", misc.switch_display); | 
					
						
							|  |  |  |     } else if (misc.close_reason) { | 
					
						
							|  |  |  |       this.msgbox("error", "Connection Error", misc.close_reason); | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |       this.close(); | 
					
						
							|  |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2022-01-26 12:39:44 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-26 18:58:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-31 00:48:04 +08:00
										 |  |  |   getRemember(): Boolean { | 
					
						
							|  |  |  |     return this._options["remember"] || false; | 
					
						
							| 
									
										
										
										
											2022-01-26 18:58:55 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |   setRemember(v: Boolean) { | 
					
						
							|  |  |  |     this.setOption("remember", v); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-26 18:58:55 +08:00
										 |  |  |   getOption(name: string): any { | 
					
						
							|  |  |  |     return this._options[name]; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   setOption(name: string, value: any) { | 
					
						
							| 
									
										
										
										
											2022-01-30 19:48:41 +08:00
										 |  |  |     if (value == undefined) { | 
					
						
							|  |  |  |       delete this._options[name]; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       this._options[name] = value; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this._options["tm"] = new Date().getTime(); | 
					
						
							|  |  |  |     const peers = globals.getPeers(); | 
					
						
							|  |  |  |     peers[this._id] = this._options; | 
					
						
							|  |  |  |     localStorage.setItem("peers", JSON.stringify(peers)); | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |   inputKey( | 
					
						
							|  |  |  |     name: string, | 
					
						
							| 
									
										
										
										
											2022-02-03 21:26:35 +08:00
										 |  |  |     down: boolean, | 
					
						
							|  |  |  |     press: boolean, | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     alt: Boolean, | 
					
						
							|  |  |  |     ctrl: Boolean, | 
					
						
							|  |  |  |     shift: Boolean, | 
					
						
							|  |  |  |     command: Boolean | 
					
						
							|  |  |  |   ) { | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |     const key_event = mapKey(name, globals.isDesktop()); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     if (!key_event) return; | 
					
						
							| 
									
										
										
										
											2022-04-25 18:27:15 +08:00
										 |  |  |     if (alt && (name == "VK_MENU" || name == "RAlt")) { | 
					
						
							| 
									
										
										
										
											2022-02-03 21:26:35 +08:00
										 |  |  |       alt = false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-04-25 18:27:15 +08:00
										 |  |  |     if (ctrl && (name == "VK_CONTROL" || name == "RControl")) { | 
					
						
							| 
									
										
										
										
											2022-02-03 21:26:35 +08:00
										 |  |  |       ctrl = false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-04-25 18:27:15 +08:00
										 |  |  |     if (shift && (name == "VK_SHIFT" || name == "RShift")) { | 
					
						
							| 
									
										
										
										
											2022-02-03 21:26:35 +08:00
										 |  |  |       shift = false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |     if (command && (name == "Meta" || name == "RWin")) { | 
					
						
							| 
									
										
										
										
											2022-02-03 21:26:35 +08:00
										 |  |  |       command = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     key_event.down = down; | 
					
						
							|  |  |  |     key_event.press = press; | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     key_event.modifiers = this.getMod(alt, ctrl, shift, command); | 
					
						
							|  |  |  |     this._ws?.sendMessage({ key_event }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ctrlAltDel() { | 
					
						
							|  |  |  |     const key_event = message.KeyEvent.fromPartial({ down: true }); | 
					
						
							|  |  |  |     if (this._peerInfo?.platform == "Windows") { | 
					
						
							|  |  |  |       key_event.control_key = message.ControlKey.CtrlAltDel; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       key_event.control_key = message.ControlKey.Delete; | 
					
						
							|  |  |  |       key_event.modifiers = this.getMod(true, true, false, false); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this._ws?.sendMessage({ key_event }); | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   inputString(seq: string) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     const key_event = message.KeyEvent.fromPartial({ seq }); | 
					
						
							|  |  |  |     this._ws?.sendMessage({ key_event }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switchDisplay(display: number) { | 
					
						
							|  |  |  |     const switch_display = message.SwitchDisplay.fromPartial({ display }); | 
					
						
							|  |  |  |     const misc = message.Misc.fromPartial({ switch_display }); | 
					
						
							|  |  |  |     this._ws?.sendMessage({ misc }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async inputOsPassword(seq: string) { | 
					
						
							|  |  |  |     this.inputMouse(); | 
					
						
							|  |  |  |     await sleep(50); | 
					
						
							|  |  |  |     this.inputMouse(0, 3, 3); | 
					
						
							|  |  |  |     await sleep(50); | 
					
						
							|  |  |  |     this.inputMouse(1 | (1 << 3)); | 
					
						
							|  |  |  |     this.inputMouse(2 | (1 << 3)); | 
					
						
							|  |  |  |     await sleep(1200); | 
					
						
							|  |  |  |     const key_event = message.KeyEvent.fromPartial({ press: true, seq }); | 
					
						
							|  |  |  |     this._ws?.sendMessage({ key_event }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   lockScreen() { | 
					
						
							|  |  |  |     const key_event = message.KeyEvent.fromPartial({ | 
					
						
							|  |  |  |       down: true, | 
					
						
							|  |  |  |       control_key: message.ControlKey.LockScreen, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     this._ws?.sendMessage({ key_event }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getMod(alt: Boolean, ctrl: Boolean, shift: Boolean, command: Boolean) { | 
					
						
							|  |  |  |     const mod: message.ControlKey[] = []; | 
					
						
							|  |  |  |     if (alt) mod.push(message.ControlKey.Alt); | 
					
						
							|  |  |  |     if (ctrl) mod.push(message.ControlKey.Control); | 
					
						
							|  |  |  |     if (shift) mod.push(message.ControlKey.Shift); | 
					
						
							|  |  |  |     if (command) mod.push(message.ControlKey.Meta); | 
					
						
							|  |  |  |     return mod; | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |   inputMouse( | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     mask: number = 0, | 
					
						
							|  |  |  |     x: number = 0, | 
					
						
							|  |  |  |     y: number = 0, | 
					
						
							|  |  |  |     alt: Boolean = false, | 
					
						
							|  |  |  |     ctrl: Boolean = false, | 
					
						
							|  |  |  |     shift: Boolean = false, | 
					
						
							|  |  |  |     command: Boolean = false | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |   ) { | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     const mouse_event = message.MouseEvent.fromPartial({ | 
					
						
							|  |  |  |       mask, | 
					
						
							|  |  |  |       x, | 
					
						
							|  |  |  |       y, | 
					
						
							|  |  |  |       modifiers: this.getMod(alt, ctrl, shift, command), | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     this._ws?.sendMessage({ mouse_event }); | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   toggleOption(name: string) { | 
					
						
							|  |  |  |     const v = !this._options[name]; | 
					
						
							|  |  |  |     const option = message.OptionMessage.fromPartial({}); | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |     const v2 = v | 
					
						
							|  |  |  |       ? message.OptionMessage_BoolOption.Yes | 
					
						
							|  |  |  |       : message.OptionMessage_BoolOption.No; | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |     switch (name) { | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "show-remote-cursor": | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         option.show_remote_cursor = v2; | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "disable-audio": | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         option.disable_audio = v2; | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "disable-clipboard": | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         option.disable_clipboard = v2; | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "lock-after-session-end": | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         option.lock_after_session_end = v2; | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "privacy-mode": | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         option.privacy_mode = v2; | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "block-input": | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         option.block_input = message.OptionMessage_BoolOption.Yes; | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "unblock-input": | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |         option.block_input = message.OptionMessage_BoolOption.No; | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |     if (name.indexOf("block-input") < 0) this.setOption(name, v); | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |     const misc = message.Misc.fromPartial({ option }); | 
					
						
							|  |  |  |     this._ws?.sendMessage({ misc }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-31 00:34:45 +08:00
										 |  |  |   getImageQuality() { | 
					
						
							| 
									
										
										
										
											2022-02-05 01:55:23 +08:00
										 |  |  |     return this.getOption("image-quality"); | 
					
						
							| 
									
										
										
										
											2022-01-31 00:34:45 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |   getImageQualityEnum( | 
					
						
							|  |  |  |     value: string, | 
					
						
							|  |  |  |     ignoreDefault: Boolean | 
					
						
							|  |  |  |   ): message.ImageQuality | undefined { | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |     switch (value) { | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "low": | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         return message.ImageQuality.Low; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "best": | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         return message.ImageQuality.Best; | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |       case "balanced": | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |         return ignoreDefault ? undefined : message.ImageQuality.Balanced; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         return undefined; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setImageQuality(value: string) { | 
					
						
							| 
									
										
										
										
											2022-01-29 21:49:19 +08:00
										 |  |  |     this.setOption("image-quality", value); | 
					
						
							| 
									
										
										
										
											2022-01-30 03:39:54 +08:00
										 |  |  |     const image_quality = this.getImageQualityEnum(value, false); | 
					
						
							|  |  |  |     if (image_quality == undefined) return; | 
					
						
							|  |  |  |     const option = message.OptionMessage.fromPartial({ image_quality }); | 
					
						
							| 
									
										
										
										
											2022-01-29 11:31:05 +08:00
										 |  |  |     const misc = message.Misc.fromPartial({ option }); | 
					
						
							|  |  |  |     this._ws?.sendMessage({ misc }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-31 00:34:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   loadVideoDecoder() { | 
					
						
							|  |  |  |     this._videoDecoder?.close(); | 
					
						
							|  |  |  |     loadVp9((decoder: any) => { | 
					
						
							|  |  |  |       this._videoDecoder = decoder; | 
					
						
							|  |  |  |       console.log("vp9 loaded"); | 
					
						
							|  |  |  |       console.log(decoder); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-06 03:38:32 +08:00
										 |  |  | function testDelay() { | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |   var nearest = ""; | 
					
						
							| 
									
										
										
										
											2022-02-06 03:38:32 +08:00
										 |  |  |   HOSTS.forEach((host) => { | 
					
						
							|  |  |  |     const now = new Date().getTime(); | 
					
						
							|  |  |  |     new Websock(getrUriFromRs(host), true).open().then(() => { | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |       console.log("latency of " + host + ": " + (new Date().getTime() - now)); | 
					
						
							| 
									
										
										
										
											2022-02-06 03:38:32 +08:00
										 |  |  |       if (!nearest) { | 
					
						
							|  |  |  |         HOST = host; | 
					
						
							| 
									
										
										
										
											2022-02-06 16:24:31 +08:00
										 |  |  |         localStorage.setItem("rendezvous-server", host); | 
					
						
							| 
									
										
										
										
											2022-02-06 03:38:32 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2022-01-20 01:00:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-06 03:38:32 +08:00
										 |  |  | testDelay(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 02:27:49 +08:00
										 |  |  | function getDefaultUri(isRelay: Boolean = false): string { | 
					
						
							| 
									
										
										
										
											2022-01-26 18:58:55 +08:00
										 |  |  |   const host = localStorage.getItem("custom-rendezvous-server"); | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |   return getrUriFromRs(host || HOST, isRelay); | 
					
						
							| 
									
										
										
										
											2022-01-20 02:27:49 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  | function getrUriFromRs( | 
					
						
							|  |  |  |   uri: string, | 
					
						
							|  |  |  |   isRelay: Boolean = false, | 
					
						
							|  |  |  |   roffset: number = 0 | 
					
						
							|  |  |  | ): string { | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |   if (uri.indexOf(":") > 0) { | 
					
						
							|  |  |  |     const tmp = uri.split(":"); | 
					
						
							| 
									
										
										
										
											2022-01-20 02:27:49 +08:00
										 |  |  |     const port = parseInt(tmp[1]); | 
					
						
							| 
									
										
										
										
											2022-03-26 16:30:38 +08:00
										 |  |  |     uri = tmp[0] + ":" + (port + (isRelay ? roffset || 3 : 2)); | 
					
						
							| 
									
										
										
										
											2022-01-20 02:27:49 +08:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2022-02-06 03:38:32 +08:00
										 |  |  |     uri += ":" + (PORT + (isRelay ? 3 : 2)); | 
					
						
							| 
									
										
										
										
											2022-01-20 02:27:49 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-01-20 12:49:57 +08:00
										 |  |  |   return SCHEMA + uri; | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  | function hash(datas: (string | Uint8Array)[]): Uint8Array { | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |   const hasher = new sha256.Hash(); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |   datas.forEach((data) => { | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  |     if (typeof data == "string") { | 
					
						
							| 
									
										
										
										
											2022-01-20 18:41:35 +08:00
										 |  |  |       data = new TextEncoder().encode(data); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return hasher.update(data); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2022-01-20 18:02:20 +08:00
										 |  |  |   return hasher.digest(); | 
					
						
							| 
									
										
										
										
											2022-01-20 21:58:28 +08:00
										 |  |  | } |