Make list messaging explicit

This commit is contained in:
Bernd Schoolmann 2024-11-21 15:16:22 +01:00
parent 4283970b53
commit 6435845438
No known key found for this signature in database
7 changed files with 36 additions and 36 deletions

View File

@ -17,7 +17,7 @@ pub mod importer;
pub struct BitwardenDesktopAgent { pub struct BitwardenDesktopAgent {
keystore: ssh_agent::KeyStore, keystore: ssh_agent::KeyStore,
cancellation_token: CancellationToken, cancellation_token: CancellationToken,
show_ui_request_tx: tokio::sync::mpsc::Sender<(u32, String)>, show_ui_request_tx: tokio::sync::mpsc::Sender<(u32, (String, bool))>,
get_ui_response_rx: Arc<Mutex<tokio::sync::broadcast::Receiver<(u32, bool)>>>, get_ui_response_rx: Arc<Mutex<tokio::sync::broadcast::Receiver<(u32, bool)>>>,
request_id: Arc<Mutex<u32>>, request_id: Arc<Mutex<u32>>,
/// before first unlock, or after account switching, listing keys should require an unlock to get a list of public keys /// before first unlock, or after account switching, listing keys should require an unlock to get a list of public keys
@ -35,8 +35,9 @@ impl ssh_agent::Agent for BitwardenDesktopAgent {
let request_id = self.get_request_id().await; let request_id = self.get_request_id().await;
let mut rx_channel = self.get_ui_response_rx.lock().await.resubscribe(); let mut rx_channel = self.get_ui_response_rx.lock().await.resubscribe();
let message = (request_id, (ssh_key.cipher_uuid.clone(), false));
self.show_ui_request_tx self.show_ui_request_tx
.send((request_id, ssh_key.cipher_uuid.clone())) .send(message)
.await .await
.expect("Should send request to ui"); .expect("Should send request to ui");
while let Ok((id, response)) = rx_channel.recv().await { while let Ok((id, response)) = rx_channel.recv().await {
@ -55,8 +56,9 @@ impl ssh_agent::Agent for BitwardenDesktopAgent {
let request_id = self.get_request_id().await; let request_id = self.get_request_id().await;
let mut rx_channel = self.get_ui_response_rx.lock().await.resubscribe(); let mut rx_channel = self.get_ui_response_rx.lock().await.resubscribe();
let message = (request_id, ("".to_string(), true));
self.show_ui_request_tx self.show_ui_request_tx
.send((request_id, "".to_string())) .send(message)
.await .await
.expect("Should send request to ui"); .expect("Should send request to ui");
while let Ok((id, response)) = rx_channel.recv().await { while let Ok((id, response)) = rx_channel.recv().await {

View File

@ -14,7 +14,7 @@ use super::BitwardenDesktopAgent;
impl BitwardenDesktopAgent { impl BitwardenDesktopAgent {
pub async fn start_server( pub async fn start_server(
auth_request_tx: tokio::sync::mpsc::Sender<(u32, String)>, auth_request_tx: tokio::sync::mpsc::Sender<(u32, (String, bool))>,
auth_response_rx: Arc<Mutex<tokio::sync::broadcast::Receiver<(u32, bool)>>>, auth_response_rx: Arc<Mutex<tokio::sync::broadcast::Receiver<(u32, bool)>>>,
) -> Result<Self, anyhow::Error> { ) -> Result<Self, anyhow::Error> {
let agent = BitwardenDesktopAgent { let agent = BitwardenDesktopAgent {

View File

@ -12,7 +12,7 @@ use super::BitwardenDesktopAgent;
impl BitwardenDesktopAgent { impl BitwardenDesktopAgent {
pub async fn start_server( pub async fn start_server(
auth_request_tx: tokio::sync::mpsc::Sender<(u32, String)>, auth_request_tx: tokio::sync::mpsc::Sender<(u32, (String, bool))>,
auth_response_rx: Arc<Mutex<tokio::sync::broadcast::Receiver<(u32, bool)>>>, auth_response_rx: Arc<Mutex<tokio::sync::broadcast::Receiver<(u32, bool)>>>,
) -> Result<Self, anyhow::Error> { ) -> Result<Self, anyhow::Error> {
let agent_state = BitwardenDesktopAgent { let agent_state = BitwardenDesktopAgent {

View File

@ -69,7 +69,7 @@ export declare namespace sshagent {
status: SshKeyImportStatus status: SshKeyImportStatus
sshKey?: SshKey sshKey?: SshKey
} }
export function serve(callback: (err: Error | null, arg: string) => any): Promise<SshAgentState> export function serve(callback: (err: Error | null, arg0: string, arg1: boolean) => any): Promise<SshAgentState>
export function stop(agentState: SshAgentState): void export function stop(agentState: SshAgentState): void
export function isRunning(agentState: SshAgentState): boolean export function isRunning(agentState: SshAgentState): boolean
export function setKeys(agentState: SshAgentState, newKeys: Array<PrivateKey>): void export function setKeys(agentState: SshAgentState, newKeys: Array<PrivateKey>): void

View File

@ -247,15 +247,15 @@ pub mod sshagent {
#[napi] #[napi]
pub async fn serve( pub async fn serve(
callback: ThreadsafeFunction<String, CalleeHandled>, callback: ThreadsafeFunction<(String, bool), CalleeHandled>,
) -> napi::Result<SshAgentState> { ) -> napi::Result<SshAgentState> {
let (auth_request_tx, mut auth_request_rx) = tokio::sync::mpsc::channel::<(u32, String)>(32); let (auth_request_tx, mut auth_request_rx) = tokio::sync::mpsc::channel::<(u32, (String, bool))>(32);
let (auth_response_tx, auth_response_rx) = tokio::sync::broadcast::channel::<(u32, bool)>(32); let (auth_response_tx, auth_response_rx) = tokio::sync::broadcast::channel::<(u32, bool)>(32);
let auth_response_tx_arc = Arc::new(Mutex::new(auth_response_tx)); let auth_response_tx_arc = Arc::new(Mutex::new(auth_response_tx));
tokio::spawn(async move { tokio::spawn(async move {
let _ = auth_response_rx; let _ = auth_response_rx;
while let Some((request_id, cipher_uuid)) = auth_request_rx.recv().await { while let Some((request_id, (cipher_uuid, is_list_request))) = auth_request_rx.recv().await {
let cloned_request_id = request_id.clone(); let cloned_request_id = request_id.clone();
let cloned_cipher_uuid = cipher_uuid.clone(); let cloned_cipher_uuid = cipher_uuid.clone();
let cloned_response_tx_arc = auth_response_tx_arc.clone(); let cloned_response_tx_arc = auth_response_tx_arc.clone();
@ -266,7 +266,7 @@ pub mod sshagent {
let auth_response_tx_arc = cloned_response_tx_arc; let auth_response_tx_arc = cloned_response_tx_arc;
let callback = cloned_callback; let callback = cloned_callback;
let promise_result: Result<Promise<bool>, napi::Error> = let promise_result: Result<Promise<bool>, napi::Error> =
callback.call_async(Ok(cipher_uuid)).await; callback.call_async(Ok((cipher_uuid, is_list_request))).await;
match promise_result { match promise_result {
Ok(promise_result) => match promise_result.await { Ok(promise_result) => match promise_result.await {
Ok(result) => { Ok(result) => {

View File

@ -27,7 +27,7 @@ export class MainSshAgentService {
init() { init() {
// handle sign request passing to UI // handle sign request passing to UI
sshagent sshagent
.serve(async (err: Error, cipherId: string) => { .serve(async (err: Error, cipherId: string, isListRequest: boolean) => {
// clear all old (> SIGN_TIMEOUT) requests // clear all old (> SIGN_TIMEOUT) requests
this.requestResponses = this.requestResponses.filter( this.requestResponses = this.requestResponses.filter(
(response) => response.timestamp > new Date(Date.now() - this.SIGN_TIMEOUT), (response) => response.timestamp > new Date(Date.now() - this.SIGN_TIMEOUT),
@ -37,6 +37,7 @@ export class MainSshAgentService {
const id_for_this_request = this.request_id; const id_for_this_request = this.request_id;
this.messagingService.send("sshagent.signrequest", { this.messagingService.send("sshagent.signrequest", {
cipherId, cipherId,
isListRequest,
requestId: id_for_this_request, requestId: id_for_this_request,
}); });

View File

@ -115,36 +115,33 @@ export class SshAgentService implements OnDestroy {
), ),
), ),
// This concatMap handles showing the dialog to approve the request. // This concatMap handles showing the dialog to approve the request.
concatMap(([message, ciphers]) => { switchMap(([message, ciphers]) => {
const cipherId = message.cipherId as string; const cipherId = message.cipherId as string;
const isListRequest = message.isListRequest as boolean;
const requestId = message.requestId as number; const requestId = message.requestId as number;
// cipherid is empty has the special meaning of "unlock in order to list public keys" if (isListRequest) {
if (cipherId == "") { (async () => {
return of(true).pipe( const sshCiphers = ciphers.filter(
switchMap(async (result) => { (cipher) => cipher.type === CipherType.SshKey && !cipher.isDeleted,
const sshCiphers = ciphers.filter( );
(cipher) => cipher.type === CipherType.SshKey && !cipher.isDeleted, const keys = sshCiphers.map((cipher) => {
); return {
const keys = sshCiphers.map((cipher) => { name: cipher.name,
return { privateKey: cipher.sshKey.privateKey,
name: cipher.name, cipherId: cipher.id,
privateKey: cipher.sshKey.privateKey, };
cipherId: cipher.id, });
}; await ipc.platform.sshAgent.setKeys(keys);
}); await ipc.platform.sshAgent.signRequestResponse(requestId, true);
await ipc.platform.sshAgent.setKeys(keys); })().catch((e) => this.logService.error("Failed to respond to SSH request", e));
await ipc.platform.sshAgent.signRequestResponse(requestId, Boolean(result)); return;
}),
);
} }
if (ciphers === undefined) { if (ciphers === undefined) {
return of(false).pipe( ipc.platform.sshAgent
switchMap((result) => .signRequestResponse(requestId, false)
ipc.platform.sshAgent.signRequestResponse(requestId, Boolean(result)), .catch((e) => this.logService.error("Failed to respond to SSH request", e));
),
);
} }
const cipher = ciphers.find((cipher) => cipher.id == cipherId); const cipher = ciphers.find((cipher) => cipher.id == cipherId);
@ -158,7 +155,7 @@ export class SshAgentService implements OnDestroy {
return dialogRef.closed.pipe( return dialogRef.closed.pipe(
switchMap((result) => { switchMap((result) => {
return ipc.platform.sshAgent.signRequestResponse(requestId, Boolean(result)); return ipc.platform.sshAgent.signRequestResponse(requestId, result);
}), }),
); );
}), }),