2022-01-20 21:58:28 +08:00
|
|
|
import Websock from "./websock";
|
|
|
|
import * as message from "./message.js";
|
|
|
|
import * as rendezvous from "./rendezvous.js";
|
|
|
|
import { loadVp9, loadOpus } 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-20 01:00:35 +08:00
|
|
|
|
2022-01-20 02:27:49 +08:00
|
|
|
const PORT = 21116;
|
2022-01-27 01:30:29 +08:00
|
|
|
const HOST = "rs-sg.rustdesk.com";
|
|
|
|
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-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;
|
|
|
|
_audioDecoder: any;
|
2022-01-26 12:39:44 +08:00
|
|
|
_password: string | undefined;
|
2022-01-26 18:58:55 +08:00
|
|
|
_options: 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-01-26 12:39:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
async start(id: string) {
|
2022-01-26 18:58:55 +08:00
|
|
|
try {
|
2022-01-27 01:30:29 +08:00
|
|
|
this._options =
|
|
|
|
JSON.parse(localStorage.getItem("peers") || "{}")[id] || {};
|
2022-01-26 18:58:55 +08:00
|
|
|
} catch (e) {
|
|
|
|
this._options = {};
|
|
|
|
}
|
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-20 21:58:28 +08:00
|
|
|
loadVp9((decoder: any) => {
|
|
|
|
this._videoDecoder = decoder;
|
|
|
|
console.log("vp9 loaded");
|
|
|
|
console.log(decoder);
|
|
|
|
});
|
|
|
|
loadOpus((decoder: any) => {
|
|
|
|
this._audioDecoder = decoder;
|
|
|
|
console.log("opus loaded");
|
|
|
|
});
|
2022-01-20 18:02:20 +08:00
|
|
|
const uri = getDefaultUri();
|
|
|
|
const ws = new Websock(uri);
|
2022-01-20 01:00:35 +08:00
|
|
|
this._ws = ws;
|
|
|
|
this._id = id;
|
2022-01-27 13:24:40 +08:00
|
|
|
console.log(new Date() + ": Conntecting to rendezvoous server: " + uri + ", for " + id);
|
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 rendezvoous server");
|
2022-01-20 01:00:35 +08:00
|
|
|
const connType = rendezvous.ConnType.DEFAULT_CONN;
|
|
|
|
const natType = rendezvous.NatType.SYMMETRIC;
|
2022-01-20 15:41:11 +08:00
|
|
|
const punchHoleRequest = rendezvous.PunchHoleRequest.fromPartial({
|
2022-01-20 01:00:35 +08:00
|
|
|
id,
|
2022-01-27 01:30:29 +08:00
|
|
|
licenceKey: localStorage.getItem("key") || undefined,
|
2022-01-20 01:00:35 +08:00
|
|
|
connType,
|
|
|
|
natType,
|
|
|
|
});
|
|
|
|
ws.sendRendezvous({ punchHoleRequest });
|
|
|
|
const msg = ws.parseRendezvous(await ws.next());
|
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-20 01:00:35 +08:00
|
|
|
const phr = msg.punchHoleResponse;
|
|
|
|
const rr = msg.relayResponse;
|
|
|
|
if (phr) {
|
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;
|
|
|
|
default:
|
|
|
|
if (phr?.otherFailure) {
|
2022-01-20 21:58:28 +08:00
|
|
|
this.msgbox("error", "Error", phr?.otherFailure);
|
2022-01-20 18:02:20 +08:00
|
|
|
}
|
2022-01-20 01:00:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (rr) {
|
|
|
|
await this.connectRelay(rr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async connectRelay(rr: rendezvous.RelayResponse) {
|
|
|
|
const pk = rr.pk;
|
|
|
|
let uri = rr.relayServer;
|
2022-01-20 02:27:49 +08:00
|
|
|
if (uri) {
|
|
|
|
uri = getrUriFromRs(uri);
|
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-01-20 02:27:49 +08:00
|
|
|
const ws = new Websock(uri);
|
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-20 15:41:11 +08:00
|
|
|
const requestRelay = rendezvous.RequestRelay.fromPartial({
|
2022-01-27 01:30:29 +08:00
|
|
|
licenceKey: localStorage.getItem("key") || undefined,
|
2022-01-20 01:00:35 +08:00
|
|
|
uuid,
|
|
|
|
});
|
|
|
|
ws.sendRendezvous({ requestRelay });
|
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 {
|
|
|
|
pk = await globals.verify(pk, RS_PK).catch();
|
|
|
|
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-01-27 23:32:51 +08:00
|
|
|
this._ws?.sendMessage({});
|
2022-01-20 15:41:11 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const msg = this._ws?.parseMessage(await this._ws?.next());
|
|
|
|
let signedId: any = msg?.signedId;
|
|
|
|
if (!signedId) {
|
|
|
|
console.error("Handshake failed: invalid message type");
|
2022-01-27 23:32:51 +08:00
|
|
|
this._ws?.sendMessage({});
|
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");
|
|
|
|
const publicKey = message.PublicKey.fromPartial({});
|
2022-01-27 23:32:51 +08:00
|
|
|
this._ws?.sendMessage({ publicKey });
|
2022-01-20 15:41:11 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
signedId = new TextDecoder().decode(signedId!);
|
2022-01-20 21:58:28 +08:00
|
|
|
const tmp = signedId.split("\0");
|
2022-01-20 15:41:11 +08:00
|
|
|
const id = tmp[0];
|
|
|
|
let theirPk = tmp[1];
|
|
|
|
if (id != this._id!) {
|
|
|
|
console.error("Handshake failed: sign failure");
|
2022-01-27 23:32:51 +08:00
|
|
|
this._ws?.sendMessage({});
|
2022-01-20 15:41:11 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
theirPk = globals.decodeBase64(theirPk);
|
|
|
|
if (theirPk.length != 32) {
|
2022-01-20 21:58:28 +08:00
|
|
|
console.error(
|
|
|
|
"Handshake failed: invalid public box key length from peer"
|
|
|
|
);
|
2022-01-27 23:32:51 +08:00
|
|
|
this._ws?.sendMessage({});
|
2022-01-20 15:41:11 +08:00
|
|
|
return;
|
2022-01-20 12:49:57 +08:00
|
|
|
}
|
2022-01-20 15:41:11 +08:00
|
|
|
const [mySk, asymmetricValue] = globals.genBoxKeyPair();
|
|
|
|
const secretKey = globals.genSecretKey();
|
|
|
|
const symmetricValue = globals.seal(secretKey, theirPk, mySk);
|
2022-01-20 21:58:28 +08:00
|
|
|
const publicKey = message.PublicKey.fromPartial({
|
|
|
|
asymmetricValue,
|
|
|
|
symmetricValue,
|
|
|
|
});
|
2022-01-27 23:32:51 +08:00
|
|
|
this._ws?.sendMessage({ publicKey });
|
2022-01-20 21:58:28 +08:00
|
|
|
this._ws?.setSecretKey(secretKey);
|
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) {
|
|
|
|
const msg = this._ws?.parseMessage(await this._ws?.next());
|
|
|
|
if (msg?.hash) {
|
|
|
|
this._hash = msg?.hash;
|
2022-01-27 13:24:40 +08:00
|
|
|
if (!this._password) this.msgbox("input-password", "Password Required", "");
|
2022-01-27 23:32:51 +08:00
|
|
|
this.login(this._password);
|
2022-01-20 18:02:20 +08:00
|
|
|
} else if (msg?.testDelay) {
|
|
|
|
const testDelay = msg?.testDelay;
|
|
|
|
if (!testDelay.fromClient) {
|
2022-01-27 23:32:51 +08:00
|
|
|
this._ws?.sendMessage({ testDelay });
|
2022-01-20 18:02:20 +08:00
|
|
|
}
|
2022-01-20 18:41:35 +08:00
|
|
|
} else if (msg?.loginResponse) {
|
|
|
|
const r = msg?.loginResponse;
|
|
|
|
if (r.error) {
|
2022-01-20 21:58:28 +08:00
|
|
|
this.msgbox("error", "Error", r.error);
|
2022-01-20 18:41:35 +08:00
|
|
|
} else if (r.peerInfo) {
|
2022-01-26 12:39:44 +08:00
|
|
|
this.handlePeerInfo(r.peerInfo);
|
2022-01-20 18:41:35 +08:00
|
|
|
}
|
2022-01-20 18:44:28 +08:00
|
|
|
} else if (msg?.videoFrame) {
|
2022-01-20 21:58:28 +08:00
|
|
|
this.handleVideoFrame(msg?.videoFrame!);
|
2022-01-26 12:39:44 +08:00
|
|
|
} else if (msg?.clipboard) {
|
|
|
|
const cb = msg?.clipboard;
|
2022-01-27 18:58:29 +08:00
|
|
|
if (cb.compress) cb.content = await globals.decompress(cb.content)!;
|
2022-01-26 12:39:44 +08:00
|
|
|
globals.pushEvent("clipboard", cb);
|
|
|
|
} else if (msg?.cursorData) {
|
|
|
|
const cd = msg?.cursorData;
|
2022-01-27 18:58:29 +08:00
|
|
|
cd.colors = await globals.decompress(cd.colors)!;
|
2022-01-26 12:39:44 +08:00
|
|
|
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) {
|
|
|
|
//
|
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-01-28 04:30:38 +08:00
|
|
|
// globals.I420ToARGB(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();
|
|
|
|
this._audioDecoder?.close();
|
2022-01-20 18:41:35 +08:00
|
|
|
}
|
|
|
|
|
2022-01-27 23:32:51 +08:00
|
|
|
refresh() {
|
2022-01-26 12:39:44 +08:00
|
|
|
const misc = message.Misc.fromPartial({
|
|
|
|
refreshVideo: 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-27 23:32:51 +08:00
|
|
|
login(password: string | undefined, _remember: Boolean = false) {
|
2022-01-26 12:39:44 +08:00
|
|
|
this._password = password;
|
2022-01-27 13:24:40 +08:00
|
|
|
if (password) {
|
|
|
|
const salt = this._hash?.salt;
|
|
|
|
let p = hash([password, salt!]);
|
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-27 23:32:51 +08:00
|
|
|
this._sendLoginMessage();
|
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-20 18:41:35 +08:00
|
|
|
const loginRequest = message.LoginRequest.fromPartial({
|
|
|
|
username: this._id!,
|
2022-01-20 21:58:28 +08:00
|
|
|
myId: "web", // to-do
|
|
|
|
myName: "web", // to-do
|
2022-01-20 18:41:35 +08:00
|
|
|
password,
|
|
|
|
});
|
2022-01-27 23:32:51 +08:00
|
|
|
this._ws?.sendMessage({ loginRequest });
|
2022-01-20 18:41:35 +08:00
|
|
|
}
|
2022-01-20 18:44:28 +08:00
|
|
|
|
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-01-21 00:41:02 +08:00
|
|
|
// dec.sync();
|
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) => {
|
|
|
|
if (ok && dec.frameBuffer) {
|
2022-01-20 21:58:28 +08:00
|
|
|
this.draw(dec.frameBuffer);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2022-01-26 18:58:55 +08:00
|
|
|
|
|
|
|
getRemember(): any {
|
2022-01-27 01:30:29 +08:00
|
|
|
return this._options["remember"];
|
2022-01-26 18:58:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
getOption(name: string): any {
|
|
|
|
return this._options[name];
|
|
|
|
}
|
2022-01-20 01:00:35 +08:00
|
|
|
}
|
|
|
|
|
2022-01-20 21:58:28 +08:00
|
|
|
// @ts-ignore
|
2022-01-20 01:00:35 +08:00
|
|
|
async function testDelay() {
|
2022-01-20 02:27:49 +08:00
|
|
|
const ws = new Websock(getDefaultUri(false));
|
2022-01-20 01:00:35 +08:00
|
|
|
await ws.open();
|
|
|
|
console.log(ws.latency());
|
|
|
|
}
|
|
|
|
|
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-01-20 21:58:28 +08:00
|
|
|
return SCHEMA + (host || HOST) + ":" + (PORT + (isRelay ? 3 : 2));
|
2022-01-20 02:27:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
function getrUriFromRs(uri: string): 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-01-20 21:58:28 +08:00
|
|
|
uri = tmp[0] + ":" + (port + 2);
|
2022-01-20 02:27:49 +08:00
|
|
|
} else {
|
2022-01-20 21:58:28 +08:00
|
|
|
uri += ":" + (PORT + 3);
|
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
|
|
|
}
|