Skip to content

Commit

Permalink
Merge pull request #322 from nymtech/jon/connect-arguments
Browse files Browse the repository at this point in the history
Import credential in vpnd
  • Loading branch information
octol authored Apr 23, 2024
2 parents 4047975 + e001146 commit d663d6e
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 24 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions nym-vpnc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ license.workspace = true

[dependencies]
anyhow.workspace = true
bs58.workspace = true
clap = { workspace = true, features = ["derive"] }
parity-tokio-ipc.workspace = true
prost.workspace = true
Expand Down
68 changes: 66 additions & 2 deletions nym-vpnc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
use std::path::{Path, PathBuf};

use anyhow::Context;
use clap::{Parser, Subcommand};
use clap::{Args, Parser, Subcommand};
use nym_vpn_proto::{
nym_vpnd_client::NymVpndClient, ConnectRequest, DisconnectRequest, StatusRequest,
nym_vpnd_client::NymVpndClient, ConnectRequest, DisconnectRequest, ImportUserCredentialRequest,
StatusRequest,
};
use parity_tokio_ipc::Endpoint as IpcEndpoint;
use tonic::transport::{Channel as TonicChannel, Endpoint as TonicEndpoint};
Expand All @@ -27,6 +28,49 @@ enum Command {
Connect,
Disconnect,
Status,
ImportCredential(ImportCredentialArgs),
}

#[derive(Args)]
pub(crate) struct ImportCredentialArgs {
#[command(flatten)]
pub(crate) credential_type: ImportCredentialType,

// currently hidden as there exists only a single serialization standard
#[arg(long, hide = true)]
pub(crate) version: Option<u8>,
}

#[derive(Args, Clone)]
#[group(required = true, multiple = false)]
pub(crate) struct ImportCredentialType {
/// Credential encoded using base58.
#[arg(long)]
pub(crate) credential_data: Option<String>,

/// Path to the credential file.
#[arg(long)]
pub(crate) credential_path: Option<PathBuf>,
}

fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}

// Workaround until clap supports enums for ArgGroups
pub(crate) enum ImportCredentialTypeEnum {
Path(PathBuf),
Data(String),
}

impl From<ImportCredentialType> for ImportCredentialTypeEnum {
fn from(ict: ImportCredentialType) -> Self {
match (ict.credential_data, ict.credential_path) {
(Some(data), None) => ImportCredentialTypeEnum::Data(data),
(None, Some(path)) => ImportCredentialTypeEnum::Path(path),
_ => unreachable!(),
}
}
}

#[tokio::main]
Expand All @@ -36,6 +80,7 @@ async fn main() -> anyhow::Result<()> {
Command::Connect => connect(&args).await?,
Command::Disconnect => disconnect(&args).await?,
Command::Status => status(&args).await?,
Command::ImportCredential(ref import_args) => import_credential(&args, import_args).await?,
}
Ok(())
}
Expand Down Expand Up @@ -97,3 +142,22 @@ async fn status(args: &CliArgs) -> anyhow::Result<()> {
println!("{:?}", response);
Ok(())
}

async fn import_credential(
args: &CliArgs,
import_args: &ImportCredentialArgs,
) -> anyhow::Result<()> {
let import_type: ImportCredentialTypeEnum = import_args.credential_type.clone().into();
let request = match import_type {
ImportCredentialTypeEnum::Path(_path) => todo!(),
ImportCredentialTypeEnum::Data(data) => {
let bin = parse_encoded_credential_data(&data)?;
tonic::Request::new(ImportUserCredentialRequest { credential: bin })
}
};

let mut client = get_client(args).await?;
let response = client.import_user_credential(request).await?.into_inner();
println!("{:?}", response);
Ok(())
}
21 changes: 19 additions & 2 deletions nym-vpnd/src/command_interface/connection_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use tokio::sync::{mpsc::UnboundedSender, oneshot};
use tracing::{info, warn};

use crate::service::{
VpnServiceCommand, VpnServiceConnectResult, VpnServiceDisconnectResult, VpnServiceStatusResult,
ConnectArgs, VpnServiceCommand, VpnServiceConnectResult, VpnServiceDisconnectResult,
VpnServiceImportUserCredentialResult, VpnServiceStatusResult,
};

