1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
use anyhow::Context as _;
use std::io::Read as _;
pub fn login() -> anyhow::Result<()> {
simple_action(rbw::protocol::Action::Login, "login")
}
pub fn unlock() -> anyhow::Result<()> {
simple_action(rbw::protocol::Action::Unlock, "unlock")
}
pub fn sync() -> anyhow::Result<()> {
simple_action(rbw::protocol::Action::Sync, "sync")
}
pub fn lock() -> anyhow::Result<()> {
simple_action(rbw::protocol::Action::Lock, "lock")
}
pub fn quit() -> anyhow::Result<()> {
match crate::sock::Sock::connect() {
Ok(mut sock) => {
let runtime_dir = rbw::dirs::runtime_dir();
let pidfile = runtime_dir.join("pidfile");
let mut pid = String::new();
std::fs::File::open(pidfile)?.read_to_string(&mut pid)?;
let pid = nix::unistd::Pid::from_raw(pid.parse()?);
sock.send(&rbw::protocol::Request {
tty: std::env::var("TTY").ok(),
action: rbw::protocol::Action::Quit,
})?;
wait_for_exit(pid)?;
Ok(())
}
Err(e) => {
if e.kind() == std::io::ErrorKind::ConnectionRefused {
Ok(())
} else {
Err(e.into())
}
}
}
}
pub fn decrypt(cipherstring: &str) -> anyhow::Result<String> {
let mut sock = crate::sock::Sock::connect()
.context("failed to connect to rbw-agent")?;
sock.send(&rbw::protocol::Request {
tty: std::env::var("TTY").ok(),
action: rbw::protocol::Action::Decrypt {
cipherstring: cipherstring.to_string(),
},
})?;
let res = sock.recv()?;
match res {
rbw::protocol::Response::Decrypt { plaintext } => Ok(plaintext),
rbw::protocol::Response::Error { error } => {
Err(anyhow::anyhow!("failed to decrypt: {}", error))
}
_ => Err(anyhow::anyhow!("unexpected message: {:?}", res)),
}
}
pub fn encrypt(plaintext: &str) -> anyhow::Result<String> {
let mut sock = crate::sock::Sock::connect()
.context("failed to connect to rbw-agent")?;
sock.send(&rbw::protocol::Request {
tty: std::env::var("TTY").ok(),
action: rbw::protocol::Action::Encrypt {
plaintext: plaintext.to_string(),
},
})?;
let res = sock.recv()?;
match res {
rbw::protocol::Response::Encrypt { cipherstring } => Ok(cipherstring),
rbw::protocol::Response::Error { error } => {
Err(anyhow::anyhow!("failed to encrypt: {}", error))
}
_ => Err(anyhow::anyhow!("unexpected message: {:?}", res)),
}
}
fn simple_action(
action: rbw::protocol::Action,
desc: &str,
) -> anyhow::Result<()> {
let mut sock = crate::sock::Sock::connect()
.context("failed to connect to rbw-agent")?;
sock.send(&rbw::protocol::Request {
tty: std::env::var("TTY").ok(),
action,
})?;
let res = sock.recv()?;
match res {
rbw::protocol::Response::Ack => Ok(()),
rbw::protocol::Response::Error { error } => {
Err(anyhow::anyhow!("failed to {}: {}", desc, error))
}
_ => Err(anyhow::anyhow!("unexpected message: {:?}", res)),
}
}
fn wait_for_exit(pid: nix::unistd::Pid) -> anyhow::Result<()> {
loop {
if nix::sys::signal::kill(pid, None).is_err() {
break;
}
std::thread::sleep(std::time::Duration::from_millis(10));
}
Ok(())
}
|