msgLoop works
This commit is contained in:
parent
70c213a60a
commit
b8ff266d76
@ -2,6 +2,7 @@ import Websock from './websock';
|
|||||||
import * as message from './message.js';
|
import * as message from './message.js';
|
||||||
import * as rendezvous from './rendezvous.js';
|
import * as rendezvous from './rendezvous.js';
|
||||||
import { loadVp9, loadOpus } from './codec';
|
import { loadVp9, loadOpus } from './codec';
|
||||||
|
import * as sha256 from "fast-sha256";
|
||||||
import * as globals from './globals';
|
import * as globals from './globals';
|
||||||
|
|
||||||
const PORT = 21116;
|
const PORT = 21116;
|
||||||
@ -9,11 +10,15 @@ const HOST = 'rs-sg.rustdesk.com';
|
|||||||
const licenceKey = '';
|
const licenceKey = '';
|
||||||
const SCHEMA = 'ws://';
|
const SCHEMA = 'ws://';
|
||||||
|
|
||||||
|
type MsgboxCallback = (type: string, title: string, text: string) => void;
|
||||||
|
|
||||||
export default class Connection {
|
export default class Connection {
|
||||||
_msgs: any[];
|
_msgs: any[];
|
||||||
_ws: Websock | undefined;
|
_ws: Websock | undefined;
|
||||||
_interval: any;
|
_interval: any;
|
||||||
_id: string;
|
_id: string;
|
||||||
|
_hash: message.Hash | undefined;
|
||||||
|
_msgbox: MsgboxCallback | undefined;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._msgs = [];
|
this._msgs = [];
|
||||||
@ -31,11 +36,18 @@ export default class Connection {
|
|||||||
this._ws?.close();
|
this._ws?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMsgbox(callback: MsgboxCallback) {
|
||||||
|
this._msgbox = callback;
|
||||||
|
}
|
||||||
|
|
||||||
async start(id: string) {
|
async start(id: string) {
|
||||||
const ws = new Websock(getDefaultUri());
|
const uri = getDefaultUri();
|
||||||
|
const ws = new Websock(uri);
|
||||||
this._ws = ws;
|
this._ws = ws;
|
||||||
this._id = id;
|
this._id = id;
|
||||||
|
console.log(new Date() + ': Conntecting to rendezvoous server: ' + uri);
|
||||||
await ws.open();
|
await ws.open();
|
||||||
|
console.log(new Date() + ': Connected to rendezvoous server');
|
||||||
const connType = rendezvous.ConnType.DEFAULT_CONN;
|
const connType = rendezvous.ConnType.DEFAULT_CONN;
|
||||||
const natType = rendezvous.NatType.SYMMETRIC;
|
const natType = rendezvous.NatType.SYMMETRIC;
|
||||||
const punchHoleRequest = rendezvous.PunchHoleRequest.fromPartial({
|
const punchHoleRequest = rendezvous.PunchHoleRequest.fromPartial({
|
||||||
@ -46,15 +58,27 @@ export default class Connection {
|
|||||||
});
|
});
|
||||||
ws.sendRendezvous({ punchHoleRequest });
|
ws.sendRendezvous({ punchHoleRequest });
|
||||||
const msg = ws.parseRendezvous(await ws.next());
|
const msg = ws.parseRendezvous(await ws.next());
|
||||||
|
ws.close();
|
||||||
|
console.log(new Date() + ': Got relay response');
|
||||||
const phr = msg.punchHoleResponse;
|
const phr = msg.punchHoleResponse;
|
||||||
const rr = msg.relayResponse;
|
const rr = msg.relayResponse;
|
||||||
if (phr) {
|
if (phr) {
|
||||||
if (phr.failure != rendezvous.PunchHoleResponse_Failure.UNKNOWN) {
|
if (phr.failure != rendezvous.PunchHoleResponse_Failure.UNKNOWN) {
|
||||||
switch (phr?.failure) {
|
switch (phr?.failure) {
|
||||||
case rendezvous.PunchHoleResponse_Failure.ID_NOT_EXIST:
|
case rendezvous.PunchHoleResponse_Failure.ID_NOT_EXIST:
|
||||||
|
this.msgbox('error', 'Error', 'ID does not exist');
|
||||||
break;
|
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) {
|
} else if (rr) {
|
||||||
await this.connectRelay(rr);
|
await this.connectRelay(rr);
|
||||||
@ -70,9 +94,10 @@ export default class Connection {
|
|||||||
uri = getDefaultUri(true);
|
uri = getDefaultUri(true);
|
||||||
}
|
}
|
||||||
const uuid = rr.uuid;
|
const uuid = rr.uuid;
|
||||||
|
console.log(new Date() + ': Connecting to relay server: ' + uri);
|
||||||
const ws = new Websock(uri);
|
const ws = new Websock(uri);
|
||||||
await ws.open();
|
await ws.open();
|
||||||
console.log('Connected to relay server');
|
console.log(new Date() + ': Connected to relay server');
|
||||||
this._ws = ws;
|
this._ws = ws;
|
||||||
const requestRelay = rendezvous.RequestRelay.fromPartial({
|
const requestRelay = rendezvous.RequestRelay.fromPartial({
|
||||||
licenceKey,
|
licenceKey,
|
||||||
@ -80,6 +105,7 @@ export default class Connection {
|
|||||||
});
|
});
|
||||||
ws.sendRendezvous({ requestRelay });
|
ws.sendRendezvous({ requestRelay });
|
||||||
await this.secure(pk);
|
await this.secure(pk);
|
||||||
|
await this.msgLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
async secure(pk: Uint8Array | undefined) {
|
async secure(pk: Uint8Array | undefined) {
|
||||||
@ -140,6 +166,25 @@ export default class Connection {
|
|||||||
await this._ws?.sendMessage({ publicKey });
|
await this._ws?.sendMessage({ publicKey });
|
||||||
this._ws?.setSecretKey(secretKey)
|
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() {
|
async function testDelay() {
|
||||||
@ -163,3 +208,9 @@ function getrUriFromRs(uri: string): string {
|
|||||||
}
|
}
|
||||||
return SCHEMA + uri;
|
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();
|
||||||
|
}
|
@ -8,13 +8,19 @@ export function setConn(conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getConn() {
|
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();
|
const conn = new Connection();
|
||||||
setConn(conn);
|
setConn(conn);
|
||||||
await conn.start('124931507');
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sodium;
|
let sodium;
|
||||||
@ -49,12 +55,22 @@ export function seal(unsigned, theirPk, ourSk) {
|
|||||||
return sodium.crypto_box_easy(unsigned, nonce, 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) {
|
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) {
|
export function decrypt(signed, nonce, key) {
|
||||||
return sodium.crypto_secretbox_open_easy(signed, nonce, key);
|
return sodium.crypto_secretbox_open_easy(signed, makeOnce(nonce), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.startConn = startConn;
|
|
33
src/ui.js
33
src/ui.js
@ -1,6 +1,6 @@
|
|||||||
import "./style.css";
|
import "./style.css";
|
||||||
import "./connection";
|
import "./connection";
|
||||||
import { startConn } from "./globals";
|
import * as globals from "./globals";
|
||||||
|
|
||||||
const app = document.querySelector('#app');
|
const app = document.querySelector('#app');
|
||||||
|
|
||||||
@ -17,6 +17,10 @@ if (app) {
|
|||||||
<button id="confirm" id="confirm()">Confirm</button>
|
<button id="confirm" id="confirm()">Confirm</button>
|
||||||
<button id="cancel" onclick="cancel();">Cancel</button>
|
<button id="cancel" onclick="cancel();">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="status" style="display: none;">
|
||||||
|
<div id="text" style="line-height: 2em"></div>
|
||||||
|
<button id="cancel" onclick="cancel();">Cancel</button>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
document.body.onload = () => {
|
document.body.onload = () => {
|
||||||
@ -35,14 +39,39 @@ if (app) {
|
|||||||
localStorage.setItem('id', id.value);
|
localStorage.setItem('id', id.value);
|
||||||
const key = document.querySelector('#key');
|
const key = document.querySelector('#key');
|
||||||
localStorage.setItem('key', key.value);
|
localStorage.setItem('key', key.value);
|
||||||
|
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#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';
|
document.querySelector('div#password').style.display = 'block';
|
||||||
startConn(id);
|
} else if (!type) {
|
||||||
|
document.querySelector('div#status').style.display = 'none';
|
||||||
|
} else {
|
||||||
|
document.querySelector('div#status').style.display = 'block';
|
||||||
|
document.querySelector('div#text').innerHTML = '<div style="color: red; font-weight: bold;">' + text + '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.cancel = () => {
|
window.cancel = () => {
|
||||||
|
globals.close();
|
||||||
document.querySelector('div#connect').style.display = 'block';
|
document.querySelector('div#connect').style.display = 'block';
|
||||||
document.querySelector('div#password').style.display = 'none';
|
document.querySelector('div#password').style.display = 'none';
|
||||||
|
document.querySelector('div#status').style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
window.confirm = () => {
|
window.confirm = () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as message from "./message.js";
|
import * as message from "./message.js";
|
||||||
import * as rendezvous from "./rendezvous.js";
|
import * as rendezvous from "./rendezvous.js";
|
||||||
import * as sha256 from "fast-sha256";
|
import * as globals from "./globals";
|
||||||
|
|
||||||
type Keys = "message" | "open" | "close" | "error";
|
type Keys = "message" | "open" | "close" | "error";
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ export default class Websock {
|
|||||||
_buf: Uint8Array[];
|
_buf: Uint8Array[];
|
||||||
_status: any;
|
_status: any;
|
||||||
_latency: number;
|
_latency: number;
|
||||||
_secretKey: any;
|
_secretKey: [Uint8Array, number, number] | undefined;
|
||||||
|
|
||||||
constructor(uri: string) {
|
constructor(uri: string) {
|
||||||
this._eventHandlers = {
|
this._eventHandlers = {
|
||||||
@ -31,14 +31,18 @@ export default class Websock {
|
|||||||
return this._latency;
|
return this._latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSecretKey(key: any) {
|
setSecretKey(key: Uint8Array) {
|
||||||
this._secretKey = key;
|
this._secretKey = [key, 0, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage(data: any) {
|
sendMessage(json: any) {
|
||||||
this._websocket.send(
|
let data = message.Message.encode(message.Message.fromPartial(json)).finish();
|
||||||
message.Message.encode(message.Message.fromPartial(data)).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) {
|
sendRendezvous(data: any) {
|
||||||
@ -144,15 +148,14 @@ export default class Websock {
|
|||||||
|
|
||||||
_recv_message(e: any) {
|
_recv_message(e: any) {
|
||||||
if (e.data instanceof window.ArrayBuffer) {
|
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._buf.push(bytes);
|
||||||
}
|
}
|
||||||
this._eventHandlers.message(e.data);
|
this._eventHandlers.message(e.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
hash(datas: [Uint8Array]): Uint8Array {
|
|
||||||
const hasher = new sha256.Hash();
|
|
||||||
datas.forEach((data) => hasher.update(data));
|
|
||||||
return hasher.digest();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user