From b8ff266d76895a23dde358ee030c275d037ba89f Mon Sep 17 00:00:00 2001 From: open-trade Date: Thu, 20 Jan 2022 18:02:20 +0800 Subject: [PATCH] msgLoop works --- src/connection.ts | 57 ++++++++++++++++++++++++++++++++++++++++++++--- src/globals.js | 32 +++++++++++++++++++------- src/ui.js | 37 ++++++++++++++++++++++++++---- src/websock.ts | 33 ++++++++++++++------------- 4 files changed, 129 insertions(+), 30 deletions(-) diff --git a/src/connection.ts b/src/connection.ts index f0cd100d1..a2311e123 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -2,6 +2,7 @@ import Websock from './websock'; import * as message from './message.js'; import * as rendezvous from './rendezvous.js'; import { loadVp9, loadOpus } from './codec'; +import * as sha256 from "fast-sha256"; import * as globals from './globals'; const PORT = 21116; @@ -9,11 +10,15 @@ const HOST = 'rs-sg.rustdesk.com'; const licenceKey = ''; const SCHEMA = 'ws://'; +type MsgboxCallback = (type: string, title: string, text: string) => void; + export default class Connection { _msgs: any[]; _ws: Websock | undefined; _interval: any; _id: string; + _hash: message.Hash | undefined; + _msgbox: MsgboxCallback | undefined; constructor() { this._msgs = []; @@ -31,11 +36,18 @@ export default class Connection { this._ws?.close(); } + setMsgbox(callback: MsgboxCallback) { + this._msgbox = callback; + } + async start(id: string) { - const ws = new Websock(getDefaultUri()); + const uri = getDefaultUri(); + const ws = new Websock(uri); this._ws = ws; this._id = id; + console.log(new Date() + ': Conntecting to rendezvoous server: ' + uri); await ws.open(); + console.log(new Date() + ': Connected to rendezvoous server'); const connType = rendezvous.ConnType.DEFAULT_CONN; const natType = rendezvous.NatType.SYMMETRIC; const punchHoleRequest = rendezvous.PunchHoleRequest.fromPartial({ @@ -46,15 +58,27 @@ export default class Connection { }); ws.sendRendezvous({ punchHoleRequest }); const msg = ws.parseRendezvous(await ws.next()); + ws.close(); + console.log(new Date() + ': Got relay response'); const phr = msg.punchHoleResponse; const rr = msg.relayResponse; if (phr) { if (phr.failure != rendezvous.PunchHoleResponse_Failure.UNKNOWN) { switch (phr?.failure) { case rendezvous.PunchHoleResponse_Failure.ID_NOT_EXIST: + this.msgbox('error', 'Error', 'ID does not exist'); break; + case rendezvous.PunchHoleResponse_Failure.OFFLINE: + this.msgbox('error', 'Error', 'Remote desktop is offline'); + break; + case rendezvous.PunchHoleResponse_Failure.LICENSE_MISMATCH: + this.msgbox('error', 'Error', 'Key mismatch'); + break; + default: + if (phr?.otherFailure) { + this.msgbox('error', 'Error', phr?.otherFailure); + } } - ws.close(); } } else if (rr) { await this.connectRelay(rr); @@ -70,9 +94,10 @@ export default class Connection { uri = getDefaultUri(true); } const uuid = rr.uuid; + console.log(new Date() + ': Connecting to relay server: ' + uri); const ws = new Websock(uri); await ws.open(); - console.log('Connected to relay server'); + console.log(new Date() + ': Connected to relay server'); this._ws = ws; const requestRelay = rendezvous.RequestRelay.fromPartial({ licenceKey, @@ -80,6 +105,7 @@ export default class Connection { }); ws.sendRendezvous({ requestRelay }); await this.secure(pk); + await this.msgLoop(); } async secure(pk: Uint8Array | undefined) { @@ -140,6 +166,25 @@ export default class Connection { await this._ws?.sendMessage({ publicKey }); this._ws?.setSecretKey(secretKey) } + + async msgLoop() { + while (true) { + const msg = this._ws?.parseMessage(await this._ws?.next()); + if (msg?.hash) { + this._hash = msg?.hash; + this.msgbox("input-password", "Password Required", ""); + } else if (msg?.testDelay) { + const testDelay = msg?.testDelay; + if (!testDelay.fromClient) { + await this._ws?.sendMessage({ testDelay }); + } + } + } + } + + msgbox(type_: string, title: string, text: string) { + this._msgbox?.(type_, title, text); + } } async function testDelay() { @@ -162,4 +207,10 @@ function getrUriFromRs(uri: string): string { uri += ':' + (PORT + 3); } return SCHEMA + uri; +} + +function hash(datas: [string]): Uint8Array { + const hasher = new sha256.Hash(); + datas.forEach((data) => hasher.update(new TextEncoder().encode(data))); + return hasher.digest(); } \ No newline at end of file diff --git a/src/globals.js b/src/globals.js index f804f5278..cd3828dec 100644 --- a/src/globals.js +++ b/src/globals.js @@ -8,13 +8,19 @@ export function setConn(conn) { } export function getConn() { - return windows.currentConnection; + return window.currentConnection; } -export async function startConn(id) { +export function close() { + getConn()?.close(); + setConn(undefined); +} + +export function newConn() { + window.currentConnection?.close(); const conn = new Connection(); setConn(conn); - await conn.start('124931507'); + return conn; } let sodium; @@ -49,12 +55,22 @@ export function seal(unsigned, theirPk, ourSk) { return sodium.crypto_box_easy(unsigned, nonce, theirPk, ourSk); } +function makeOnce(value) { + var byteArray = Array(24).fill(0); + + for (var index = 0; index < byteArray.length && value > 0; index++) { + var byte = value & 0xff; + byteArray[index] = byte; + value = (value - byte) / 256; + } + + return Uint8Array.from(byteArray); +}; + export function encrypt(unsigned, nonce, key) { - return sodium.crypto_secretbox_easy(unsigned, nonce, key); + return sodium.crypto_secretbox_easy(unsigned, makeOnce(nonce), key); } export function decrypt(signed, nonce, key) { - return sodium.crypto_secretbox_open_easy(signed, nonce, key); -} - -window.startConn = startConn; \ No newline at end of file + return sodium.crypto_secretbox_open_easy(signed, makeOnce(nonce), key); +} \ No newline at end of file diff --git a/src/ui.js b/src/ui.js index 9bae1326c..e2495d1b3 100644 --- a/src/ui.js +++ b/src/ui.js @@ -1,6 +1,6 @@ import "./style.css"; import "./connection"; -import { startConn } from "./globals"; +import * as globals from "./globals"; const app = document.querySelector('#app'); @@ -17,6 +17,10 @@ if (app) { + `; document.body.onload = () => { @@ -35,14 +39,39 @@ if (app) { localStorage.setItem('id', id.value); const key = document.querySelector('#key'); localStorage.setItem('key', key.value); - document.querySelector('div#connect').style.display = 'none'; - document.querySelector('div#password').style.display = 'block'; - startConn(id); + const func = async () => { + const conn = globals.newConn(); + conn.setMsgbox(msgbox); + document.querySelector('div#status').style.display = 'block'; + document.querySelector('div#connect').style.display = 'none'; + document.querySelector('div#text').innerHTML = 'Connecting ...'; + try { + await conn.start(id.value); + } catch (e) { + msgbox('error', 'Error', e); + } + }; + func(); + } + + function msgbox(type, title, text) { + if (!globals.getConn()) return; + if (type == 'input-password') { + document.querySelector('div#status').style.display = 'none'; + document.querySelector('div#password').style.display = 'block'; + } else if (!type) { + document.querySelector('div#status').style.display = 'none'; + } else { + document.querySelector('div#status').style.display = 'block'; + document.querySelector('div#text').innerHTML = '
' + text + '
'; + } } window.cancel = () => { + globals.close(); document.querySelector('div#connect').style.display = 'block'; document.querySelector('div#password').style.display = 'none'; + document.querySelector('div#status').style.display = 'none'; } window.confirm = () => { diff --git a/src/websock.ts b/src/websock.ts index f09cc181e..1ce2c45e7 100644 --- a/src/websock.ts +++ b/src/websock.ts @@ -1,6 +1,6 @@ import * as message from "./message.js"; import * as rendezvous from "./rendezvous.js"; -import * as sha256 from "fast-sha256"; +import * as globals from "./globals"; type Keys = "message" | "open" | "close" | "error"; @@ -10,7 +10,7 @@ export default class Websock { _buf: Uint8Array[]; _status: any; _latency: number; - _secretKey: any; + _secretKey: [Uint8Array, number, number] | undefined; constructor(uri: string) { this._eventHandlers = { @@ -31,14 +31,18 @@ export default class Websock { return this._latency; } - setSecretKey(key: any) { - this._secretKey = key; + setSecretKey(key: Uint8Array) { + this._secretKey = [key, 0, 0]; } - sendMessage(data: any) { - this._websocket.send( - message.Message.encode(message.Message.fromPartial(data)).finish() - ); + sendMessage(json: any) { + let data = message.Message.encode(message.Message.fromPartial(json)).finish(); + let k = this._secretKey; + if (k) { + k[1] += 1; + data = globals.encrypt(data, k[1], k[0]); + } + this._websocket.send(data); } sendRendezvous(data: any) { @@ -144,15 +148,14 @@ export default class Websock { _recv_message(e: any) { if (e.data instanceof window.ArrayBuffer) { - const bytes = new Uint8Array(e.data); + let bytes = new Uint8Array(e.data); + const k = this._secretKey; + if (k) { + k[2] += 1; + bytes = globals.decrypt(bytes, k[2], k[0]); + } this._buf.push(bytes); } this._eventHandlers.message(e.data); } - - hash(datas: [Uint8Array]): Uint8Array { - const hasher = new sha256.Hash(); - datas.forEach((data) => hasher.update(data)); - return hasher.digest(); - } }