add share to guest by web client

This commit is contained in:
ljw
2024-10-09 15:52:17 +08:00
parent 3d203971b8
commit bf98a51285
15 changed files with 8729 additions and 14 deletions
+36
View File
@@ -0,0 +1,36 @@
import Clipboard from 'clipboard'
import { ElMessage } from 'element-plus'
import { T } from '@/utils/i18n'
export function handleClipboard (text, event) {
const clipboard = new Clipboard(event.target.toString(), {
text: () => text,
})
clipboard.on('success', () => {
ElMessage.success(T('CopySuccess'))
clipboard.destroy()
})
clipboard.on('error', () => {
ElMessage.error(T('CopyFailed'))
clipboard.destroy()
})
clipboard.onClick(event)
}
export function copyImage (targetNode) {
if (window.getSelection) {
// chrome等主流浏览器
var selection = window.getSelection()
selection.removeAllRanges()
var range = document.createRange()
range.selectNode(targetNode)
selection.addRange(range)
} else if (document.body.createTextRange) {
console.log('IE')
// ie
const range = document.body.createTextRange()
range.moveToElementText(targetNode)
range.select()
}
document.execCommand('copy')
}
+65
View File
@@ -282,5 +282,70 @@
},
"PleaseSelectData": {
"One": "Please select data"
},
"PasswordType": {
"One": "Password Type"
},
"OncePassword": {
"One": "One-time Password"
},
"FixedPassword": {
"One": "Fixed Password"
},
"FixedPasswordWarning": {
"One": "Fixed passwords may be leaked, so please use them with caution and use one-time passwords is recommended"
},
"ExpireTime": {
"One": "Expire Time"
},
"ShareByWebClient": {
"One": "Share By Web Client"
},
"Minutes": {
"One": "{param} Minute",
"Other": "{param} Minutes"
},
"Hours": {
"One": "{param} Hour",
"Other": "{param} Hours"
},
"Days": {
"One": "{param} Day",
"Other": "{param} Days"
},
"Weeks": {
"One": "{param} Week",
"Other": "{param} Weeks"
},
"Months": {
"One": "{param} Month",
"Other": "{param} Months"
},
"Forever": {
"One": "Forever"
},
"Error": {
"One": "Error"
},
"IDNotExist": {
"One": "ID does not exist"
},
"RemoteDesktopOffline": {
"One": "Remote desktop is offline"
},
"KeyMismatch": {
"One": "Key mismatch"
},
"KeyOveruse": {
"One": "Key overuse"
},
"Link": {
"One": "Link"
},
"CopySuccess": {
"One": "Copy Success"
},
"CopyFailed": {
"One": "Copy Failed"
}
}
+60
View File
@@ -274,5 +274,65 @@
},
"PleaseSelectData": {
"One": "请选择数据"
},
"PasswordType": {
"One": "密码类型"
},
"OncePassword": {
"One": "一次性密码"
},
"FixedPassword": {
"One": "固定密码"
},
"FixedPasswordWarning": {
"One": "固定密码可能存在泄露风险,请谨慎使用,建议使用一次性密码"
},
"ExpireTime": {
"One": "过期时间"
},
"ShareByWebClient": {
"One": "通过 Web Client 分享"
},
"Minutes": {
"One": "{param} 分钟"
},
"Hours": {
"One": "{param} 小时"
},
"Days": {
"One": "{param} 天"
},
"Weeks": {
"One": "{param} 周"
},
"Months": {
"One": "{param} 月"
},
"Forever": {
"One": "永久"
},
"Error": {
"One": "错误"
},
"IDNotExist": {
"One": "ID 不存在"
},
"RemoteDesktopOffline": {
"One": "远程电脑不在线"
},
"KeyMismatch": {
"One": "KEY不匹配"
},
"KeyOveruse": {
"One": "KEY使用过度"
},
"Link": {
"One": "链接"
},
"CopySuccess": {
"One": "复制成功"
},
"CopyFailed": {
"One": "复制失败"
}
}
+1 -1
View File
@@ -28,7 +28,7 @@ service.interceptors.request.use(
const app = useAppStore()
const lang = app.setting.lang
if (lang) {
console.log('lang', lang)
// console.log('lang', lang)
config.headers['Accept-Language'] = lang
}
+84 -1
View File
@@ -1,5 +1,10 @@
import { ref } from 'vue'
import { config } from '@/api/rustdesk'
import Websock from '@/utils/webclient/websock'
import * as rendezvous from '@/utils/webclient/rendezvous'
import * as message from '@/utils/webclient/message'
import { ElMessageBox } from 'element-plus'
import { T } from '@/utils/i18n'
export const toWebClientLink = (row) => {
window.open(`${rustdeskConfig.value.api_server}/webclient/#/?id=${row.id}`)
@@ -23,4 +28,82 @@ export function loadRustdeskConfig () {
rustdeskConfig,
}
}
const { rustdeskConfig } = loadRustdeskConfig()
export const { rustdeskConfig } = loadRustdeskConfig()
export async function getPeerSlat (id) {
const [addr, port] = rustdeskConfig.value.id_server.split(':')
if (!addr) {
return
}
const scheme = location.protocol === 'https:' ? 'wss' : 'ws'
const ws = new Websock(`${scheme}://${addr}:21118`, true)
await ws.open()
const conn_type = rendezvous.ConnType.DEFAULT_CONN
const nat_type = rendezvous.NatType.SYMMETRIC
const punch_hole_request = rendezvous.PunchHoleRequest.fromPartial({
id,
licence_key: rustdeskConfig.value.key || undefined,
conn_type,
nat_type,
token: undefined,
})
ws.sendRendezvous({ punch_hole_request })
//rendezvous.RendezvousMessage
const msg = (await ws.next())
ws.close()
console.log(new Date() + ': Got relay response', msg)
const phr = msg.punch_hole_response
const rr = msg.relay_response
if (phr) {
if (phr?.other_failure) {
this.msgbox('error', 'Error', phr?.other_failure)
return
}
if (phr.failure != rendezvous.PunchHoleResponse_Failure.UNRECOGNIZED) {
switch (phr?.failure) {
case rendezvous.PunchHoleResponse_Failure.ID_NOT_EXIST:
ElMessageBox.alert(T('IDNotExist'), T('Error'))
break
case rendezvous.PunchHoleResponse_Failure.OFFLINE:
ElMessageBox.alert(T('RemoteDesktopOffline'), T('Error'))
break
case rendezvous.PunchHoleResponse_Failure.LICENSE_MISMATCH:
ElMessageBox.alert(T('KeyMismatch'), T('Error'))
break
case rendezvous.PunchHoleResponse_Failure.LICENSE_OVERUSE:
ElMessageBox.alert(T('KeyOveruse'), T('Error'))
break
}
}
return false
} else if (rr) {
const uuid = rr.uuid
console.log(new Date() + ': Connecting to relay server')
const _ws = new Websock(`${scheme}://${addr}:21119`, false)
await _ws.open()
console.log(new Date() + ': Connected to relay server')
const request_relay = rendezvous.RequestRelay.fromPartial({
licence_key: rustdeskConfig.value.key || undefined,
uuid,
})
_ws.sendRendezvous({ request_relay })
//暂不支持pk
const public_key = message.PublicKey.fromPartial({})
_ws?.sendMessage({ public_key })
// const secure = (await this.secure(pk)) || false;
// globals.pushEvent("connection_ready", { secure, direct: false });
while (true) {
const msg = (await _ws?.next())
console.log('msg', msg)
if (msg?.hash) {
console.log('hash msg.....', msg.hash)
_ws.close()
return msg.hash
}
}
return false
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+183
View File
@@ -0,0 +1,183 @@
import * as message from "./message.js";
import * as rendezvous from "./rendezvous.js";
type Keys = "message" | "open" | "close" | "error";
export default class Websock {
_websocket: WebSocket;
_eventHandlers: { [key in Keys]: Function };
_buf: (rendezvous.RendezvousMessage | message.Message)[];
_status: any;
_latency: number;
_secretKey: [Uint8Array, number, number] | undefined;
_uri: string;
_isRendezvous: boolean;
constructor(uri: string, isRendezvous: boolean = true) {
this._eventHandlers = {
message: (_: any) => {},
open: () => {},
close: () => {},
error: () => {},
};
this._uri = uri;
this._status = "";
this._buf = [];
this._websocket = new WebSocket(uri);
this._websocket.onmessage = this._recv_message.bind(this);
this._websocket.binaryType = "arraybuffer";
this._latency = new Date().getTime();
this._isRendezvous = isRendezvous;
}
latency(): number {
return this._latency;
}
setSecretKey(key: Uint8Array) {
this._secretKey = [key, 0, 0];
}
sendMessage(json: message.DeepPartial<message.Message>) {
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: rendezvous.DeepPartial<rendezvous.RendezvousMessage>) {
this._websocket.send(
rendezvous.RendezvousMessage.encode(
rendezvous.RendezvousMessage.fromPartial(data)
).finish()
);
}
parseMessage(data: Uint8Array) {
return message.Message.decode(data);
}
parseRendezvous(data: Uint8Array) {
return rendezvous.RendezvousMessage.decode(data);
}
// Event Handlers
off(evt: Keys) {
this._eventHandlers[evt] = () => {};
}
on(evt: Keys, handler: Function) {
this._eventHandlers[evt] = handler;
}
async open(timeout: number = 12000): Promise<Websock> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (this._status != "open") {
reject(this._status || "Timeout");
}
}, timeout);
this._websocket.onopen = () => {
this._latency = new Date().getTime() - this._latency;
this._status = "open";
console.debug(">> WebSock.onopen");
if (this._websocket?.protocol) {
console.info(
"Server choose sub-protocol: " + this._websocket.protocol
);
}
this._eventHandlers.open();
console.info("WebSock.onopen");
resolve(this);
};
this._websocket.onclose = (e) => {
if (this._status == "open") {
// e.code 1000 means that the connection was closed normally.
//
}
this._status = e;
console.error("WebSock.onclose: ");
console.error(e);
this._eventHandlers.close(e);
reject("Reset by the peer");
};
this._websocket.onerror = (e: any) => {
if (!this._status) {
reject("Failed to connect to " + (this._isRendezvous ? "rendezvous" : "relay") + " server");
return;
}
this._status = e;
console.error("WebSock.onerror: ")
console.error(e);
this._eventHandlers.error(e);
};
});
}
async next(
timeout = 12000
): Promise<rendezvous.RendezvousMessage | message.Message> {
const func = (
resolve: (value: rendezvous.RendezvousMessage | message.Message) => void,
reject: (reason: any) => void,
tm0: number
) => {
// console.log('next')
if (this._buf.length) {
resolve(this._buf[0]);
this._buf.splice(0, 1);
} else {
if (this._status != "open") {
reject(this._status);
return;
}
if (new Date().getTime() > tm0 + timeout) {
reject("Timeout");
} else {
setTimeout(() => func(resolve, reject, tm0), 1);
}
}
};
return new Promise((resolve, reject) => {
func(resolve, reject, new Date().getTime());
});
}
close() {
this._status = "";
if (this._websocket) {
if (
this._websocket.readyState === WebSocket.OPEN ||
this._websocket.readyState === WebSocket.CONNECTING
) {
console.info("Closing WebSocket connection");
this._websocket.close();
}
this._websocket.onmessage = () => {};
}
}
_recv_message(e: any) {
if (e.data instanceof window.ArrayBuffer) {
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(
this._isRendezvous
? this.parseRendezvous(bytes)
: this.parseMessage(bytes)
);
}
this._eventHandlers.message(e.data);
}
}