This commit is contained in:
Asura
2022-07-20 19:51:09 -07:00
110 changed files with 4942 additions and 1487 deletions

View File

@@ -318,9 +318,10 @@ class SessionList: Reactor.Component {
<li #tunnel>{translate('TCP Tunneling')}</li>
{false && !handler.using_public_server() && <li #force-always-relay><span>{svg_checkmark}</span>{translate('Always connect via relay')}</li>}
<li #rdp>RDP<EditRdpPort /></li>
<li #wol>{translate('WOL')}</li>
<div .separator />
<li #rename>{translate('Rename')}</li>
{this.type != "fav" && this.type != "lan" && <li #remove>{translate('Remove')}</li>}
{this.type != "lan" && <li #rename>{translate('Rename')}</li>}
{this.type != "fav" && <li #remove>{translate('Remove')}</li>}
{is_win && <li #shortcut>{translate('Create Desktop Shortcut')}</li>}
<li #forget-password>{translate('Unremember Password')}</li>
{(!this.type || this.type == "fav") && <li #add-fav>{translate('Add to Favorites')}</li>}
@@ -419,6 +420,8 @@ class SessionList: Reactor.Component {
createNewConnect(id, "connect");
} else if (action == "transfer") {
createNewConnect(id, "file-transfer");
} else if (action == "wol") {
handler.send_wol(id);
} else if (action == "remove") {
if (this.type == "ab") {
for (var i = 0; i < ab.peers.length; ++i) {
@@ -429,6 +432,9 @@ class SessionList: Reactor.Component {
break;
}
}
} else if (this.type == "lan") {
handler.remove_discovered(id);
app.update();
} else {
handler.remove_peer(id);
app.update();

View File

@@ -204,7 +204,7 @@ impl ConnectionManager {
let mut req = FileTransferSendConfirmRequest {
id,
file_num,
union: Some(file_transfer_send_confirm_request::Union::offset_blk(0)),
union: Some(file_transfer_send_confirm_request::Union::OffsetBlk(0)),
..Default::default()
};
let digest = FileTransferDigest {

View File

@@ -120,7 +120,7 @@ textarea:empty {
@ELLIPSIS;
}
div.password svg {
div.password svg:not(.checkmark) {
padding-left: 1em;
size: 16px;
color: #ddd;

View File

@@ -141,7 +141,7 @@ function adjustBorder() {
if (el) el.attributes.toggleClass("active", view.windowState == View.WINDOW_FULL_SCREEN);
}
var svg_checkmark = <svg viewBox="0 0 492 492"><path d="M484 105l-16-17a27 27 0 00-38 0L204 315 62 173c-5-5-12-7-19-7s-14 2-19 7L8 189a27 27 0 000 38l160 160v1l16 16c5 5 12 8 19 8 8 0 14-3 20-8l16-16v-1l245-244a27 27 0 000-38z"/></svg>;
var svg_checkmark = <svg class="checkmark" viewBox="0 0 492 492"><path d="M484 105l-16-17a27 27 0 00-38 0L204 315 62 173c-5-5-12-7-19-7s-14 2-19 7L8 189a27 27 0 000 38l160 160v1l16 16c5 5 12 8 19 8 8 0 14-3 20-8l16-16v-1l245-244a27 27 0 000-38z"/></svg>;
var svg_edit = <svg #edit viewBox="0 0 384 384">
<path d="M0 304v80h80l236-236-80-80zM378 56L328 6c-8-8-22-8-30 0l-39 39 80 80 39-39c8-8 8-22 0-30z"/>
</svg>;

View File

@@ -403,3 +403,18 @@ div.remote-session svg#menu {
background: none;
color: white;
}
svg#refresh-password {
display: inline-block;
stroke:#ddd;
}
svg#refresh-password:hover {
stroke:color(text);
}
li:disabled, li:disabled:hover {
color: color(lighter-text);
background: color(menu);
}

View File

@@ -20,6 +20,7 @@ var svg_menu = <svg #menu viewBox="0 0 512 512">
<circle cx="256" cy="448" r="64"/>
<circle cx="256" cy="64" r="64"/>
</svg>;
var svg_refresh_password = <svg #refresh-password xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 2v6h6M2.66 15.57a10 10 0 1 0 .57-8.38"/></svg>;
var my_id = "";
function get_id() {
@@ -520,10 +521,6 @@ class App: Reactor.Component
var is_can_screen_recording = handler.is_can_screen_recording(false);
return
<div .app>
<popup><menu.context #edit-password-context>
<li #refresh-password>{translate('Refresh random password')}</li>
<li #set-password>{translate('Set your own password')}</li>
</menu></popup>
<div .left-pane>
<div>
<div .title>{translate('Your Desktop')}</div>
@@ -533,8 +530,7 @@ class App: Reactor.Component
{key_confirmed ? <input type="text" readonly value={formatId(get_id())}/> : translate("Generating ...")}
</div>
<div .your-desktop>
<div>{translate('Password')}</div>
<Password />
<PasswordArea />
</div>
</div>
{!is_win || handler.is_installed() ? "": <InstallMe />}
@@ -806,44 +802,151 @@ function watch_screen_recording() {
class PasswordEyeArea : Reactor.Component {
render() {
var show = handler.is_random_password_valid();
var value = show ? handler.get_random_password() : "-";
return
<div .eye-area style="width: *">
<input|text @{this.input} readonly value="******" />
{svg_eye}
<input|text @{this.input} readonly value={value} />
{svg_refresh_password}
</div>;
}
event mouseenter {
var me = this;
me.leaved = false;
me.timer(300ms, function() {
if (me.leaved) return;
me.input.value = handler.get_password();
});
}
event mouseleave {
this.leaved = true;
this.input.value = "******";
event click $(svg#refresh-password) (_, me) {
if (handler.is_random_password_valid()) handler.update_random_password();
this.update();
}
}
class Password: Reactor.Component {
var verificationMethodMenu;
class VerificationMethodMenu: Reactor.Component {
function this() {
verificationMethodMenu = this;
}
function render() {
return <div .password style="flow:horizontal">
<PasswordEyeArea />
{svg_edit}
if (!this.show) return <li />;
var me = this;
self.timer(1ms, function() { me.toggleMenuState() });
return <li>{translate('Verification Method')}
<menu #verification-method>
<li #verification-method-security><span>{svg_checkmark}</span>{translate('Enable security password')}</li>
<li #verification-method-random><span>{svg_checkmark}</span>{translate('Enable random password')}</li>
</menu>
</li>;
}
function toggleMenuState() {
var security_enabled = handler.is_security_password_enabled();
var random_enabled = handler.is_random_password_enabled();
var onetime_enabled = handler.is_onetime_password_enabled();
for (var (index, el) in this.$$(menu#verification-method>li)) {
if (index == 0) el.attributes.toggleClass("selected", security_enabled);
if (index == 1) el.attributes.toggleClass("selected", random_enabled);
}
}
event click $(menu#verification-method>li) (_, me) {
switch (me.id.substring('verification-method-'.length)) {
case 'security':
{
var security_enabled = handler.is_security_password_enabled();
handler.set_security_password_enabled(!security_enabled);
}
break;
case 'random':
{
var random_enabled = handler.is_random_password_enabled();
handler.set_random_password_enabled(!random_enabled);
}
break;
}
this.toggleMenuState();
passwordArea.update();
}
}
var randomPasswordUpdateMethodMenu;
class RandomPasswordUpdateMethodMenu: Reactor.Component {
function this() {
randomPasswordUpdateMethodMenu = this;
}
function render() {
if (!this.show) return <li />;
var me = this;
var random_enabled = handler.is_random_password_enabled();
self.timer(1ms, function() { me.toggleMenuState() });
return <li disabled={ random_enabled ? "false" : "true" }>{translate('Random Password After Session')}
<menu #random-password-update-method>
<li #random-password-update-method-keep><span>{svg_checkmark}</span>{translate('Keep')}</li>
<li #random-password-update-method-update><span>{svg_checkmark}</span>{translate('Update')}</li>
<li #random-password-update-method-disable><span>{svg_checkmark}</span>{translate('Disable')}</li>
</menu>
</li>;
}
function toggleMenuState() {
var method = handler.random_password_update_method();
for (var (index, el) in this.$$(menu#random-password-update-method>li)) {
if (index == 0) el.attributes.toggleClass("selected", method == "KEEP");
if (index == 1) el.attributes.toggleClass("selected", method == "UPDATE");
if (index == 2) el.attributes.toggleClass("selected", method == "DISABLE");
}
}
event click $(menu#random-password-update-method>li) (_, me) {
if (me.id === 'random-password-update-method-keep') handler.set_random_password_update_method("KEEP");
if (me.id === 'random-password-update-method-update') handler.set_random_password_update_method("UPDATE");
if (me.id === 'random-password-update-method-disable') handler.set_random_password_update_method("DISABLE");
this.toggleMenuState();
passwordArea.update();
}
}
var passwordArea;
class PasswordArea: Reactor.Component {
function this() {
passwordArea = this;
}
function render() {
var onetime_enabled = handler.is_onetime_password_enabled();
return
<div>
<div>{translate(onetime_enabled ? 'Onetime Password' : 'Password')}</div>
<div .password style="flow:horizontal">
{this.renderPop()}
<PasswordEyeArea />
{svg_edit}
</div>
</div>;
}
event click $(svg#edit) (_, me) {
var menu = $(menu#edit-password-context);
me.popup(menu);
function renderPop() {
var security_enabled = handler.is_security_password_enabled();
var random_enabled = handler.is_random_password_enabled();
var onetime_enabled = handler.is_onetime_password_enabled();
var onetime_activated = handler.is_onetime_password_activated();
return <popup><menu.context #edit-password-context>
<li #enable-onetime-password disabled={ random_enabled ? "false" : "true" }>{translate(onetime_enabled ? "Disable onetime password" : "Enable onetime password")}</li>
<li #activate-onetime-password disabled={ !random_enabled || !onetime_enabled || onetime_activated ? "true" : "false" }>{translate('Activate onetime password')}</li>
<div .separator />
<VerificationMethodMenu />
<div .separator />
<li #set-password disabled={ security_enabled ? "false" : "true" }>{translate('Set security password')}</li>
<div .separator />
<RandomPasswordUpdateMethodMenu />
</menu></popup>;
}
event click $(li#refresh-password) {
handler.update_password("");
this.update();
event click $(svg#edit) (_, me) {
randomPasswordUpdateMethodMenu.update({show: true });
verificationMethodMenu.update({show: true });
var menu = $(menu#edit-password-context);
me.popup(menu);
}
event click $(li#set-password) {
@@ -862,12 +965,36 @@ class Password: Reactor.Component {
if (p0 != p1) {
return translate("The confirmation is not identical.");
}
handler.update_password(p0);
handler.set_security_password(p0);
me.update();
});
}
event click $(li#enable-onetime-password) {
var onetime_enabled = handler.is_onetime_password_enabled();
handler.set_onetime_password_enabled(!onetime_enabled);
passwordArea.update();
}
event click $(li#activate-onetime-password) {
handler.set_onetime_password_activated(true);
passwordArea.update();
}
}
var last_password_description = "";
function updatePasswordArea() {
self.timer(1s, function() {
var description = handler.password_description();
if (last_password_description != description) {
last_password_description = description
passwordArea.update();
}
updatePasswordArea();
});
}
updatePasswordArea();
class ID: Reactor.Component {
function render() {
return <input type="text" #remote_id .outline-focus novalue={translate("Enter Remote ID")} maxlength="21"

View File

@@ -258,10 +258,10 @@ pub fn check_main_window() {
let app = format!("/Applications/{}.app", crate::get_app_name());
let my_uid = sys
.process((std::process::id() as i32).into())
.map(|x| x.uid)
.map(|x| x.user_id())
.unwrap_or_default();
for (_, p) in sys.processes().iter() {
if p.cmd().len() == 1 && p.uid == my_uid && p.cmd()[0].contains(&app) {
if p.cmd().len() == 1 && p.user_id() == my_uid && p.cmd()[0].contains(&app) {
return;
}
}

View File

@@ -904,7 +904,7 @@ impl Handler {
fn get_char(&mut self, name: String, code: i32) -> String {
if let Some(key_event) = self.get_key_event(1, &name, code) {
match key_event.union {
Some(key_event::Union::chr(chr)) => {
Some(key_event::Union::Chr(chr)) => {
if let Some(chr) = std::char::from_u32(chr as _) {
return chr.to_string();
}
@@ -1763,6 +1763,11 @@ impl Remote {
// log::info!("new msg from ui, {}",data);
match data {
Data::Close => {
let mut misc = Misc::new();
misc.set_close_reason("".to_owned());
let mut msg = Message::new();
msg.set_misc(misc);
allow_err!(peer.send(&msg).await);
return false;
}
Data::Login((password, remember)) => {
@@ -1940,9 +1945,9 @@ impl Remote {
id,
file_num,
union: if need_override {
Some(file_transfer_send_confirm_request::Union::offset_blk(0))
Some(file_transfer_send_confirm_request::Union::OffsetBlk(0))
} else {
Some(file_transfer_send_confirm_request::Union::skip(true))
Some(file_transfer_send_confirm_request::Union::Skip(true))
},
..Default::default()
});
@@ -1958,9 +1963,9 @@ impl Remote {
id,
file_num,
union: if need_override {
Some(file_transfer_send_confirm_request::Union::offset_blk(0))
Some(file_transfer_send_confirm_request::Union::OffsetBlk(0))
} else {
Some(file_transfer_send_confirm_request::Union::skip(true))
Some(file_transfer_send_confirm_request::Union::Skip(true))
},
..Default::default()
});
@@ -2147,7 +2152,7 @@ impl Remote {
async fn handle_msg_from_peer(&mut self, data: &[u8], peer: &mut Stream) -> bool {
if let Ok(msg_in) = Message::parse_from_bytes(&data) {
match msg_in.union {
Some(message::Union::video_frame(vf)) => {
Some(message::Union::VideoFrame(vf)) => {
if !self.first_frame {
self.first_frame = true;
self.handler.call2("closeSuccess", &make_args!());
@@ -2163,16 +2168,16 @@ impl Remote {
};
self.video_sender.send(MediaData::VideoFrame(vf)).ok();
}
Some(message::Union::hash(hash)) => {
Some(message::Union::Hash(hash)) => {
self.handler.handle_hash(hash, peer).await;
}
Some(message::Union::login_response(lr)) => match lr.union {
Some(login_response::Union::error(err)) => {
Some(message::Union::LoginResponse(lr)) => match lr.union {
Some(login_response::Union::Error(err)) => {
if !self.handler.handle_login_error(&err) {
return false;
}
}
Some(login_response::Union::peer_info(pi)) => {
Some(login_response::Union::PeerInfo(pi)) => {
self.handler.handle_peer_info(pi);
self.check_clipboard_file_context();
if !(self.handler.is_file_transfer()
@@ -2199,22 +2204,22 @@ impl Remote {
}
_ => {}
},
Some(message::Union::cursor_data(cd)) => {
Some(message::Union::CursorData(cd)) => {
self.handler.set_cursor_data(cd);
}
Some(message::Union::cursor_id(id)) => {
Some(message::Union::CursorId(id)) => {
self.handler.set_cursor_id(id.to_string());
}
Some(message::Union::cursor_position(cp)) => {
Some(message::Union::CursorPosition(cp)) => {
self.handler.set_cursor_position(cp);
}
Some(message::Union::clipboard(cb)) => {
Some(message::Union::Clipboard(cb)) => {
if !self.handler.lc.read().unwrap().disable_clipboard {
update_clipboard(cb, Some(&self.old_clipboard));
}
}
#[cfg(windows)]
Some(message::Union::cliprdr(clip)) => {
Some(message::Union::Cliprdr(clip)) => {
if !self.handler.lc.read().unwrap().disable_clipboard {
if let Some(context) = &mut self.clipboard_file_context {
if let Some(clip) = msg_2_clip(clip) {
@@ -2223,9 +2228,9 @@ impl Remote {
}
}
}
Some(message::Union::file_response(fr)) => {
Some(message::Union::FileResponse(fr)) => {
match fr.union {
Some(file_response::Union::dir(fd)) => {
Some(file_response::Union::Dir(fd)) => {
#[cfg(windows)]
let entries = fd.entries.to_vec();
#[cfg(not(windows))]
@@ -2248,7 +2253,7 @@ impl Remote {
job.files = entries;
}
}
Some(file_response::Union::digest(digest)) => {
Some(file_response::Union::Digest(digest)) => {
if digest.is_upload {
if let Some(job) = fs::get_job(digest.id, &mut self.read_jobs) {
if let Some(file) = job.files().get(digest.file_num as usize) {
@@ -2259,9 +2264,9 @@ impl Remote {
id: digest.id,
file_num: digest.file_num,
union: Some(if overwrite {
file_transfer_send_confirm_request::Union::offset_blk(0)
file_transfer_send_confirm_request::Union::OffsetBlk(0)
} else {
file_transfer_send_confirm_request::Union::skip(
file_transfer_send_confirm_request::Union::Skip(
true,
)
}),
@@ -2294,7 +2299,7 @@ impl Remote {
let msg= new_send_confirm(FileTransferSendConfirmRequest {
id: digest.id,
file_num: digest.file_num,
union: Some(file_transfer_send_confirm_request::Union::skip(true)),
union: Some(file_transfer_send_confirm_request::Union::Skip(true)),
..Default::default()
});
allow_err!(peer.send(&msg).await);
@@ -2306,9 +2311,9 @@ impl Remote {
id: digest.id,
file_num: digest.file_num,
union: Some(if overwrite {
file_transfer_send_confirm_request::Union::offset_blk(0)
file_transfer_send_confirm_request::Union::OffsetBlk(0)
} else {
file_transfer_send_confirm_request::Union::skip(true)
file_transfer_send_confirm_request::Union::Skip(true)
}),
..Default::default()
},
@@ -2331,7 +2336,7 @@ impl Remote {
FileTransferSendConfirmRequest {
id: digest.id,
file_num: digest.file_num,
union: Some(file_transfer_send_confirm_request::Union::offset_blk(0)),
union: Some(file_transfer_send_confirm_request::Union::OffsetBlk(0)),
..Default::default()
},
);
@@ -2346,7 +2351,7 @@ impl Remote {
}
}
}
Some(file_response::Union::block(block)) => {
Some(file_response::Union::Block(block)) => {
log::info!(
"file response block, file id:{}, file num: {}",
block.id,
@@ -2359,27 +2364,27 @@ impl Remote {
self.update_jobs_status();
}
}
Some(file_response::Union::done(d)) => {
Some(file_response::Union::Done(d)) => {
if let Some(job) = fs::get_job(d.id, &mut self.write_jobs) {
job.modify_time();
fs::remove_job(d.id, &mut self.write_jobs);
}
self.handle_job_status(d.id, d.file_num, None);
}
Some(file_response::Union::error(e)) => {
Some(file_response::Union::Error(e)) => {
self.handle_job_status(e.id, e.file_num, Some(e.error));
}
_ => {}
}
}
Some(message::Union::misc(misc)) => match misc.union {
Some(misc::Union::audio_format(f)) => {
Some(message::Union::Misc(misc)) => match misc.union {
Some(misc::Union::AudioFormat(f)) => {
self.audio_sender.send(MediaData::AudioFormat(f)).ok();
}
Some(misc::Union::chat_message(c)) => {
Some(misc::Union::ChatMessage(c)) => {
self.handler.call("newMessage", &make_args!(c.text));
}
Some(misc::Union::permission_info(p)) => {
Some(misc::Union::PermissionInfo(p)) => {
log::info!("Change permission {:?} -> {}", p.permission, p.enabled);
match p.permission.enum_value_or_default() {
Permission::Keyboard => {
@@ -2407,7 +2412,7 @@ impl Remote {
}
}
}
Some(misc::Union::switch_display(s)) => {
Some(misc::Union::SwitchDisplay(s)) => {
self.handler.call("switchDisplay", &make_args!(s.display));
self.video_sender.send(MediaData::Reset).ok();
if s.width > 0 && s.height > 0 {
@@ -2423,27 +2428,27 @@ impl Remote {
self.handler.set_display(s.x, s.y, s.width, s.height);
}
}
Some(misc::Union::close_reason(c)) => {
Some(misc::Union::CloseReason(c)) => {
self.handler.msgbox("error", "Connection Error", &c);
return false;
}
Some(misc::Union::back_notification(notification)) => {
Some(misc::Union::BackNotification(notification)) => {
if !self.handle_back_notification(notification).await {
return false;
}
}
_ => {}
},
Some(message::Union::test_delay(t)) => {
Some(message::Union::TestDelay(t)) => {
self.handler.handle_test_delay(t, peer).await;
}
Some(message::Union::audio_frame(frame)) => {
Some(message::Union::AudioFrame(frame)) => {
if !self.handler.lc.read().unwrap().disable_audio {
self.audio_sender.send(MediaData::AudioFrame(frame)).ok();
}
}
Some(message::Union::file_action(action)) => match action.union {
Some(file_action::Union::send_confirm(c)) => {
Some(message::Union::FileAction(action)) => match action.union {
Some(file_action::Union::SendConfirm(c)) => {
if let Some(job) = fs::get_job(c.id, &mut self.read_jobs) {
job.confirm(&c);
}
@@ -2458,13 +2463,13 @@ impl Remote {
async fn handle_back_notification(&mut self, notification: BackNotification) -> bool {
match notification.union {
Some(back_notification::Union::block_input_state(state)) => {
Some(back_notification::Union::BlockInputState(state)) => {
self.handle_back_msg_block_input(
state.enum_value_or(back_notification::BlockInputState::StateUnknown),
)
.await;
}
Some(back_notification::Union::privacy_mode_state(state)) => {
Some(back_notification::Union::PrivacyModeState(state)) => {
if !self
.handle_back_msg_privacy_mode(
state.enum_value_or(back_notification::PrivacyModeState::StateUnknown),