Skip to content

Commit

Permalink
Import base58 credential end-to-end
Browse files Browse the repository at this point in the history
  • Loading branch information
octol committed Apr 23, 2024
1 parent 857264f commit 376bdb6
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 17 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
65 changes: 58 additions & 7 deletions nym-vpnc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
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, ImportUserCredentialRequest,
StatusRequest,
Expand All @@ -28,7 +28,49 @@ enum Command {
Connect,
Disconnect,
Status,
ImportCredential,
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 @@ -38,7 +80,7 @@ async fn main() -> anyhow::Result<()> {
Command::Connect => connect(&args).await?,
Command::Disconnect => disconnect(&args).await?,
Command::Status => status(&args).await?,
Command::ImportCredential => import_credential(&args).await?,
Command::ImportCredential(ref import_args) => import_credential(&args, import_args).await?,
}
Ok(())
}
Expand Down Expand Up @@ -101,11 +143,20 @@ async fn status(args: &CliArgs) -> anyhow::Result<()> {
Ok(())
}

async fn import_credential(args: &CliArgs) -> anyhow::Result<()> {
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 request = tonic::Request::new(ImportUserCredentialRequest {
credential: "some_credential".to_string(),
});
let response = client.import_user_credential(request).await?.into_inner();
println!("{:?}", response);
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion nym-vpnd/src/command_interface/connection_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl CommandInterfaceConnectionHandler {

pub(crate) async fn handle_import_credential(
&self,
credential: String,
credential: Vec<u8>,
) -> VpnServiceImportUserCredentialResult {
let (tx, rx) = oneshot::channel();
self.vpn_command_tx
Expand Down
6 changes: 4 additions & 2 deletions nym-vpnd/src/command_interface/listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,14 @@ impl NymVpnd for CommandInterface {

async fn import_user_credential(
&self,
_request: tonic::Request<ImportUserCredentialRequest>,
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("".to_string())
.handle_import_credential(credential)
.await;

info!("Returning import credential response");
Expand Down
11 changes: 5 additions & 6 deletions nym-vpnd/src/service/vpn_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::sync::Arc;

use futures::channel::mpsc::UnboundedSender;
use futures::SinkExt;
use nym_vpn_lib::credentials::import_credential_base58;
use nym_vpn_lib::credentials::import_credential;
use nym_vpn_lib::gateway_directory::{self};
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::sync::oneshot;
Expand Down Expand Up @@ -34,10 +34,9 @@ pub enum VpnServiceCommand {
Connect(oneshot::Sender<VpnServiceConnectResult>, ConnectArgs),
Disconnect(oneshot::Sender<VpnServiceDisconnectResult>),
Status(oneshot::Sender<VpnServiceStatusResult>),
#[allow(unused)]
ImportCredential(
oneshot::Sender<VpnServiceImportUserCredentialResult>,
String,
Vec<u8>,
),
}

Expand Down Expand Up @@ -85,7 +84,6 @@ pub enum VpnServiceStatusResult {
ConnectionFailed(String),
}

#[allow(unused)]
#[derive(Debug)]
pub enum VpnServiceImportUserCredentialResult {
Success,
Expand Down Expand Up @@ -220,16 +218,17 @@ impl NymVpnService {

async fn handle_import_credential(
&mut self,
credential: String,
credential: Vec<u8>,
) -> VpnServiceImportUserCredentialResult {
// BUG: this is not correct after a connect/disconnect cycle
let is_running = self.vpn_ctrl_sender.is_some();
if is_running {
return VpnServiceImportUserCredentialResult::Fail(
"Can't import credential while VPN is running".to_string(),
);
}

match import_credential_base58(&credential, self.data_dir.clone()).await {
match import_credential(credential, self.data_dir.clone()).await {
Ok(()) => VpnServiceImportUserCredentialResult::Success,
Err(err) => VpnServiceImportUserCredentialResult::Fail(err.to_string()),
}
Expand Down
2 changes: 1 addition & 1 deletion proto/nym/vpn.proto
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ message SetUserCredentialsRequest {
}

message ImportUserCredentialRequest {
string credential = 1;
bytes credential = 1;
}

message ImportUserCredentialResponse {
Expand Down

0 comments on commit 376bdb6

Please sign in to comment.