summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/file_fetcher.rs278
-rw-r--r--cli/global_state.rs9
-rw-r--r--cli/lib.rs14
-rw-r--r--cli/ops/compiler.rs15
-rw-r--r--cli/ops/runtime_compiler.rs12
-rw-r--r--cli/permissions.rs13
-rw-r--r--cli/state.rs16
-rw-r--r--cli/tests/integration_tests.rs2
-rw-r--r--cli/tsc.rs50
9 files changed, 342 insertions, 67 deletions
diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs
index c4e0e4fec..2e75517e6 100644
--- a/cli/file_fetcher.rs
+++ b/cli/file_fetcher.rs
@@ -6,6 +6,7 @@ use crate::http_util::create_http_client;
use crate::http_util::FetchOnceResult;
use crate::msg;
use crate::op_error::OpError;
+use crate::permissions::Permissions;
use deno_core::ErrBox;
use deno_core::ModuleSpecifier;
use futures::future::FutureExt;
@@ -109,6 +110,7 @@ impl SourceFileFetcher {
pub fn fetch_cached_source_file(
&self,
specifier: &ModuleSpecifier,
+ permissions: Permissions,
) -> Option<SourceFile> {
let maybe_source_file = self.source_file_cache.get(specifier.to_string());
@@ -123,7 +125,7 @@ impl SourceFileFetcher {
// future, because it doesn't actually do any asynchronous
// action in that path.
if let Ok(maybe_source_file) =
- self.get_source_file_from_local_cache(specifier.as_url())
+ self.get_source_file_from_local_cache(specifier.as_url(), &permissions)
{
return maybe_source_file;
}
@@ -148,6 +150,7 @@ impl SourceFileFetcher {
&self,
specifier: &ModuleSpecifier,
maybe_referrer: Option<ModuleSpecifier>,
+ permissions: Permissions,
) -> Result<SourceFile, ErrBox> {
let module_url = specifier.as_url().to_owned();
debug!("fetch_source_file specifier: {} ", &module_url);
@@ -167,6 +170,7 @@ impl SourceFileFetcher {
self.use_disk_cache,
self.no_remote,
self.cached_only,
+ &permissions,
)
.await;
@@ -222,6 +226,7 @@ impl SourceFileFetcher {
fn get_source_file_from_local_cache(
&self,
module_url: &Url,
+ permissions: &Permissions,
) -> Result<Option<SourceFile>, ErrBox> {
let url_scheme = module_url.scheme();
let is_local_file = url_scheme == "file";
@@ -229,7 +234,7 @@ impl SourceFileFetcher {
// Local files are always fetched from disk bypassing cache entirely.
if is_local_file {
- return self.fetch_local_file(&module_url).map(Some);
+ return self.fetch_local_file(&module_url, permissions).map(Some);
}
self.fetch_cached_remote_source(&module_url)
@@ -252,6 +257,7 @@ impl SourceFileFetcher {
use_disk_cache: bool,
no_remote: bool,
cached_only: bool,
+ permissions: &Permissions,
) -> Result<SourceFile, ErrBox> {
let url_scheme = module_url.scheme();
let is_local_file = url_scheme == "file";
@@ -259,7 +265,7 @@ impl SourceFileFetcher {
// Local files are always fetched from disk bypassing cache entirely.
if is_local_file {
- return self.fetch_local_file(&module_url);
+ return self.fetch_local_file(&module_url, permissions);
}
// The file is remote, fail if `no_remote` is true.
@@ -276,18 +282,29 @@ impl SourceFileFetcher {
// Fetch remote file and cache on-disk for subsequent access
self
- .fetch_remote_source(&module_url, use_disk_cache, cached_only, 10)
+ .fetch_remote_source(
+ &module_url,
+ use_disk_cache,
+ cached_only,
+ 10,
+ permissions,
+ )
.await
}
/// Fetch local source file.
- fn fetch_local_file(&self, module_url: &Url) -> Result<SourceFile, ErrBox> {
+ fn fetch_local_file(
+ &self,
+ module_url: &Url,
+ permissions: &Permissions,
+ ) -> Result<SourceFile, ErrBox> {
let filepath = module_url.to_file_path().map_err(|()| {
ErrBox::from(OpError::uri_error(
"File URL contains invalid path".to_owned(),
))
})?;
+ permissions.check_read(&filepath)?;
let source_code = match fs::read(filepath.clone()) {
Ok(c) => c,
Err(e) => return Err(e.into()),
@@ -390,12 +407,17 @@ impl SourceFileFetcher {
use_disk_cache: bool,
cached_only: bool,
redirect_limit: i64,
+ permissions: &Permissions,
) -> Pin<Box<dyn Future<Output = Result<SourceFile, ErrBox>>>> {
if redirect_limit < 0 {
let e = OpError::http("too many redirects".to_string());
return futures::future::err(e.into()).boxed_local();
}
+ if let Err(e) = permissions.check_net_url(&module_url) {
+ return futures::future::err(e.into()).boxed_local();
+ }
+
let is_blacklisted =
check_cache_blacklist(module_url, self.cache_blacklist.as_ref());
// First try local cache
@@ -441,6 +463,7 @@ impl SourceFileFetcher {
Ok((_, headers)) => headers.get("etag").map(String::from),
Err(_) => None,
};
+ let permissions = permissions.clone();
let http_client = self.http_client.clone();
// Single pass fetch, either yields code or yields redirect.
let f = async move {
@@ -463,6 +486,7 @@ impl SourceFileFetcher {
use_disk_cache,
cached_only,
redirect_limit - 1,
+ &permissions,
)
.await
}
@@ -752,11 +776,15 @@ mod tests {
if cfg!(windows) {
// Should fail: missing drive letter.
let u = Url::parse("file:///etc/passwd").unwrap();
- fetcher.fetch_local_file(&u).unwrap_err();
+ fetcher
+ .fetch_local_file(&u, &Permissions::allow_all())
+ .unwrap_err();
} else {
// Should fail: local network paths are not supported on unix.
let u = Url::parse("file://server/etc/passwd").unwrap();
- fetcher.fetch_local_file(&u).unwrap_err();
+ fetcher
+ .fetch_local_file(&u, &Permissions::allow_all())
+ .unwrap_err();
}
}
@@ -774,7 +802,13 @@ mod tests {
let cache_filename = fetcher.http_cache.get_cache_filename(&module_url);
let result = fetcher
- .get_source_file(&module_url, true, false, false)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r = result.unwrap();
@@ -795,7 +829,13 @@ mod tests {
metadata.write(&cache_filename).unwrap();
let result2 = fetcher_1
- .get_source_file(&module_url, true, false, false)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result2.is_ok());
let r2 = result2.unwrap();
@@ -818,7 +858,13 @@ mod tests {
metadata.write(&cache_filename).unwrap();
let result3 = fetcher_2
- .get_source_file(&module_url_1, true, false, false)
+ .get_source_file(
+ &module_url_1,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result3.is_ok());
let r3 = result3.unwrap();
@@ -839,7 +885,13 @@ mod tests {
// and don't use cache
let fetcher = setup_file_fetcher(temp_dir.path());
let result4 = fetcher
- .get_source_file(&module_url_2, false, false, false)
+ .get_source_file(
+ &module_url_2,
+ false,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result4.is_ok());
let r4 = result4.unwrap();
@@ -863,7 +915,13 @@ mod tests {
let cache_filename = fetcher.http_cache.get_cache_filename(&module_url);
let result = fetcher
- .get_source_file(&module_url, true, false, false)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r = result.unwrap();
@@ -883,7 +941,13 @@ mod tests {
metadata.write(&cache_filename).unwrap();
let result2 = fetcher
- .get_source_file(&module_url, true, false, false)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result2.is_ok());
let r2 = result2.unwrap();
@@ -903,7 +967,13 @@ mod tests {
// process) and don't use cache
let fetcher = setup_file_fetcher(temp_dir.path());
let result3 = fetcher
- .get_source_file(&module_url_1, false, false, false)
+ .get_source_file(
+ &module_url_1,
+ false,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result3.is_ok());
let r3 = result3.unwrap();
@@ -930,7 +1000,9 @@ mod tests {
fetcher.http_cache.get_cache_filename(&specifier.as_url());
// first download
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
let headers_file_name =
@@ -946,7 +1018,9 @@ mod tests {
// `use_disk_cache` is set to false, this can be verified using source
// header file creation timestamp (should be the same as after first
// download)
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
let result = fs::File::open(&headers_file_name);
@@ -984,7 +1058,13 @@ mod tests {
// Test basic follow and headers recording
let result = fetcher
- .get_source_file(&redirect_module_url, true, false, false)
+ .get_source_file(
+ &redirect_module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let mod_meta = result.unwrap();
@@ -1033,7 +1113,13 @@ mod tests {
// Test double redirects and headers recording
let result = fetcher
- .get_source_file(&double_redirect_url, true, false, false)
+ .get_source_file(
+ &double_redirect_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let mod_meta = result.unwrap();
@@ -1080,7 +1166,13 @@ mod tests {
// Test that redirect target is not downloaded twice for different redirect source.
let result = fetcher
- .get_source_file(&double_redirect_url, true, false, false)
+ .get_source_file(
+ &double_redirect_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let result = fs::File::open(&target_path);
@@ -1095,7 +1187,13 @@ mod tests {
// using source header file creation timestamp (should be the same as
// after first `get_source_file`)
let result = fetcher
- .get_source_file(&redirect_url, true, false, false)
+ .get_source_file(
+ &redirect_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let result = fs::File::open(&target_path_);
@@ -1121,12 +1219,24 @@ mod tests {
// Test that redirections can be limited
let result = fetcher
- .fetch_remote_source(&double_redirect_url, false, false, 2)
+ .fetch_remote_source(
+ &double_redirect_url,
+ false,
+ false,
+ 2,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let result = fetcher
- .fetch_remote_source(&double_redirect_url, false, false, 1)
+ .fetch_remote_source(
+ &double_redirect_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_err());
// FIXME(bartlomieju):
@@ -1161,7 +1271,13 @@ mod tests {
// Test basic follow and headers recording
let result = fetcher
- .get_source_file(&redirect_module_url, true, false, false)
+ .get_source_file(
+ &redirect_module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let mod_meta = result.unwrap();
@@ -1193,7 +1309,13 @@ mod tests {
Url::parse("http://localhost:4545/cli/tests/002_hello.ts").unwrap();
// Remote modules are not allowed
let result = fetcher
- .get_source_file(&module_url, true, true, false)
+ .get_source_file(
+ &module_url,
+ true,
+ true,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_err());
// FIXME(bartlomieju):
@@ -1216,7 +1338,13 @@ mod tests {
// file hasn't been cached before
let result = fetcher
- .get_source_file(&module_url, true, false, true)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ true,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_err());
// FIXME(bartlomieju):
@@ -1225,12 +1353,24 @@ mod tests {
// download and cache file
let result = fetcher_1
- .get_source_file(&module_url_1, true, false, false)
+ .get_source_file(
+ &module_url_1,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
// module is already cached, should be ok even with `cached_only`
let result = fetcher_2
- .get_source_file(&module_url_2, true, false, true)
+ .get_source_file(
+ &module_url_2,
+ true,
+ false,
+ true,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
drop(http_server_guard);
@@ -1244,7 +1384,13 @@ mod tests {
Url::parse("http://127.0.0.1:4545/cli/tests/subdir/mt_video_mp2t.t3.ts")
.unwrap();
let result = fetcher
- .fetch_remote_source(&module_url, false, false, 10)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 10,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r = result.unwrap();
@@ -1289,7 +1435,13 @@ mod tests {
let module_url_3_ = module_url_3.clone();
let result = fetcher
- .fetch_remote_source(&module_url, false, false, 10)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 10,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r = result.unwrap();
@@ -1298,7 +1450,13 @@ mod tests {
let (_, headers) = fetcher.http_cache.get(&module_url).unwrap();
assert_eq!(headers.get("content-type").unwrap(), "text/typescript");
let result = fetcher_1
- .fetch_remote_source(&module_url_2, false, false, 10)
+ .fetch_remote_source(
+ &module_url_2,
+ false,
+ false,
+ 10,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r2 = result.unwrap();
@@ -1309,7 +1467,13 @@ mod tests {
// test unknown extension
let result = fetcher_2
- .fetch_remote_source(&module_url_3, false, false, 10)
+ .fetch_remote_source(
+ &module_url_3,
+ false,
+ false,
+ 10,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r3 = result.unwrap();
@@ -1328,14 +1492,18 @@ mod tests {
// Test failure case.
let specifier =
ModuleSpecifier::resolve_url(file_url!("/baddir/hello.ts")).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_err());
let p =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("js/main.ts");
let specifier =
ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
}
@@ -1347,14 +1515,18 @@ mod tests {
// Test failure case.
let specifier =
ModuleSpecifier::resolve_url(file_url!("/baddir/hello.ts")).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_err());
let p =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("js/main.ts");
let specifier =
ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
}
@@ -1367,7 +1539,9 @@ mod tests {
.join("tests/001_hello.js");
let specifier =
ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
}
@@ -1611,7 +1785,13 @@ mod tests {
Url::parse("http://127.0.0.1:4545/etag_script.ts").unwrap();
let source = fetcher
- .fetch_remote_source(&module_url, false, false, 1)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await;
assert!(source.is_ok());
let source = source.unwrap();
@@ -1633,7 +1813,13 @@ mod tests {
let file_name = fetcher.http_cache.get_cache_filename(&module_url);
let _ = fs::write(&file_name, "changed content");
let cached_source = fetcher
- .fetch_remote_source(&module_url, false, false, 1)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await
.unwrap();
assert_eq!(cached_source.source_code, b"changed content");
@@ -1732,7 +1918,13 @@ mod tests {
let module_url =
Url::parse("http://127.0.0.1:4545/xTypeScriptTypes.js").unwrap();
let source = fetcher
- .fetch_remote_source(&module_url, false, false, 1)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await;
assert!(source.is_ok());
let source = source.unwrap();
@@ -1752,7 +1944,13 @@ mod tests {
let module_url =
Url::parse("http://127.0.0.1:4545/referenceTypes.js").unwrap();
let source = fetcher
- .fetch_remote_source(&module_url, false, false, 1)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await;
assert!(source.is_ok());
let source = source.unwrap();
diff --git a/cli/global_state.rs b/cli/global_state.rs
index b91ba5b10..4e9bdbb99 100644
--- a/cli/global_state.rs
+++ b/cli/global_state.rs
@@ -86,7 +86,6 @@ impl GlobalState {
compiler_starts: AtomicUsize::new(0),
compile_lock: AsyncMutex::new(()),
};
-
Ok(GlobalState(Arc::new(inner)))
}
@@ -95,6 +94,7 @@ impl GlobalState {
module_specifier: ModuleSpecifier,
maybe_referrer: Option<ModuleSpecifier>,
target_lib: TargetLib,
+ permissions: Permissions,
) -> Result<CompiledModule, ErrBox> {
let state1 = self.clone();
let state2 = self.clone();
@@ -102,7 +102,7 @@ impl GlobalState {
let out = self
.file_fetcher
- .fetch_source_file(&module_specifier, maybe_referrer)
+ .fetch_source_file(&module_specifier, maybe_referrer, permissions.clone())
.await?;
// TODO(ry) Try to lift compile_lock as high up in the call stack for
@@ -115,14 +115,14 @@ impl GlobalState {
| msg::MediaType::JSX => {
state1
.ts_compiler
- .compile(state1.clone(), &out, target_lib)
+ .compile(state1.clone(), &out, target_lib, permissions.clone())
.await
}
msg::MediaType::JavaScript => {
if state1.ts_compiler.compile_js {
state2
.ts_compiler
- .compile(state1.clone(), &out, target_lib)
+ .compile(state1.clone(), &out, target_lib, permissions.clone())
.await
} else {
if let Some(types_url) = out.types_url.clone() {
@@ -132,6 +132,7 @@ impl GlobalState {
.fetch_source_file(
&types_specifier,
Some(module_specifier.clone()),
+ permissions.clone(),
)
.await
.ok();
diff --git a/cli/lib.rs b/cli/lib.rs
index 97b497e95..0b88d7346 100644
--- a/cli/lib.rs
+++ b/cli/lib.rs
@@ -73,6 +73,7 @@ use crate::global_state::GlobalState;
use crate::msg::MediaType;
use crate::op_error::OpError;
use crate::ops::io::get_stdio;
+use crate::permissions::Permissions;
use crate::state::DebugType;
use crate::state::State;
use crate::tsc::TargetLib;
@@ -187,7 +188,7 @@ async fn print_file_info(
let out = global_state
.file_fetcher
- .fetch_source_file(&module_specifier, None)
+ .fetch_source_file(&module_specifier, None, Permissions::allow_all())
.await?;
println!(
@@ -205,7 +206,12 @@ async fn print_file_info(
let module_specifier_ = module_specifier.clone();
global_state
.clone()
- .fetch_compiled_module(module_specifier_, None, TargetLib::Main)
+ .fetch_compiled_module(
+ module_specifier_,
+ None,
+ TargetLib::Main,
+ Permissions::allow_all(),
+ )
.await?;
if out.media_type == msg::MediaType::TypeScript
@@ -407,7 +413,9 @@ async fn doc_command(
let fetcher = self.clone();
async move {
- let source_file = fetcher.fetch_source_file(&specifier, None).await?;
+ let source_file = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await?;
String::from_utf8(source_file.source_code)
.map_err(|_| OpError::other("failed to parse".to_string()))
}
diff --git a/cli/ops/compiler.rs b/cli/ops/compiler.rs
index 83b6d944c..b84401187 100644
--- a/cli/ops/compiler.rs
+++ b/cli/ops/compiler.rs
@@ -69,7 +69,11 @@ fn op_fetch_source_files(
None
};
- let global_state = state.borrow().global_state.clone();
+ let s = state.borrow();
+ let global_state = s.global_state.clone();
+ let permissions = s.permissions.clone();
+ let perms_ = permissions.clone();
+ drop(s);
let file_fetcher = global_state.file_fetcher.clone();
let specifiers = args.specifiers.clone();
let future = async move {
@@ -78,6 +82,7 @@ fn op_fetch_source_files(
.map(|specifier| {
let file_fetcher_ = file_fetcher.clone();
let ref_specifier_ = ref_specifier.clone();
+ let perms_ = perms_.clone();
async move {
let resolved_specifier = ModuleSpecifier::resolve_url(&specifier)
.expect("Invalid specifier");
@@ -100,7 +105,7 @@ fn op_fetch_source_files(
}
}
file_fetcher_
- .fetch_source_file(&resolved_specifier, ref_specifier_)
+ .fetch_source_file(&resolved_specifier, ref_specifier_, perms_)
.await
}
.boxed_local()
@@ -118,7 +123,11 @@ fn op_fetch_source_files(
let types_specifier = ModuleSpecifier::from(types_url);
global_state
.file_fetcher
- .fetch_source_file(&types_specifier, ref_specifier.clone())
+ .fetch_source_file(
+ &types_specifier,
+ ref_specifier.clone(),
+ permissions.clone(),
+ )
.await
.map_err(OpError::from)?
}
diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs
index e44d6fa8b..f3b741861 100644
--- a/cli/ops/runtime_compiler.rs
+++ b/cli/ops/runtime_compiler.rs
@@ -30,10 +30,13 @@ fn op_compile(
) -> Result<JsonOp, OpError> {
state.check_unstable("Deno.compile");
let args: CompileArgs = serde_json::from_value(args)?;
- let global_state = state.borrow().global_state.clone();
+ let s = state.borrow();
+ let global_state = s.global_state.clone();
+ let permissions = s.permissions.clone();
let fut = async move {
runtime_compile(
global_state,
+ permissions,
&args.root_name,
&args.sources,
args.bundle,
@@ -58,9 +61,12 @@ fn op_transpile(
) -> Result<JsonOp, OpError> {
state.check_unstable("Deno.transpile");
let args: TranspileArgs = serde_json::from_value(args)?;
- let global_state = state.borrow().global_state.clone();
+ let s = state.borrow();
+ let global_state = s.global_state.clone();
+ let permissions = s.permissions.clone();
let fut = async move {
- runtime_transpile(global_state, &args.sources, &args.options).await
+ runtime_transpile(global_state, permissions, &args.sources, &args.options)
+ .await
}
.boxed_local();
Ok(JsonOp::Async(fut))
diff --git a/cli/permissions.rs b/cli/permissions.rs
index a56754f18..bc4d0844e 100644
--- a/cli/permissions.rs
+++ b/cli/permissions.rs
@@ -134,6 +134,19 @@ impl Permissions {
}
}
+ pub fn allow_all() -> Self {
+ Self {
+ allow_read: PermissionState::from(true),
+ allow_write: PermissionState::from(true),
+ allow_net: PermissionState::from(true),
+ allow_env: PermissionState::from(true),
+ allow_run: PermissionState::from(true),
+ allow_plugin: PermissionState::from(true),
+ allow_hrtime: PermissionState::from(true),
+ ..Default::default()
+ }
+ }
+
pub fn check_run(&self) -> Result<(), OpError> {
self
.allow_run
diff --git a/cli/state.rs b/cli/state.rs
index 8c425d700..9501ed286 100644
--- a/cli/state.rs
+++ b/cli/state.rs
@@ -67,6 +67,7 @@ pub struct StateInner {
pub seeded_rng: Option<StdRng>,
pub target_lib: TargetLib,
pub debug_type: DebugType,
+ pub is_main: bool,
}
impl State {
@@ -314,9 +315,20 @@ impl ModuleLoader for State {
let module_url_specified = module_specifier.to_string();
let global_state = state.global_state.clone();
let target_lib = state.target_lib.clone();
+ let permissions = if state.is_main {
+ Permissions::allow_all()
+ } else {
+ state.permissions.clone()
+ };
+
let fut = async move {
let compiled_module = global_state
- .fetch_compiled_module(module_specifier, maybe_referrer, target_lib)
+ .fetch_compiled_module(
+ module_specifier,
+ maybe_referrer,
+ target_lib,
+ permissions,
+ )
.await?;
Ok(deno_core::ModuleSource {
// Real module name, might be different from initial specifier
@@ -395,6 +407,7 @@ impl State {
seeded_rng,
target_lib: TargetLib::Main,
debug_type,
+ is_main: true,
}));
Ok(Self(state))
@@ -430,6 +443,7 @@ impl State {
seeded_rng,
target_lib: TargetLib::Worker,
debug_type: DebugType::Dependent,
+ is_main: false,
}));
Ok(Self(state))
diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs
index 4897422b9..61e1fca7d 100644
--- a/cli/tests/integration_tests.rs
+++ b/cli/tests/integration_tests.rs
@@ -1019,6 +1019,7 @@ fn workers() {
.arg("test")
.arg("--reload")
.arg("--allow-net")
+ .arg("--allow-read")
.arg("--unstable")
.arg("workers_test.ts")
.spawn()
@@ -1036,6 +1037,7 @@ fn compiler_api() {
.arg("test")
.arg("--unstable")
.arg("--reload")
+ .arg("--allow-read")
.arg("compiler_api_test.ts")
.spawn()
.unwrap()
diff --git a/cli/tsc.rs b/cli/tsc.rs
index f0b617246..f207558a5 100644
--- a/cli/tsc.rs
+++ b/cli/tsc.rs
@@ -11,6 +11,7 @@ use crate::global_state::GlobalState;
use crate::msg;
use crate::op_error::OpError;
use crate::ops;
+use crate::permissions::Permissions;
use crate::source_maps::SourceMapGetter;
use crate::startup_data;
use crate::state::State;
@@ -343,12 +344,19 @@ impl TsCompiler {
/// Create a new V8 worker with snapshot of TS compiler and setup compiler's
/// runtime.
- fn setup_worker(global_state: GlobalState) -> CompilerWorker {
+ fn setup_worker(
+ global_state: GlobalState,
+ permissions: Permissions,
+ ) -> CompilerWorker {
let entry_point =
ModuleSpecifier::resolve_url_or_path("./__$deno$ts_compiler.ts").unwrap();
- let worker_state =
- State::new(global_state.clone(), None, entry_point, DebugType::Internal)
- .expect("Unable to create worker state");
+ let worker_state = State::new(
+ global_state.clone(),
+ Some(permissions),
+ entry_point,
+ DebugType::Internal,
+ )
+ .expect("Unable to create worker state");
// Count how many times we start the compiler worker.
global_state.compiler_starts.fetch_add(1, Ordering::SeqCst);
@@ -384,7 +392,9 @@ impl TsCompiler {
global_state.flags.unstable,
);
- let msg = execute_in_thread(global_state.clone(), req_msg).await?;
+ let permissions = Permissions::allow_all();
+ let msg =
+ execute_in_thread(global_state.clone(), permissions, req_msg).await?;
let json_str = std::str::from_utf8(&msg).unwrap();
debug!("Message: {}", json_str);
@@ -440,6 +450,7 @@ impl TsCompiler {
global_state: GlobalState,
source_file: &SourceFile,
target: TargetLib,
+ permissions: Permissions,
) -> Result<CompiledModule, ErrBox> {
if self.has_compiled(&source_file.url) {
return self.get_compiled_module(&source_file.url);
@@ -492,7 +503,8 @@ impl TsCompiler {
module_url.to_string()
);
- let msg = execute_in_thread(global_state.clone(), req_msg).await?;
+ let msg =
+ execute_in_thread(global_state.clone(), permissions, req_msg).await?;
let json_str = std::str::from_utf8(&msg).unwrap();
let compile_response: CompileResponse = serde_json::from_str(json_str)?;
@@ -597,7 +609,7 @@ impl TsCompiler {
) -> std::io::Result<()> {
let source_file = self
.file_fetcher
- .fetch_cached_source_file(&module_specifier)
+ .fetch_cached_source_file(&module_specifier, Permissions::allow_all())
.expect("Source file not found");
// NOTE: JavaScript files are only cached to disk if `checkJs`
@@ -612,6 +624,10 @@ impl TsCompiler {
.get_cache_filename_with_extension(module_specifier.as_url(), "js");
self.disk_cache.set(&js_key, contents.as_bytes())?;
self.mark_compiled(module_specifier.as_url());
+ let source_file = self
+ .file_fetcher
+ .fetch_cached_source_file(&module_specifier, Permissions::allow_all())
+ .expect("Source file not found");
let version_hash = source_code_version_hash(
&source_file.source_code,
@@ -665,7 +681,7 @@ impl TsCompiler {
) -> std::io::Result<()> {
let source_file = self
.file_fetcher
- .fetch_cached_source_file(&module_specifier)
+ .fetch_cached_source_file(&module_specifier, Permissions::allow_all())
.expect("Source file not found");
// NOTE: JavaScript files are only cached to disk if `checkJs`
@@ -720,7 +736,7 @@ impl TsCompiler {
if let Some(module_specifier) = self.try_to_resolve(script_name) {
return self
.file_fetcher
- .fetch_cached_source_file(&module_specifier);
+ .fetch_cached_source_file(&module_specifier, Permissions::allow_all());
}
None
@@ -743,6 +759,7 @@ impl TsCompiler {
async fn execute_in_thread(
global_state: GlobalState,
+ permissions: Permissions,
req: Buf,
) -> Result<Buf, ErrBox> {
let (handle_sender, handle_receiver) =
@@ -750,7 +767,7 @@ async fn execute_in_thread(
let builder =
std::thread::Builder::new().name("deno-ts-compiler".to_string());
let join_handle = builder.spawn(move || {
- let worker = TsCompiler::setup_worker(global_state.clone());
+ let worker = TsCompiler::setup_worker(global_state.clone(), permissions);
handle_sender.send(Ok(worker.thread_safe_handle())).unwrap();
drop(handle_sender);
tokio_util::run_basic(worker).expect("Panic in event loop");
@@ -772,6 +789,7 @@ async fn execute_in_thread(
/// This function is used by `Deno.compile()` and `Deno.bundle()` APIs.
pub async fn runtime_compile<S: BuildHasher>(
global_state: GlobalState,
+ permissions: Permissions,
root_name: &str,
sources: &Option<HashMap<String, String, S>>,
bundle: bool,
@@ -792,7 +810,7 @@ pub async fn runtime_compile<S: BuildHasher>(
let compiler = global_state.ts_compiler.clone();
- let msg = execute_in_thread(global_state, req_msg).await?;
+ let msg = execute_in_thread(global_state, permissions, req_msg).await?;
let json_str = std::str::from_utf8(&msg).unwrap();
// TODO(bartlomieju): factor `bundle` path into separate function `runtime_bundle`
@@ -816,6 +834,7 @@ pub async fn runtime_compile<S: BuildHasher>(
/// This function is used by `Deno.transpileOnly()` API.
pub async fn runtime_transpile<S: BuildHasher>(
global_state: GlobalState,
+ permissions: Permissions,
sources: &HashMap<String, String, S>,
options: &Option<String>,
) -> Result<Value, OpError> {
@@ -828,7 +847,7 @@ pub async fn runtime_transpile<S: BuildHasher>(
.into_boxed_str()
.into_boxed_bytes();
- let msg = execute_in_thread(global_state, req_msg).await?;
+ let msg = execute_in_thread(global_state, permissions, req_msg).await?;
let json_str = std::str::from_utf8(&msg).unwrap();
let v = serde_json::from_str::<serde_json::Value>(json_str)
.expect("Error decoding JSON string.");
@@ -862,7 +881,12 @@ mod tests {
GlobalState::mock(vec![String::from("deno"), String::from("hello.js")]);
let result = mock_state
.ts_compiler
- .compile(mock_state.clone(), &out, TargetLib::Main)
+ .compile(
+ mock_state.clone(),
+ &out,
+ TargetLib::Main,
+ Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
assert!(result