Skip to content

Commit c9fcfcc

Browse files
committed
Merge branch 'osc52'
2 parents 28e6259 + dcc2240 commit c9fcfcc

File tree

5 files changed

+76
-31
lines changed

5 files changed

+76
-31
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@ scrypt = "0.10.0"
4444
aes-gcm = "0.9.4"
4545
hex = "0.4.3"
4646
qrcode = "0.12.0"
47-
urlencoding = "2.1.0"
47+
urlencoding = "2.1.0"
48+
base64 = "0.13.0"

src/database_management.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ use utils::{check_elements, get_db_path, millis_before_next_step};
99
use crate::cryptography;
1010
use crate::otp::otp_element::OTPElement;
1111
use crate::otp::otp_helper::get_otp_code;
12-
use crate::utils;
13-
use copypasta_ext::prelude::ClipboardProvider;
14-
use copypasta_ext::x11_fork::ClipboardContext;
12+
use crate::utils::{self, copy_string_to_clipboard, CopyType};
1513
use zeroize::Zeroize;
1614

1715
pub fn get_elements() -> Result<Vec<OTPElement>, String> {
@@ -53,11 +51,12 @@ pub fn print_elements_matching(issuer: Option<&str>, label: Option<&str>) -> Res
5351
otp_code,
5452
millis_before_next_step() / 1000
5553
);
56-
if let Ok(mut ctx) = ClipboardContext::new() {
57-
match ctx.set_contents(otp_code) {
58-
Ok(_) => println!("Copied to clipboard"),
59-
Err(_) => println!("Cannot copy OTP Code to clipboard"),
60-
};
54+
match copy_string_to_clipboard(otp_code) {
55+
Ok(result) => match result {
56+
CopyType::Native => println!("Copied to clipboard"),
57+
CopyType::OSC52 => println!("Remote copied to clipboard"),
58+
},
59+
Err(()) => println!("Cannot copy to clipboard"),
6160
}
6261
println!();
6362
});

src/interface/handler.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
22

33
use crate::interface::app::{App, AppResult};
44
use crate::interface::page::Page::*;
5-
use copypasta_ext::prelude::*;
6-
use copypasta_ext::x11_fork::ClipboardContext;
5+
use crate::utils::{copy_string_to_clipboard, CopyType};
76

87
use super::page::Page;
98

@@ -36,7 +35,10 @@ fn handle_key_events_search_bar(key_event: KeyEvent, app: &mut App) {
3635
search_and_select(app);
3736
}
3837
}
39-
KeyCode::Enter => copy_selected_code_to_clipboard(app),
38+
KeyCode::Enter => {
39+
app.label_text = copy_selected_code_to_clipboard(app);
40+
app.print_percentage = false;
41+
}
4042
KeyCode::Esc => {
4143
app.search_bar_focused = false;
4244
}
@@ -107,26 +109,33 @@ fn handle_key_events_main(key_event: KeyEvent, app: &mut App) {
107109

108110
KeyCode::Char('/') => app.search_bar_focused = true,
109111

110-
KeyCode::Enter => copy_selected_code_to_clipboard(app),
112+
KeyCode::Enter => {
113+
app.label_text = copy_selected_code_to_clipboard(app);
114+
app.print_percentage = false;
115+
}
111116
_ => {}
112117
}
113118
}
114119

115-
fn copy_selected_code_to_clipboard(app: &mut App) {
116-
if let Some(selected) = app.table.state.selected() {
117-
if let Some(element) = app.table.items.get(selected) {
118-
if let Some(otp_code) = element.get(3) {
119-
// in some occasions we can't copy contents to clipboard, so let's check for a good result
120-
if let Ok(mut ctx) = ClipboardContext::new() {
121-
match ctx.set_contents(otp_code.to_owned()) {
122-
Ok(_) => app.label_text = String::from("Copied!"),
123-
Err(_) => app.label_text = String::from("Cannot copy"),
120+
fn copy_selected_code_to_clipboard(app: &mut App) -> String {
121+
match app.table.state.selected() {
122+
Some(selected) => match app.table.items.get(selected) {
123+
Some(element) => match element.get(3) {
124+
Some(otp_code) => {
125+
if let Ok(result) = copy_string_to_clipboard(otp_code.to_owned()) {
126+
match result {
127+
CopyType::Native => "Copied!".to_string(),
128+
CopyType::OSC52 => "Remote copied!".to_string(),
129+
}
130+
} else {
131+
"Cannot copy".to_string()
124132
}
125-
app.print_percentage = false;
126-
app.current_page = Main;
127133
}
128-
}
129-
}
134+
None => "Cannot get OTP Code column".to_string(),
135+
},
136+
None => format!("Cannot fetch element from index: {}", selected),
137+
},
138+
None => "No code selected".to_string(),
130139
}
131140
}
132141

src/utils.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1-
use std::env;
1+
use copypasta_ext::prelude::*;
2+
use copypasta_ext::x11_fork::ClipboardContext;
3+
use crossterm::style::Print;
4+
#[cfg(not(debug_assertions))]
5+
use dirs::home_dir;
26
use std::fs::File;
37
use std::io::prelude::*;
48
use std::path::PathBuf;
59
use std::time::{SystemTime, UNIX_EPOCH};
6-
7-
#[cfg(not(debug_assertions))]
8-
use dirs::home_dir;
10+
use std::{env, io};
911

1012
use crate::otp::otp_element::OTPElement;
1113

14+
pub enum CopyType {
15+
Native,
16+
OSC52,
17+
}
18+
1219
pub fn get_db_path() -> PathBuf {
1320
match env::var("COTP_DB_PATH") {
1421
Ok(value) => PathBuf::from(value),
@@ -50,7 +57,7 @@ pub fn create_db_if_needed() -> Result<bool, ()> {
5057
}
5158
}
5259
if !db_path.exists() {
53-
return match std::fs::File::create(db_path) {
60+
return match File::create(db_path) {
5461
Ok(_f) => Ok(true),
5562
Err(_e) => Err(()),
5663
};
@@ -114,6 +121,34 @@ pub fn prompt_for_passwords(message: &str, minimum_password_length: usize, verif
114121
password
115122
}
116123

124+
fn in_ssh_shell() -> bool {
125+
return !env::var("SSH_CONNECTION")
126+
.unwrap_or_default()
127+
.trim()
128+
.is_empty();
129+
}
130+
131+
pub fn copy_string_to_clipboard(content: String) -> Result<CopyType, ()> {
132+
if in_ssh_shell() {
133+
// We do not use copypasta_ext::osc52 module because we have enabled terminal raw mode, so we print with crossterm utilities
134+
// Check https://github.com/timvisee/rust-clipboard-ext/blob/371df19d2f961882a21c957f396d1e24548d1f28/src/osc52.rs#L92
135+
return match crossterm::execute!(
136+
io::stdout(),
137+
Print(format!("\x1B]52;c;{}\x07", base64::encode(content)))
138+
) {
139+
Ok(_) => Ok(CopyType::OSC52),
140+
Err(_) => Err(()),
141+
};
142+
} else if let Ok(mut ctx) = ClipboardContext::new() {
143+
return if ctx.set_contents(content).is_ok() {
144+
Ok(CopyType::Native)
145+
} else {
146+
Err(())
147+
};
148+
}
149+
Err(())
150+
}
151+
117152
#[cfg(test)]
118153
mod tests {
119154
use super::create_db_if_needed;

0 commit comments

Comments
 (0)