mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-27 12:17:35 +03:00
Adds safety check for valid package names
This commit is contained in:
parent
c61cd3459a
commit
73b550011e
@ -40,13 +40,20 @@ impl Command for Init {
|
||||
}
|
||||
|
||||
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
let path = current_dir()?;
|
||||
// Derive the package directory path.
|
||||
let mut path = current_dir()?;
|
||||
|
||||
// Check that the given package name is valid.
|
||||
let package_name = path
|
||||
.file_stem()
|
||||
.ok_or_else(|| anyhow!("Project name invalid"))?
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
if !LeoPackage::is_package_name_valid(&package_name) {
|
||||
return Err(anyhow!("Invalid Leo project name"));
|
||||
}
|
||||
|
||||
// Check that the current package directory path exists.
|
||||
if !path.exists() {
|
||||
return Err(anyhow!("Directory does not exist"));
|
||||
}
|
||||
|
@ -43,13 +43,17 @@ impl Command for New {
|
||||
}
|
||||
|
||||
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
let mut path = current_dir()?;
|
||||
// Check that the given package name is valid.
|
||||
let package_name = self.name;
|
||||
if !LeoPackage::is_package_name_valid(&package_name) {
|
||||
return Err(anyhow!("Invalid Leo project name"));
|
||||
}
|
||||
|
||||
// Derive the package directory path
|
||||
// Derive the package directory path.
|
||||
let mut path = current_dir()?;
|
||||
path.push(&package_name);
|
||||
|
||||
// Verify the package directory path does not exist yet
|
||||
// Verify the package directory path does not exist yet.
|
||||
if path.exists() {
|
||||
return Err(anyhow!("Directory already exists {:?}", path));
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ use tracing::span::Span;
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Prove {
|
||||
#[structopt(long = "skip-key-check", help = "Skip key verification on Setup stage")]
|
||||
pub(super) skip_key_check: bool,
|
||||
pub(crate) skip_key_check: bool,
|
||||
}
|
||||
|
||||
impl Command for Prove {
|
||||
|
@ -30,7 +30,7 @@ use tracing::span::Span;
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Run {
|
||||
#[structopt(long = "skip-key-check", help = "Skip key verification on Setup stage")]
|
||||
skip_key_check: bool,
|
||||
pub(crate) skip_key_check: bool,
|
||||
}
|
||||
|
||||
impl Command for Run {
|
||||
|
@ -35,7 +35,7 @@ use tracing::span::Span;
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Setup {
|
||||
#[structopt(long = "skip-key-check", help = "Skip key verification")]
|
||||
pub(super) skip_key_check: bool,
|
||||
pub(crate) skip_key_check: bool,
|
||||
}
|
||||
|
||||
impl Command for Setup {
|
||||
|
@ -36,7 +36,7 @@ use tracing::span::Span;
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Test {
|
||||
#[structopt(short = "f", long = "file", name = "file")]
|
||||
files: Vec<PathBuf>,
|
||||
pub(crate) files: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Command for Test {
|
||||
|
@ -35,15 +35,15 @@ pub enum Automatic {
|
||||
pub struct Update {
|
||||
/// List all available versions of Leo
|
||||
#[structopt(short, long)]
|
||||
list: bool,
|
||||
pub(crate) list: bool,
|
||||
|
||||
/// For Aleo Studio only
|
||||
#[structopt(short, long)]
|
||||
studio: bool,
|
||||
pub(crate) studio: bool,
|
||||
|
||||
/// Setting for automatic updates of Leo
|
||||
#[structopt(subcommand)]
|
||||
automatic: Option<Automatic>,
|
||||
pub(crate) automatic: Option<Automatic>,
|
||||
}
|
||||
|
||||
impl Command for Update {
|
||||
|
@ -39,34 +39,34 @@ const PEDERSEN_HASH_PATH: &str = "./examples/pedersen-hash/";
|
||||
|
||||
#[test]
|
||||
pub fn build_pedersen_hash() -> Result<()> {
|
||||
Build::new().apply(context()?, ())?;
|
||||
(Build {}).apply(context()?, ())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn setup_pedersen_hash() -> Result<()> {
|
||||
let build = Build::new().apply(context()?, ())?;
|
||||
Setup::new(false).apply(context()?, build.clone())?;
|
||||
Setup::new(true).apply(context()?, build)?;
|
||||
let build = (Build {}).apply(context()?, ())?;
|
||||
(Setup { skip_key_check: false }).apply(context()?, build.clone())?;
|
||||
(Setup { skip_key_check: true }).apply(context()?, build)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn prove_pedersen_hash() -> Result<()> {
|
||||
let build = Build::new().apply(context()?, ())?;
|
||||
let setup = Setup::new(false).apply(context()?, build)?;
|
||||
Prove::new(false).apply(context()?, setup.clone())?;
|
||||
Prove::new(true).apply(context()?, setup)?;
|
||||
let build = (Build {}).apply(context()?, ())?;
|
||||
let setup = (Setup { skip_key_check: false }).apply(context()?, build)?;
|
||||
(Prove { skip_key_check: false }).apply(context()?, setup.clone())?;
|
||||
(Prove { skip_key_check: true }).apply(context()?, setup)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn run_pedersen_hash() -> Result<()> {
|
||||
let build = Build::new().apply(context()?, ())?;
|
||||
let setup = Setup::new(false).apply(context()?, build)?;
|
||||
let prove = Prove::new(false).apply(context()?, setup)?;
|
||||
Run::new(false).apply(context()?, prove.clone())?;
|
||||
Run::new(true).apply(context()?, prove)?;
|
||||
let build = (Build {}).apply(context()?, ())?;
|
||||
let setup = (Setup { skip_key_check: false }).apply(context()?, build)?;
|
||||
let prove = (Prove { skip_key_check: false }).apply(context()?, setup)?;
|
||||
(Run { skip_key_check: false }).apply(context()?, prove.clone())?;
|
||||
(Run { skip_key_check: true }).apply(context()?, prove)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -75,14 +75,14 @@ pub fn test_pedersen_hash() -> Result<()> {
|
||||
let mut main_file = PathBuf::from(PEDERSEN_HASH_PATH);
|
||||
main_file.push("src/main.leo");
|
||||
|
||||
Test::new(Vec::new()).apply(context()?, ())?;
|
||||
Test::new(vec![main_file]).apply(context()?, ())?;
|
||||
(Test { files: vec![] }).apply(context()?, ())?;
|
||||
(Test { files: vec![main_file] }).apply(context()?, ())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_logout() -> Result<()> {
|
||||
Logout::new().apply(context()?, ())?;
|
||||
(Logout {}).apply(context()?, ())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -111,12 +111,40 @@ pub fn login_incorrect_credentials_or_token() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
pub fn leo_update_and_update_automatic() -> Result<()> {
|
||||
Update::new(true, true, None).apply(context()?, ())?;
|
||||
Update::new(false, true, None).apply(context()?, ())?;
|
||||
Update::new(false, false, None).apply(context()?, ())?;
|
||||
let update = Update {
|
||||
list: true,
|
||||
studio: true,
|
||||
automatic: None,
|
||||
};
|
||||
update.apply(context()?, ())?;
|
||||
|
||||
Update::new(false, false, Some(UpdateAutomatic::Automatic { value: true })).apply(context()?, ())?;
|
||||
Update::new(false, false, Some(UpdateAutomatic::Automatic { value: false })).apply(context()?, ())?;
|
||||
let update = Update {
|
||||
list: false,
|
||||
studio: true,
|
||||
automatic: None,
|
||||
};
|
||||
update.apply(context()?, ())?;
|
||||
|
||||
let update = Update {
|
||||
list: false,
|
||||
studio: false,
|
||||
automatic: None,
|
||||
};
|
||||
update.apply(context()?, ())?;
|
||||
|
||||
let update = Update {
|
||||
list: false,
|
||||
studio: false,
|
||||
automatic: Some(UpdateAutomatic::Automatic { value: true }),
|
||||
};
|
||||
update.apply(context()?, ())?;
|
||||
|
||||
let update = Update {
|
||||
list: false,
|
||||
studio: false,
|
||||
automatic: Some(UpdateAutomatic::Automatic { value: false }),
|
||||
};
|
||||
update.apply(context()?, ())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -26,6 +26,9 @@ pub enum PackageError {
|
||||
#[error("Failed to initialize package {:?} ({:?})", _0, _1)]
|
||||
FailedToInitialize(String, OsString),
|
||||
|
||||
#[error("Invalid project name: {:?}", _0)]
|
||||
InvalidPackageName(String),
|
||||
|
||||
#[error("`{}` metadata: {}", _0, _1)]
|
||||
Removing(&'static str, io::Error),
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ use std::io;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ManifestError {
|
||||
#[error("{}: {}", _0, _1)]
|
||||
Crate(&'static str, String),
|
||||
|
||||
#[error("`{}` creating: {}", _0, _1)]
|
||||
Creating(&'static str, io::Error),
|
||||
|
||||
@ -36,3 +39,9 @@ pub enum ManifestError {
|
||||
#[error("`{}` writing: {}", _0, _1)]
|
||||
Writing(&'static str, io::Error),
|
||||
}
|
||||
|
||||
impl From<crate::errors::PackageError> for ManifestError {
|
||||
fn from(error: crate::errors::PackageError) -> Self {
|
||||
ManifestError::Crate("leo-package", error.to_string())
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,11 @@ impl LeoPackage {
|
||||
package::Package::initialize(package_name, is_lib, path)
|
||||
}
|
||||
|
||||
/// Returns `true` if the given Leo package name is valid.
|
||||
pub fn is_package_name_valid(package_name: &str) -> bool {
|
||||
package::Package::is_package_name_valid(package_name)
|
||||
}
|
||||
|
||||
/// Removes an imported Leo package
|
||||
pub fn remove_imported_package(package_name: &str, path: &Path) -> Result<(), PackageError> {
|
||||
package::Package::remove_imported_package(package_name, path)
|
||||
|
@ -34,17 +34,51 @@ pub struct Package {
|
||||
}
|
||||
|
||||
impl Package {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
pub fn new(package_name: &str) -> Result<Self, PackageError> {
|
||||
// Check that the package name is valid.
|
||||
if !Self::is_package_name_valid(package_name) {
|
||||
return Err(PackageError::InvalidPackageName(package_name.to_string()));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
name: package_name.to_owned(),
|
||||
version: "0.1.0".to_owned(),
|
||||
description: None,
|
||||
license: None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `true` if the package name is valid.
|
||||
///
|
||||
/// Package names must be lowercase and composed solely
|
||||
/// of ASCII alphanumeric characters, and may be word-separated
|
||||
/// by a single dash '-'.
|
||||
pub fn is_package_name_valid(package_name: &str) -> bool {
|
||||
// Check that the package name:
|
||||
// 1. is lowercase,
|
||||
// 2. is ASCII alphanumeric or a dash.
|
||||
package_name.chars().all(|x| {
|
||||
if !x.is_lowercase() {
|
||||
tracing::error!("Project names must be all lowercase");
|
||||
return false;
|
||||
}
|
||||
|
||||
if x.is_ascii_alphanumeric() || x == '-' {
|
||||
tracing::error!("Project names must be ASCII alphanumeric, and may be word-separated with a dash");
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `true` if a package is can be initialized at a given path.
|
||||
pub fn can_initialize(package_name: &str, is_lib: bool, path: &Path) -> bool {
|
||||
// Check that the package name is valid.
|
||||
if !Self::is_package_name_valid(package_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut result = true;
|
||||
let mut existing_files = vec![];
|
||||
|
||||
@ -91,6 +125,11 @@ impl Package {
|
||||
|
||||
/// Returns `true` if a package is initialized at the given path
|
||||
pub fn is_initialized(package_name: &str, is_lib: bool, path: &Path) -> bool {
|
||||
// Check that the package name is valid.
|
||||
if !Self::is_package_name_valid(package_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the manifest file exists.
|
||||
if !Manifest::exists_at(&path) {
|
||||
return false;
|
||||
@ -137,7 +176,7 @@ impl Package {
|
||||
// Next, initialize this directory as a Leo package.
|
||||
{
|
||||
// Create the manifest file.
|
||||
Manifest::new(&package_name).write_to(&path)?;
|
||||
Manifest::new(&package_name)?.write_to(&path)?;
|
||||
|
||||
// Verify that the .gitignore file does not exist.
|
||||
if !Gitignore::exists_at(&path) {
|
||||
|
@ -39,11 +39,11 @@ pub struct Manifest {
|
||||
}
|
||||
|
||||
impl Manifest {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
project: Package::new(package_name),
|
||||
pub fn new(package_name: &str) -> Result<Self, ManifestError> {
|
||||
Ok(Self {
|
||||
project: Package::new(package_name)?,
|
||||
remote: None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn filename() -> String {
|
||||
|
@ -52,7 +52,10 @@ fn initialize_fails_with_existing_manifest() {
|
||||
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
|
||||
|
||||
// Manually add a manifest file to the `test_directory`
|
||||
Manifest::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
|
||||
Manifest::new(TEST_PACKAGE_NAME)
|
||||
.unwrap()
|
||||
.write_to(&test_directory)
|
||||
.unwrap();
|
||||
|
||||
// Attempt to initialize a package at the `test_directory`
|
||||
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory).is_err());
|
||||
|
Loading…
Reference in New Issue
Block a user