mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-15934] Add agent-forwarding detection and git signing detection parsers (#12371)
* Add agent-forwarding detection and git signing detection parsers * Cleanup * Pin russh version * Run cargo fmt * Fix build * Update apps/desktop/desktop_native/core/src/ssh_agent/mod.rs Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com> * Pass through entire namespace * Move to bytes crate * Fix clippy errors * Fix clippy warning * Run cargo fmt * Fix build * Add renovate for bytes * Fix clippy warn --------- Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
This commit is contained in:
1
.github/renovate.json5
vendored
1
.github/renovate.json5
vendored
@@ -123,6 +123,7 @@
|
|||||||
matchPackageNames: [
|
matchPackageNames: [
|
||||||
"@emotion/css",
|
"@emotion/css",
|
||||||
"@webcomponents/custom-elements",
|
"@webcomponents/custom-elements",
|
||||||
|
"bytes",
|
||||||
"concurrently",
|
"concurrently",
|
||||||
"cross-env",
|
"cross-env",
|
||||||
"del",
|
"del",
|
||||||
|
|||||||
3
apps/desktop/desktop_native/Cargo.lock
generated
3
apps/desktop/desktop_native/Cargo.lock
generated
@@ -439,7 +439,7 @@ checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "bitwarden-russh"
|
name = "bitwarden-russh"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/bitwarden/bitwarden-russh.git?rev=23b50e3bbe6d56ef19ab0e98e8bb1462cb6d77ae#23b50e3bbe6d56ef19ab0e98e8bb1462cb6d77ae"
|
source = "git+https://github.com/bitwarden/bitwarden-russh.git?rev=3d48f140fd506412d186203238993163a8c4e536#3d48f140fd506412d186203238993163a8c4e536"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
@@ -942,6 +942,7 @@ dependencies = [
|
|||||||
"base64",
|
"base64",
|
||||||
"bitwarden-russh",
|
"bitwarden-russh",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"bytes",
|
||||||
"cbc",
|
"cbc",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"desktop_objc",
|
"desktop_objc",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ manual_test = []
|
|||||||
aes = "=0.8.4"
|
aes = "=0.8.4"
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
arboard = { version = "=3.4.1", default-features = false, features = [
|
arboard = { version = "=3.4.1", default-features = false, features = [
|
||||||
"wayland-data-control",
|
"wayland-data-control",
|
||||||
] }
|
] }
|
||||||
argon2 = { version = "=0.5.3", features = ["zeroize"] }
|
argon2 = { version = "=0.5.3", features = ["zeroize"] }
|
||||||
base64 = "=0.22.1"
|
base64 = "=0.22.1"
|
||||||
@@ -39,12 +39,12 @@ scopeguard = "=1.2.0"
|
|||||||
sha2 = "=0.10.8"
|
sha2 = "=0.10.8"
|
||||||
ssh-encoding = "=0.2.0"
|
ssh-encoding = "=0.2.0"
|
||||||
ssh-key = { version = "=0.6.7", default-features = false, features = [
|
ssh-key = { version = "=0.6.7", default-features = false, features = [
|
||||||
"encryption",
|
"encryption",
|
||||||
"ed25519",
|
"ed25519",
|
||||||
"rsa",
|
"rsa",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
] }
|
] }
|
||||||
bitwarden-russh = { git = "https://github.com/bitwarden/bitwarden-russh.git", rev = "23b50e3bbe6d56ef19ab0e98e8bb1462cb6d77ae" }
|
bitwarden-russh = { git = "https://github.com/bitwarden/bitwarden-russh.git", rev = "3d48f140fd506412d186203238993163a8c4e536" }
|
||||||
tokio = { workspace = true, features = ["io-util", "sync", "macros", "net"] }
|
tokio = { workspace = true, features = ["io-util", "sync", "macros", "net"] }
|
||||||
tokio-stream = { workspace = true, features = ["net"] }
|
tokio-stream = { workspace = true, features = ["net"] }
|
||||||
tokio-util = { workspace = true, features = ["codec"] }
|
tokio-util = { workspace = true, features = ["codec"] }
|
||||||
@@ -53,21 +53,22 @@ typenum = "=1.17.0"
|
|||||||
pkcs8 = { version = "=0.10.2", features = ["alloc", "encryption", "pem"] }
|
pkcs8 = { version = "=0.10.2", features = ["alloc", "encryption", "pem"] }
|
||||||
rsa = "=0.9.6"
|
rsa = "=0.9.6"
|
||||||
ed25519 = { version = "=2.2.3", features = ["pkcs8"] }
|
ed25519 = { version = "=2.2.3", features = ["pkcs8"] }
|
||||||
sysinfo = { version = "=0.33.1", features = ["windows"] }
|
bytes = "1.9.0"
|
||||||
|
sysinfo = { version = "0.33.1", features = ["windows"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
widestring = { version = "=1.1.0", optional = true }
|
widestring = { version = "=1.1.0", optional = true }
|
||||||
windows = { version = "=0.58.0", features = [
|
windows = { version = "=0.58.0", features = [
|
||||||
"Foundation",
|
"Foundation",
|
||||||
"Security_Credentials_UI",
|
"Security_Credentials_UI",
|
||||||
"Security_Cryptography",
|
"Security_Cryptography",
|
||||||
"Storage_Streams",
|
"Storage_Streams",
|
||||||
"Win32_Foundation",
|
"Win32_Foundation",
|
||||||
"Win32_Security_Credentials",
|
"Win32_Security_Credentials",
|
||||||
"Win32_System_WinRT",
|
"Win32_System_WinRT",
|
||||||
"Win32_UI_Input_KeyboardAndMouse",
|
"Win32_UI_Input_KeyboardAndMouse",
|
||||||
"Win32_UI_WindowsAndMessaging",
|
"Win32_UI_WindowsAndMessaging",
|
||||||
"Win32_System_Pipes",
|
"Win32_System_Pipes",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dev-dependencies]
|
[target.'cfg(windows)'.dev-dependencies]
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ mod peercred_unix_listener_stream;
|
|||||||
|
|
||||||
pub mod importer;
|
pub mod importer;
|
||||||
pub mod peerinfo;
|
pub mod peerinfo;
|
||||||
|
mod request_parser;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BitwardenDesktopAgent {
|
pub struct BitwardenDesktopAgent {
|
||||||
keystore: ssh_agent::KeyStore,
|
keystore: ssh_agent::KeyStore,
|
||||||
@@ -35,19 +37,37 @@ pub struct SshAgentUIRequest {
|
|||||||
pub cipher_id: Option<String>,
|
pub cipher_id: Option<String>,
|
||||||
pub process_name: String,
|
pub process_name: String,
|
||||||
pub is_list: bool,
|
pub is_list: bool,
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
pub is_forwarding: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ssh_agent::Agent<peerinfo::models::PeerInfo> for BitwardenDesktopAgent {
|
impl ssh_agent::Agent<peerinfo::models::PeerInfo> for BitwardenDesktopAgent {
|
||||||
async fn confirm(&self, ssh_key: Key, info: &peerinfo::models::PeerInfo) -> bool {
|
async fn confirm(&self, ssh_key: Key, data: &[u8], info: &peerinfo::models::PeerInfo) -> bool {
|
||||||
if !self.is_running() {
|
if !self.is_running() {
|
||||||
println!("[BitwardenDesktopAgent] Agent is not running, but tried to call confirm");
|
println!("[BitwardenDesktopAgent] Agent is not running, but tried to call confirm");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let request_id = self.get_request_id().await;
|
let request_id = self.get_request_id().await;
|
||||||
|
let request_data = match request_parser::parse_request(data) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(e) => {
|
||||||
|
println!("[SSH Agent] Error while parsing request: {}", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let namespace = match request_data {
|
||||||
|
request_parser::SshAgentSignRequest::SshSigRequest(ref req) => {
|
||||||
|
Some(req.namespace.clone())
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"[SSH Agent] Confirming request from application: {}",
|
"[SSH Agent] Confirming request from application: {}, is_forwarding: {}, namespace: {}",
|
||||||
info.process_name()
|
info.process_name(),
|
||||||
|
info.is_forwarding(),
|
||||||
|
namespace.clone().unwrap_or_default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut rx_channel = self.get_ui_response_rx.lock().await.resubscribe();
|
let mut rx_channel = self.get_ui_response_rx.lock().await.resubscribe();
|
||||||
@@ -57,6 +77,8 @@ impl ssh_agent::Agent<peerinfo::models::PeerInfo> for BitwardenDesktopAgent {
|
|||||||
cipher_id: Some(ssh_key.cipher_uuid.clone()),
|
cipher_id: Some(ssh_key.cipher_uuid.clone()),
|
||||||
process_name: info.process_name().to_string(),
|
process_name: info.process_name().to_string(),
|
||||||
is_list: false,
|
is_list: false,
|
||||||
|
namespace,
|
||||||
|
is_forwarding: info.is_forwarding(),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.expect("Should send request to ui");
|
.expect("Should send request to ui");
|
||||||
@@ -81,6 +103,8 @@ impl ssh_agent::Agent<peerinfo::models::PeerInfo> for BitwardenDesktopAgent {
|
|||||||
cipher_id: None,
|
cipher_id: None,
|
||||||
process_name: info.process_name().to_string(),
|
process_name: info.process_name().to_string(),
|
||||||
is_list: true,
|
is_list: true,
|
||||||
|
namespace: None,
|
||||||
|
is_forwarding: info.is_forwarding(),
|
||||||
};
|
};
|
||||||
self.show_ui_request_tx
|
self.show_ui_request_tx
|
||||||
.send(message)
|
.send(message)
|
||||||
@@ -93,6 +117,17 @@ impl ssh_agent::Agent<peerinfo::models::PeerInfo> for BitwardenDesktopAgent {
|
|||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn set_is_forwarding(
|
||||||
|
&self,
|
||||||
|
is_forwarding: bool,
|
||||||
|
connection_info: &peerinfo::models::PeerInfo,
|
||||||
|
) {
|
||||||
|
// is_forwarding can only be added but never removed from a connection
|
||||||
|
if is_forwarding {
|
||||||
|
connection_info.set_forwarding(is_forwarding);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitwardenDesktopAgent {
|
impl BitwardenDesktopAgent {
|
||||||
|
|||||||
@@ -34,9 +34,7 @@ impl Stream for PeercredUnixListenerStream {
|
|||||||
return Poll::Ready(Some(Ok((stream, PeerInfo::unknown()))));
|
return Poll::Ready(Some(Ok((stream, PeerInfo::unknown()))));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => return Poll::Ready(Some(Ok((stream, PeerInfo::unknown())))),
|
||||||
return Poll::Ready(Some(Ok((stream, PeerInfo::unknown()))));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let peer_info = peerinfo::gather::get_peer_info(pid as u32);
|
let peer_info = peerinfo::gather::get_peer_info(pid as u32);
|
||||||
match peer_info {
|
match peer_info {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::sync::{atomic::AtomicBool, Arc};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Peerinfo represents the information of a peer process connecting over a socket.
|
* Peerinfo represents the information of a peer process connecting over a socket.
|
||||||
* This can be later extended to include more information (icon, app name) for the corresponding application.
|
* This can be later extended to include more information (icon, app name) for the corresponding application.
|
||||||
@@ -7,6 +9,7 @@ pub struct PeerInfo {
|
|||||||
uid: u32,
|
uid: u32,
|
||||||
pid: u32,
|
pid: u32,
|
||||||
process_name: String,
|
process_name: String,
|
||||||
|
is_forwarding: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PeerInfo {
|
impl PeerInfo {
|
||||||
@@ -15,6 +18,16 @@ impl PeerInfo {
|
|||||||
uid,
|
uid,
|
||||||
pid,
|
pid,
|
||||||
process_name,
|
process_name,
|
||||||
|
is_forwarding: Arc::new(AtomicBool::new(false)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unknown() -> Self {
|
||||||
|
Self {
|
||||||
|
uid: 0,
|
||||||
|
pid: 0,
|
||||||
|
process_name: "Unknown application".to_string(),
|
||||||
|
is_forwarding: Arc::new(AtomicBool::new(false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +43,13 @@ impl PeerInfo {
|
|||||||
&self.process_name
|
&self.process_name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unknown() -> Self {
|
pub fn is_forwarding(&self) -> bool {
|
||||||
Self::new(0, 0, "Unknown application".to_string())
|
self.is_forwarding
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_forwarding(&self, value: bool) {
|
||||||
|
self.is_forwarding
|
||||||
|
.store(value, std::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
use bytes::{Buf, Bytes};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct SshSigRequest {
|
||||||
|
pub namespace: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct SignRequest {}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum SshAgentSignRequest {
|
||||||
|
SshSigRequest(SshSigRequest),
|
||||||
|
SignRequest(SignRequest),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_request(data: &[u8]) -> Result<SshAgentSignRequest, anyhow::Error> {
|
||||||
|
let mut data = Bytes::copy_from_slice(data);
|
||||||
|
let magic_header = "SSHSIG";
|
||||||
|
let header = data.split_to(magic_header.len());
|
||||||
|
|
||||||
|
// sshsig; based on https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig
|
||||||
|
if header == magic_header.as_bytes() {
|
||||||
|
let _version = data.get_u32();
|
||||||
|
|
||||||
|
// read until null byte
|
||||||
|
let namespace = data
|
||||||
|
.into_iter()
|
||||||
|
.take_while(|&x| x != 0)
|
||||||
|
.collect::<Vec<u8>>();
|
||||||
|
let namespace =
|
||||||
|
String::from_utf8(namespace).map_err(|_| anyhow::anyhow!("Invalid namespace"))?;
|
||||||
|
|
||||||
|
Ok(SshAgentSignRequest::SshSigRequest(SshSigRequest {
|
||||||
|
namespace,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
// regular sign request
|
||||||
|
Ok(SshAgentSignRequest::SignRequest(SignRequest {}))
|
||||||
|
}
|
||||||
|
}
|
||||||
9
apps/desktop/desktop_native/napi/index.d.ts
vendored
9
apps/desktop/desktop_native/napi/index.d.ts
vendored
@@ -67,7 +67,14 @@ export declare namespace sshagent {
|
|||||||
status: SshKeyImportStatus
|
status: SshKeyImportStatus
|
||||||
sshKey?: SshKey
|
sshKey?: SshKey
|
||||||
}
|
}
|
||||||
export function serve(callback: (err: Error | null, arg0: string | undefined | null, arg1: boolean, arg2: string) => any): Promise<SshAgentState>
|
export interface SshUiRequest {
|
||||||
|
cipherId?: string
|
||||||
|
isList: boolean
|
||||||
|
processName: string
|
||||||
|
isForwarding: boolean
|
||||||
|
namespace?: string
|
||||||
|
}
|
||||||
|
export function serve(callback: (err: Error | null, arg: SshUiRequest) => 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
|
||||||
|
|||||||
@@ -243,9 +243,18 @@ pub mod sshagent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct SshUIRequest {
|
||||||
|
pub cipher_id: Option<String>,
|
||||||
|
pub is_list: bool,
|
||||||
|
pub process_name: String,
|
||||||
|
pub is_forwarding: bool,
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub async fn serve(
|
pub async fn serve(
|
||||||
callback: ThreadsafeFunction<(Option<String>, bool, String), CalleeHandled>,
|
callback: ThreadsafeFunction<SshUIRequest, CalleeHandled>,
|
||||||
) -> napi::Result<SshAgentState> {
|
) -> napi::Result<SshAgentState> {
|
||||||
let (auth_request_tx, mut auth_request_rx) =
|
let (auth_request_tx, mut auth_request_rx) =
|
||||||
tokio::sync::mpsc::channel::<desktop_core::ssh_agent::SshAgentUIRequest>(32);
|
tokio::sync::mpsc::channel::<desktop_core::ssh_agent::SshAgentUIRequest>(32);
|
||||||
@@ -262,11 +271,13 @@ 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> = callback
|
let promise_result: Result<Promise<bool>, napi::Error> = callback
|
||||||
.call_async(Ok((
|
.call_async(Ok(SshUIRequest {
|
||||||
request.cipher_id,
|
cipher_id: request.cipher_id,
|
||||||
request.is_list,
|
is_list: request.is_list,
|
||||||
request.process_name,
|
process_name: request.process_name,
|
||||||
)))
|
is_forwarding: request.is_forwarding,
|
||||||
|
namespace: request.namespace,
|
||||||
|
}))
|
||||||
.await;
|
.await;
|
||||||
match promise_result {
|
match promise_result {
|
||||||
Ok(promise_result) => match promise_result.await {
|
Ok(promise_result) => match promise_result.await {
|
||||||
|
|||||||
@@ -3509,9 +3509,27 @@
|
|||||||
"sshkeyApprovalTitle": {
|
"sshkeyApprovalTitle": {
|
||||||
"message": "Confirm SSH key usage"
|
"message": "Confirm SSH key usage"
|
||||||
},
|
},
|
||||||
|
"agentForwardingWarningTitle": {
|
||||||
|
"message": "Warning: Agent Forwarding"
|
||||||
|
},
|
||||||
|
"agentForwardingWarningText": {
|
||||||
|
"message": "This request comes from a remote device that you are logged into"
|
||||||
|
},
|
||||||
"sshkeyApprovalMessageInfix": {
|
"sshkeyApprovalMessageInfix": {
|
||||||
"message": "is requesting access to"
|
"message": "is requesting access to"
|
||||||
},
|
},
|
||||||
|
"sshkeyApprovalMessageSuffix": {
|
||||||
|
"message": "in order to"
|
||||||
|
},
|
||||||
|
"sshActionLogin": {
|
||||||
|
"message": "authenticate to a server"
|
||||||
|
},
|
||||||
|
"sshActionSign": {
|
||||||
|
"message": "sign a message"
|
||||||
|
},
|
||||||
|
"sshActionGitSign": {
|
||||||
|
"message": "sign a git commit"
|
||||||
|
},
|
||||||
"unknownApplication": {
|
"unknownApplication": {
|
||||||
"message": "An application"
|
"message": "An application"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,8 +2,17 @@
|
|||||||
<bit-dialog>
|
<bit-dialog>
|
||||||
<div class="tw-font-semibold" bitDialogTitle>{{ "sshkeyApprovalTitle" | i18n }}</div>
|
<div class="tw-font-semibold" bitDialogTitle>{{ "sshkeyApprovalTitle" | i18n }}</div>
|
||||||
<div bitDialogContent>
|
<div bitDialogContent>
|
||||||
|
<app-callout
|
||||||
|
type="warning"
|
||||||
|
title="{{ 'agentForwardingWarningTitle' | i18n }}"
|
||||||
|
*ngIf="params.isAgentForwarding"
|
||||||
|
>
|
||||||
|
{{ 'agentForwardingWarningText' | i18n }}
|
||||||
|
</app-callout>
|
||||||
|
|
||||||
<b>{{params.applicationName}}</b> {{ "sshkeyApprovalMessageInfix" | i18n }}
|
<b>{{params.applicationName}}</b> {{ "sshkeyApprovalMessageInfix" | i18n }}
|
||||||
<b>{{params.cipherName}}</b>.
|
<b>{{params.cipherName}}</b>
|
||||||
|
{{ "sshkeyApprovalMessageSuffix" | i18n }} {{ params.action | i18n }}
|
||||||
</div>
|
</div>
|
||||||
<div bitDialogFooter>
|
<div bitDialogFooter>
|
||||||
<button type="submit" bitButton bitFormButton buttonType="primary">
|
<button type="submit" bitButton bitFormButton buttonType="primary">
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import { CipherFormGeneratorComponent } from "@bitwarden/vault";
|
|||||||
export interface ApproveSshRequestParams {
|
export interface ApproveSshRequestParams {
|
||||||
cipherName: string;
|
cipherName: string;
|
||||||
applicationName: string;
|
applicationName: string;
|
||||||
|
isAgentForwarding: boolean;
|
||||||
|
action: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -44,11 +46,26 @@ export class ApproveSshRequestComponent {
|
|||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
static open(dialogService: DialogService, cipherName: string, applicationName: string) {
|
static open(
|
||||||
|
dialogService: DialogService,
|
||||||
|
cipherName: string,
|
||||||
|
applicationName: string,
|
||||||
|
isAgentForwarding: boolean,
|
||||||
|
namespace: string,
|
||||||
|
) {
|
||||||
|
let actioni18nKey = "sshActionLogin";
|
||||||
|
if (namespace === "git") {
|
||||||
|
actioni18nKey = "sshActionGitSign";
|
||||||
|
} else if (namespace != null && namespace != "") {
|
||||||
|
actioni18nKey = "sshActionSign";
|
||||||
|
}
|
||||||
|
|
||||||
return dialogService.open<boolean, ApproveSshRequestParams>(ApproveSshRequestComponent, {
|
return dialogService.open<boolean, ApproveSshRequestParams>(ApproveSshRequestComponent, {
|
||||||
data: {
|
data: {
|
||||||
cipherName,
|
cipherName,
|
||||||
applicationName,
|
applicationName,
|
||||||
|
isAgentForwarding,
|
||||||
|
action: actioni18nKey,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,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, isListRequest: boolean, processName: string) => {
|
.serve(async (err: Error, sshUiRequest: sshagent.SshUiRequest) => {
|
||||||
// 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),
|
||||||
@@ -56,10 +56,12 @@ export class MainSshAgentService {
|
|||||||
this.request_id += 1;
|
this.request_id += 1;
|
||||||
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: sshUiRequest.cipherId,
|
||||||
isListRequest,
|
isListRequest: sshUiRequest.isList,
|
||||||
requestId: id_for_this_request,
|
requestId: id_for_this_request,
|
||||||
processName,
|
processName: sshUiRequest.processName,
|
||||||
|
isAgentForwarding: sshUiRequest.isForwarding,
|
||||||
|
namespace: sshUiRequest.namespace,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await firstValueFrom(
|
const result = await firstValueFrom(
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ export class SshAgentService implements OnDestroy {
|
|||||||
const isListRequest = message.isListRequest as boolean;
|
const isListRequest = message.isListRequest as boolean;
|
||||||
const requestId = message.requestId as number;
|
const requestId = message.requestId as number;
|
||||||
let application = message.processName as string;
|
let application = message.processName as string;
|
||||||
|
const namespace = message.namespace as string;
|
||||||
|
const isAgentForwarding = message.isAgentForwarding as boolean;
|
||||||
if (application == "") {
|
if (application == "") {
|
||||||
application = this.i18nService.t("unknownApplication");
|
application = this.i18nService.t("unknownApplication");
|
||||||
}
|
}
|
||||||
@@ -181,6 +183,8 @@ export class SshAgentService implements OnDestroy {
|
|||||||
this.dialogService,
|
this.dialogService,
|
||||||
cipher.name,
|
cipher.name,
|
||||||
application,
|
application,
|
||||||
|
isAgentForwarding,
|
||||||
|
namespace,
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await firstValueFrom(dialogRef.closed);
|
const result = await firstValueFrom(dialogRef.closed);
|
||||||
|
|||||||
Reference in New Issue
Block a user