This commit is contained in:
rustdesk 2022-01-26 12:39:44 +08:00
parent 2846804234
commit f4c3198037
4 changed files with 183 additions and 24 deletions

View File

@ -15,6 +15,7 @@
"libsodium": "^0.7.9",
"libsodium-wrappers": "^0.7.9",
"ogv": "^1.8.6",
"ts-proto": "^1.101.0"
"ts-proto": "^1.101.0",
"zstddec": "^0.0.2"
}
}

View File

@ -19,16 +19,22 @@ export default class Connection {
_interval: any;
_id: string;
_hash: message.Hash | undefined;
_msgbox: MsgboxCallback | undefined;
_draw: DrawCallback | undefined;
_msgbox: MsgboxCallback;
_draw: DrawCallback;
_peerInfo: message.PeerInfo | undefined;
_firstFrame: Boolean | undefined;
_videoDecoder: any;
_audioDecoder: any;
_password: string | undefined;
constructor() {
this._msgbox = globals.msgbox;
this._draw = globals.draw;
this._msgs = [];
this._id = "";
}
async start(id: string) {
this._interval = setInterval(() => {
while (this._msgs.length) {
this._ws?.sendMessage(this._msgs[0]);
@ -44,9 +50,6 @@ export default class Connection {
this._audioDecoder = decoder;
console.log("opus loaded");
});
}
async start(id: string) {
const uri = getDefaultUri();
const ws = new Websock(uri);
this._ws = ws;
@ -69,7 +72,7 @@ export default class Connection {
const phr = msg.punchHoleResponse;
const rr = msg.relayResponse;
if (phr) {
if (phr.failure != rendezvous.PunchHoleResponse_Failure.UNKNOWN) {
if (phr.failure != rendezvous.PunchHoleResponse_Failure.UNRECOGNIZED) {
switch (phr?.failure) {
case rendezvous.PunchHoleResponse_Failure.ID_NOT_EXIST:
this.msgbox("error", "Error", "ID does not exist");
@ -110,7 +113,8 @@ export default class Connection {
uuid,
});
ws.sendRendezvous({ requestRelay });
await this.secure(pk);
const secure = (await this.secure(pk)) || false;
globals.pushEvent("connection_ready", { secure, direct: false });
await this.msgLoop();
}
@ -179,6 +183,7 @@ export default class Connection {
});
await this._ws?.sendMessage({ publicKey });
this._ws?.setSecretKey(secretKey);
return true;
}
async msgLoop() {
@ -186,7 +191,7 @@ export default class Connection {
const msg = this._ws?.parseMessage(await this._ws?.next());
if (msg?.hash) {
this._hash = msg?.hash;
await this.handleHash();
await this.login(this._password);
this.msgbox("input-password", "Password Required", "");
} else if (msg?.testDelay) {
const testDelay = msg?.testDelay;
@ -198,23 +203,30 @@ export default class Connection {
if (r.error) {
this.msgbox("error", "Error", r.error);
} else if (r.peerInfo) {
this._peerInfo = r.peerInfo;
this.msgbox(
"success",
"Successful",
"Connected, waiting for image..."
);
this.handlePeerInfo(r.peerInfo);
}
} else if (msg?.videoFrame) {
this.handleVideoFrame(msg?.videoFrame!);
} else if (msg?.clipboard) {
const cb = msg?.clipboard;
if (cb.compress) cb.content = globals.decompress(cb.content);
globals.pushEvent("clipboard", cb);
} else if (msg?.cursorData) {
const cd = msg?.cursorData;
cd.colors = globals.decompress(cd.colors);
globals.pushEvent("cursor_data", cd);
} else if (msg?.cursorId) {
globals.pushEvent("cursor_id", { id: msg?.cursorId });
} else if (msg?.cursorPosition) {
globals.pushEvent("cursor_position", msg?.cursorPosition);
} else if (msg?.misc) {
this.handleMisc(msg?.misc);
} else if (msg?.audioFrame) {
//
}
}
}
async handleHash() {
await this._sendLoginMessage();
}
msgbox(type_: string, title: string, text: string) {
this._msgbox?.(type_, title, text);
}
@ -224,12 +236,20 @@ export default class Connection {
}
close() {
this._msgs = [];
clearInterval(this._interval);
this._ws?.close();
this._videoDecoder?.close();
this._audioDecoder?.close();
}
async refresh() {
const misc = message.Misc.fromPartial({
refreshVideo: true,
});
await this._ws?.sendMessage({ misc });
}
setMsgbox(callback: MsgboxCallback) {
this._msgbox = callback;
}
@ -238,19 +258,27 @@ export default class Connection {
this._draw = callback;
}
async login(password: string) {
async login(password: string | undefined, _remember: Boolean = false) {
this._password = password;
this.msgbox("connecting", "Connecting...", "Logging in...");
let salt = this._hash?.salt;
if (salt) {
const salt = this._hash?.salt;
if (salt && password) {
let p = hash([password, salt]);
let challenge = this._hash?.challenge;
const challenge = this._hash?.challenge;
if (challenge) {
p = hash([p, challenge]);
await this._sendLoginMessage(p);
}
} else {
await this._sendLoginMessage();
}
}
async reconnect() {
this.close();
await this.start(this._id);
}
async _sendLoginMessage(password: Uint8Array | undefined = undefined) {
const loginRequest = message.LoginRequest.fromPartial({
username: this._id!,
@ -267,7 +295,7 @@ export default class Connection {
this._firstFrame = true;
}
if (vf.vp9s) {
let dec = this._videoDecoder;
const dec = this._videoDecoder;
// dec.sync();
vf.vp9s.frames.forEach((f) => {
dec.processFrame(f.data.slice(0).buffer, (ok: any) => {
@ -278,6 +306,44 @@ export default class Connection {
});
}
}
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);
}
handleMisc(misc: message.Misc) {
if (misc.audioFormat) {
//
} else if (misc.permissionInfo) {
const p = misc.permissionInfo;
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 });
} else if (misc.switchDisplay) {
globals.pushEvent("switch_display", misc.switchDisplay);
} else if (misc.closeReason) {
this.msgbox("error", "Connection Error", misc.closeReason);
}
}
}
// @ts-ignore

View File

@ -1,7 +1,39 @@
import Connection from "./connection";
import _sodium from "libsodium-wrappers";
import { ZSTDecoder } from 'zstddec';
const decompressor = new ZSTDDecoder();
await decompressor.init();
var currentFrame = undefined;
var events = [];
window.currentConnection = undefined;
window.getRgba = () => currentFrame;
window.getLanguage = () => navigator.language;
export function msgbox(type, title, text) {
text = text.toLowerCase();
var hasRetry = msgtype == "error"
&& title == "Connection Error"
&& !text.indexOf("offline") >= 0
&& !text.indexOf("exist") >= 0
&& !text.indexOf("handshake") >= 0
&& !text.indexOf("failed") >= 0
&& !text.indexOf("resolve") >= 0
&& !text.indexOf("mismatch") >= 0
&& !text.indexOf("manually") >= 0;
events.push({ name: 'msgbox', type, title, text, hasRetry });
}
export function pushEvent(name, payload) {
payload.name = name;
events.push(payload);
}
export function draw(frame) {
currentFrame = frame;
}
export function setConn(conn) {
window.currentConnection = conn;
@ -14,6 +46,7 @@ export function getConn() {
export function close() {
getConn()?.close();
setConn(undefined);
currentFrame = undefined;
}
export function newConn() {
@ -73,4 +106,58 @@ export function encrypt(unsigned, nonce, key) {
export function decrypt(signed, nonce, key) {
return sodium.crypto_secretbox_open_easy(signed, makeOnce(nonce), key);
}
export function decompress(compressedArray) {
const MAX = 1024 * 1024 * 64;
const MIN = 1024 * 1024;
let n = 30 * data.length;
if (n > MAX) {
n = MAX;
}
if (n < MIN) {
n = MIN;
}
try {
return decompressor.decode(compressedArray, n);
} catch (e) {
console.error('decompress failed: ' + e);
}
}
window.setByName = (name, value) => {
switch (name) {
case 'connect':
newConn();
break;
case 'login':
currentConnection.login(value.password, value.remember);
break;
case 'close':
close();
break;
case 'refresh':
currentConnection.refresh();
break;
case 'reconnect':
currentConnection.reconnect();
break;
default:
break;
}
}
window.getByName = (name, value) => {
switch (name) {
case 'peers':
return localStorage.getItem('peers');
break;
case 'event':
if (events.length) {
const e = events[0];
events.splice(0, 1);
return e;
}
break;
}
}

View File

@ -376,3 +376,8 @@ vite@^2.7.2:
rollup "^2.59.0"
optionalDependencies:
fsevents "~2.3.2"
zstddec@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/zstddec/-/zstddec-0.0.2.tgz#57e2f28dd1ff56b750e07d158a43f0611ad9eeb4"
integrity sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==