mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 16:49:18 -05:00
feat(runtime/permissions): prompt fallback (#9376)
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com> Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
This commit is contained in:
parent
8b49d948f5
commit
fefe93c91b
19 changed files with 460 additions and 251 deletions
|
@ -516,7 +516,7 @@ impl FileFetcher {
|
||||||
fn fetch_remote(
|
fn fetch_remote(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
permissions: &Permissions,
|
permissions: &mut Permissions,
|
||||||
redirect_limit: i64,
|
redirect_limit: i64,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<File, AnyError>> + Send>> {
|
) -> Pin<Box<dyn Future<Output = Result<File, AnyError>> + Send>> {
|
||||||
debug!("FileFetcher::fetch_remote() - specifier: {}", specifier);
|
debug!("FileFetcher::fetch_remote() - specifier: {}", specifier);
|
||||||
|
@ -560,7 +560,7 @@ impl FileFetcher {
|
||||||
};
|
};
|
||||||
let maybe_auth_token = self.auth_tokens.get(&specifier);
|
let maybe_auth_token = self.auth_tokens.get(&specifier);
|
||||||
let specifier = specifier.clone();
|
let specifier = specifier.clone();
|
||||||
let permissions = permissions.clone();
|
let mut permissions = permissions.clone();
|
||||||
let client = self.http_client.clone();
|
let client = self.http_client.clone();
|
||||||
let file_fetcher = self.clone();
|
let file_fetcher = self.clone();
|
||||||
// A single pass of fetch either yields code or yields a redirect.
|
// A single pass of fetch either yields code or yields a redirect.
|
||||||
|
@ -580,7 +580,7 @@ impl FileFetcher {
|
||||||
FetchOnceResult::Redirect(redirect_url, headers) => {
|
FetchOnceResult::Redirect(redirect_url, headers) => {
|
||||||
file_fetcher.http_cache.set(&specifier, headers, &[])?;
|
file_fetcher.http_cache.set(&specifier, headers, &[])?;
|
||||||
file_fetcher
|
file_fetcher
|
||||||
.fetch_remote(&redirect_url, &permissions, redirect_limit - 1)
|
.fetch_remote(&redirect_url, &mut permissions, redirect_limit - 1)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
FetchOnceResult::Code(bytes, headers) => {
|
FetchOnceResult::Code(bytes, headers) => {
|
||||||
|
@ -600,7 +600,7 @@ impl FileFetcher {
|
||||||
pub async fn fetch(
|
pub async fn fetch(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
permissions: &Permissions,
|
permissions: &mut Permissions,
|
||||||
) -> Result<File, AnyError> {
|
) -> Result<File, AnyError> {
|
||||||
debug!("FileFetcher::fetch() - specifier: {}", specifier);
|
debug!("FileFetcher::fetch() - specifier: {}", specifier);
|
||||||
let scheme = get_validated_scheme(specifier)?;
|
let scheme = get_validated_scheme(specifier)?;
|
||||||
|
@ -718,7 +718,7 @@ mod tests {
|
||||||
async fn test_fetch(specifier: &ModuleSpecifier) -> (File, FileFetcher) {
|
async fn test_fetch(specifier: &ModuleSpecifier) -> (File, FileFetcher) {
|
||||||
let (file_fetcher, _) = setup(CacheSetting::ReloadAll, None);
|
let (file_fetcher, _) = setup(CacheSetting::ReloadAll, None);
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(specifier, &Permissions::allow_all())
|
.fetch(specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
(result.unwrap(), file_fetcher)
|
(result.unwrap(), file_fetcher)
|
||||||
|
@ -730,7 +730,7 @@ mod tests {
|
||||||
let _http_server_guard = test_util::http_server();
|
let _http_server_guard = test_util::http_server();
|
||||||
let (file_fetcher, _) = setup(CacheSetting::ReloadAll, None);
|
let (file_fetcher, _) = setup(CacheSetting::ReloadAll, None);
|
||||||
let result: Result<File, AnyError> = file_fetcher
|
let result: Result<File, AnyError> = file_fetcher
|
||||||
.fetch_remote(specifier, &Permissions::allow_all(), 1)
|
.fetch_remote(specifier, &mut Permissions::allow_all(), 1)
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let (_, headers) = file_fetcher.http_cache.get(specifier).unwrap();
|
let (_, headers) = file_fetcher.http_cache.get(specifier).unwrap();
|
||||||
|
@ -1011,7 +1011,7 @@ mod tests {
|
||||||
file_fetcher.insert_cached(file.clone());
|
file_fetcher.insert_cached(file.clone());
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let result_file = result.unwrap();
|
let result_file = result.unwrap();
|
||||||
|
@ -1028,7 +1028,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
@ -1059,7 +1059,7 @@ mod tests {
|
||||||
let specifier = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap();
|
let specifier = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap();
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1089,7 +1089,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1113,7 +1113,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1136,7 +1136,7 @@ mod tests {
|
||||||
metadata.write(&cache_filename).unwrap();
|
metadata.write(&cache_filename).unwrap();
|
||||||
|
|
||||||
let result = file_fetcher_01
|
let result = file_fetcher_01
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1157,7 +1157,7 @@ mod tests {
|
||||||
metadata.write(&cache_filename).unwrap();
|
metadata.write(&cache_filename).unwrap();
|
||||||
|
|
||||||
let result = file_fetcher_02
|
let result = file_fetcher_02
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1179,7 +1179,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.expect("setup failed");
|
.expect("setup failed");
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1214,7 +1214,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = file_fetcher_01
|
let result = file_fetcher_01
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
@ -1234,7 +1234,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.expect("could not create file fetcher");
|
.expect("could not create file fetcher");
|
||||||
let result = file_fetcher_02
|
let result = file_fetcher_02
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
@ -1273,7 +1273,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1334,7 +1334,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1406,7 +1406,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = file_fetcher_01
|
let result = file_fetcher_01
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
@ -1426,7 +1426,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.expect("could not create file fetcher");
|
.expect("could not create file fetcher");
|
||||||
let result = file_fetcher_02
|
let result = file_fetcher_02
|
||||||
.fetch(&redirected_specifier, &Permissions::allow_all())
|
.fetch(&redirected_specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
@ -1453,12 +1453,12 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch_remote(&specifier, &Permissions::allow_all(), 2)
|
.fetch_remote(&specifier, &mut Permissions::allow_all(), 2)
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch_remote(&specifier, &Permissions::allow_all(), 1)
|
.fetch_remote(&specifier, &mut Permissions::allow_all(), 1)
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
||||||
|
@ -1491,7 +1491,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1539,7 +1539,7 @@ mod tests {
|
||||||
resolve_url("http://localhost:4545/cli/tests/002_hello.ts").unwrap();
|
resolve_url("http://localhost:4545/cli/tests/002_hello.ts").unwrap();
|
||||||
|
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
let err = result.unwrap_err();
|
let err = result.unwrap_err();
|
||||||
|
@ -1574,7 +1574,7 @@ mod tests {
|
||||||
resolve_url("http://localhost:4545/cli/tests/002_hello.ts").unwrap();
|
resolve_url("http://localhost:4545/cli/tests/002_hello.ts").unwrap();
|
||||||
|
|
||||||
let result = file_fetcher_01
|
let result = file_fetcher_01
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
let err = result.unwrap_err();
|
let err = result.unwrap_err();
|
||||||
|
@ -1582,12 +1582,12 @@ mod tests {
|
||||||
assert_eq!(err.to_string(), "Specifier not found in cache: \"http://localhost:4545/cli/tests/002_hello.ts\", --cached-only is specified.");
|
assert_eq!(err.to_string(), "Specifier not found in cache: \"http://localhost:4545/cli/tests/002_hello.ts\", --cached-only is specified.");
|
||||||
|
|
||||||
let result = file_fetcher_02
|
let result = file_fetcher_02
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
let result = file_fetcher_01
|
let result = file_fetcher_01
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
@ -1605,7 +1605,7 @@ mod tests {
|
||||||
fs::write(fixture_path.clone(), r#"console.log("hello deno");"#)
|
fs::write(fixture_path.clone(), r#"console.log("hello deno");"#)
|
||||||
.expect("could not write file");
|
.expect("could not write file");
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
@ -1614,7 +1614,7 @@ mod tests {
|
||||||
fs::write(fixture_path, r#"console.log("goodbye deno");"#)
|
fs::write(fixture_path, r#"console.log("goodbye deno");"#)
|
||||||
.expect("could not write file");
|
.expect("could not write file");
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await;
|
.await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let file = result.unwrap();
|
let file = result.unwrap();
|
||||||
|
|
11
cli/flags.rs
11
cli/flags.rs
|
@ -149,7 +149,7 @@ pub struct Flags {
|
||||||
pub lock_write: bool,
|
pub lock_write: bool,
|
||||||
pub log_level: Option<Level>,
|
pub log_level: Option<Level>,
|
||||||
pub no_check: bool,
|
pub no_check: bool,
|
||||||
pub no_prompts: bool,
|
pub prompt: bool,
|
||||||
pub no_remote: bool,
|
pub no_remote: bool,
|
||||||
pub reload: bool,
|
pub reload: bool,
|
||||||
pub repl: bool,
|
pub repl: bool,
|
||||||
|
@ -244,6 +244,7 @@ impl From<Flags> for PermissionsOptions {
|
||||||
allow_read: flags.allow_read,
|
allow_read: flags.allow_read,
|
||||||
allow_run: flags.allow_run,
|
allow_run: flags.allow_run,
|
||||||
allow_write: flags.allow_write,
|
allow_write: flags.allow_write,
|
||||||
|
prompt: flags.prompt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1428,6 +1429,11 @@ fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||||
.long("allow-all")
|
.long("allow-all")
|
||||||
.help("Allow all permissions"),
|
.help("Allow all permissions"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("prompt")
|
||||||
|
.long("prompt")
|
||||||
|
.help("Fallback to prompt if required permission wasn't passed"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_subcommand<'a, 'b>() -> App<'a, 'b> {
|
fn run_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
|
@ -1844,6 +1850,9 @@ fn permission_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||||
flags.allow_plugin = true;
|
flags.allow_plugin = true;
|
||||||
flags.allow_hrtime = true;
|
flags.allow_hrtime = true;
|
||||||
}
|
}
|
||||||
|
if matches.is_present("prompt") {
|
||||||
|
flags.prompt = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(ry) move this to utility module and add test.
|
// TODO(ry) move this to utility module and add test.
|
||||||
|
|
|
@ -347,7 +347,7 @@ impl ModuleRegistry {
|
||||||
let specifier = origin_url.join(CONFIG_PATH)?;
|
let specifier = origin_url.join(CONFIG_PATH)?;
|
||||||
let file = self
|
let file = self
|
||||||
.file_fetcher
|
.file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await?;
|
.await?;
|
||||||
let config: RegistryConfigurationJson = serde_json::from_str(&file.source)?;
|
let config: RegistryConfigurationJson = serde_json::from_str(&file.source)?;
|
||||||
validate_config(&config)?;
|
validate_config(&config)?;
|
||||||
|
@ -609,7 +609,7 @@ impl ModuleRegistry {
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let file = self
|
let file = self
|
||||||
.file_fetcher
|
.file_fetcher
|
||||||
.fetch(&specifier, &Permissions::allow_all())
|
.fetch(&specifier, &mut Permissions::allow_all())
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
error!(
|
error!(
|
||||||
|
|
|
@ -60,7 +60,7 @@ async fn op_emit(
|
||||||
let args: EmitArgs = serde_json::from_value(args)?;
|
let args: EmitArgs = serde_json::from_value(args)?;
|
||||||
let root_specifier = args.root_specifier;
|
let root_specifier = args.root_specifier;
|
||||||
let program_state = state.borrow().borrow::<Arc<ProgramState>>().clone();
|
let program_state = state.borrow().borrow::<Arc<ProgramState>>().clone();
|
||||||
let runtime_permissions = {
|
let mut runtime_permissions = {
|
||||||
let state = state.borrow();
|
let state = state.borrow();
|
||||||
state.borrow::<Permissions>().clone()
|
state.borrow::<Permissions>().clone()
|
||||||
};
|
};
|
||||||
|
@ -86,7 +86,7 @@ async fn op_emit(
|
||||||
} else {
|
} else {
|
||||||
let file = program_state
|
let file = program_state
|
||||||
.file_fetcher
|
.file_fetcher
|
||||||
.fetch(&import_map_specifier, &runtime_permissions)
|
.fetch(&import_map_specifier, &mut runtime_permissions)
|
||||||
.await?;
|
.await?;
|
||||||
ImportMap::from_json(import_map_specifier.as_str(), &file.source)?
|
ImportMap::from_json(import_map_specifier.as_str(), &file.source)?
|
||||||
};
|
};
|
||||||
|
|
|
@ -108,7 +108,7 @@ impl ProgramState {
|
||||||
format!("Bad URL (\"{}\") for import map.", import_map_url),
|
format!("Bad URL (\"{}\") for import map.", import_map_url),
|
||||||
)?;
|
)?;
|
||||||
let file = file_fetcher
|
let file = file_fetcher
|
||||||
.fetch(&import_map_specifier, &Permissions::allow_all())
|
.fetch(&import_map_specifier, &mut Permissions::allow_all())
|
||||||
.await?;
|
.await?;
|
||||||
let import_map =
|
let import_map =
|
||||||
ImportMap::from_json(import_map_specifier.as_str(), &file.source)?;
|
ImportMap::from_json(import_map_specifier.as_str(), &file.source)?;
|
||||||
|
@ -149,7 +149,7 @@ impl ProgramState {
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
specifier: ModuleSpecifier,
|
specifier: ModuleSpecifier,
|
||||||
lib: TypeLib,
|
lib: TypeLib,
|
||||||
runtime_permissions: Permissions,
|
mut runtime_permissions: Permissions,
|
||||||
is_dynamic: bool,
|
is_dynamic: bool,
|
||||||
maybe_import_map: Option<ImportMap>,
|
maybe_import_map: Option<ImportMap>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
|
|
|
@ -257,7 +257,7 @@ impl SpecifierHandler for FetchHandler {
|
||||||
// When the module graph fetches dynamic modules, the set of dynamic
|
// When the module graph fetches dynamic modules, the set of dynamic
|
||||||
// permissions need to be applied. Other static imports have all
|
// permissions need to be applied. Other static imports have all
|
||||||
// permissions.
|
// permissions.
|
||||||
let permissions = if is_dynamic {
|
let mut permissions = if is_dynamic {
|
||||||
self.runtime_permissions.clone()
|
self.runtime_permissions.clone()
|
||||||
} else {
|
} else {
|
||||||
Permissions::allow_all()
|
Permissions::allow_all()
|
||||||
|
@ -267,7 +267,7 @@ impl SpecifierHandler for FetchHandler {
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
let source_file = file_fetcher
|
let source_file = file_fetcher
|
||||||
.fetch(&requested_specifier, &permissions)
|
.fetch(&requested_specifier, &mut permissions)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
let err = if let Some(e) = err.downcast_ref::<std::io::Error>() {
|
let err = if let Some(e) = err.downcast_ref::<std::io::Error>() {
|
||||||
|
|
|
@ -220,7 +220,7 @@ pub fn compile_to_runtime_flags(
|
||||||
lock_write: false,
|
lock_write: false,
|
||||||
log_level: flags.log_level,
|
log_level: flags.log_level,
|
||||||
no_check: false,
|
no_check: false,
|
||||||
no_prompts: flags.no_prompts,
|
prompt: flags.prompt,
|
||||||
no_remote: false,
|
no_remote: false,
|
||||||
reload: false,
|
reload: false,
|
||||||
repl: false,
|
repl: false,
|
||||||
|
|
|
@ -86,19 +86,19 @@ pub struct HttpClientDefaults {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FetchPermissions {
|
pub trait FetchPermissions {
|
||||||
fn check_net_url(&self, _url: &Url) -> Result<(), AnyError>;
|
fn check_net_url(&mut self, _url: &Url) -> Result<(), AnyError>;
|
||||||
fn check_read(&self, _p: &Path) -> Result<(), AnyError>;
|
fn check_read(&mut self, _p: &Path) -> Result<(), AnyError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For use with `op_fetch` when the user does not want permissions.
|
/// For use with `op_fetch` when the user does not want permissions.
|
||||||
pub struct NoFetchPermissions;
|
pub struct NoFetchPermissions;
|
||||||
|
|
||||||
impl FetchPermissions for NoFetchPermissions {
|
impl FetchPermissions for NoFetchPermissions {
|
||||||
fn check_net_url(&self, _url: &Url) -> Result<(), AnyError> {
|
fn check_net_url(&mut self, _url: &Url) -> Result<(), AnyError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_read(&self, _p: &Path) -> Result<(), AnyError> {
|
fn check_read(&mut self, _p: &Path) -> Result<(), AnyError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ where
|
||||||
let scheme = url.scheme();
|
let scheme = url.scheme();
|
||||||
let (request_rid, request_body_rid) = match scheme {
|
let (request_rid, request_body_rid) = match scheme {
|
||||||
"http" | "https" => {
|
"http" | "https" => {
|
||||||
let permissions = state.borrow::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check_net_url(&url)?;
|
permissions.check_net_url(&url)?;
|
||||||
|
|
||||||
let mut request = client.request(method, url);
|
let mut request = client.request(method, url);
|
||||||
|
@ -442,7 +442,7 @@ where
|
||||||
FP: FetchPermissions + 'static,
|
FP: FetchPermissions + 'static,
|
||||||
{
|
{
|
||||||
if let Some(ca_file) = args.ca_file.clone() {
|
if let Some(ca_file) = args.ca_file.clone() {
|
||||||
let permissions = state.borrow::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check_read(&PathBuf::from(ca_file))?;
|
permissions.check_read(&PathBuf::from(ca_file))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,14 +49,14 @@ pub struct WsCaData(pub Vec<u8>);
|
||||||
pub struct WsUserAgent(pub String);
|
pub struct WsUserAgent(pub String);
|
||||||
|
|
||||||
pub trait WebSocketPermissions {
|
pub trait WebSocketPermissions {
|
||||||
fn check_net_url(&self, _url: &url::Url) -> Result<(), AnyError>;
|
fn check_net_url(&mut self, _url: &url::Url) -> Result<(), AnyError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For use with `op_websocket_*` when the user does not want permissions.
|
/// For use with `op_websocket_*` when the user does not want permissions.
|
||||||
pub struct NoWebSocketPermissions;
|
pub struct NoWebSocketPermissions;
|
||||||
|
|
||||||
impl WebSocketPermissions for NoWebSocketPermissions {
|
impl WebSocketPermissions for NoWebSocketPermissions {
|
||||||
fn check_net_url(&self, _url: &url::Url) -> Result<(), AnyError> {
|
fn check_net_url(&mut self, _url: &url::Url) -> Result<(), AnyError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ where
|
||||||
WP: WebSocketPermissions + 'static,
|
WP: WebSocketPermissions + 'static,
|
||||||
{
|
{
|
||||||
state
|
state
|
||||||
.borrow::<WP>()
|
.borrow_mut::<WP>()
|
||||||
.check_net_url(&url::Url::parse(&url)?)?;
|
.check_net_url(&url::Url::parse(&url)?)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -113,8 +113,8 @@ where
|
||||||
WP: WebSocketPermissions + 'static,
|
WP: WebSocketPermissions + 'static,
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let s = state.borrow();
|
let mut s = state.borrow_mut();
|
||||||
s.borrow::<WP>()
|
s.borrow_mut::<WP>()
|
||||||
.check_net_url(&url::Url::parse(&args.url)?)
|
.check_net_url(&url::Url::parse(&args.url)?)
|
||||||
.expect(
|
.expect(
|
||||||
"Permission check should have been done in op_ws_check_permission",
|
"Permission check should have been done in op_ws_check_permission",
|
||||||
|
|
|
@ -149,7 +149,7 @@ fn open_helper(
|
||||||
let _ = mode; // avoid unused warning
|
let _ = mode; // avoid unused warning
|
||||||
}
|
}
|
||||||
|
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
let options = args.options;
|
let options = args.options;
|
||||||
|
|
||||||
if options.read {
|
if options.read {
|
||||||
|
@ -409,7 +409,7 @@ fn op_chdir(
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let d = PathBuf::from(&directory);
|
let d = PathBuf::from(&directory);
|
||||||
state.borrow::<Permissions>().read.check(&d)?;
|
state.borrow_mut::<Permissions>().read.check(&d)?;
|
||||||
set_current_dir(&d)?;
|
set_current_dir(&d)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -429,7 +429,7 @@ fn op_mkdir_sync(
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let path = Path::new(&args.path).to_path_buf();
|
let path = Path::new(&args.path).to_path_buf();
|
||||||
let mode = args.mode.unwrap_or(0o777) & 0o777;
|
let mode = args.mode.unwrap_or(0o777) & 0o777;
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive);
|
debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive);
|
||||||
let mut builder = std::fs::DirBuilder::new();
|
let mut builder = std::fs::DirBuilder::new();
|
||||||
builder.recursive(args.recursive);
|
builder.recursive(args.recursive);
|
||||||
|
@ -451,8 +451,8 @@ async fn op_mkdir_async(
|
||||||
let mode = args.mode.unwrap_or(0o777) & 0o777;
|
let mode = args.mode.unwrap_or(0o777) & 0o777;
|
||||||
|
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
@ -486,7 +486,7 @@ fn op_chmod_sync(
|
||||||
let path = Path::new(&args.path).to_path_buf();
|
let path = Path::new(&args.path).to_path_buf();
|
||||||
let mode = args.mode & 0o777;
|
let mode = args.mode & 0o777;
|
||||||
|
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
debug!("op_chmod_sync {} {:o}", path.display(), mode);
|
debug!("op_chmod_sync {} {:o}", path.display(), mode);
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
|
@ -513,8 +513,8 @@ async fn op_chmod_async(
|
||||||
let mode = args.mode & 0o777;
|
let mode = args.mode & 0o777;
|
||||||
|
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
@ -552,7 +552,7 @@ fn op_chown_sync(
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let path = Path::new(&args.path).to_path_buf();
|
let path = Path::new(&args.path).to_path_buf();
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
debug!(
|
debug!(
|
||||||
"op_chown_sync {} {:?} {:?}",
|
"op_chown_sync {} {:?} {:?}",
|
||||||
path.display(),
|
path.display(),
|
||||||
|
@ -582,8 +582,8 @@ async fn op_chown_async(
|
||||||
let path = Path::new(&args.path).to_path_buf();
|
let path = Path::new(&args.path).to_path_buf();
|
||||||
|
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
@ -624,7 +624,7 @@ fn op_remove_sync(
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&args.path);
|
||||||
let recursive = args.recursive;
|
let recursive = args.recursive;
|
||||||
|
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
use std::os::windows::prelude::MetadataExt;
|
use std::os::windows::prelude::MetadataExt;
|
||||||
|
@ -667,8 +667,8 @@ async fn op_remove_async(
|
||||||
let recursive = args.recursive;
|
let recursive = args.recursive;
|
||||||
|
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
@ -722,7 +722,7 @@ fn op_copy_file_sync(
|
||||||
let from = PathBuf::from(&args.from);
|
let from = PathBuf::from(&args.from);
|
||||||
let to = PathBuf::from(&args.to);
|
let to = PathBuf::from(&args.to);
|
||||||
|
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&from)?;
|
permissions.read.check(&from)?;
|
||||||
permissions.write.check(&to)?;
|
permissions.write.check(&to)?;
|
||||||
|
|
||||||
|
@ -748,8 +748,8 @@ async fn op_copy_file_async(
|
||||||
let to = PathBuf::from(&args.to);
|
let to = PathBuf::from(&args.to);
|
||||||
|
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&from)?;
|
permissions.read.check(&from)?;
|
||||||
permissions.write.check(&to)?;
|
permissions.write.check(&to)?;
|
||||||
}
|
}
|
||||||
|
@ -861,7 +861,7 @@ fn op_stat_sync(
|
||||||
) -> Result<FsStat, AnyError> {
|
) -> Result<FsStat, AnyError> {
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&args.path);
|
||||||
let lstat = args.lstat;
|
let lstat = args.lstat;
|
||||||
state.borrow::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
debug!("op_stat_sync {} {}", path.display(), lstat);
|
debug!("op_stat_sync {} {}", path.display(), lstat);
|
||||||
let metadata = if lstat {
|
let metadata = if lstat {
|
||||||
std::fs::symlink_metadata(&path)?
|
std::fs::symlink_metadata(&path)?
|
||||||
|
@ -880,8 +880,8 @@ async fn op_stat_async(
|
||||||
let lstat = args.lstat;
|
let lstat = args.lstat;
|
||||||
|
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
@ -904,7 +904,7 @@ fn op_realpath_sync(
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, AnyError> {
|
||||||
let path = PathBuf::from(&path);
|
let path = PathBuf::from(&path);
|
||||||
|
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&path)?;
|
permissions.read.check(&path)?;
|
||||||
if path.is_relative() {
|
if path.is_relative() {
|
||||||
permissions.read.check_blind(¤t_dir()?, "CWD")?;
|
permissions.read.check_blind(¤t_dir()?, "CWD")?;
|
||||||
|
@ -926,8 +926,8 @@ async fn op_realpath_async(
|
||||||
let path = PathBuf::from(&path);
|
let path = PathBuf::from(&path);
|
||||||
|
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&path)?;
|
permissions.read.check(&path)?;
|
||||||
if path.is_relative() {
|
if path.is_relative() {
|
||||||
permissions.read.check_blind(¤t_dir()?, "CWD")?;
|
permissions.read.check_blind(¤t_dir()?, "CWD")?;
|
||||||
|
@ -962,7 +962,7 @@ fn op_read_dir_sync(
|
||||||
) -> Result<Vec<DirEntry>, AnyError> {
|
) -> Result<Vec<DirEntry>, AnyError> {
|
||||||
let path = PathBuf::from(&path);
|
let path = PathBuf::from(&path);
|
||||||
|
|
||||||
state.borrow::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
|
|
||||||
debug!("op_read_dir_sync {}", path.display());
|
debug!("op_read_dir_sync {}", path.display());
|
||||||
let entries: Vec<_> = std::fs::read_dir(path)?
|
let entries: Vec<_> = std::fs::read_dir(path)?
|
||||||
|
@ -998,8 +998,8 @@ async fn op_read_dir_async(
|
||||||
) -> Result<Vec<DirEntry>, AnyError> {
|
) -> Result<Vec<DirEntry>, AnyError> {
|
||||||
let path = PathBuf::from(&path);
|
let path = PathBuf::from(&path);
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
}
|
}
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_read_dir_async {}", path.display());
|
debug!("op_read_dir_async {}", path.display());
|
||||||
|
@ -1047,7 +1047,7 @@ fn op_rename_sync(
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
let oldpath = PathBuf::from(&args.oldpath);
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&args.newpath);
|
||||||
|
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&oldpath)?;
|
permissions.read.check(&oldpath)?;
|
||||||
permissions.write.check(&oldpath)?;
|
permissions.write.check(&oldpath)?;
|
||||||
permissions.write.check(&newpath)?;
|
permissions.write.check(&newpath)?;
|
||||||
|
@ -1064,8 +1064,8 @@ async fn op_rename_async(
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
let oldpath = PathBuf::from(&args.oldpath);
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&args.newpath);
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&oldpath)?;
|
permissions.read.check(&oldpath)?;
|
||||||
permissions.write.check(&oldpath)?;
|
permissions.write.check(&oldpath)?;
|
||||||
permissions.write.check(&newpath)?;
|
permissions.write.check(&newpath)?;
|
||||||
|
@ -1098,7 +1098,7 @@ fn op_link_sync(
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
let oldpath = PathBuf::from(&args.oldpath);
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&args.newpath);
|
||||||
|
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&oldpath)?;
|
permissions.read.check(&oldpath)?;
|
||||||
permissions.write.check(&oldpath)?;
|
permissions.write.check(&oldpath)?;
|
||||||
permissions.read.check(&newpath)?;
|
permissions.read.check(&newpath)?;
|
||||||
|
@ -1118,8 +1118,8 @@ async fn op_link_async(
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&args.newpath);
|
||||||
|
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&oldpath)?;
|
permissions.read.check(&oldpath)?;
|
||||||
permissions.write.check(&oldpath)?;
|
permissions.write.check(&oldpath)?;
|
||||||
permissions.read.check(&newpath)?;
|
permissions.read.check(&newpath)?;
|
||||||
|
@ -1159,7 +1159,7 @@ fn op_symlink_sync(
|
||||||
let oldpath = PathBuf::from(&args.oldpath);
|
let oldpath = PathBuf::from(&args.oldpath);
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&args.newpath);
|
||||||
|
|
||||||
state.borrow::<Permissions>().write.check(&newpath)?;
|
state.borrow_mut::<Permissions>().write.check(&newpath)?;
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"op_symlink_sync {} {}",
|
"op_symlink_sync {} {}",
|
||||||
|
@ -1209,8 +1209,8 @@ async fn op_symlink_async(
|
||||||
let newpath = PathBuf::from(&args.newpath);
|
let newpath = PathBuf::from(&args.newpath);
|
||||||
|
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow::<Permissions>().write.check(&newpath)?;
|
state.borrow_mut::<Permissions>().write.check(&newpath)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
@ -1259,7 +1259,7 @@ fn op_read_link_sync(
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, AnyError> {
|
||||||
let path = PathBuf::from(&path);
|
let path = PathBuf::from(&path);
|
||||||
|
|
||||||
state.borrow::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
|
|
||||||
debug!("op_read_link_value {}", path.display());
|
debug!("op_read_link_value {}", path.display());
|
||||||
let target = std::fs::read_link(&path)?.into_os_string();
|
let target = std::fs::read_link(&path)?.into_os_string();
|
||||||
|
@ -1274,8 +1274,8 @@ async fn op_read_link_async(
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, AnyError> {
|
||||||
let path = PathBuf::from(&path);
|
let path = PathBuf::from(&path);
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow::<Permissions>().read.check(&path)?;
|
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||||
}
|
}
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_read_link_async {}", path.display());
|
debug!("op_read_link_async {}", path.display());
|
||||||
|
@ -1349,7 +1349,7 @@ fn op_truncate_sync(
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&args.path);
|
||||||
let len = args.len;
|
let len = args.len;
|
||||||
|
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
|
|
||||||
debug!("op_truncate_sync {} {}", path.display(), len);
|
debug!("op_truncate_sync {} {}", path.display(), len);
|
||||||
let f = std::fs::OpenOptions::new().write(true).open(&path)?;
|
let f = std::fs::OpenOptions::new().write(true).open(&path)?;
|
||||||
|
@ -1365,8 +1365,8 @@ async fn op_truncate_async(
|
||||||
let path = PathBuf::from(&args.path);
|
let path = PathBuf::from(&args.path);
|
||||||
let len = args.len;
|
let len = args.len;
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
}
|
}
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("op_truncate_async {} {}", path.display(), len);
|
debug!("op_truncate_async {} {}", path.display(), len);
|
||||||
|
@ -1441,7 +1441,7 @@ fn op_make_temp_dir_sync(
|
||||||
let suffix = args.suffix.map(String::from);
|
let suffix = args.suffix.map(String::from);
|
||||||
|
|
||||||
state
|
state
|
||||||
.borrow::<Permissions>()
|
.borrow_mut::<Permissions>()
|
||||||
.write
|
.write
|
||||||
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
||||||
|
|
||||||
|
@ -1469,9 +1469,9 @@ async fn op_make_temp_dir_async(
|
||||||
let prefix = args.prefix.map(String::from);
|
let prefix = args.prefix.map(String::from);
|
||||||
let suffix = args.suffix.map(String::from);
|
let suffix = args.suffix.map(String::from);
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state
|
state
|
||||||
.borrow::<Permissions>()
|
.borrow_mut::<Permissions>()
|
||||||
.write
|
.write
|
||||||
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
||||||
}
|
}
|
||||||
|
@ -1504,7 +1504,7 @@ fn op_make_temp_file_sync(
|
||||||
let suffix = args.suffix.map(String::from);
|
let suffix = args.suffix.map(String::from);
|
||||||
|
|
||||||
state
|
state
|
||||||
.borrow::<Permissions>()
|
.borrow_mut::<Permissions>()
|
||||||
.write
|
.write
|
||||||
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
||||||
|
|
||||||
|
@ -1532,9 +1532,9 @@ async fn op_make_temp_file_async(
|
||||||
let prefix = args.prefix.map(String::from);
|
let prefix = args.prefix.map(String::from);
|
||||||
let suffix = args.suffix.map(String::from);
|
let suffix = args.suffix.map(String::from);
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let mut state = state.borrow_mut();
|
||||||
state
|
state
|
||||||
.borrow::<Permissions>()
|
.borrow_mut::<Permissions>()
|
||||||
.write
|
.write
|
||||||
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
||||||
}
|
}
|
||||||
|
@ -1648,7 +1648,7 @@ fn op_utime_sync(
|
||||||
let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
|
let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
|
||||||
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
||||||
|
|
||||||
state.borrow::<Permissions>().write.check(&path)?;
|
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||||
filetime::set_file_times(path, atime, mtime)?;
|
filetime::set_file_times(path, atime, mtime)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1664,7 +1664,11 @@ async fn op_utime_async(
|
||||||
let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
|
let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1);
|
||||||
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1);
|
||||||
|
|
||||||
state.borrow().borrow::<Permissions>().write.check(&path)?;
|
state
|
||||||
|
.borrow_mut()
|
||||||
|
.borrow_mut::<Permissions>()
|
||||||
|
.write
|
||||||
|
.check(&path)?;
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
filetime::set_file_times(path, atime, mtime)?;
|
filetime::set_file_times(path, atime, mtime)?;
|
||||||
|
@ -1681,7 +1685,7 @@ fn op_cwd(
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, AnyError> {
|
||||||
let path = current_dir()?;
|
let path = current_dir()?;
|
||||||
state
|
state
|
||||||
.borrow::<Permissions>()
|
.borrow_mut::<Permissions>()
|
||||||
.read
|
.read
|
||||||
.check_blind(&path, "CWD")?;
|
.check_blind(&path, "CWD")?;
|
||||||
let path_str = into_string(path.into_os_string())?;
|
let path_str = into_string(path.into_os_string())?;
|
||||||
|
|
|
@ -109,7 +109,7 @@ fn op_fs_events_open(
|
||||||
};
|
};
|
||||||
for path in &args.paths {
|
for path in &args.paths {
|
||||||
state
|
state
|
||||||
.borrow::<Permissions>()
|
.borrow_mut::<Permissions>()
|
||||||
.read
|
.read
|
||||||
.check(&PathBuf::from(path))?;
|
.check(&PathBuf::from(path))?;
|
||||||
watcher.watch(path, recursive_mode)?;
|
watcher.watch(path, recursive_mode)?;
|
||||||
|
|
|
@ -224,8 +224,8 @@ async fn op_datagram_send(
|
||||||
transport_args: ArgsEnum::Ip(args),
|
transport_args: ArgsEnum::Ip(args),
|
||||||
} if transport == "udp" => {
|
} if transport == "udp" => {
|
||||||
{
|
{
|
||||||
let s = state.borrow();
|
let mut s = state.borrow_mut();
|
||||||
s.borrow::<Permissions>()
|
s.borrow_mut::<Permissions>()
|
||||||
.net
|
.net
|
||||||
.check(&(&args.hostname, Some(args.port)))?;
|
.check(&(&args.hostname, Some(args.port)))?;
|
||||||
}
|
}
|
||||||
|
@ -251,8 +251,8 @@ async fn op_datagram_send(
|
||||||
} if transport == "unixpacket" => {
|
} if transport == "unixpacket" => {
|
||||||
let address_path = Path::new(&args.path);
|
let address_path = Path::new(&args.path);
|
||||||
{
|
{
|
||||||
let s = state.borrow();
|
let mut s = state.borrow_mut();
|
||||||
s.borrow::<Permissions>().write.check(&address_path)?;
|
s.borrow_mut::<Permissions>().write.check(&address_path)?;
|
||||||
}
|
}
|
||||||
let resource = state
|
let resource = state
|
||||||
.borrow()
|
.borrow()
|
||||||
|
@ -289,9 +289,9 @@ async fn op_connect(
|
||||||
transport_args: ArgsEnum::Ip(args),
|
transport_args: ArgsEnum::Ip(args),
|
||||||
} if transport == "tcp" => {
|
} if transport == "tcp" => {
|
||||||
{
|
{
|
||||||
let state_ = state.borrow();
|
let mut state_ = state.borrow_mut();
|
||||||
state_
|
state_
|
||||||
.borrow::<Permissions>()
|
.borrow_mut::<Permissions>()
|
||||||
.net
|
.net
|
||||||
.check(&(&args.hostname, Some(args.port)))?;
|
.check(&(&args.hostname, Some(args.port)))?;
|
||||||
}
|
}
|
||||||
|
@ -327,9 +327,15 @@ async fn op_connect(
|
||||||
let address_path = Path::new(&args.path);
|
let address_path = Path::new(&args.path);
|
||||||
super::check_unstable2(&state, "Deno.connect");
|
super::check_unstable2(&state, "Deno.connect");
|
||||||
{
|
{
|
||||||
let state_ = state.borrow();
|
let mut state_ = state.borrow_mut();
|
||||||
state_.borrow::<Permissions>().read.check(&address_path)?;
|
state_
|
||||||
state_.borrow::<Permissions>().write.check(&address_path)?;
|
.borrow_mut::<Permissions>()
|
||||||
|
.read
|
||||||
|
.check(&address_path)?;
|
||||||
|
state_
|
||||||
|
.borrow_mut::<Permissions>()
|
||||||
|
.write
|
||||||
|
.check(&address_path)?;
|
||||||
}
|
}
|
||||||
let path = args.path;
|
let path = args.path;
|
||||||
let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?;
|
let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?;
|
||||||
|
@ -443,7 +449,6 @@ fn op_listen(
|
||||||
args: ListenArgs,
|
args: ListenArgs,
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<OpConn, AnyError> {
|
) -> Result<OpConn, AnyError> {
|
||||||
let permissions = state.borrow::<Permissions>();
|
|
||||||
match args {
|
match args {
|
||||||
ListenArgs {
|
ListenArgs {
|
||||||
transport,
|
transport,
|
||||||
|
@ -453,7 +458,10 @@ fn op_listen(
|
||||||
if transport == "udp" {
|
if transport == "udp" {
|
||||||
super::check_unstable(state, "Deno.listenDatagram");
|
super::check_unstable(state, "Deno.listenDatagram");
|
||||||
}
|
}
|
||||||
permissions.net.check(&(&args.hostname, Some(args.port)))?;
|
state
|
||||||
|
.borrow_mut::<Permissions>()
|
||||||
|
.net
|
||||||
|
.check(&(&args.hostname, Some(args.port)))?;
|
||||||
}
|
}
|
||||||
let addr = resolve_addr_sync(&args.hostname, args.port)?
|
let addr = resolve_addr_sync(&args.hostname, args.port)?
|
||||||
.next()
|
.next()
|
||||||
|
@ -497,6 +505,7 @@ fn op_listen(
|
||||||
if transport == "unixpacket" {
|
if transport == "unixpacket" {
|
||||||
super::check_unstable(state, "Deno.listenDatagram");
|
super::check_unstable(state, "Deno.listenDatagram");
|
||||||
}
|
}
|
||||||
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.read.check(&address_path)?;
|
permissions.read.check(&address_path)?;
|
||||||
permissions.write.check(&address_path)?;
|
permissions.write.check(&address_path)?;
|
||||||
}
|
}
|
||||||
|
@ -604,8 +613,8 @@ async fn op_dns_resolve(
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
let s = state.borrow();
|
let mut s = state.borrow_mut();
|
||||||
let perm = s.borrow::<Permissions>();
|
let perm = s.borrow_mut::<Permissions>();
|
||||||
|
|
||||||
// Checks permission against the name servers which will be actually queried.
|
// Checks permission against the name servers which will be actually queried.
|
||||||
for ns in config.name_servers() {
|
for ns in config.name_servers() {
|
||||||
|
|
|
@ -32,7 +32,7 @@ fn op_exec_path(
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, AnyError> {
|
||||||
let current_exe = env::current_exe().unwrap();
|
let current_exe = env::current_exe().unwrap();
|
||||||
state
|
state
|
||||||
.borrow::<Permissions>()
|
.borrow_mut::<Permissions>()
|
||||||
.read
|
.read
|
||||||
.check_blind(¤t_exe, "exec_path")?;
|
.check_blind(¤t_exe, "exec_path")?;
|
||||||
// Now apply URL parser to current exe to get fully resolved path, otherwise
|
// Now apply URL parser to current exe to get fully resolved path, otherwise
|
||||||
|
@ -54,7 +54,7 @@ fn op_set_env(
|
||||||
args: SetEnv,
|
args: SetEnv,
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
state.borrow::<Permissions>().env.check()?;
|
state.borrow_mut::<Permissions>().env.check()?;
|
||||||
let invalid_key =
|
let invalid_key =
|
||||||
args.key.is_empty() || args.key.contains(&['=', '\0'] as &[char]);
|
args.key.is_empty() || args.key.contains(&['=', '\0'] as &[char]);
|
||||||
let invalid_value = args.value.contains('\0');
|
let invalid_value = args.value.contains('\0');
|
||||||
|
@ -70,7 +70,7 @@ fn op_env(
|
||||||
_args: (),
|
_args: (),
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<HashMap<String, String>, AnyError> {
|
) -> Result<HashMap<String, String>, AnyError> {
|
||||||
state.borrow::<Permissions>().env.check()?;
|
state.borrow_mut::<Permissions>().env.check()?;
|
||||||
Ok(env::vars().collect())
|
Ok(env::vars().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ fn op_get_env(
|
||||||
key: String,
|
key: String,
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<Option<String>, AnyError> {
|
) -> Result<Option<String>, AnyError> {
|
||||||
state.borrow::<Permissions>().env.check()?;
|
state.borrow_mut::<Permissions>().env.check()?;
|
||||||
if key.is_empty() || key.contains(&['=', '\0'] as &[char]) {
|
if key.is_empty() || key.contains(&['=', '\0'] as &[char]) {
|
||||||
return Err(type_error("Key contains invalid characters."));
|
return Err(type_error("Key contains invalid characters."));
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ fn op_delete_env(
|
||||||
key: String,
|
key: String,
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
state.borrow::<Permissions>().env.check()?;
|
state.borrow_mut::<Permissions>().env.check()?;
|
||||||
if key.is_empty() || key.contains(&['=', '\0'] as &[char]) {
|
if key.is_empty() || key.contains(&['=', '\0'] as &[char]) {
|
||||||
return Err(type_error("Key contains invalid characters."));
|
return Err(type_error("Key contains invalid characters."));
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ fn op_loadavg(
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<(f64, f64, f64), AnyError> {
|
) -> Result<(f64, f64, f64), AnyError> {
|
||||||
super::check_unstable(state, "Deno.loadavg");
|
super::check_unstable(state, "Deno.loadavg");
|
||||||
state.borrow::<Permissions>().env.check()?;
|
state.borrow_mut::<Permissions>().env.check()?;
|
||||||
match sys_info::loadavg() {
|
match sys_info::loadavg() {
|
||||||
Ok(loadavg) => Ok((loadavg.one, loadavg.five, loadavg.fifteen)),
|
Ok(loadavg) => Ok((loadavg.one, loadavg.five, loadavg.fifteen)),
|
||||||
Err(_) => Ok((0.0, 0.0, 0.0)),
|
Err(_) => Ok((0.0, 0.0, 0.0)),
|
||||||
|
@ -129,7 +129,7 @@ fn op_hostname(
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, AnyError> {
|
||||||
super::check_unstable(state, "Deno.hostname");
|
super::check_unstable(state, "Deno.hostname");
|
||||||
state.borrow::<Permissions>().env.check()?;
|
state.borrow_mut::<Permissions>().env.check()?;
|
||||||
let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string());
|
let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string());
|
||||||
Ok(hostname)
|
Ok(hostname)
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ fn op_os_release(
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, AnyError> {
|
||||||
super::check_unstable(state, "Deno.osRelease");
|
super::check_unstable(state, "Deno.osRelease");
|
||||||
state.borrow::<Permissions>().env.check()?;
|
state.borrow_mut::<Permissions>().env.check()?;
|
||||||
let release = sys_info::os_release().unwrap_or_else(|_| "".to_string());
|
let release = sys_info::os_release().unwrap_or_else(|_| "".to_string());
|
||||||
Ok(release)
|
Ok(release)
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ fn op_system_memory_info(
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<Option<MemInfo>, AnyError> {
|
) -> Result<Option<MemInfo>, AnyError> {
|
||||||
super::check_unstable(state, "Deno.systemMemoryInfo");
|
super::check_unstable(state, "Deno.systemMemoryInfo");
|
||||||
state.borrow::<Permissions>().env.check()?;
|
state.borrow_mut::<Permissions>().env.check()?;
|
||||||
match sys_info::mem_info() {
|
match sys_info::mem_info() {
|
||||||
Ok(info) => Ok(Some(MemInfo {
|
Ok(info) => Ok(Some(MemInfo {
|
||||||
total: info.total,
|
total: info.total,
|
||||||
|
@ -191,7 +191,7 @@ fn op_system_cpu_info(
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<CpuInfo, AnyError> {
|
) -> Result<CpuInfo, AnyError> {
|
||||||
super::check_unstable(state, "Deno.systemCpuInfo");
|
super::check_unstable(state, "Deno.systemCpuInfo");
|
||||||
state.borrow::<Permissions>().env.check()?;
|
state.borrow_mut::<Permissions>().env.check()?;
|
||||||
|
|
||||||
let cores = sys_info::cpu_num().ok();
|
let cores = sys_info::cpu_num().ok();
|
||||||
let speed = sys_info::cpu_speed().ok();
|
let speed = sys_info::cpu_speed().ok();
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub fn op_open_plugin(
|
||||||
let filename = PathBuf::from(&filename);
|
let filename = PathBuf::from(&filename);
|
||||||
|
|
||||||
super::check_unstable(state, "Deno.openPlugin");
|
super::check_unstable(state, "Deno.openPlugin");
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.plugin.check()?;
|
permissions.plugin.check()?;
|
||||||
|
|
||||||
debug!("Loading Plugin: {:#?}", filename);
|
debug!("Loading Plugin: {:#?}", filename);
|
||||||
|
|
|
@ -97,7 +97,7 @@ fn op_run(
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<RunInfo, AnyError> {
|
) -> Result<RunInfo, AnyError> {
|
||||||
let args = run_args.cmd;
|
let args = run_args.cmd;
|
||||||
state.borrow::<Permissions>().run.check(&args[0])?;
|
state.borrow_mut::<Permissions>().run.check(&args[0])?;
|
||||||
let env = run_args.env;
|
let env = run_args.env;
|
||||||
let cwd = run_args.cwd;
|
let cwd = run_args.cwd;
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ fn op_kill(
|
||||||
_zero_copy: Option<ZeroCopyBuf>,
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
super::check_unstable(state, "Deno.kill");
|
super::check_unstable(state, "Deno.kill");
|
||||||
state.borrow::<Permissions>().run.check_all()?;
|
state.borrow_mut::<Permissions>().run.check_all()?;
|
||||||
|
|
||||||
kill(args.pid, args.signo)?;
|
kill(args.pid, args.signo)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -31,7 +31,7 @@ fn op_main_module(
|
||||||
if main_url.scheme() == "file" {
|
if main_url.scheme() == "file" {
|
||||||
let main_path = std::env::current_dir().unwrap().join(main_url.to_string());
|
let main_path = std::env::current_dir().unwrap().join(main_url.to_string());
|
||||||
state
|
state
|
||||||
.borrow::<Permissions>()
|
.borrow_mut::<Permissions>()
|
||||||
.read
|
.read
|
||||||
.check_blind(&main_path, "main_module")?;
|
.check_blind(&main_path, "main_module")?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ fn op_now(
|
||||||
// If the permission is not enabled
|
// If the permission is not enabled
|
||||||
// Round the nano result on 2 milliseconds
|
// Round the nano result on 2 milliseconds
|
||||||
// see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision
|
// see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision
|
||||||
if op_state.borrow::<Permissions>().hrtime.check().is_err() {
|
if op_state.borrow_mut::<Permissions>().hrtime.check().is_err() {
|
||||||
subsec_nanos -= subsec_nanos % reduced_time_precision;
|
subsec_nanos -= subsec_nanos % reduced_time_precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,8 +107,8 @@ async fn op_start_tls(
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
super::check_unstable2(&state, "Deno.startTls");
|
super::check_unstable2(&state, "Deno.startTls");
|
||||||
let s = state.borrow();
|
let mut s = state.borrow_mut();
|
||||||
let permissions = s.borrow::<Permissions>();
|
let permissions = s.borrow_mut::<Permissions>();
|
||||||
permissions.net.check(&(&domain, Some(0)))?;
|
permissions.net.check(&(&domain, Some(0)))?;
|
||||||
if let Some(path) = &args.cert_file {
|
if let Some(path) = &args.cert_file {
|
||||||
permissions.read.check(Path::new(&path))?;
|
permissions.read.check(Path::new(&path))?;
|
||||||
|
@ -170,8 +170,8 @@ async fn op_connect_tls(
|
||||||
assert_eq!(args.transport, "tcp");
|
assert_eq!(args.transport, "tcp");
|
||||||
|
|
||||||
{
|
{
|
||||||
let s = state.borrow();
|
let mut s = state.borrow_mut();
|
||||||
let permissions = s.borrow::<Permissions>();
|
let permissions = s.borrow_mut::<Permissions>();
|
||||||
permissions.net.check(&(&args.hostname, Some(args.port)))?;
|
permissions.net.check(&(&args.hostname, Some(args.port)))?;
|
||||||
if let Some(path) = &args.cert_file {
|
if let Some(path) = &args.cert_file {
|
||||||
permissions.read.check(Path::new(&path))?;
|
permissions.read.check(Path::new(&path))?;
|
||||||
|
@ -313,7 +313,7 @@ fn op_listen_tls(
|
||||||
let cert_file = args.cert_file;
|
let cert_file = args.cert_file;
|
||||||
let key_file = args.key_file;
|
let key_file = args.key_file;
|
||||||
{
|
{
|
||||||
let permissions = state.borrow::<Permissions>();
|
let permissions = state.borrow_mut::<Permissions>();
|
||||||
permissions.net.check(&(&args.hostname, Some(args.port)))?;
|
permissions.net.check(&(&args.hostname, Some(args.port)))?;
|
||||||
permissions.read.check(Path::new(&cert_file))?;
|
permissions.read.check(Path::new(&cert_file))?;
|
||||||
permissions.read.check(Path::new(&key_file))?;
|
permissions.read.check(Path::new(&key_file))?;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::fs_util::resolve_from_cwd;
|
use crate::fs_util::resolve_from_cwd;
|
||||||
use deno_core::error::custom_error;
|
use deno_core::error::custom_error;
|
||||||
|
@ -33,23 +34,35 @@ pub enum PermissionState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PermissionState {
|
impl PermissionState {
|
||||||
/// Check the permission state.
|
/// Check the permission state. bool is whether a prompt was issued.
|
||||||
fn check(self, name: &str, info: Option<&str>) -> Result<(), AnyError> {
|
fn check(
|
||||||
if self == PermissionState::Granted {
|
self,
|
||||||
log_perm_access(&format!(
|
name: &str,
|
||||||
|
info: Option<&str>,
|
||||||
|
prompt: bool,
|
||||||
|
) -> (Result<(), AnyError>, bool) {
|
||||||
|
let access = format!(
|
||||||
"{} access{}",
|
"{} access{}",
|
||||||
name,
|
name,
|
||||||
info.map_or(Default::default(), |info| { format!(" to {}", info) }),
|
info.map_or(String::new(), |info| { format!(" to {}", info) }),
|
||||||
));
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let message = format!(
|
|
||||||
"Requires {} access{}, run again with the --allow-{} flag",
|
|
||||||
name,
|
|
||||||
info.map_or(Default::default(), |info| { format!(" to {}", info) }),
|
|
||||||
name
|
|
||||||
);
|
);
|
||||||
Err(custom_error("PermissionDenied", message))
|
let result = if self == PermissionState::Granted
|
||||||
|
|| (prompt
|
||||||
|
&& self == PermissionState::Prompt
|
||||||
|
&& permission_prompt(&access))
|
||||||
|
{
|
||||||
|
log_perm_access(&access);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(custom_error(
|
||||||
|
"PermissionDenied",
|
||||||
|
format!(
|
||||||
|
"Requires {}, run again with the --allow-{} flag",
|
||||||
|
access, name
|
||||||
|
),
|
||||||
|
))
|
||||||
|
};
|
||||||
|
(result, prompt && self == PermissionState::Prompt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +87,7 @@ pub struct UnitPermission {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
pub state: PermissionState,
|
pub state: PermissionState,
|
||||||
|
pub prompt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnitPermission {
|
impl UnitPermission {
|
||||||
|
@ -99,8 +113,16 @@ impl UnitPermission {
|
||||||
self.state
|
self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(&self) -> Result<(), AnyError> {
|
pub fn check(&mut self) -> Result<(), AnyError> {
|
||||||
self.state.check(self.name, None)
|
let (result, prompted) = self.state.check(self.name, None, self.prompt);
|
||||||
|
if prompted {
|
||||||
|
if result.is_ok() {
|
||||||
|
self.state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.state = PermissionState::Denied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +135,8 @@ pub struct UnaryPermission<T: Eq + Hash> {
|
||||||
pub global_state: PermissionState,
|
pub global_state: PermissionState,
|
||||||
pub granted_list: HashSet<T>,
|
pub granted_list: HashSet<T>,
|
||||||
pub denied_list: HashSet<T>,
|
pub denied_list: HashSet<T>,
|
||||||
|
#[serde(skip)]
|
||||||
|
pub prompt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)]
|
||||||
|
@ -234,24 +258,46 @@ impl UnaryPermission<ReadDescriptor> {
|
||||||
self.query(path)
|
self.query(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(&self, path: &Path) -> Result<(), AnyError> {
|
pub fn check(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||||
let (resolved_path, display_path) = resolved_and_display_path(path);
|
let (resolved_path, display_path) = resolved_and_display_path(path);
|
||||||
self
|
let (result, prompted) = self.query(Some(&resolved_path)).check(
|
||||||
.query(Some(&resolved_path))
|
self.name,
|
||||||
.check(self.name, Some(&format!("\"{}\"", display_path.display())))
|
Some(&format!("\"{}\"", display_path.display())),
|
||||||
|
self.prompt,
|
||||||
|
);
|
||||||
|
if prompted {
|
||||||
|
if result.is_ok() {
|
||||||
|
self.granted_list.insert(ReadDescriptor(resolved_path));
|
||||||
|
} else {
|
||||||
|
self.denied_list.insert(ReadDescriptor(resolved_path));
|
||||||
|
self.global_state = PermissionState::Denied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// As `check()`, but permission error messages will anonymize the path
|
/// As `check()`, but permission error messages will anonymize the path
|
||||||
/// by replacing it with the given `display`.
|
/// by replacing it with the given `display`.
|
||||||
pub fn check_blind(
|
pub fn check_blind(
|
||||||
&self,
|
&mut self,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
display: &str,
|
display: &str,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let resolved_path = resolve_from_cwd(path).unwrap();
|
let resolved_path = resolve_from_cwd(path).unwrap();
|
||||||
self
|
let (result, prompted) = self.query(Some(&resolved_path)).check(
|
||||||
.query(Some(&resolved_path))
|
self.name,
|
||||||
.check(self.name, Some(&format!("<{}>", display)))
|
Some(&format!("<{}>", display)),
|
||||||
|
self.prompt,
|
||||||
|
);
|
||||||
|
if prompted {
|
||||||
|
if result.is_ok() {
|
||||||
|
self.granted_list.insert(ReadDescriptor(resolved_path));
|
||||||
|
} else {
|
||||||
|
self.denied_list.insert(ReadDescriptor(resolved_path));
|
||||||
|
self.global_state = PermissionState::Denied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,11 +386,22 @@ impl UnaryPermission<WriteDescriptor> {
|
||||||
self.query(path)
|
self.query(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(&self, path: &Path) -> Result<(), AnyError> {
|
pub fn check(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||||
let (resolved_path, display_path) = resolved_and_display_path(path);
|
let (resolved_path, display_path) = resolved_and_display_path(path);
|
||||||
self
|
let (result, prompted) = self.query(Some(&resolved_path)).check(
|
||||||
.query(Some(&resolved_path))
|
self.name,
|
||||||
.check(self.name, Some(&format!("\"{}\"", display_path.display())))
|
Some(&format!("\"{}\"", display_path.display())),
|
||||||
|
self.prompt,
|
||||||
|
);
|
||||||
|
if prompted {
|
||||||
|
if result.is_ok() {
|
||||||
|
self.granted_list.insert(WriteDescriptor(resolved_path));
|
||||||
|
} else {
|
||||||
|
self.denied_list.insert(WriteDescriptor(resolved_path));
|
||||||
|
self.global_state = PermissionState::Denied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,16 +502,27 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check<T: AsRef<str>>(
|
pub fn check<T: AsRef<str>>(
|
||||||
&self,
|
&mut self,
|
||||||
host: &(T, Option<u16>),
|
host: &(T, Option<u16>),
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
self.query(Some(host)).check(
|
let new_host = NetDescriptor::new(&host);
|
||||||
|
let (result, prompted) = self.query(Some(host)).check(
|
||||||
self.name,
|
self.name,
|
||||||
Some(&format!("\"{}\"", NetDescriptor::new(&host))),
|
Some(&format!("\"{}\"", new_host)),
|
||||||
)
|
self.prompt,
|
||||||
|
);
|
||||||
|
if prompted {
|
||||||
|
if result.is_ok() {
|
||||||
|
self.granted_list.insert(new_host);
|
||||||
|
} else {
|
||||||
|
self.denied_list.insert(new_host);
|
||||||
|
self.global_state = PermissionState::Denied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_url(&self, url: &url::Url) -> Result<(), AnyError> {
|
pub fn check_url(&mut self, url: &url::Url) -> Result<(), AnyError> {
|
||||||
let hostname = url
|
let hostname = url
|
||||||
.host_str()
|
.host_str()
|
||||||
.ok_or_else(|| uri_error("Missing host"))?
|
.ok_or_else(|| uri_error("Missing host"))?
|
||||||
|
@ -463,9 +531,21 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
None => hostname.clone(),
|
None => hostname.clone(),
|
||||||
Some(port) => format!("{}:{}", hostname, port),
|
Some(port) => format!("{}:{}", hostname, port),
|
||||||
};
|
};
|
||||||
self
|
let host = &(&hostname, url.port_or_known_default());
|
||||||
.query(Some(&(hostname, url.port_or_known_default())))
|
let (result, prompted) = self.query(Some(host)).check(
|
||||||
.check(self.name, Some(&format!("\"{}\"", display_host)))
|
self.name,
|
||||||
|
Some(&format!("\"{}\"", display_host)),
|
||||||
|
self.prompt,
|
||||||
|
);
|
||||||
|
if prompted {
|
||||||
|
if result.is_ok() {
|
||||||
|
self.granted_list.insert(NetDescriptor::new(&host));
|
||||||
|
} else {
|
||||||
|
self.denied_list.insert(NetDescriptor::new(&host));
|
||||||
|
self.global_state = PermissionState::Denied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,49 +616,34 @@ impl UnaryPermission<RunDescriptor> {
|
||||||
self.query(cmd)
|
self.query(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(&self, cmd: &str) -> Result<(), AnyError> {
|
pub fn check(&mut self, cmd: &str) -> Result<(), AnyError> {
|
||||||
self
|
let (result, prompted) = self.query(Some(cmd)).check(
|
||||||
.query(Some(cmd))
|
self.name,
|
||||||
.check(self.name, Some(&format!("\"{}\"", cmd)))
|
Some(&format!("\"{}\"", cmd)),
|
||||||
}
|
self.prompt,
|
||||||
|
);
|
||||||
pub fn check_all(&self) -> Result<(), AnyError> {
|
if prompted {
|
||||||
self.query(None).check(self.name, Some("all"))
|
if result.is_ok() {
|
||||||
}
|
self.granted_list.insert(RunDescriptor(cmd.to_string()));
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
|
||||||
pub struct BooleanPermission {
|
|
||||||
pub name: &'static str,
|
|
||||||
pub description: &'static str,
|
|
||||||
pub state: PermissionState,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BooleanPermission {
|
|
||||||
pub fn query(&self) -> PermissionState {
|
|
||||||
self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request(&mut self) -> PermissionState {
|
|
||||||
if self.state == PermissionState::Prompt {
|
|
||||||
if permission_prompt(&format!("access to {}", self.description)) {
|
|
||||||
self.state = PermissionState::Granted;
|
|
||||||
} else {
|
} else {
|
||||||
self.state = PermissionState::Denied;
|
self.denied_list.insert(RunDescriptor(cmd.to_string()));
|
||||||
|
self.global_state = PermissionState::Denied;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.state
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn revoke(&mut self) -> PermissionState {
|
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||||
if self.state == PermissionState::Granted {
|
let (result, prompted) =
|
||||||
self.state = PermissionState::Prompt;
|
self.query(None).check(self.name, Some("all"), self.prompt);
|
||||||
|
if prompted {
|
||||||
|
if result.is_ok() {
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.global_state = PermissionState::Denied;
|
||||||
}
|
}
|
||||||
self.state
|
|
||||||
}
|
}
|
||||||
|
result
|
||||||
pub fn check(&self) -> Result<(), AnyError> {
|
|
||||||
self.state.check(self.name, None)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,11 +667,13 @@ pub struct PermissionsOptions {
|
||||||
pub allow_read: Option<Vec<PathBuf>>,
|
pub allow_read: Option<Vec<PathBuf>>,
|
||||||
pub allow_run: Option<Vec<String>>,
|
pub allow_run: Option<Vec<String>>,
|
||||||
pub allow_write: Option<Vec<PathBuf>>,
|
pub allow_write: Option<Vec<PathBuf>>,
|
||||||
|
pub prompt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Permissions {
|
impl Permissions {
|
||||||
pub fn new_read(
|
pub fn new_read(
|
||||||
state: &Option<Vec<PathBuf>>,
|
state: &Option<Vec<PathBuf>>,
|
||||||
|
prompt: bool,
|
||||||
) -> UnaryPermission<ReadDescriptor> {
|
) -> UnaryPermission<ReadDescriptor> {
|
||||||
UnaryPermission::<ReadDescriptor> {
|
UnaryPermission::<ReadDescriptor> {
|
||||||
name: "read",
|
name: "read",
|
||||||
|
@ -614,11 +681,13 @@ impl Permissions {
|
||||||
global_state: global_state_from_option(state),
|
global_state: global_state_from_option(state),
|
||||||
granted_list: resolve_read_allowlist(&state),
|
granted_list: resolve_read_allowlist(&state),
|
||||||
denied_list: Default::default(),
|
denied_list: Default::default(),
|
||||||
|
prompt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_write(
|
pub fn new_write(
|
||||||
state: &Option<Vec<PathBuf>>,
|
state: &Option<Vec<PathBuf>>,
|
||||||
|
prompt: bool,
|
||||||
) -> UnaryPermission<WriteDescriptor> {
|
) -> UnaryPermission<WriteDescriptor> {
|
||||||
UnaryPermission::<WriteDescriptor> {
|
UnaryPermission::<WriteDescriptor> {
|
||||||
name: "write",
|
name: "write",
|
||||||
|
@ -626,11 +695,13 @@ impl Permissions {
|
||||||
global_state: global_state_from_option(state),
|
global_state: global_state_from_option(state),
|
||||||
granted_list: resolve_write_allowlist(&state),
|
granted_list: resolve_write_allowlist(&state),
|
||||||
denied_list: Default::default(),
|
denied_list: Default::default(),
|
||||||
|
prompt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_net(
|
pub fn new_net(
|
||||||
state: &Option<Vec<String>>,
|
state: &Option<Vec<String>>,
|
||||||
|
prompt: bool,
|
||||||
) -> UnaryPermission<NetDescriptor> {
|
) -> UnaryPermission<NetDescriptor> {
|
||||||
UnaryPermission::<NetDescriptor> {
|
UnaryPermission::<NetDescriptor> {
|
||||||
name: "net",
|
name: "net",
|
||||||
|
@ -645,15 +716,22 @@ impl Permissions {
|
||||||
})
|
})
|
||||||
.unwrap_or_else(HashSet::new),
|
.unwrap_or_else(HashSet::new),
|
||||||
denied_list: Default::default(),
|
denied_list: Default::default(),
|
||||||
|
prompt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_env(state: bool) -> UnitPermission {
|
pub fn new_env(state: bool, prompt: bool) -> UnitPermission {
|
||||||
boolean_permission_from_flag_bool(state, "env", "environment variables")
|
boolean_permission_from_flag_bool(
|
||||||
|
state,
|
||||||
|
"env",
|
||||||
|
"environment variables",
|
||||||
|
prompt,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_run(
|
pub fn new_run(
|
||||||
state: &Option<Vec<String>>,
|
state: &Option<Vec<String>>,
|
||||||
|
prompt: bool,
|
||||||
) -> UnaryPermission<RunDescriptor> {
|
) -> UnaryPermission<RunDescriptor> {
|
||||||
UnaryPermission::<RunDescriptor> {
|
UnaryPermission::<RunDescriptor> {
|
||||||
name: "run",
|
name: "run",
|
||||||
|
@ -664,45 +742,51 @@ impl Permissions {
|
||||||
.map(|v| v.iter().map(|x| RunDescriptor(x.clone())).collect())
|
.map(|v| v.iter().map(|x| RunDescriptor(x.clone())).collect())
|
||||||
.unwrap_or_else(HashSet::new),
|
.unwrap_or_else(HashSet::new),
|
||||||
denied_list: Default::default(),
|
denied_list: Default::default(),
|
||||||
|
prompt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_plugin(state: bool) -> UnitPermission {
|
pub fn new_plugin(state: bool, prompt: bool) -> UnitPermission {
|
||||||
boolean_permission_from_flag_bool(state, "plugin", "open a plugin")
|
boolean_permission_from_flag_bool(state, "plugin", "open a plugin", prompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_hrtime(state: bool) -> UnitPermission {
|
pub fn new_hrtime(state: bool, prompt: bool) -> UnitPermission {
|
||||||
boolean_permission_from_flag_bool(state, "hrtime", "high precision time")
|
boolean_permission_from_flag_bool(
|
||||||
|
state,
|
||||||
|
"hrtime",
|
||||||
|
"high precision time",
|
||||||
|
prompt,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_options(opts: &PermissionsOptions) -> Self {
|
pub fn from_options(opts: &PermissionsOptions) -> Self {
|
||||||
Self {
|
Self {
|
||||||
read: Permissions::new_read(&opts.allow_read),
|
read: Permissions::new_read(&opts.allow_read, opts.prompt),
|
||||||
write: Permissions::new_write(&opts.allow_write),
|
write: Permissions::new_write(&opts.allow_write, opts.prompt),
|
||||||
net: Permissions::new_net(&opts.allow_net),
|
net: Permissions::new_net(&opts.allow_net, opts.prompt),
|
||||||
env: Permissions::new_env(opts.allow_env),
|
env: Permissions::new_env(opts.allow_env, opts.prompt),
|
||||||
run: Permissions::new_run(&opts.allow_run),
|
run: Permissions::new_run(&opts.allow_run, opts.prompt),
|
||||||
plugin: Permissions::new_plugin(opts.allow_plugin),
|
plugin: Permissions::new_plugin(opts.allow_plugin, opts.prompt),
|
||||||
hrtime: Permissions::new_hrtime(opts.allow_hrtime),
|
hrtime: Permissions::new_hrtime(opts.allow_hrtime, opts.prompt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allow_all() -> Self {
|
pub fn allow_all() -> Self {
|
||||||
Self {
|
Self {
|
||||||
read: Permissions::new_read(&Some(vec![])),
|
read: Permissions::new_read(&Some(vec![]), false),
|
||||||
write: Permissions::new_write(&Some(vec![])),
|
write: Permissions::new_write(&Some(vec![]), false),
|
||||||
net: Permissions::new_net(&Some(vec![])),
|
net: Permissions::new_net(&Some(vec![]), false),
|
||||||
env: Permissions::new_env(true),
|
env: Permissions::new_env(true, false),
|
||||||
run: Permissions::new_run(&Some(vec![])),
|
run: Permissions::new_run(&Some(vec![]), false),
|
||||||
plugin: Permissions::new_plugin(true),
|
plugin: Permissions::new_plugin(true, false),
|
||||||
hrtime: Permissions::new_hrtime(true),
|
hrtime: Permissions::new_hrtime(true, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper function that determines if the module specifier is a local or
|
/// A helper function that determines if the module specifier is a local or
|
||||||
/// remote, and performs a read or net check for the specifier.
|
/// remote, and performs a read or net check for the specifier.
|
||||||
pub fn check_specifier(
|
pub fn check_specifier(
|
||||||
&self,
|
&mut self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
match specifier.scheme() {
|
match specifier.scheme() {
|
||||||
|
@ -721,17 +805,17 @@ impl Permissions {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl deno_fetch::FetchPermissions for Permissions {
|
impl deno_fetch::FetchPermissions for Permissions {
|
||||||
fn check_net_url(&self, url: &url::Url) -> Result<(), AnyError> {
|
fn check_net_url(&mut self, url: &url::Url) -> Result<(), AnyError> {
|
||||||
self.net.check_url(url)
|
self.net.check_url(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_read(&self, path: &Path) -> Result<(), AnyError> {
|
fn check_read(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||||
self.read.check(path)
|
self.read.check(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl deno_websocket::WebSocketPermissions for Permissions {
|
impl deno_websocket::WebSocketPermissions for Permissions {
|
||||||
fn check_net_url(&self, url: &url::Url) -> Result<(), AnyError> {
|
fn check_net_url(&mut self, url: &url::Url) -> Result<(), AnyError> {
|
||||||
self.net.check_url(url)
|
self.net.check_url(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -747,6 +831,7 @@ fn boolean_permission_from_flag_bool(
|
||||||
flag: bool,
|
flag: bool,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
description: &'static str,
|
description: &'static str,
|
||||||
|
prompt: bool,
|
||||||
) -> UnitPermission {
|
) -> UnitPermission {
|
||||||
UnitPermission {
|
UnitPermission {
|
||||||
name,
|
name,
|
||||||
|
@ -756,6 +841,7 @@ fn boolean_permission_from_flag_bool(
|
||||||
} else {
|
} else {
|
||||||
PermissionState::Prompt
|
PermissionState::Prompt
|
||||||
},
|
},
|
||||||
|
prompt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,9 +896,10 @@ fn permission_prompt(message: &str) -> bool {
|
||||||
if !atty::is(atty::Stream::Stdin) || !atty::is(atty::Stream::Stderr) {
|
if !atty::is(atty::Stream::Stdin) || !atty::is(atty::Stream::Stderr) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
let opts = "[g/d (g = grant, d = deny)] ";
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"{} ️Deno requests {}. Grant? [g/d (g = grant, d = deny)] ",
|
"{} ️Deno requests {}. Grant? {}",
|
||||||
PERMISSION_EMOJI, message
|
PERMISSION_EMOJI, message, opts
|
||||||
);
|
);
|
||||||
// print to stderr so that if deno is > to a file this is still displayed.
|
// print to stderr so that if deno is > to a file this is still displayed.
|
||||||
eprint!("{}", colors::bold(&msg));
|
eprint!("{}", colors::bold(&msg));
|
||||||
|
@ -832,8 +919,7 @@ fn permission_prompt(message: &str) -> bool {
|
||||||
'd' => return false,
|
'd' => return false,
|
||||||
_ => {
|
_ => {
|
||||||
// If we don't get a recognized option try again.
|
// If we don't get a recognized option try again.
|
||||||
let msg_again =
|
let msg_again = format!("Unrecognized option '{}' {}", ch, opts);
|
||||||
format!("Unrecognized option '{}' [g/d (g = grant, d = deny)] ", ch);
|
|
||||||
eprint!("{}", colors::bold(&msg_again));
|
eprint!("{}", colors::bold(&msg_again));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -879,7 +965,7 @@ mod tests {
|
||||||
PathBuf::from("/b/c"),
|
PathBuf::from("/b/c"),
|
||||||
];
|
];
|
||||||
|
|
||||||
let perms = Permissions::from_options(&PermissionsOptions {
|
let mut perms = Permissions::from_options(&PermissionsOptions {
|
||||||
allow_read: Some(allowlist.clone()),
|
allow_read: Some(allowlist.clone()),
|
||||||
allow_write: Some(allowlist),
|
allow_write: Some(allowlist),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -939,7 +1025,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_net_with_values() {
|
fn test_check_net_with_values() {
|
||||||
let perms = Permissions::from_options(&PermissionsOptions {
|
let mut perms = Permissions::from_options(&PermissionsOptions {
|
||||||
allow_net: Some(svec![
|
allow_net: Some(svec![
|
||||||
"localhost",
|
"localhost",
|
||||||
"deno.land",
|
"deno.land",
|
||||||
|
@ -981,7 +1067,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_net_only_flag() {
|
fn test_check_net_only_flag() {
|
||||||
let perms = Permissions::from_options(&PermissionsOptions {
|
let mut perms = Permissions::from_options(&PermissionsOptions {
|
||||||
allow_net: Some(svec![]), // this means `--allow-net` is present without values following `=` sign
|
allow_net: Some(svec![]), // this means `--allow-net` is present without values following `=` sign
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
@ -1015,7 +1101,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_net_no_flag() {
|
fn test_check_net_no_flag() {
|
||||||
let perms = Permissions::from_options(&PermissionsOptions {
|
let mut perms = Permissions::from_options(&PermissionsOptions {
|
||||||
allow_net: None,
|
allow_net: None,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
@ -1049,7 +1135,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_net_url() {
|
fn test_check_net_url() {
|
||||||
let perms = Permissions::from_options(&PermissionsOptions {
|
let mut perms = Permissions::from_options(&PermissionsOptions {
|
||||||
allow_net: Some(svec![
|
allow_net: Some(svec![
|
||||||
"localhost",
|
"localhost",
|
||||||
"deno.land",
|
"deno.land",
|
||||||
|
@ -1113,7 +1199,7 @@ mod tests {
|
||||||
} else {
|
} else {
|
||||||
vec![PathBuf::from("/a")]
|
vec![PathBuf::from("/a")]
|
||||||
};
|
};
|
||||||
let perms = Permissions::from_options(&PermissionsOptions {
|
let mut perms = Permissions::from_options(&PermissionsOptions {
|
||||||
allow_read: Some(read_allowlist),
|
allow_read: Some(read_allowlist),
|
||||||
allow_net: Some(svec!["localhost"]),
|
allow_net: Some(svec!["localhost"]),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -1151,7 +1237,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_invalid_specifiers() {
|
fn check_invalid_specifiers() {
|
||||||
let perms = Permissions::allow_all();
|
let mut perms = Permissions::allow_all();
|
||||||
|
|
||||||
let mut test_cases = vec![];
|
let mut test_cases = vec![];
|
||||||
|
|
||||||
|
@ -1175,15 +1261,15 @@ mod tests {
|
||||||
let perms2 = Permissions {
|
let perms2 = Permissions {
|
||||||
read: UnaryPermission {
|
read: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_read(&Some(vec![PathBuf::from("/foo")]))
|
..Permissions::new_read(&Some(vec![PathBuf::from("/foo")]), false)
|
||||||
},
|
},
|
||||||
write: UnaryPermission {
|
write: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_write(&Some(vec![PathBuf::from("/foo")]))
|
..Permissions::new_write(&Some(vec![PathBuf::from("/foo")]), false)
|
||||||
},
|
},
|
||||||
net: UnaryPermission {
|
net: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_net(&Some(svec!["127.0.0.1:8000"]))
|
..Permissions::new_net(&Some(svec!["127.0.0.1:8000"]), false)
|
||||||
},
|
},
|
||||||
env: UnitPermission {
|
env: UnitPermission {
|
||||||
state: PermissionState::Prompt,
|
state: PermissionState::Prompt,
|
||||||
|
@ -1191,7 +1277,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
run: UnaryPermission {
|
run: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_run(&Some(svec!["deno"]))
|
..Permissions::new_run(&Some(svec!["deno"]), false)
|
||||||
},
|
},
|
||||||
plugin: UnitPermission {
|
plugin: UnitPermission {
|
||||||
state: PermissionState::Prompt,
|
state: PermissionState::Prompt,
|
||||||
|
@ -1276,15 +1362,15 @@ mod tests {
|
||||||
let mut perms = Permissions {
|
let mut perms = Permissions {
|
||||||
read: UnaryPermission {
|
read: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_read(&Some(vec![PathBuf::from("/foo")]))
|
..Permissions::new_read(&Some(vec![PathBuf::from("/foo")]), false)
|
||||||
},
|
},
|
||||||
write: UnaryPermission {
|
write: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_write(&Some(vec![PathBuf::from("/foo")]))
|
..Permissions::new_write(&Some(vec![PathBuf::from("/foo")]), false)
|
||||||
},
|
},
|
||||||
net: UnaryPermission {
|
net: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_net(&Some(svec!["127.0.0.1"]))
|
..Permissions::new_net(&Some(svec!["127.0.0.1"]), false)
|
||||||
},
|
},
|
||||||
env: UnitPermission {
|
env: UnitPermission {
|
||||||
state: PermissionState::Granted,
|
state: PermissionState::Granted,
|
||||||
|
@ -1292,7 +1378,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
run: UnaryPermission {
|
run: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_run(&Some(svec!["deno"]))
|
..Permissions::new_run(&Some(svec!["deno"]), false)
|
||||||
},
|
},
|
||||||
plugin: UnitPermission {
|
plugin: UnitPermission {
|
||||||
state: PermissionState::Prompt,
|
state: PermissionState::Prompt,
|
||||||
|
@ -1319,4 +1405,105 @@ mod tests {
|
||||||
assert_eq!(perms.hrtime.revoke(), PermissionState::Denied);
|
assert_eq!(perms.hrtime.revoke(), PermissionState::Denied);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_check() {
|
||||||
|
let mut perms = Permissions {
|
||||||
|
read: Permissions::new_read(&None, true),
|
||||||
|
write: Permissions::new_write(&None, true),
|
||||||
|
net: Permissions::new_net(&None, true),
|
||||||
|
env: Permissions::new_env(false, true),
|
||||||
|
run: Permissions::new_run(&None, true),
|
||||||
|
plugin: Permissions::new_plugin(false, true),
|
||||||
|
hrtime: Permissions::new_hrtime(false, true),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _guard = PERMISSION_PROMPT_GUARD.lock().unwrap();
|
||||||
|
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.read.check(&Path::new("/foo")).is_ok());
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.read.check(&Path::new("/foo")).is_ok());
|
||||||
|
assert!(perms.read.check(&Path::new("/bar")).is_err());
|
||||||
|
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.write.check(&Path::new("/foo")).is_ok());
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.write.check(&Path::new("/foo")).is_ok());
|
||||||
|
assert!(perms.write.check(&Path::new("/bar")).is_err());
|
||||||
|
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.net.check(&("127.0.0.1", Some(8000))).is_ok());
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.net.check(&("127.0.0.1", Some(8000))).is_ok());
|
||||||
|
assert!(perms.net.check(&("127.0.0.1", Some(8001))).is_err());
|
||||||
|
assert!(perms.net.check(&("127.0.0.1", None)).is_err());
|
||||||
|
assert!(perms.net.check(&("deno.land", Some(8000))).is_err());
|
||||||
|
assert!(perms.net.check(&("deno.land", None)).is_err());
|
||||||
|
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.run.check("cat").is_ok());
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.run.check("cat").is_ok());
|
||||||
|
assert!(perms.run.check("ls").is_err());
|
||||||
|
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.hrtime.check().is_ok());
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.hrtime.check().is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_check_fail() {
|
||||||
|
let mut perms = Permissions {
|
||||||
|
read: Permissions::new_read(&None, true),
|
||||||
|
write: Permissions::new_write(&None, true),
|
||||||
|
net: Permissions::new_net(&None, true),
|
||||||
|
env: Permissions::new_env(false, true),
|
||||||
|
run: Permissions::new_run(&None, true),
|
||||||
|
plugin: Permissions::new_plugin(false, true),
|
||||||
|
hrtime: Permissions::new_hrtime(false, true),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _guard = PERMISSION_PROMPT_GUARD.lock().unwrap();
|
||||||
|
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.read.check(&Path::new("/foo")).is_err());
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.read.check(&Path::new("/foo")).is_err());
|
||||||
|
assert!(perms.read.check(&Path::new("/bar")).is_ok());
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.read.check(&Path::new("/bar")).is_ok());
|
||||||
|
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.write.check(&Path::new("/foo")).is_err());
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.write.check(&Path::new("/foo")).is_err());
|
||||||
|
assert!(perms.write.check(&Path::new("/bar")).is_ok());
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.write.check(&Path::new("/bar")).is_ok());
|
||||||
|
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.net.check(&("127.0.0.1", Some(8000))).is_err());
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.net.check(&("127.0.0.1", Some(8000))).is_err());
|
||||||
|
assert!(perms.net.check(&("127.0.0.1", Some(8001))).is_ok());
|
||||||
|
assert!(perms.net.check(&("deno.land", Some(8000))).is_ok());
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.net.check(&("127.0.0.1", Some(8001))).is_ok());
|
||||||
|
assert!(perms.net.check(&("deno.land", Some(8000))).is_ok());
|
||||||
|
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.run.check("cat").is_err());
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.run.check("cat").is_err());
|
||||||
|
assert!(perms.run.check("ls").is_ok());
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.run.check("ls").is_ok());
|
||||||
|
|
||||||
|
set_prompt_result(false);
|
||||||
|
assert!(perms.hrtime.check().is_err());
|
||||||
|
set_prompt_result(true);
|
||||||
|
assert!(perms.hrtime.check().is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue