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

View File

@ -1,7 +1,39 @@
import Connection from "./connection"; import Connection from "./connection";
import _sodium from "libsodium-wrappers"; 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.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) { export function setConn(conn) {
window.currentConnection = conn; window.currentConnection = conn;
@ -14,6 +46,7 @@ export function getConn() {
export function close() { export function close() {
getConn()?.close(); getConn()?.close();
setConn(undefined); setConn(undefined);
currentFrame = undefined;
} }
export function newConn() { export function newConn() {
@ -74,3 +107,57 @@ export function encrypt(unsigned, nonce, key) {
export function decrypt(signed, nonce, key) { export function decrypt(signed, nonce, key) {
return sodium.crypto_secretbox_open_easy(signed, makeOnce(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" rollup "^2.59.0"
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" 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==