show client username, check whether credential exists before requesting confirmation from frontend
This commit is contained in:
parent
9bc9cb56c1
commit
c6e22fc91b
@ -5,7 +5,8 @@ use sysinfo::{
|
||||
SystemExt,
|
||||
Pid,
|
||||
PidExt,
|
||||
ProcessExt
|
||||
ProcessExt,
|
||||
UserExt,
|
||||
};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
@ -16,6 +17,7 @@ use crate::errors::*;
|
||||
pub struct Client {
|
||||
pub pid: u32,
|
||||
pub exe: Option<PathBuf>,
|
||||
pub username: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +25,8 @@ pub fn get_client(pid: u32, parent: bool) -> Result<Client, ClientInfoError> {
|
||||
let sys_pid = Pid::from_u32(pid);
|
||||
let mut sys = System::new();
|
||||
sys.refresh_process(sys_pid);
|
||||
sys.refresh_users_list();
|
||||
|
||||
let mut proc = sys.process(sys_pid)
|
||||
.ok_or(ClientInfoError::ProcessNotFound)?;
|
||||
|
||||
@ -34,10 +38,15 @@ pub fn get_client(pid: u32, parent: bool) -> Result<Client, ClientInfoError> {
|
||||
.ok_or(ClientInfoError::ParentProcessNotFound)?;
|
||||
}
|
||||
|
||||
let username = proc.user_id()
|
||||
.map(|uid| sys.get_user_by_id(uid))
|
||||
.flatten()
|
||||
.map(|u| u.name().to_owned());
|
||||
|
||||
let exe = match proc.exe() {
|
||||
p if p == Path::new("") => None,
|
||||
p => Some(PathBuf::from(p)),
|
||||
};
|
||||
|
||||
Ok(Client { pid: proc.pid().as_u32(), exe })
|
||||
Ok(Client { pid: proc.pid().as_u32(), exe, username })
|
||||
}
|
||||
|
@ -139,3 +139,10 @@ pub trait PersistentCredential: for<'a> Deserialize<'a> + Sized {
|
||||
Ok(creds)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn random_uuid() -> Uuid {
|
||||
// a bit weird to use salt() for this, but it's convenient
|
||||
let random_bytes = Crypto::salt();
|
||||
Uuid::from_slice(&random_bytes[..16]).unwrap()
|
||||
}
|
||||
|
@ -6,12 +6,11 @@ use ssh_agent_lib::proto::message::{
|
||||
};
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio::sync::oneshot;
|
||||
use tokio_util::codec::Framed;
|
||||
|
||||
use crate::clientinfo;
|
||||
use crate::errors::*;
|
||||
use crate::ipc::{Approval, RequestNotification, RequestNotificationDetail};
|
||||
use crate::ipc::{Approval, RequestNotificationDetail};
|
||||
use crate::state::AppState;
|
||||
|
||||
use super::{CloseWaiter, Stream};
|
||||
|
@ -1,17 +1,17 @@
|
||||
use sqlx::types::uuid::Uuid;
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
use crate::clientinfo::{self, Client};
|
||||
use crate::credentials::{
|
||||
self,
|
||||
Credential,
|
||||
CredentialRecord,
|
||||
Crypto,
|
||||
DockerCredential
|
||||
DockerCredential,
|
||||
};
|
||||
use crate::errors::*;
|
||||
use crate::ipc::{Approval, AwsRequestNotification, RequestNotificationDetail, RequestResponse};
|
||||
use crate::ipc::{Approval, RequestNotificationDetail};
|
||||
use crate::shortcuts::{self, ShortcutAction};
|
||||
use crate::state::AppState;
|
||||
use super::{
|
||||
@ -116,11 +116,22 @@ async fn get_docker_credential(
|
||||
app_handle: AppHandle,
|
||||
waiter: CloseWaiter<'_>,
|
||||
) -> Result<CliResponse, HandlerError> {
|
||||
let state = app_handle.state::<AppState>();
|
||||
let credential_id = state.credential_id(&server_url).await.unwrap_or(None);
|
||||
if credential_id.is_none() {
|
||||
return Err(
|
||||
HandlerError::NoCredentials(
|
||||
GetCredentialsError::Load(
|
||||
LoadCredentialsError::NoCredentials
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let detail = RequestNotificationDetail::new_docker(client, server_url.clone());
|
||||
let response = super::send_credentials_request(detail, app_handle.clone(), waiter).await?;
|
||||
match response.approval {
|
||||
Approval::Approved => {
|
||||
let state = app_handle.state::<AppState>();
|
||||
let creds = state.get_docker_credential(&server_url).await?;
|
||||
Ok(CliResponse::Credential(CliCredential::Docker(creds)))
|
||||
},
|
||||
@ -139,9 +150,12 @@ async fn store_docker_credential(
|
||||
|
||||
// eventually ask the frontend to confirm here
|
||||
|
||||
// a bit weird but convenient
|
||||
let random_bytes = Crypto::salt();
|
||||
let id = Uuid::from_slice(&random_bytes[..16]).unwrap();
|
||||
// for some reason Docker likes to call `store` immediately with whatever it gets
|
||||
// back from every `get` operation, so we have to check for an existing credential
|
||||
let id = state.credential_id(&docker_credential.server_url)
|
||||
.await
|
||||
.map_err(|e| GetCredentialsError::Load(e))?
|
||||
.unwrap_or_else(|| credentials::random_uuid());
|
||||
|
||||
let record = CredentialRecord {
|
||||
id,
|
||||
|
@ -9,7 +9,6 @@ use tokio::io::AsyncReadExt;
|
||||
use tokio::sync::oneshot;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::clientinfo::Client;
|
||||
use crate::credentials::{
|
||||
AwsBaseCredential,
|
||||
AwsSessionCredential,
|
||||
|
@ -148,6 +148,13 @@ impl AppState {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn credential_id(&self, name: &str) -> Result<Option<Uuid>, LoadCredentialsError> {
|
||||
let res = sqlx::query_scalar!(r#"SELECT id as "id: Uuid" FROM credentials WHERE name = ?"#, name)
|
||||
.fetch_optional(&self.pool)
|
||||
.await;
|
||||
Ok(res?)
|
||||
}
|
||||
|
||||
pub async fn save_credential(&self, record: CredentialRecord) -> Result<(), SaveCredentialsError> {
|
||||
let session = self.app_session.read().await;
|
||||
let crypto = session.try_get_crypto()?;
|
||||
|
@ -7,6 +7,7 @@
|
||||
import ShowResponse from './approve/ShowResponse.svelte';
|
||||
import Unlock from './Unlock.svelte';
|
||||
|
||||
console.log($appState.currentRequest);
|
||||
|
||||
// Extra 50ms so the window can finish disappearing before the redraw
|
||||
const rehideDelay = Math.min(5000, $appState.config.rehide_ms + 100);
|
||||
|
@ -14,7 +14,7 @@
|
||||
// Extract executable name from full path
|
||||
const client = $appState.currentRequest.client;
|
||||
const m = client.exe?.match(/\/([^/]+?$)|\\([^\\]+?$)/);
|
||||
const appName = m[1] || m[2];
|
||||
const appName = m ? m[1] || m[2] : '';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
@ -61,6 +61,8 @@
|
||||
<code class="">{@html client.exe ? breakPath(client.exe) : 'Unknown'}</code>
|
||||
<div class="text-right">PID:</div>
|
||||
<code>{client.pid}</code>
|
||||
<div class="text-right">User:</div>
|
||||
<code>{client.username ?? 'Unknown'}</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user