mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
feat: Add requesting API name to permission prompt (#15936)
Co-authored-by: Leo Kettmeir <crowlkats@toaxl.com>
This commit is contained in:
parent
a344368603
commit
212b7dd6da
18 changed files with 530 additions and 235 deletions
|
@ -167,8 +167,12 @@ impl FetchHandler for DefaultFileFetchHandler {
|
|||
}
|
||||
|
||||
pub trait FetchPermissions {
|
||||
fn check_net_url(&mut self, _url: &Url) -> Result<(), AnyError>;
|
||||
fn check_read(&mut self, _p: &Path) -> Result<(), AnyError>;
|
||||
fn check_net_url(
|
||||
&mut self,
|
||||
_url: &Url,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
fn check_read(&mut self, _p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
}
|
||||
|
||||
pub fn get_declaration() -> PathBuf {
|
||||
|
@ -215,7 +219,7 @@ where
|
|||
type_error("NetworkError when attempting to fetch resource.")
|
||||
})?;
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_read(&path)?;
|
||||
permissions.check_read(&path, "fetch()")?;
|
||||
|
||||
if method != Method::GET {
|
||||
return Err(type_error(format!(
|
||||
|
@ -240,7 +244,7 @@ where
|
|||
}
|
||||
"http" | "https" => {
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_net_url(&url)?;
|
||||
permissions.check_net_url(&url, "fetch()")?;
|
||||
|
||||
let mut request = client.request(method.clone(), url);
|
||||
|
||||
|
@ -535,7 +539,7 @@ where
|
|||
if let Some(proxy) = args.proxy.clone() {
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
let url = Url::parse(&proxy.url)?;
|
||||
permissions.check_net_url(&url)?;
|
||||
permissions.check_net_url(&url, "Deno.createHttpClient()")?;
|
||||
}
|
||||
|
||||
let client_cert_chain_and_key = {
|
||||
|
|
|
@ -1135,7 +1135,7 @@ where
|
|||
check_unstable(state, "Deno.serve");
|
||||
state
|
||||
.borrow_mut::<P>()
|
||||
.check_net(&(&opts.hostname, Some(opts.port)))?;
|
||||
.check_net(&(&opts.hostname, Some(opts.port)), "Deno.serve()")?;
|
||||
|
||||
let addr = resolve_addr_sync(&opts.hostname, opts.port)?
|
||||
.next()
|
||||
|
@ -1377,6 +1377,7 @@ pub trait FlashPermissions {
|
|||
fn check_net<T: AsRef<str>>(
|
||||
&mut self,
|
||||
_host: &(T, Option<u16>),
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,11 @@ pub trait NetPermissions {
|
|||
fn check_net<T: AsRef<str>>(
|
||||
&mut self,
|
||||
_host: &(T, Option<u16>),
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
fn check_read(&mut self, _p: &Path) -> Result<(), AnyError>;
|
||||
fn check_write(&mut self, _p: &Path) -> Result<(), AnyError>;
|
||||
fn check_read(&mut self, _p: &Path, _api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write(&mut self, _p: &Path, _api_name: &str)
|
||||
-> Result<(), AnyError>;
|
||||
}
|
||||
|
||||
/// `UnstableChecker` is a struct so it can be placed inside `GothamState`;
|
||||
|
|
|
@ -252,8 +252,10 @@ where
|
|||
} if transport == "udp" => {
|
||||
{
|
||||
let mut s = state.borrow_mut();
|
||||
s.borrow_mut::<NP>()
|
||||
.check_net(&(&args.hostname, Some(args.port)))?;
|
||||
s.borrow_mut::<NP>().check_net(
|
||||
&(&args.hostname, Some(args.port)),
|
||||
"Deno.DatagramConn.send()",
|
||||
)?;
|
||||
}
|
||||
let addr = resolve_addr(&args.hostname, args.port)
|
||||
.await?
|
||||
|
@ -278,7 +280,8 @@ where
|
|||
let address_path = Path::new(&args.path);
|
||||
{
|
||||
let mut s = state.borrow_mut();
|
||||
s.borrow_mut::<NP>().check_write(address_path)?;
|
||||
s.borrow_mut::<NP>()
|
||||
.check_write(address_path, "Deno.DatagramConn.send()")?;
|
||||
}
|
||||
let resource = state
|
||||
.borrow()
|
||||
|
@ -319,7 +322,7 @@ where
|
|||
let mut state_ = state.borrow_mut();
|
||||
state_
|
||||
.borrow_mut::<NP>()
|
||||
.check_net(&(&args.hostname, Some(args.port)))?;
|
||||
.check_net(&(&args.hostname, Some(args.port)), "Deno.connect()")?;
|
||||
}
|
||||
let addr = resolve_addr(&args.hostname, args.port)
|
||||
.await?
|
||||
|
@ -354,8 +357,12 @@ where
|
|||
super::check_unstable2(&state, "Deno.connect");
|
||||
{
|
||||
let mut state_ = state.borrow_mut();
|
||||
state_.borrow_mut::<NP>().check_read(address_path)?;
|
||||
state_.borrow_mut::<NP>().check_write(address_path)?;
|
||||
state_
|
||||
.borrow_mut::<NP>()
|
||||
.check_read(address_path, "Deno.connect()")?;
|
||||
state_
|
||||
.borrow_mut::<NP>()
|
||||
.check_write(address_path, "Deno.connect()")?;
|
||||
}
|
||||
let path = args.path;
|
||||
let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?;
|
||||
|
@ -494,9 +501,10 @@ where
|
|||
if transport == "udp" {
|
||||
super::check_unstable(state, "Deno.listenDatagram");
|
||||
}
|
||||
state
|
||||
.borrow_mut::<NP>()
|
||||
.check_net(&(&args.hostname, Some(args.port)))?;
|
||||
state.borrow_mut::<NP>().check_net(
|
||||
&(&args.hostname, Some(args.port)),
|
||||
"Deno.listenDatagram()",
|
||||
)?;
|
||||
}
|
||||
let addr = resolve_addr_sync(&args.hostname, args.port)?
|
||||
.next()
|
||||
|
@ -540,9 +548,14 @@ where
|
|||
if transport == "unixpacket" {
|
||||
super::check_unstable(state, "Deno.listenDatagram");
|
||||
}
|
||||
let api_name = if transport == "unix" {
|
||||
"Deno.listen()"
|
||||
} else {
|
||||
"Deno.listenDatagram()"
|
||||
};
|
||||
let permissions = state.borrow_mut::<NP>();
|
||||
permissions.check_read(address_path)?;
|
||||
permissions.check_write(address_path)?;
|
||||
permissions.check_read(address_path, api_name)?;
|
||||
permissions.check_write(address_path, api_name)?;
|
||||
}
|
||||
let (rid, local_addr) = if transport == "unix" {
|
||||
net_unix::listen_unix(state, address_path)?
|
||||
|
@ -678,7 +691,7 @@ where
|
|||
let socker_addr = &ns.socket_addr;
|
||||
let ip = socker_addr.ip().to_string();
|
||||
let port = socker_addr.port();
|
||||
perm.check_net(&(ip, Some(port)))?;
|
||||
perm.check_net(&(ip, Some(port)), "Deno.resolveDns()")?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1010,15 +1023,24 @@ mod tests {
|
|||
fn check_net<T: AsRef<str>>(
|
||||
&mut self,
|
||||
_host: &(T, Option<u16>),
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_read(&mut self, _p: &Path) -> Result<(), AnyError> {
|
||||
fn check_read(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_write(&mut self, _p: &Path) -> Result<(), AnyError> {
|
||||
fn check_write(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -799,7 +799,7 @@ where
|
|||
{
|
||||
let mut s = state.borrow_mut();
|
||||
let permissions = s.borrow_mut::<NP>();
|
||||
permissions.check_net(&(hostname, Some(0)))?;
|
||||
permissions.check_net(&(hostname, Some(0)), "Deno.startTls()")?;
|
||||
}
|
||||
|
||||
let ca_certs = args
|
||||
|
@ -904,9 +904,9 @@ where
|
|||
{
|
||||
let mut s = state.borrow_mut();
|
||||
let permissions = s.borrow_mut::<NP>();
|
||||
permissions.check_net(&(hostname, Some(port)))?;
|
||||
permissions.check_net(&(hostname, Some(port)), "Deno.connectTls()")?;
|
||||
if let Some(path) = cert_file {
|
||||
permissions.check_read(Path::new(path))?;
|
||||
permissions.check_read(Path::new(path), "Deno.connectTls()")?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1051,12 +1051,12 @@ where
|
|||
|
||||
{
|
||||
let permissions = state.borrow_mut::<NP>();
|
||||
permissions.check_net(&(hostname, Some(port)))?;
|
||||
permissions.check_net(&(hostname, Some(port)), "Deno.listenTls()")?;
|
||||
if let Some(path) = cert_file {
|
||||
permissions.check_read(Path::new(path))?;
|
||||
permissions.check_read(Path::new(path), "Deno.listenTls()")?;
|
||||
}
|
||||
if let Some(path) = key_file {
|
||||
permissions.check_read(Path::new(path))?;
|
||||
permissions.check_read(Path::new(path), "Deno.listenTls()")?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -191,6 +191,7 @@
|
|||
this[_url] = wsURL.href;
|
||||
|
||||
ops.op_ws_check_permission_and_cancel_handle(
|
||||
"WebSocket.abort()",
|
||||
this[_url],
|
||||
false,
|
||||
);
|
||||
|
@ -227,6 +228,7 @@
|
|||
PromisePrototypeThen(
|
||||
core.opAsync(
|
||||
"op_ws_create",
|
||||
"new WebSocket()",
|
||||
wsURL.href,
|
||||
ArrayPrototypeJoin(protocols, ", "),
|
||||
),
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
}
|
||||
|
||||
const cancelRid = ops.op_ws_check_permission_and_cancel_handle(
|
||||
"WebSocketStream.abort()",
|
||||
this[_url],
|
||||
true,
|
||||
);
|
||||
|
@ -150,6 +151,7 @@
|
|||
PromisePrototypeThen(
|
||||
core.opAsync(
|
||||
"op_ws_create",
|
||||
"new WebSocketStream()",
|
||||
this[_url],
|
||||
options.protocols
|
||||
? ArrayPrototypeJoin(options.protocols, ", ")
|
||||
|
|
|
@ -61,7 +61,11 @@ pub struct WsRootStore(pub Option<RootCertStore>);
|
|||
pub struct WsUserAgent(pub String);
|
||||
|
||||
pub trait WebSocketPermissions {
|
||||
fn check_net_url(&mut self, _url: &url::Url) -> Result<(), AnyError>;
|
||||
fn check_net_url(
|
||||
&mut self,
|
||||
_url: &url::Url,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
}
|
||||
|
||||
/// `UnsafelyIgnoreCertificateErrors` is a wrapper struct so it can be placed inside `GothamState`;
|
||||
|
@ -211,6 +215,7 @@ impl Resource for WsCancelResource {
|
|||
#[op]
|
||||
pub fn op_ws_check_permission_and_cancel_handle<WP>(
|
||||
state: &mut OpState,
|
||||
api_name: String,
|
||||
url: String,
|
||||
cancel_handle: bool,
|
||||
) -> Result<Option<ResourceId>, AnyError>
|
||||
|
@ -219,7 +224,7 @@ where
|
|||
{
|
||||
state
|
||||
.borrow_mut::<WP>()
|
||||
.check_net_url(&url::Url::parse(&url)?)?;
|
||||
.check_net_url(&url::Url::parse(&url)?, &api_name)?;
|
||||
|
||||
if cancel_handle {
|
||||
let rid = state
|
||||
|
@ -242,6 +247,7 @@ pub struct CreateResponse {
|
|||
#[op]
|
||||
pub async fn op_ws_create<WP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
api_name: String,
|
||||
url: String,
|
||||
protocols: String,
|
||||
cancel_handle: Option<ResourceId>,
|
||||
|
@ -253,7 +259,7 @@ where
|
|||
{
|
||||
let mut s = state.borrow_mut();
|
||||
s.borrow_mut::<WP>()
|
||||
.check_net_url(&url::Url::parse(&url)?)
|
||||
.check_net_url(&url::Url::parse(&url)?, &api_name)
|
||||
.expect(
|
||||
"Permission check should have been done in op_ws_check_permission",
|
||||
);
|
||||
|
|
|
@ -72,6 +72,7 @@ mod not_docs {
|
|||
fn check_net_url(
|
||||
&mut self,
|
||||
_url: &deno_core::url::Url,
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
@ -79,6 +80,7 @@ mod not_docs {
|
|||
fn check_read(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
@ -88,6 +90,7 @@ mod not_docs {
|
|||
fn check_net_url(
|
||||
&mut self,
|
||||
_url: &deno_core::url::Url,
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
@ -120,6 +123,7 @@ mod not_docs {
|
|||
fn check_net<T: AsRef<str>>(
|
||||
&mut self,
|
||||
_host: &(T, Option<u16>),
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
@ -138,6 +142,7 @@ mod not_docs {
|
|||
fn check_net<T: AsRef<str>>(
|
||||
&mut self,
|
||||
_host: &(T, Option<u16>),
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
@ -145,6 +150,7 @@ mod not_docs {
|
|||
fn check_read(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
@ -152,6 +158,7 @@ mod not_docs {
|
|||
fn check_write(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
|
|
@ -16,8 +16,12 @@
|
|||
String,
|
||||
} = window.__bootstrap.primordials;
|
||||
|
||||
function opKill(pid, signo) {
|
||||
ops.op_kill(pid, signo);
|
||||
function opKill(pid, signo, apiName) {
|
||||
ops.op_kill(pid, signo, apiName);
|
||||
}
|
||||
|
||||
function kill(pid, signo) {
|
||||
opKill(pid, signo, "Deno.kill()");
|
||||
}
|
||||
|
||||
function opRunStatus(rid) {
|
||||
|
@ -91,7 +95,7 @@
|
|||
}
|
||||
|
||||
kill(signo) {
|
||||
opKill(this.pid, signo);
|
||||
opKill(this.pid, signo, "Deno.Process.kill()");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,6 +130,6 @@
|
|||
window.__bootstrap.process = {
|
||||
run,
|
||||
Process,
|
||||
kill: opKill,
|
||||
kill,
|
||||
};
|
||||
})(this);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
|
||||
|
||||
function spawnChild(command, {
|
||||
function spawnChildInner(command, apiName, {
|
||||
args = [],
|
||||
cwd = undefined,
|
||||
clearEnv = false,
|
||||
|
@ -44,13 +44,17 @@
|
|||
stdin,
|
||||
stdout,
|
||||
stderr,
|
||||
});
|
||||
}, apiName);
|
||||
return new Child(illegalConstructorKey, {
|
||||
...child,
|
||||
signal,
|
||||
});
|
||||
}
|
||||
|
||||
function spawnChild(command, options = {}) {
|
||||
return spawnChildInner(command, "Deno.spawnChild()", options);
|
||||
}
|
||||
|
||||
async function collectOutput(readableStream) {
|
||||
if (!(readableStream instanceof ReadableStream)) {
|
||||
return null;
|
||||
|
@ -204,7 +208,7 @@
|
|||
if (this.#rid === null) {
|
||||
throw new TypeError("Child process has already terminated.");
|
||||
}
|
||||
ops.op_kill(this.#pid, signo);
|
||||
ops.op_kill(this.#pid, signo, "Deno.Child.kill()");
|
||||
}
|
||||
|
||||
ref() {
|
||||
|
@ -228,7 +232,7 @@
|
|||
"Piped stdin is not supported for this function, use 'Deno.spawnChild()' instead",
|
||||
);
|
||||
}
|
||||
return spawnChild(command, options).output();
|
||||
return spawnChildInner(command, "Deno.spawn()", options).output();
|
||||
}
|
||||
|
||||
function spawnSync(command, {
|
||||
|
|
|
@ -126,6 +126,7 @@ fn open_helper(
|
|||
path: &str,
|
||||
mode: Option<u32>,
|
||||
options: Option<&OpenOptions>,
|
||||
api_name: &str,
|
||||
) -> Result<(PathBuf, std::fs::OpenOptions), AnyError> {
|
||||
let path = Path::new(path).to_path_buf();
|
||||
|
||||
|
@ -147,7 +148,7 @@ fn open_helper(
|
|||
|
||||
match options {
|
||||
None => {
|
||||
permissions.read.check(&path)?;
|
||||
permissions.read.check(&path, Some(api_name))?;
|
||||
open_options
|
||||
.read(true)
|
||||
.create(false)
|
||||
|
@ -158,11 +159,11 @@ fn open_helper(
|
|||
}
|
||||
Some(options) => {
|
||||
if options.read {
|
||||
permissions.read.check(&path)?;
|
||||
permissions.read.check(&path, Some(api_name))?;
|
||||
}
|
||||
|
||||
if options.write || options.append {
|
||||
permissions.write.check(&path)?;
|
||||
permissions.write.check(&path, Some(api_name))?;
|
||||
}
|
||||
|
||||
open_options
|
||||
|
@ -185,7 +186,8 @@ fn op_open_sync(
|
|||
options: Option<OpenOptions>,
|
||||
mode: Option<u32>,
|
||||
) -> Result<ResourceId, AnyError> {
|
||||
let (path, open_options) = open_helper(state, &path, mode, options.as_ref())?;
|
||||
let (path, open_options) =
|
||||
open_helper(state, &path, mode, options.as_ref(), "Deno.openSync()")?;
|
||||
let std_file = open_options.open(&path).map_err(|err| {
|
||||
Error::new(err.kind(), format!("{}, open '{}'", err, path.display()))
|
||||
})?;
|
||||
|
@ -201,8 +203,13 @@ async fn op_open_async(
|
|||
options: Option<OpenOptions>,
|
||||
mode: Option<u32>,
|
||||
) -> Result<ResourceId, AnyError> {
|
||||
let (path, open_options) =
|
||||
open_helper(&mut state.borrow_mut(), &path, mode, options.as_ref())?;
|
||||
let (path, open_options) = open_helper(
|
||||
&mut state.borrow_mut(),
|
||||
&path,
|
||||
mode,
|
||||
options.as_ref(),
|
||||
"Deno.open()",
|
||||
)?;
|
||||
let std_file = tokio::task::spawn_blocking(move || {
|
||||
open_options.open(path.clone()).map_err(|err| {
|
||||
Error::new(err.kind(), format!("{}, open '{}'", err, path.display()))
|
||||
|
@ -240,6 +247,7 @@ fn op_write_file_sync(
|
|||
&path,
|
||||
mode,
|
||||
Some(&write_open_options(create, append)),
|
||||
"Deno.writeFileSync()",
|
||||
)?;
|
||||
write_file(&path, open_options, mode, data)
|
||||
}
|
||||
|
@ -267,6 +275,7 @@ async fn op_write_file_async(
|
|||
&path,
|
||||
mode,
|
||||
Some(&write_open_options(create, append)),
|
||||
"Deno.writeFile()",
|
||||
)?;
|
||||
let write_future = tokio::task::spawn_blocking(move || {
|
||||
write_file(&path, open_options, mode, data)
|
||||
|
@ -517,7 +526,10 @@ fn op_umask(state: &mut OpState, mask: Option<u32>) -> Result<u32, AnyError> {
|
|||
#[op]
|
||||
fn op_chdir(state: &mut OpState, directory: String) -> Result<(), AnyError> {
|
||||
let d = PathBuf::from(&directory);
|
||||
state.borrow_mut::<Permissions>().read.check(&d)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(&d, Some("Deno.chdir()"))?;
|
||||
set_current_dir(&d).map_err(|err| {
|
||||
Error::new(err.kind(), format!("{}, chdir '{}'", err, directory))
|
||||
})?;
|
||||
|
@ -536,7 +548,10 @@ pub struct MkdirArgs {
|
|||
fn op_mkdir_sync(state: &mut OpState, args: MkdirArgs) -> Result<(), AnyError> {
|
||||
let path = Path::new(&args.path).to_path_buf();
|
||||
let mode = args.mode.unwrap_or(0o777) & 0o777;
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.mkdirSync()"))?;
|
||||
debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive);
|
||||
let mut builder = std::fs::DirBuilder::new();
|
||||
builder.recursive(args.recursive);
|
||||
|
@ -561,7 +576,10 @@ async fn op_mkdir_async(
|
|||
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.mkdir()"))?;
|
||||
}
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
|
@ -591,7 +609,10 @@ fn op_chmod_sync(
|
|||
let path = Path::new(&path);
|
||||
let mode = mode & 0o777;
|
||||
|
||||
state.borrow_mut::<Permissions>().write.check(path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(path, Some("Deno.chmodSync()"))?;
|
||||
raw_chmod(path, mode)
|
||||
}
|
||||
|
||||
|
@ -606,7 +627,10 @@ async fn op_chmod_async(
|
|||
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.chmod()"))?;
|
||||
}
|
||||
|
||||
tokio::task::spawn_blocking(move || raw_chmod(&path, mode))
|
||||
|
@ -642,7 +666,10 @@ fn op_chown_sync(
|
|||
#[cfg_attr(windows, allow(unused_variables))] gid: Option<u32>,
|
||||
) -> Result<(), AnyError> {
|
||||
let path = Path::new(&path).to_path_buf();
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.chownSync()"))?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use crate::errors::get_nix_error_class;
|
||||
|
@ -675,7 +702,10 @@ async fn op_chown_async(
|
|||
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.chown()"))?;
|
||||
}
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
|
@ -709,7 +739,10 @@ fn op_remove_sync(
|
|||
) -> Result<(), AnyError> {
|
||||
let path = PathBuf::from(&path);
|
||||
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.removeSync()"))?;
|
||||
|
||||
#[cfg(not(unix))]
|
||||
use std::os::windows::prelude::MetadataExt;
|
||||
|
@ -755,7 +788,10 @@ async fn op_remove_async(
|
|||
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.remove()"))?;
|
||||
}
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
|
@ -806,8 +842,12 @@ fn op_copy_file_sync(
|
|||
let to_path = PathBuf::from(&to);
|
||||
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
permissions.read.check(&from_path)?;
|
||||
permissions.write.check(&to_path)?;
|
||||
permissions
|
||||
.read
|
||||
.check(&from_path, Some("Deno.copyFileSync()"))?;
|
||||
permissions
|
||||
.write
|
||||
.check(&to_path, Some("Deno.copyFileSync()"))?;
|
||||
|
||||
// On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput
|
||||
// See https://github.com/rust-lang/rust/issues/54800
|
||||
|
@ -903,8 +943,8 @@ async fn op_copy_file_async(
|
|||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
permissions.read.check(&from)?;
|
||||
permissions.write.check(&to)?;
|
||||
permissions.read.check(&from, Some("Deno.copyFile()"))?;
|
||||
permissions.write.check(&to, Some("Deno.copyFile()"))?;
|
||||
}
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
|
@ -1062,7 +1102,10 @@ fn op_stat_sync(
|
|||
out_buf: &mut [u32],
|
||||
) -> Result<(), AnyError> {
|
||||
let path = PathBuf::from(&path);
|
||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(&path, Some("Deno.statSync()"))?;
|
||||
let err_mapper = |err: Error| {
|
||||
Error::new(err.kind(), format!("{}, stat '{}'", err, path.display()))
|
||||
};
|
||||
|
@ -1088,7 +1131,10 @@ async fn op_stat_async(
|
|||
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(&path, Some("Deno.stat()"))?;
|
||||
}
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
|
@ -1115,9 +1161,13 @@ fn op_realpath_sync(
|
|||
let path = PathBuf::from(&path);
|
||||
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
permissions.read.check(&path)?;
|
||||
permissions.read.check(&path, Some("Deno.realPathSync()"))?;
|
||||
if path.is_relative() {
|
||||
permissions.read.check_blind(¤t_dir()?, "CWD")?;
|
||||
permissions.read.check_blind(
|
||||
¤t_dir()?,
|
||||
"CWD",
|
||||
"Deno.realPathSync()",
|
||||
)?;
|
||||
}
|
||||
|
||||
debug!("op_realpath_sync {}", path.display());
|
||||
|
@ -1138,9 +1188,13 @@ async fn op_realpath_async(
|
|||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
permissions.read.check(&path)?;
|
||||
permissions.read.check(&path, Some("Deno.realPath()"))?;
|
||||
if path.is_relative() {
|
||||
permissions.read.check_blind(¤t_dir()?, "CWD")?;
|
||||
permissions.read.check_blind(
|
||||
¤t_dir()?,
|
||||
"CWD",
|
||||
"Deno.realPath()",
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1172,7 +1226,10 @@ fn op_read_dir_sync(
|
|||
) -> Result<Vec<DirEntry>, AnyError> {
|
||||
let path = PathBuf::from(&path);
|
||||
|
||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(&path, Some("Deno.readDirSync()"))?;
|
||||
|
||||
debug!("op_read_dir_sync {}", path.display());
|
||||
let err_mapper = |err: Error| {
|
||||
|
@ -1213,7 +1270,10 @@ async fn op_read_dir_async(
|
|||
let path = PathBuf::from(&path);
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(&path, Some("Deno.readDir()"))?;
|
||||
}
|
||||
tokio::task::spawn_blocking(move || {
|
||||
debug!("op_read_dir_async {}", path.display());
|
||||
|
@ -1260,9 +1320,15 @@ fn op_rename_sync(
|
|||
let newpath = PathBuf::from(&newpath);
|
||||
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
permissions.read.check(&oldpath)?;
|
||||
permissions.write.check(&oldpath)?;
|
||||
permissions.write.check(&newpath)?;
|
||||
permissions
|
||||
.read
|
||||
.check(&oldpath, Some("Deno.renameSync()"))?;
|
||||
permissions
|
||||
.write
|
||||
.check(&oldpath, Some("Deno.renameSync()"))?;
|
||||
permissions
|
||||
.write
|
||||
.check(&newpath, Some("Deno.renameSync()"))?;
|
||||
|
||||
let err_mapper = |err: Error| {
|
||||
Error::new(
|
||||
|
@ -1290,9 +1356,9 @@ async fn op_rename_async(
|
|||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
permissions.read.check(&oldpath)?;
|
||||
permissions.write.check(&oldpath)?;
|
||||
permissions.write.check(&newpath)?;
|
||||
permissions.read.check(&oldpath, Some("Deno.rename()"))?;
|
||||
permissions.write.check(&oldpath, Some("Deno.rename()"))?;
|
||||
permissions.write.check(&newpath, Some("Deno.rename()"))?;
|
||||
}
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let err_mapper = |err: Error| {
|
||||
|
@ -1323,10 +1389,10 @@ fn op_link_sync(
|
|||
let newpath = PathBuf::from(&newpath);
|
||||
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
permissions.read.check(&oldpath)?;
|
||||
permissions.write.check(&oldpath)?;
|
||||
permissions.read.check(&newpath)?;
|
||||
permissions.write.check(&newpath)?;
|
||||
permissions.read.check(&oldpath, Some("Deno.linkSync()"))?;
|
||||
permissions.write.check(&oldpath, Some("Deno.linkSync()"))?;
|
||||
permissions.read.check(&newpath, Some("Deno.linkSync()"))?;
|
||||
permissions.write.check(&newpath, Some("Deno.linkSync()"))?;
|
||||
|
||||
let err_mapper = |err: Error| {
|
||||
Error::new(
|
||||
|
@ -1355,10 +1421,10 @@ async fn op_link_async(
|
|||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
permissions.read.check(&oldpath)?;
|
||||
permissions.write.check(&oldpath)?;
|
||||
permissions.read.check(&newpath)?;
|
||||
permissions.write.check(&newpath)?;
|
||||
permissions.read.check(&oldpath, Some("Deno.link()"))?;
|
||||
permissions.write.check(&oldpath, Some("Deno.link()"))?;
|
||||
permissions.read.check(&newpath, Some("Deno.link()"))?;
|
||||
permissions.write.check(&newpath, Some("Deno.link()"))?;
|
||||
}
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
|
@ -1390,8 +1456,14 @@ fn op_symlink_sync(
|
|||
let oldpath = PathBuf::from(&oldpath);
|
||||
let newpath = PathBuf::from(&newpath);
|
||||
|
||||
state.borrow_mut::<Permissions>().write.check_all()?;
|
||||
state.borrow_mut::<Permissions>().read.check_all()?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check_all(Some("Deno.symlinkSync()"))?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check_all(Some("Deno.symlinkSync()"))?;
|
||||
|
||||
let err_mapper = |err: Error| {
|
||||
Error::new(
|
||||
|
@ -1450,8 +1522,14 @@ async fn op_symlink_async(
|
|||
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().write.check_all()?;
|
||||
state.borrow_mut::<Permissions>().read.check_all()?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check_all(Some("Deno.symlink()"))?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check_all(Some("Deno.symlink()"))?;
|
||||
}
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
|
@ -1510,7 +1588,10 @@ fn op_read_link_sync(
|
|||
) -> Result<String, AnyError> {
|
||||
let path = PathBuf::from(&path);
|
||||
|
||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(&path, Some("Deno.readLink()"))?;
|
||||
|
||||
debug!("op_read_link_value {}", path.display());
|
||||
let err_mapper = |err: Error| {
|
||||
|
@ -1534,7 +1615,10 @@ async fn op_read_link_async(
|
|||
let path = PathBuf::from(&path);
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(&path, Some("Deno.readLink()"))?;
|
||||
}
|
||||
tokio::task::spawn_blocking(move || {
|
||||
debug!("op_read_link_async {}", path.display());
|
||||
|
@ -1590,7 +1674,10 @@ fn op_truncate_sync(
|
|||
) -> Result<(), AnyError> {
|
||||
let path = PathBuf::from(&path);
|
||||
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.truncateSync()"))?;
|
||||
|
||||
debug!("op_truncate_sync {} {}", path.display(), len);
|
||||
let err_mapper = |err: Error| {
|
||||
|
@ -1617,7 +1704,10 @@ async fn op_truncate_async(
|
|||
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.truncate()"))?;
|
||||
}
|
||||
tokio::task::spawn_blocking(move || {
|
||||
debug!("op_truncate_async {} {}", path.display(), len);
|
||||
|
@ -1700,10 +1790,10 @@ fn op_make_temp_dir_sync(
|
|||
let prefix = args.prefix.map(String::from);
|
||||
let suffix = args.suffix.map(String::from);
|
||||
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
||||
state.borrow_mut::<Permissions>().write.check(
|
||||
dir.clone().unwrap_or_else(temp_dir).as_path(),
|
||||
Some("Deno.makeTempDirSync()"),
|
||||
)?;
|
||||
|
||||
// TODO(piscisaureus): use byte vector for paths, not a string.
|
||||
// See https://github.com/denoland/deno/issues/627.
|
||||
|
@ -1730,10 +1820,10 @@ async fn op_make_temp_dir_async(
|
|||
let suffix = args.suffix.map(String::from);
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
||||
state.borrow_mut::<Permissions>().write.check(
|
||||
dir.clone().unwrap_or_else(temp_dir).as_path(),
|
||||
Some("Deno.makeTempDir()"),
|
||||
)?;
|
||||
}
|
||||
tokio::task::spawn_blocking(move || {
|
||||
// TODO(piscisaureus): use byte vector for paths, not a string.
|
||||
|
@ -1763,10 +1853,10 @@ fn op_make_temp_file_sync(
|
|||
let prefix = args.prefix.map(String::from);
|
||||
let suffix = args.suffix.map(String::from);
|
||||
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
||||
state.borrow_mut::<Permissions>().write.check(
|
||||
dir.clone().unwrap_or_else(temp_dir).as_path(),
|
||||
Some("Deno.makeTempFileSync()"),
|
||||
)?;
|
||||
|
||||
// TODO(piscisaureus): use byte vector for paths, not a string.
|
||||
// See https://github.com/denoland/deno/issues/627.
|
||||
|
@ -1793,10 +1883,10 @@ async fn op_make_temp_file_async(
|
|||
let suffix = args.suffix.map(String::from);
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(dir.clone().unwrap_or_else(temp_dir).as_path())?;
|
||||
state.borrow_mut::<Permissions>().write.check(
|
||||
dir.clone().unwrap_or_else(temp_dir).as_path(),
|
||||
Some("Deno.makeTempFile()"),
|
||||
)?;
|
||||
}
|
||||
tokio::task::spawn_blocking(move || {
|
||||
// TODO(piscisaureus): use byte vector for paths, not a string.
|
||||
|
@ -1873,7 +1963,10 @@ fn op_utime_sync(
|
|||
let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
|
||||
let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
|
||||
|
||||
state.borrow_mut::<Permissions>().write.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path, Some("Deno.utime()"))?;
|
||||
filetime::set_file_times(&path, atime, mtime).map_err(|err| {
|
||||
Error::new(err.kind(), format!("{}, utime '{}'", err, path.display()))
|
||||
})?;
|
||||
|
@ -1899,7 +1992,7 @@ async fn op_utime_async(
|
|||
.borrow_mut()
|
||||
.borrow_mut::<Permissions>()
|
||||
.write
|
||||
.check(&path)?;
|
||||
.check(&path, Some("Deno.utime()"))?;
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
filetime::set_file_times(&path, atime, mtime).map_err(|err| {
|
||||
|
@ -1914,10 +2007,11 @@ async fn op_utime_async(
|
|||
#[op]
|
||||
fn op_cwd(state: &mut OpState) -> Result<String, AnyError> {
|
||||
let path = current_dir()?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check_blind(&path, "CWD")?;
|
||||
state.borrow_mut::<Permissions>().read.check_blind(
|
||||
&path,
|
||||
"CWD",
|
||||
"Deno.cwd()",
|
||||
)?;
|
||||
let path_str = into_string(path.into_os_string())?;
|
||||
Ok(path_str)
|
||||
}
|
||||
|
@ -1929,7 +2023,7 @@ fn op_readfile_sync(
|
|||
) -> Result<ZeroCopyBuf, AnyError> {
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
let path = Path::new(&path);
|
||||
permissions.read.check(path)?;
|
||||
permissions.read.check(path, Some("Deno.readFileSync()"))?;
|
||||
Ok(std::fs::read(path)?.into())
|
||||
}
|
||||
|
||||
|
@ -1940,7 +2034,9 @@ fn op_readfile_text_sync(
|
|||
) -> Result<String, AnyError> {
|
||||
let permissions = state.borrow_mut::<Permissions>();
|
||||
let path = Path::new(&path);
|
||||
permissions.read.check(path)?;
|
||||
permissions
|
||||
.read
|
||||
.check(path, Some("Deno.readTextFileSync()"))?;
|
||||
Ok(string_from_utf8_lossy(std::fs::read(path)?))
|
||||
}
|
||||
|
||||
|
@ -1953,7 +2049,10 @@ async fn op_readfile_async(
|
|||
{
|
||||
let path = Path::new(&path);
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().read.check(path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(path, Some("Deno.readFile()"))?;
|
||||
}
|
||||
let fut = tokio::task::spawn_blocking(move || {
|
||||
let path = Path::new(&path);
|
||||
|
@ -1980,7 +2079,10 @@ async fn op_readfile_text_async(
|
|||
{
|
||||
let path = Path::new(&path);
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<Permissions>().read.check(path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(path, Some("Deno.readTextFile()"))?;
|
||||
}
|
||||
let fut = tokio::task::spawn_blocking(move || {
|
||||
let path = Path::new(&path);
|
||||
|
|
|
@ -118,7 +118,10 @@ fn op_fs_events_open(
|
|||
};
|
||||
for path in &args.paths {
|
||||
let path = PathBuf::from(path);
|
||||
state.borrow_mut::<Permissions>().read.check(&path)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check(&path, Some("Deno.watchFs()"))?;
|
||||
watcher.watch(&path, recursive_mode)?;
|
||||
}
|
||||
let resource = FsEventsResource {
|
||||
|
|
|
@ -61,10 +61,11 @@ fn noop_op() -> Result<(), AnyError> {
|
|||
#[op]
|
||||
fn op_exec_path(state: &mut OpState) -> Result<String, AnyError> {
|
||||
let current_exe = env::current_exe().unwrap();
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check_blind(¤t_exe, "exec_path")?;
|
||||
state.borrow_mut::<Permissions>().read.check_blind(
|
||||
¤t_exe,
|
||||
"exec_path",
|
||||
"Deno.execPath()",
|
||||
)?;
|
||||
// Now apply URL parser to current exe to get fully resolved path, otherwise
|
||||
// we might get `./` and `../` bits in `exec_path`
|
||||
let exe_url = Url::from_file_path(current_exe).unwrap();
|
||||
|
|
|
@ -144,7 +144,10 @@ struct RunInfo {
|
|||
#[op]
|
||||
fn op_run(state: &mut OpState, run_args: RunArgs) -> Result<RunInfo, AnyError> {
|
||||
let args = run_args.cmd;
|
||||
state.borrow_mut::<Permissions>().run.check(&args[0])?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.run
|
||||
.check(&args[0], Some("Deno.run()"))?;
|
||||
let env = run_args.env;
|
||||
let cwd = run_args.cwd;
|
||||
|
||||
|
@ -348,8 +351,12 @@ fn op_kill(
|
|||
state: &mut OpState,
|
||||
pid: i32,
|
||||
signal: String,
|
||||
api_name: String,
|
||||
) -> Result<(), AnyError> {
|
||||
state.borrow_mut::<Permissions>().run.check_all()?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.run
|
||||
.check_all(Some(&api_name))?;
|
||||
kill(pid, &signal)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -26,10 +26,11 @@ fn op_main_module(state: &mut OpState) -> Result<String, AnyError> {
|
|||
let main_path = std::env::current_dir()
|
||||
.context("Failed to get current working directory")?
|
||||
.join(main_url.to_string());
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.read
|
||||
.check_blind(&main_path, "main_module")?;
|
||||
state.borrow_mut::<Permissions>().read.check_blind(
|
||||
&main_path,
|
||||
"main_module",
|
||||
"Deno.mainModule",
|
||||
)?;
|
||||
}
|
||||
Ok(main)
|
||||
}
|
||||
|
|
|
@ -122,9 +122,13 @@ pub struct SpawnOutput {
|
|||
fn create_command(
|
||||
state: &mut OpState,
|
||||
args: SpawnArgs,
|
||||
api_name: &str,
|
||||
) -> Result<std::process::Command, AnyError> {
|
||||
super::check_unstable(state, "Deno.spawn");
|
||||
state.borrow_mut::<Permissions>().run.check(&args.cmd)?;
|
||||
state
|
||||
.borrow_mut::<Permissions>()
|
||||
.run
|
||||
.check(&args.cmd, Some(api_name))?;
|
||||
|
||||
let mut command = std::process::Command::new(args.cmd);
|
||||
command.args(args.args);
|
||||
|
@ -185,8 +189,10 @@ struct Child {
|
|||
fn op_spawn_child(
|
||||
state: &mut OpState,
|
||||
args: SpawnArgs,
|
||||
api_name: String,
|
||||
) -> Result<Child, AnyError> {
|
||||
let mut command = tokio::process::Command::from(create_command(state, args)?);
|
||||
let mut command =
|
||||
tokio::process::Command::from(create_command(state, args, &api_name)?);
|
||||
// TODO(@crowlkats): allow detaching processes.
|
||||
// currently deno will orphan a process when exiting with an error or Deno.exit()
|
||||
// We want to kill child when it's closed
|
||||
|
@ -246,7 +252,7 @@ fn op_spawn_sync(
|
|||
) -> Result<SpawnOutput, AnyError> {
|
||||
let stdout = matches!(args.stdio.stdout, Stdio::Piped);
|
||||
let stderr = matches!(args.stdio.stderr, Stdio::Piped);
|
||||
let output = create_command(state, args)?.output()?;
|
||||
let output = create_command(state, args, "Deno.spawnSync()")?.output()?;
|
||||
|
||||
Ok(SpawnOutput {
|
||||
status: output.status.try_into()?,
|
||||
|
|
|
@ -83,16 +83,18 @@ impl PermissionState {
|
|||
fn check(
|
||||
self,
|
||||
name: &str,
|
||||
api_name: Option<&str>,
|
||||
info: Option<&str>,
|
||||
prompt: bool,
|
||||
) -> (Result<(), AnyError>, bool) {
|
||||
self.check2(name, || info.map(|s| s.to_string()), prompt)
|
||||
self.check2(name, api_name, || info.map(|s| s.to_string()), prompt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check2(
|
||||
self,
|
||||
name: &str,
|
||||
api_name: Option<&str>,
|
||||
info: impl Fn() -> Option<String>,
|
||||
prompt: bool,
|
||||
) -> (Result<(), AnyError>, bool) {
|
||||
|
@ -107,7 +109,7 @@ impl PermissionState {
|
|||
name,
|
||||
info().map_or(String::new(), |info| { format!(" to {}", info) }),
|
||||
);
|
||||
if permission_prompt(&msg, name) {
|
||||
if permission_prompt(&msg, name, api_name) {
|
||||
Self::log_perm_access(name, info);
|
||||
(Ok(()), true)
|
||||
} else {
|
||||
|
@ -153,6 +155,7 @@ impl UnitPermission {
|
|||
if permission_prompt(
|
||||
&format!("access to {}", self.description),
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.state = PermissionState::Granted;
|
||||
} else {
|
||||
|
@ -170,7 +173,8 @@ impl UnitPermission {
|
|||
}
|
||||
|
||||
pub fn check(&mut self) -> Result<(), AnyError> {
|
||||
let (result, prompted) = self.state.check(self.name, None, self.prompt);
|
||||
let (result, prompted) =
|
||||
self.state.check(self.name, None, None, self.prompt);
|
||||
if prompted {
|
||||
if result.is_ok() {
|
||||
self.state = PermissionState::Granted;
|
||||
|
@ -339,6 +343,7 @@ impl UnaryPermission<ReadDescriptor> {
|
|||
if permission_prompt(
|
||||
&format!("read access to \"{}\"", display_path.display()),
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.insert(ReadDescriptor(resolved_path));
|
||||
PermissionState::Granted
|
||||
|
@ -356,7 +361,11 @@ impl UnaryPermission<ReadDescriptor> {
|
|||
} else {
|
||||
let state = self.query(None);
|
||||
if state == PermissionState::Prompt {
|
||||
if permission_prompt("read access", self.name) {
|
||||
if permission_prompt(
|
||||
"read access",
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.clear();
|
||||
self.global_state = PermissionState::Granted;
|
||||
PermissionState::Granted
|
||||
|
@ -386,9 +395,14 @@ impl UnaryPermission<ReadDescriptor> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn check(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||
pub fn check(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
let (result, prompted) = self.query(Some(path)).check2(
|
||||
self.name,
|
||||
api_name,
|
||||
|| Some(format!("\"{}\"", path.to_path_buf().display())),
|
||||
self.prompt,
|
||||
);
|
||||
|
@ -410,10 +424,12 @@ impl UnaryPermission<ReadDescriptor> {
|
|||
&mut self,
|
||||
path: &Path,
|
||||
display: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
let resolved_path = resolve_from_cwd(path).unwrap();
|
||||
let (result, prompted) = self.query(Some(&resolved_path)).check(
|
||||
self.name,
|
||||
Some(api_name),
|
||||
Some(&format!("<{}>", display)),
|
||||
self.prompt,
|
||||
);
|
||||
|
@ -428,9 +444,11 @@ impl UnaryPermission<ReadDescriptor> {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
||||
let (result, prompted) =
|
||||
self.query(None).check(self.name, Some("all"), self.prompt);
|
||||
self
|
||||
.query(None)
|
||||
.check(self.name, api_name, Some("all"), self.prompt);
|
||||
if prompted {
|
||||
if result.is_ok() {
|
||||
self.global_state = PermissionState::Granted;
|
||||
|
@ -494,6 +512,7 @@ impl UnaryPermission<WriteDescriptor> {
|
|||
if permission_prompt(
|
||||
&format!("write access to \"{}\"", display_path.display()),
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.insert(WriteDescriptor(resolved_path));
|
||||
PermissionState::Granted
|
||||
|
@ -511,7 +530,11 @@ impl UnaryPermission<WriteDescriptor> {
|
|||
} else {
|
||||
let state = self.query(None);
|
||||
if state == PermissionState::Prompt {
|
||||
if permission_prompt("write access", self.name) {
|
||||
if permission_prompt(
|
||||
"write access",
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.clear();
|
||||
self.global_state = PermissionState::Granted;
|
||||
PermissionState::Granted
|
||||
|
@ -541,9 +564,14 @@ impl UnaryPermission<WriteDescriptor> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn check(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||
pub fn check(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
let (result, prompted) = self.query(Some(path)).check2(
|
||||
self.name,
|
||||
api_name,
|
||||
|| Some(format!("\"{}\"", path.to_path_buf().display())),
|
||||
self.prompt,
|
||||
);
|
||||
|
@ -559,9 +587,11 @@ impl UnaryPermission<WriteDescriptor> {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
||||
let (result, prompted) =
|
||||
self.query(None).check(self.name, Some("all"), self.prompt);
|
||||
self
|
||||
.query(None)
|
||||
.check(self.name, api_name, Some("all"), self.prompt);
|
||||
if prompted {
|
||||
if result.is_ok() {
|
||||
self.global_state = PermissionState::Granted;
|
||||
|
@ -633,6 +663,7 @@ impl UnaryPermission<NetDescriptor> {
|
|||
if permission_prompt(
|
||||
&format!("network access to \"{}\"", host),
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.insert(host);
|
||||
PermissionState::Granted
|
||||
|
@ -650,7 +681,11 @@ impl UnaryPermission<NetDescriptor> {
|
|||
} else {
|
||||
let state = self.query::<&str>(None);
|
||||
if state == PermissionState::Prompt {
|
||||
if permission_prompt("network access", self.name) {
|
||||
if permission_prompt(
|
||||
"network access",
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.clear();
|
||||
self.global_state = PermissionState::Granted;
|
||||
PermissionState::Granted
|
||||
|
@ -689,10 +724,12 @@ impl UnaryPermission<NetDescriptor> {
|
|||
pub fn check<T: AsRef<str>>(
|
||||
&mut self,
|
||||
host: &(T, Option<u16>),
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
let new_host = NetDescriptor::new(&host);
|
||||
let (result, prompted) = self.query(Some(host)).check(
|
||||
self.name,
|
||||
api_name,
|
||||
Some(&format!("\"{}\"", new_host)),
|
||||
self.prompt,
|
||||
);
|
||||
|
@ -707,7 +744,11 @@ impl UnaryPermission<NetDescriptor> {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn check_url(&mut self, url: &url::Url) -> Result<(), AnyError> {
|
||||
pub fn check_url(
|
||||
&mut self,
|
||||
url: &url::Url,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
let hostname = url
|
||||
.host_str()
|
||||
.ok_or_else(|| uri_error("Missing host"))?
|
||||
|
@ -719,6 +760,7 @@ impl UnaryPermission<NetDescriptor> {
|
|||
let host = &(&hostname, url.port_or_known_default());
|
||||
let (result, prompted) = self.query(Some(host)).check(
|
||||
self.name,
|
||||
api_name,
|
||||
Some(&format!("\"{}\"", display_host)),
|
||||
self.prompt,
|
||||
);
|
||||
|
@ -737,7 +779,7 @@ impl UnaryPermission<NetDescriptor> {
|
|||
let (result, prompted) =
|
||||
self
|
||||
.query::<&str>(None)
|
||||
.check(self.name, Some("all"), self.prompt);
|
||||
.check(self.name, None, Some("all"), self.prompt);
|
||||
if prompted {
|
||||
if result.is_ok() {
|
||||
self.global_state = PermissionState::Granted;
|
||||
|
@ -788,7 +830,11 @@ impl UnaryPermission<EnvDescriptor> {
|
|||
if let Some(env) = env {
|
||||
let state = self.query(Some(env));
|
||||
if state == PermissionState::Prompt {
|
||||
if permission_prompt(&format!("env access to \"{}\"", env), self.name) {
|
||||
if permission_prompt(
|
||||
&format!("env access to \"{}\"", env),
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.insert(EnvDescriptor::new(env));
|
||||
PermissionState::Granted
|
||||
} else {
|
||||
|
@ -805,7 +851,11 @@ impl UnaryPermission<EnvDescriptor> {
|
|||
} else {
|
||||
let state = self.query(None);
|
||||
if state == PermissionState::Prompt {
|
||||
if permission_prompt("env access", self.name) {
|
||||
if permission_prompt(
|
||||
"env access",
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.clear();
|
||||
self.global_state = PermissionState::Granted;
|
||||
PermissionState::Granted
|
||||
|
@ -834,6 +884,7 @@ impl UnaryPermission<EnvDescriptor> {
|
|||
pub fn check(&mut self, env: &str) -> Result<(), AnyError> {
|
||||
let (result, prompted) = self.query(Some(env)).check(
|
||||
self.name,
|
||||
None,
|
||||
Some(&format!("\"{}\"", env)),
|
||||
self.prompt,
|
||||
);
|
||||
|
@ -850,7 +901,9 @@ impl UnaryPermission<EnvDescriptor> {
|
|||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
let (result, prompted) =
|
||||
self.query(None).check(self.name, Some("all"), self.prompt);
|
||||
self
|
||||
.query(None)
|
||||
.check(self.name, None, Some("all"), self.prompt);
|
||||
if prompted {
|
||||
if result.is_ok() {
|
||||
self.global_state = PermissionState::Granted;
|
||||
|
@ -904,7 +957,11 @@ impl UnaryPermission<RunDescriptor> {
|
|||
if let Some(cmd) = cmd {
|
||||
let state = self.query(Some(cmd));
|
||||
if state == PermissionState::Prompt {
|
||||
if permission_prompt(&format!("run access to \"{}\"", cmd), self.name) {
|
||||
if permission_prompt(
|
||||
&format!("run access to \"{}\"", cmd),
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self
|
||||
.granted_list
|
||||
.insert(RunDescriptor::from_str(cmd).unwrap());
|
||||
|
@ -927,7 +984,11 @@ impl UnaryPermission<RunDescriptor> {
|
|||
} else {
|
||||
let state = self.query(None);
|
||||
if state == PermissionState::Prompt {
|
||||
if permission_prompt("run access", self.name) {
|
||||
if permission_prompt(
|
||||
"run access",
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.clear();
|
||||
self.global_state = PermissionState::Granted;
|
||||
PermissionState::Granted
|
||||
|
@ -955,9 +1016,14 @@ impl UnaryPermission<RunDescriptor> {
|
|||
self.query(cmd)
|
||||
}
|
||||
|
||||
pub fn check(&mut self, cmd: &str) -> Result<(), AnyError> {
|
||||
pub fn check(
|
||||
&mut self,
|
||||
cmd: &str,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
let (result, prompted) = self.query(Some(cmd)).check(
|
||||
self.name,
|
||||
api_name,
|
||||
Some(&format!("\"{}\"", cmd)),
|
||||
self.prompt,
|
||||
);
|
||||
|
@ -976,9 +1042,11 @@ impl UnaryPermission<RunDescriptor> {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
||||
let (result, prompted) =
|
||||
self.query(None).check(self.name, Some("all"), self.prompt);
|
||||
self
|
||||
.query(None)
|
||||
.check(self.name, api_name, Some("all"), self.prompt);
|
||||
if prompted {
|
||||
if result.is_ok() {
|
||||
self.global_state = PermissionState::Granted;
|
||||
|
@ -1033,6 +1101,7 @@ impl UnaryPermission<FfiDescriptor> {
|
|||
if permission_prompt(
|
||||
&format!("ffi access to \"{}\"", display_path.display()),
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.insert(FfiDescriptor(resolved_path));
|
||||
PermissionState::Granted
|
||||
|
@ -1050,7 +1119,11 @@ impl UnaryPermission<FfiDescriptor> {
|
|||
} else {
|
||||
let state = self.query(None);
|
||||
if state == PermissionState::Prompt {
|
||||
if permission_prompt("ffi access", self.name) {
|
||||
if permission_prompt(
|
||||
"ffi access",
|
||||
self.name,
|
||||
Some("Deno.permissions.query()"),
|
||||
) {
|
||||
self.granted_list.clear();
|
||||
self.global_state = PermissionState::Granted;
|
||||
PermissionState::Granted
|
||||
|
@ -1082,6 +1155,7 @@ impl UnaryPermission<FfiDescriptor> {
|
|||
let (resolved_path, display_path) = resolved_and_display_path(path);
|
||||
let (result, prompted) = self.query(Some(&resolved_path)).check(
|
||||
self.name,
|
||||
None,
|
||||
Some(&format!("\"{}\"", display_path.display())),
|
||||
self.prompt,
|
||||
);
|
||||
|
@ -1098,7 +1172,7 @@ impl UnaryPermission<FfiDescriptor> {
|
|||
result
|
||||
} else {
|
||||
let (result, prompted) =
|
||||
self.query(None).check(self.name, None, self.prompt);
|
||||
self.query(None).check(self.name, None, None, self.prompt);
|
||||
|
||||
if prompted {
|
||||
if result.is_ok() {
|
||||
|
@ -1114,7 +1188,9 @@ impl UnaryPermission<FfiDescriptor> {
|
|||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
let (result, prompted) =
|
||||
self.query(None).check(self.name, Some("all"), self.prompt);
|
||||
self
|
||||
.query(None)
|
||||
.check(self.name, None, Some("all"), self.prompt);
|
||||
if prompted {
|
||||
if result.is_ok() {
|
||||
self.global_state = PermissionState::Granted;
|
||||
|
@ -1323,7 +1399,7 @@ impl Permissions {
|
|||
) -> Result<(), AnyError> {
|
||||
match specifier.scheme() {
|
||||
"file" => match specifier.to_file_path() {
|
||||
Ok(path) => self.read.check(&path),
|
||||
Ok(path) => self.read.check(&path, None),
|
||||
Err(_) => Err(uri_error(format!(
|
||||
"Invalid file path.\n Specifier: {}",
|
||||
specifier
|
||||
|
@ -1331,7 +1407,7 @@ impl Permissions {
|
|||
},
|
||||
"data" => Ok(()),
|
||||
"blob" => Ok(()),
|
||||
_ => self.net.check_url(specifier),
|
||||
_ => self.net.check_url(specifier, None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1340,14 +1416,15 @@ impl deno_flash::FlashPermissions for Permissions {
|
|||
fn check_net<T: AsRef<str>>(
|
||||
&mut self,
|
||||
host: &(T, Option<u16>),
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
self.net.check(host)
|
||||
self.net.check(host, Some(api_name))
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_node::NodePermissions for Permissions {
|
||||
fn check_read(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||
self.read.check(path)
|
||||
self.read.check(path, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1355,26 +1432,43 @@ impl deno_net::NetPermissions for Permissions {
|
|||
fn check_net<T: AsRef<str>>(
|
||||
&mut self,
|
||||
host: &(T, Option<u16>),
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
self.net.check(host)
|
||||
self.net.check(host, Some(api_name))
|
||||
}
|
||||
|
||||
fn check_read(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||
self.read.check(path)
|
||||
fn check_read(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
self.read.check(path, Some(api_name))
|
||||
}
|
||||
|
||||
fn check_write(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||
self.write.check(path)
|
||||
fn check_write(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
self.write.check(path, Some(api_name))
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_fetch::FetchPermissions for Permissions {
|
||||
fn check_net_url(&mut self, url: &url::Url) -> Result<(), AnyError> {
|
||||
self.net.check_url(url)
|
||||
fn check_net_url(
|
||||
&mut self,
|
||||
url: &url::Url,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
self.net.check_url(url, Some(api_name))
|
||||
}
|
||||
|
||||
fn check_read(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||
self.read.check(path)
|
||||
fn check_read(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
self.read.check(path, Some(api_name))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1389,8 +1483,12 @@ impl deno_web::TimersPermission for Permissions {
|
|||
}
|
||||
|
||||
impl deno_websocket::WebSocketPermissions for Permissions {
|
||||
fn check_net_url(&mut self, url: &url::Url) -> Result<(), AnyError> {
|
||||
self.net.check_url(url)
|
||||
fn check_net_url(
|
||||
&mut self,
|
||||
url: &url::Url,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
self.net.check_url(url, Some(api_name))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1808,7 +1906,7 @@ pub fn create_child_permissions(
|
|||
.net
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.net.check(&(&desc.0, desc.1)).is_ok())
|
||||
.all(|desc| main_perms.net.check(&(&desc.0, desc.1), None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
|
@ -1856,7 +1954,7 @@ pub fn create_child_permissions(
|
|||
worker_perms.read = main_perms.read.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.read.check_all().is_err() {
|
||||
if main_perms.read.check_all(None).is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.read.global_state = PermissionState::Granted;
|
||||
|
@ -1872,7 +1970,7 @@ pub fn create_child_permissions(
|
|||
.read
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.read.check(&desc.0).is_ok())
|
||||
.all(|desc| main_perms.read.check(&desc.0, None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
|
@ -1888,7 +1986,7 @@ pub fn create_child_permissions(
|
|||
worker_perms.run = main_perms.run.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.run.check_all().is_err() {
|
||||
if main_perms.run.check_all(None).is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.run.global_state = PermissionState::Granted;
|
||||
|
@ -1901,7 +1999,7 @@ pub fn create_child_permissions(
|
|||
.run
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.run.check(&desc.to_string()).is_ok())
|
||||
.all(|desc| main_perms.run.check(&desc.to_string(), None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
|
@ -1917,7 +2015,7 @@ pub fn create_child_permissions(
|
|||
worker_perms.write = main_perms.write.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.write.check_all().is_err() {
|
||||
if main_perms.write.check_all(None).is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.write.global_state = PermissionState::Granted;
|
||||
|
@ -1933,7 +2031,7 @@ pub fn create_child_permissions(
|
|||
.write
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.write.check(&desc.0).is_ok())
|
||||
.all(|desc| main_perms.write.check(&desc.0, None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
|
@ -1950,7 +2048,11 @@ pub fn create_child_permissions(
|
|||
/// Shows the permission prompt and returns the answer according to the user input.
|
||||
/// This loops until the user gives the proper input.
|
||||
#[cfg(not(test))]
|
||||
fn permission_prompt(message: &str, name: &str) -> bool {
|
||||
fn permission_prompt(
|
||||
message: &str,
|
||||
name: &str,
|
||||
api_name: Option<&str>,
|
||||
) -> bool {
|
||||
if !atty::is(atty::Stream::Stdin) || !atty::is(atty::Stream::Stderr) {
|
||||
return false;
|
||||
};
|
||||
|
@ -2084,6 +2186,9 @@ fn permission_prompt(message: &str, name: &str) -> bool {
|
|||
eprint!("{}", colors::bold("Deno requests "));
|
||||
eprint!("{}", colors::bold(message));
|
||||
eprintln!("{}", colors::bold("."));
|
||||
if let Some(api_name) = api_name {
|
||||
eprintln!(" ├ Requested by `{}` API", api_name);
|
||||
}
|
||||
let msg = format!(
|
||||
" ├ Run again with --allow-{} to bypass this prompt.",
|
||||
name
|
||||
|
@ -2104,13 +2209,13 @@ fn permission_prompt(message: &str, name: &str) -> bool {
|
|||
};
|
||||
match ch.to_ascii_lowercase() {
|
||||
'y' => {
|
||||
clear_n_lines(3);
|
||||
clear_n_lines(if api_name.is_some() { 4 } else { 3 });
|
||||
let msg = format!("Granted {}.", message);
|
||||
eprintln!("✅ {}", colors::bold(&msg));
|
||||
return true;
|
||||
}
|
||||
'n' => {
|
||||
clear_n_lines(3);
|
||||
clear_n_lines(if api_name.is_some() { 4 } else { 3 });
|
||||
let msg = format!("Denied {}.", message);
|
||||
eprintln!("❌ {}", colors::bold(&msg));
|
||||
return false;
|
||||
|
@ -2128,7 +2233,11 @@ fn permission_prompt(message: &str, name: &str) -> bool {
|
|||
// When testing, permission prompt returns the value of STUB_PROMPT_VALUE
|
||||
// which we set from the test functions.
|
||||
#[cfg(test)]
|
||||
fn permission_prompt(_message: &str, _flag: &str) -> bool {
|
||||
fn permission_prompt(
|
||||
_message: &str,
|
||||
_flag: &str,
|
||||
_api_name: Option<&str>,
|
||||
) -> bool {
|
||||
STUB_PROMPT_VALUE.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
|
@ -2177,55 +2286,67 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
// Inside of /a/specific and /a/specific/dir/name
|
||||
assert!(perms.read.check(Path::new("/a/specific/dir/name")).is_ok());
|
||||
assert!(perms.write.check(Path::new("/a/specific/dir/name")).is_ok());
|
||||
assert!(perms
|
||||
.read
|
||||
.check(Path::new("/a/specific/dir/name"), None)
|
||||
.is_ok());
|
||||
assert!(perms
|
||||
.write
|
||||
.check(Path::new("/a/specific/dir/name"), None)
|
||||
.is_ok());
|
||||
|
||||
// Inside of /a/specific but outside of /a/specific/dir/name
|
||||
assert!(perms.read.check(Path::new("/a/specific/dir")).is_ok());
|
||||
assert!(perms.write.check(Path::new("/a/specific/dir")).is_ok());
|
||||
assert!(perms.read.check(Path::new("/a/specific/dir"), None).is_ok());
|
||||
assert!(perms
|
||||
.write
|
||||
.check(Path::new("/a/specific/dir"), None)
|
||||
.is_ok());
|
||||
|
||||
// Inside of /a/specific and /a/specific/dir/name
|
||||
assert!(perms
|
||||
.read
|
||||
.check(Path::new("/a/specific/dir/name/inner"))
|
||||
.check(Path::new("/a/specific/dir/name/inner"), None)
|
||||
.is_ok());
|
||||
assert!(perms
|
||||
.write
|
||||
.check(Path::new("/a/specific/dir/name/inner"))
|
||||
.check(Path::new("/a/specific/dir/name/inner"), None)
|
||||
.is_ok());
|
||||
|
||||
// Inside of /a/specific but outside of /a/specific/dir/name
|
||||
assert!(perms.read.check(Path::new("/a/specific/other/dir")).is_ok());
|
||||
assert!(perms
|
||||
.read
|
||||
.check(Path::new("/a/specific/other/dir"), None)
|
||||
.is_ok());
|
||||
assert!(perms
|
||||
.write
|
||||
.check(Path::new("/a/specific/other/dir"))
|
||||
.check(Path::new("/a/specific/other/dir"), None)
|
||||
.is_ok());
|
||||
|
||||
// Exact match with /b/c
|
||||
assert!(perms.read.check(Path::new("/b/c")).is_ok());
|
||||
assert!(perms.write.check(Path::new("/b/c")).is_ok());
|
||||
assert!(perms.read.check(Path::new("/b/c"), None).is_ok());
|
||||
assert!(perms.write.check(Path::new("/b/c"), None).is_ok());
|
||||
|
||||
// Sub path within /b/c
|
||||
assert!(perms.read.check(Path::new("/b/c/sub/path")).is_ok());
|
||||
assert!(perms.write.check(Path::new("/b/c/sub/path")).is_ok());
|
||||
assert!(perms.read.check(Path::new("/b/c/sub/path"), None).is_ok());
|
||||
assert!(perms.write.check(Path::new("/b/c/sub/path"), None).is_ok());
|
||||
|
||||
// Sub path within /b/c, needs normalizing
|
||||
assert!(perms
|
||||
.read
|
||||
.check(Path::new("/b/c/sub/path/../path/."))
|
||||
.check(Path::new("/b/c/sub/path/../path/."), None)
|
||||
.is_ok());
|
||||
assert!(perms
|
||||
.write
|
||||
.check(Path::new("/b/c/sub/path/../path/."))
|
||||
.check(Path::new("/b/c/sub/path/../path/."), None)
|
||||
.is_ok());
|
||||
|
||||
// Inside of /b but outside of /b/c
|
||||
assert!(perms.read.check(Path::new("/b/e")).is_err());
|
||||
assert!(perms.write.check(Path::new("/b/e")).is_err());
|
||||
assert!(perms.read.check(Path::new("/b/e"), None).is_err());
|
||||
assert!(perms.write.check(Path::new("/b/e"), None).is_err());
|
||||
|
||||
// Inside of /a but outside of /a/specific
|
||||
assert!(perms.read.check(Path::new("/a/b")).is_err());
|
||||
assert!(perms.write.check(Path::new("/a/b")).is_err());
|
||||
assert!(perms.read.check(Path::new("/a/b"), None).is_err());
|
||||
assert!(perms.write.check(Path::new("/a/b"), None).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2267,7 +2388,7 @@ mod tests {
|
|||
];
|
||||
|
||||
for (host, port, is_ok) in domain_tests {
|
||||
assert_eq!(is_ok, perms.net.check(&(host, Some(port))).is_ok());
|
||||
assert_eq!(is_ok, perms.net.check(&(host, Some(port)), None).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2302,7 +2423,7 @@ mod tests {
|
|||
];
|
||||
|
||||
for (host, port) in domain_tests {
|
||||
assert!(perms.net.check(&(host, Some(port))).is_ok());
|
||||
assert!(perms.net.check(&(host, Some(port)), None).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2337,7 +2458,7 @@ mod tests {
|
|||
];
|
||||
|
||||
for (host, port) in domain_tests {
|
||||
assert!(perms.net.check(&(host, Some(port))).is_err());
|
||||
assert!(perms.net.check(&(host, Some(port)), None).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2397,7 +2518,7 @@ mod tests {
|
|||
|
||||
for (url_str, is_ok) in url_tests {
|
||||
let u = url::Url::parse(url_str).unwrap();
|
||||
assert_eq!(is_ok, perms.net.check_url(&u).is_ok());
|
||||
assert_eq!(is_ok, perms.net.check_url(&u, None).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2654,31 +2775,31 @@ mod tests {
|
|||
let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
|
||||
|
||||
prompt_value.set(true);
|
||||
assert!(perms.read.check(Path::new("/foo")).is_ok());
|
||||
assert!(perms.read.check(Path::new("/foo"), None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.read.check(Path::new("/foo")).is_ok());
|
||||
assert!(perms.read.check(Path::new("/bar")).is_err());
|
||||
assert!(perms.read.check(Path::new("/foo"), None).is_ok());
|
||||
assert!(perms.read.check(Path::new("/bar"), None).is_err());
|
||||
|
||||
prompt_value.set(true);
|
||||
assert!(perms.write.check(Path::new("/foo")).is_ok());
|
||||
assert!(perms.write.check(Path::new("/foo"), None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.write.check(Path::new("/foo")).is_ok());
|
||||
assert!(perms.write.check(Path::new("/bar")).is_err());
|
||||
assert!(perms.write.check(Path::new("/foo"), None).is_ok());
|
||||
assert!(perms.write.check(Path::new("/bar"), None).is_err());
|
||||
|
||||
prompt_value.set(true);
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8000))).is_ok());
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8000)), None).is_ok());
|
||||
prompt_value.set(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());
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8000)), None).is_ok());
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8001)), None).is_err());
|
||||
assert!(perms.net.check(&("127.0.0.1", None), None).is_err());
|
||||
assert!(perms.net.check(&("deno.land", Some(8000)), None).is_err());
|
||||
assert!(perms.net.check(&("deno.land", None), None).is_err());
|
||||
|
||||
prompt_value.set(true);
|
||||
assert!(perms.run.check("cat").is_ok());
|
||||
assert!(perms.run.check("cat", None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.run.check("cat").is_ok());
|
||||
assert!(perms.run.check("ls").is_err());
|
||||
assert!(perms.run.check("cat", None).is_ok());
|
||||
assert!(perms.run.check("ls", None).is_err());
|
||||
|
||||
prompt_value.set(true);
|
||||
assert!(perms.env.check("HOME").is_ok());
|
||||
|
@ -2704,38 +2825,38 @@ mod tests {
|
|||
let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
|
||||
|
||||
prompt_value.set(false);
|
||||
assert!(perms.read.check(Path::new("/foo")).is_err());
|
||||
assert!(perms.read.check(Path::new("/foo"), None).is_err());
|
||||
prompt_value.set(true);
|
||||
assert!(perms.read.check(Path::new("/foo")).is_err());
|
||||
assert!(perms.read.check(Path::new("/bar")).is_ok());
|
||||
assert!(perms.read.check(Path::new("/foo"), None).is_err());
|
||||
assert!(perms.read.check(Path::new("/bar"), None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.read.check(Path::new("/bar")).is_ok());
|
||||
assert!(perms.read.check(Path::new("/bar"), None).is_ok());
|
||||
|
||||
prompt_value.set(false);
|
||||
assert!(perms.write.check(Path::new("/foo")).is_err());
|
||||
assert!(perms.write.check(Path::new("/foo"), None).is_err());
|
||||
prompt_value.set(true);
|
||||
assert!(perms.write.check(Path::new("/foo")).is_err());
|
||||
assert!(perms.write.check(Path::new("/bar")).is_ok());
|
||||
assert!(perms.write.check(Path::new("/foo"), None).is_err());
|
||||
assert!(perms.write.check(Path::new("/bar"), None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.write.check(Path::new("/bar")).is_ok());
|
||||
assert!(perms.write.check(Path::new("/bar"), None).is_ok());
|
||||
|
||||
prompt_value.set(false);
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8000))).is_err());
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8000)), None).is_err());
|
||||
prompt_value.set(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());
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8000)), None).is_err());
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8001)), None).is_ok());
|
||||
assert!(perms.net.check(&("deno.land", Some(8000)), None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8001))).is_ok());
|
||||
assert!(perms.net.check(&("deno.land", Some(8000))).is_ok());
|
||||
assert!(perms.net.check(&("127.0.0.1", Some(8001)), None).is_ok());
|
||||
assert!(perms.net.check(&("deno.land", Some(8000)), None).is_ok());
|
||||
|
||||
prompt_value.set(false);
|
||||
assert!(perms.run.check("cat").is_err());
|
||||
assert!(perms.run.check("cat", None).is_err());
|
||||
prompt_value.set(true);
|
||||
assert!(perms.run.check("cat").is_err());
|
||||
assert!(perms.run.check("ls").is_ok());
|
||||
assert!(perms.run.check("cat", None).is_err());
|
||||
assert!(perms.run.check("ls", None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.run.check("ls").is_ok());
|
||||
assert!(perms.run.check("ls", None).is_ok());
|
||||
|
||||
prompt_value.set(false);
|
||||
assert!(perms.env.check("HOME").is_err());
|
||||
|
@ -2995,7 +3116,7 @@ mod tests {
|
|||
})
|
||||
.unwrap();
|
||||
prompt_value.set(false);
|
||||
assert!(main_perms.write.check(&PathBuf::from("foo")).is_err());
|
||||
assert!(main_perms.write.check(&PathBuf::from("foo"), None).is_err());
|
||||
let worker_perms = create_child_permissions(
|
||||
&mut main_perms.clone(),
|
||||
ChildPermissionsArg::none(),
|
||||
|
|
Loading…
Reference in a new issue