Skip to content

Commit

Permalink
CLI: create-workspace
Browse files Browse the repository at this point in the history
  • Loading branch information
TimeEngineer committed Jan 5, 2024
1 parent d7af8c2 commit 55e3c1b
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 4 deletions.
42 changes: 42 additions & 0 deletions cli/src/create_workspace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS

use clap::Args;
use std::path::PathBuf;

use libparsec::{get_default_config_dir, EntryName};

use crate::utils::*;

#[derive(Args)]
pub struct CreateWorkspace {
/// Parsec config directory
#[arg(short, long, default_value_os_t = get_default_config_dir())]
config_dir: PathBuf,
/// Device slughash
#[arg(short, long)]
device: Option<String>,
/// New workspace name
#[arg(short, long)]
name: EntryName,
}

pub async fn create_workspace(create_workspace: CreateWorkspace) -> anyhow::Result<()> {
let CreateWorkspace {
config_dir,
device,
name,
} = create_workspace;

load_client_and_run(config_dir, device, |client| async move {
let handle = start_spinner("Creating workspace");

client.user_ops.create_workspace(name).await?;

handle.done();

println!("Workspace has been created");

Ok(())
})
.await
}
6 changes: 6 additions & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod bootstrap_organization;
mod cancel_invitation;
mod claim_invitation;
mod create_organization;
mod create_workspace;
mod export_recovery_device;
mod greet_invitation;
mod import_recovery_device;
Expand Down Expand Up @@ -41,6 +42,8 @@ enum Command {
ClaimInvitation(claim_invitation::ClaimInvitation),
/// Create new organization
CreateOrganization(create_organization::CreateOrganization),
/// Create new workspace
CreateWorkspace(create_workspace::CreateWorkspace),
/// Export recovery device
ExportRecoveryDevice(export_recovery_device::ExportRecoveryDevice),
/// Import recovery device
Expand Down Expand Up @@ -88,6 +91,9 @@ async fn main() -> anyhow::Result<()> {
Command::CreateOrganization(create_organization) => {
create_organization::create_organization(create_organization).await
}
Command::CreateWorkspace(create_workspace) => {
create_workspace::create_workspace(create_workspace).await
}
Command::ExportRecoveryDevice(export_recovery_device) => {
export_recovery_device::export_recovery_device(export_recovery_device).await
}
Expand Down
26 changes: 26 additions & 0 deletions cli/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,32 @@ async fn list_invitations(tmp_path: TmpPath) {
)));
}

#[rstest::rstest]
#[tokio::test]
async fn create_workspace(tmp_path: TmpPath) {
let tmp_path_str = tmp_path.to_str().unwrap();
let config = get_testenv_config();
let (url, [alice, ..], _) = run_local_organization(&tmp_path, None, config)
.await
.unwrap();

set_env(&tmp_path_str, &url);

Command::cargo_bin("parsec_cli")
.unwrap()
.args([
"create-workspace",
"--device",
&alice.slughash(),
"--name",
"new-workspace",
])
.assert()
.stdout(predicates::str::contains(
"Creating workspace\nWorkspace has been created",
));
}

#[rstest::rstest]
#[tokio::test]
async fn invite_device_dance(tmp_path: TmpPath) {
Expand Down
88 changes: 85 additions & 3 deletions cli/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
use std::{future::Future, path::PathBuf, sync::Arc};

use libparsec::{
list_available_devices, load_device, AuthenticatedCmds, AvailableDevice, DeviceAccessStrategy,
DeviceFileType, DeviceLabel, HumanHandle, LocalDevice, Password, ProxyConfig, SASCode,
UserProfile,
internal::{Client, EventBus},
list_available_devices, load_device, AuthenticatedCmds, AvailableDevice, ClientConfig,
DeviceAccessStrategy, DeviceFileType, DeviceLabel, HumanHandle, LocalDevice, Password,
ProxyConfig, SASCode, UserProfile,
};
use terminal_spinners::{SpinnerBuilder, SpinnerHandle, DOTS};

Expand Down Expand Up @@ -108,6 +109,87 @@ where
Ok(())
}

pub async fn load_client_and_run<F, Fut>(
config_dir: PathBuf,
device_slughash: Option<String>,
function: F,
) -> anyhow::Result<()>
where
F: FnOnce(Client) -> Fut,
Fut: Future<Output = anyhow::Result<()>>,
{
let devices = list_available_devices(&config_dir).await;

if let Some(device_slughash) = device_slughash {
let mut possible_devices = vec![];

for device in &devices {
if device.slughash().starts_with(&device_slughash) {
possible_devices.push(device);
}
}

match possible_devices.len() {
0 => {
println!("Device `{device_slughash}` not found, available devices:");
format_devices(&devices);
}
1 => {
let device = possible_devices[0];

let device = match device.ty {
DeviceFileType::Password => {
#[cfg(feature = "testenv")]
let password = "test".to_string().into();
#[cfg(not(feature = "testenv"))]
let password = rpassword::prompt_password("password:")?.into();

let access = DeviceAccessStrategy::Password {
key_file: device.key_file_path.clone(),
password,
};

// This will fail if the password is invalid, but also if the binary is compiled with fast crypto (see libparsec_crypto)
load_device(&config_dir, &access).await?
}
DeviceFileType::Smartcard => {
let access = DeviceAccessStrategy::Smartcard {
key_file: device.key_file_path.clone(),
};

load_device(&config_dir, &access).await?
}
DeviceFileType::Recovery => {
return Err(anyhow::anyhow!(
"Unsupported device file authentication `{:?}`",
device.ty
));
}
};

let client = Client::start(
Arc::new(ClientConfig::default().into()),
EventBus::default(),
device,
)
.await?;

function(client).await?;
}
_ => {
println!("Multiple devices found for `{device_slughash}`:");
format_devices(&devices);
}
}
} else {
println!("Error: Missing option '--device'\n");
println!("Available devices:");
format_devices(&devices);
}

Ok(())
}

pub fn start_spinner(text: &'static str) -> SpinnerHandle {
SpinnerBuilder::new().spinner(&DOTS).text(text).start()
}
Expand Down
2 changes: 1 addition & 1 deletion libparsec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub use workspace::*;

pub mod internal {
pub use libparsec_client::{
claimer_retrieve_info, DeviceClaimFinalizeCtx, DeviceClaimInProgress1Ctx,
claimer_retrieve_info, Client, DeviceClaimFinalizeCtx, DeviceClaimInProgress1Ctx,
DeviceClaimInProgress2Ctx, DeviceClaimInProgress3Ctx, DeviceClaimInitialCtx,
DeviceGreetInProgress1Ctx, DeviceGreetInProgress2Ctx, DeviceGreetInProgress3Ctx,
DeviceGreetInProgress4Ctx, DeviceGreetInitialCtx, EventBus, UserClaimFinalizeCtx,
Expand Down

0 comments on commit 55e3c1b

Please sign in to comment.