pub(super) struct CommandInterfaceConnectionHandler {
Expand All @@ -20,8 +21,9 @@ impl CommandInterfaceConnectionHandler {
pub(crate) async fn handle_connect(&self) -> VpnServiceConnectResult {
info!("Starting VPN");
let (tx, rx) = oneshot::channel();
let connect_args = ConnectArgs::Default;
self.vpn_command_tx
.send(VpnServiceCommand::Connect(tx))
.send(VpnServiceCommand::Connect(tx, connect_args))
.unwrap();
info!("Sent start command to VPN");
info!("Waiting for response");
Expand Down Expand Up @@ -70,4 +72,19 @@ impl CommandInterfaceConnectionHandler {
info!("VPN status: {:?}", status);
status
}

pub(crate) async fn handle_import_credential(
&self,
credential: Vec<u8>,
) -> VpnServiceImportUserCredentialResult {
let (tx, rx) = oneshot::channel();
self.vpn_command_tx
.send(VpnServiceCommand::ImportCredential(tx, credential))
.unwrap();
info!("Sent import credential command to VPN");
info!("Waiting for response");
let result = rx.await.unwrap();
info!("VPN import credential result: {:?}", result);
result
}
}
34 changes: 32 additions & 2 deletions nym-vpnd/src/command_interface/listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use std::{

use nym_vpn_proto::{
nym_vpnd_server::NymVpnd, ConnectRequest, ConnectResponse, ConnectionStatus, DisconnectRequest,
DisconnectResponse, StatusRequest, StatusResponse,
DisconnectResponse, Error as ProtoError, ImportUserCredentialRequest,
ImportUserCredentialResponse, StatusRequest, StatusResponse,
};
use tokio::sync::mpsc::UnboundedSender;
use tracing::{error, info};
Expand Down Expand Up @@ -48,7 +49,7 @@ impl CommandInterface {
}
}

fn remove_previous_socket_file(&self) {
pub(super) fn remove_previous_socket_file(&self) {
if let ListenerType::Path(ref socket_path) = self.listener {
match fs::remove_file(socket_path) {
Ok(_) => info!(
Expand Down Expand Up @@ -117,9 +118,37 @@ impl NymVpnd for CommandInterface {
.handle_status()
.await;

let error = match status {
VpnServiceStatusResult::NotConnected => None,
VpnServiceStatusResult::Connecting => None,
VpnServiceStatusResult::Connected => None,
VpnServiceStatusResult::Disconnecting => None,
VpnServiceStatusResult::ConnectionFailed(ref reason) => Some(reason.clone()),
}
.map(|reason| ProtoError { message: reason });

info!("Returning status response");
Ok(tonic::Response::new(StatusResponse {
status: ConnectionStatus::from(status) as i32,
error,
}))
}

async fn import_user_credential(
&self,
request: tonic::Request<ImportUserCredentialRequest>,
) -> Result<tonic::Response<ImportUserCredentialResponse>, tonic::Status> {
info!("Got import credential request");

let credential = request.into_inner().credential;

let status = CommandInterfaceConnectionHandler::new(self.vpn_command_tx.clone())
.handle_import_credential(credential)
.await;

info!("Returning import credential response");
Ok(tonic::Response::new(ImportUserCredentialResponse {
success: status.is_success(),
}))
}
}
Expand All @@ -131,6 +160,7 @@ impl From<VpnServiceStatusResult> for ConnectionStatus {
VpnServiceStatusResult::Connecting => ConnectionStatus::Connecting,
VpnServiceStatusResult::Connected => ConnectionStatus::Connected,
VpnServiceStatusResult::Disconnecting => ConnectionStatus::Disconnecting,
VpnServiceStatusResult::ConnectionFailed(_reason) => ConnectionStatus::ConnectionFailed,
}
}
}
1 change: 1 addition & 0 deletions nym-vpnd/src/command_interface/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ fn spawn_socket_listener(vpn_command_tx: UnboundedSender<VpnServiceCommand>, soc
info!("Starting socket listener on: {}", socket_path.display());
tokio::task::spawn(async move {
let command_interface = CommandInterface::new_with_path(vpn_command_tx, &socket_path);
command_interface.remove_previous_socket_file();
let incoming = setup_socket_stream(&socket_path);
Server::builder()
.add_service(NymVpndServer::new(command_interface))
Expand Down
9 changes: 9 additions & 0 deletions nym-vpnd/src/service/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,12 @@ pub(super) fn read_config_file(
error,
})
}

pub(super) fn create_data_dir(data_dir: &PathBuf) -> Result<(), ConfigSetupError> {
fs::create_dir_all(data_dir).map_err(|error| ConfigSetupError::CreateDirectory {
dir: data_dir.clone(),
error,
})?;
info!("Data directory created at {:?}", data_dir);
Ok(())
}
2 changes: 1 addition & 1 deletion nym-vpnd/src/service/exit_listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl VpnServiceExitListener {
}
nym_vpn_lib::NymVpnExitStatusMessage::Failed(err) => {
error!("VPN exit: fail: {err}");
self.set_shared_state(VpnState::NotConnected);
self.set_shared_state(VpnState::ConnectionFailed(err.to_string()));
}
},
Err(err) => {
Expand Down
3 changes: 2 additions & 1 deletion nym-vpnd/src/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ mod vpn_service;

pub(crate) use start::start_vpn_service;
pub(crate) use vpn_service::{
VpnServiceCommand, VpnServiceConnectResult, VpnServiceDisconnectResult, VpnServiceStatusResult,
ConnectArgs, VpnServiceCommand, VpnServiceConnectResult, VpnServiceDisconnectResult,
VpnServiceImportUserCredentialResult, VpnServiceStatusResult,
};
Loading

0 comments on commit d663d6e

Please sign in to comment.