initial commit
This commit is contained in:
97
crates/rshc/src/cmd/session.rs
Normal file
97
crates/rshc/src/cmd/session.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
use crate::auth::AuthedClient;
|
||||
use crate::ui;
|
||||
use anyhow::{anyhow, Result};
|
||||
use argon2::password_hash::SaltString;
|
||||
use argon2::{Argon2, PasswordHasher};
|
||||
use rand::rngs::OsRng;
|
||||
use rsh_types::{OpReq, OpResp};
|
||||
|
||||
pub fn hash_password(password: &str) -> Result<String> {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
Argon2::default()
|
||||
.hash_password(password.as_bytes(), &salt)
|
||||
.map(|h| h.to_string())
|
||||
.map_err(|e| anyhow!("hash: {e}"))
|
||||
}
|
||||
|
||||
pub async fn create(client: &AuthedClient, name: String) -> Result<()> {
|
||||
let pw = inquire::Password::new("password (empty for none):")
|
||||
.without_confirmation()
|
||||
.with_display_mode(inquire::PasswordDisplayMode::Masked)
|
||||
.prompt()
|
||||
.map_err(|e| anyhow!("prompt: {e}"))?;
|
||||
let password_hash = if pw.is_empty() { None } else { Some(hash_password(&pw)?) };
|
||||
match client.req(OpReq::SessionCreate { name: name.clone(), password_hash }).await? {
|
||||
OpResp::Ok => ui::print_ok(&format!("session '{name}' created")),
|
||||
OpResp::Err(e) => return Err(anyhow!(e)),
|
||||
other => return Err(anyhow!("unexpected: {other:?}")),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete(client: &AuthedClient, name: String, yes: bool, disconnect: bool) -> Result<()> {
|
||||
if !yes {
|
||||
let ok = inquire::Confirm::new(&format!("delete session '{name}'?"))
|
||||
.with_default(false)
|
||||
.prompt()
|
||||
.map_err(|e| anyhow!("prompt: {e}"))?;
|
||||
if !ok {
|
||||
ui::print_info("cancelled");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
match client.req(OpReq::SessionDelete { name: name.clone(), disconnect }).await? {
|
||||
OpResp::Ok => ui::print_ok(&format!("session '{name}' deleted")),
|
||||
OpResp::Err(e) => return Err(anyhow!(e)),
|
||||
other => return Err(anyhow!("unexpected: {other:?}")),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
client: &AuthedClient,
|
||||
name: String,
|
||||
pw_flag: Option<Option<String>>,
|
||||
disconnect: bool,
|
||||
) -> Result<()> {
|
||||
let set_password_hash = match pw_flag {
|
||||
None => None,
|
||||
Some(Some(p)) => Some(Some(hash_password(&p)?)),
|
||||
Some(None) => {
|
||||
let entered = inquire::Password::new("new password (empty clears):")
|
||||
.without_confirmation()
|
||||
.with_display_mode(inquire::PasswordDisplayMode::Masked)
|
||||
.prompt()
|
||||
.map_err(|e| anyhow!("prompt: {e}"))?;
|
||||
if entered.is_empty() {
|
||||
Some(None)
|
||||
} else {
|
||||
Some(Some(hash_password(&entered)?))
|
||||
}
|
||||
}
|
||||
};
|
||||
match client
|
||||
.req(OpReq::SessionUpdate { name: name.clone(), set_password_hash, disconnect })
|
||||
.await?
|
||||
{
|
||||
OpResp::Ok => ui::print_ok(&format!("session '{name}' updated")),
|
||||
OpResp::Err(e) => return Err(anyhow!(e)),
|
||||
other => return Err(anyhow!("unexpected: {other:?}")),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn list(client: &AuthedClient) -> Result<()> {
|
||||
match client.req(OpReq::SessionList).await? {
|
||||
OpResp::Sessions(s) => {
|
||||
if s.is_empty() {
|
||||
ui::print_info("no sessions");
|
||||
} else {
|
||||
println!("{}", ui::sessions_table(&s));
|
||||
}
|
||||
}
|
||||
OpResp::Err(e) => return Err(anyhow!(e)),
|
||||
other => return Err(anyhow!("unexpected: {other:?}")),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user