1use std::borrow::Cow;
4use std::collections::HashSet;
5use std::ffi::OsStr;
6use std::fmt;
7use std::fmt::Debug;
8use std::hash::Hash;
9use std::net::IpAddr;
10use std::net::Ipv6Addr;
11use std::path::Path;
12use std::path::PathBuf;
13use std::string::ToString;
14use std::sync::Arc;
15
16use capacity_builder::StringBuilder;
17use deno_core::parking_lot::Mutex;
18use deno_core::serde::de;
19use deno_core::serde::Deserialize;
20use deno_core::serde::Deserializer;
21use deno_core::serde::Serialize;
22use deno_core::serde_json;
23use deno_core::unsync::sync::AtomicFlag;
24use deno_core::url::Url;
25use deno_core::ModuleSpecifier;
26use deno_path_util::normalize_path;
27use deno_path_util::url_to_file_path;
28use deno_terminal::colors;
29use fqdn::FQDN;
30use once_cell::sync::Lazy;
31
32pub mod prompter;
33use prompter::permission_prompt;
34pub use prompter::set_prompt_callbacks;
35pub use prompter::set_prompter;
36pub use prompter::PermissionPrompter;
37pub use prompter::PromptCallback;
38pub use prompter::PromptResponse;
39use prompter::PERMISSION_EMOJI;
40
41#[derive(Debug, thiserror::Error)]
42pub enum PermissionDeniedError {
43 #[error("Requires {access}, {}", format_permission_error(.name))]
44 Retryable { access: String, name: &'static str },
45 #[error("Requires {access}, which cannot be granted in this environment")]
46 Fatal { access: String },
47}
48
49fn format_permission_error(name: &'static str) -> String {
50 if is_standalone() {
51 format!("specify the required permissions during compilation using `deno compile --allow-{name}`")
52 } else {
53 format!("run again with the --allow-{name} flag")
54 }
55}
56
57macro_rules! skip_check_if_is_permission_fully_granted {
60 ($this:ident) => {
61 if $this.is_allow_all() {
62 return Ok(());
63 }
64 };
65}
66
67#[inline]
68fn resolve_from_known_cwd(path: &Path, cwd: &Path) -> PathBuf {
69 if path.is_absolute() {
70 normalize_path(path)
71 } else {
72 normalize_path(cwd.join(path))
73 }
74}
75
76static DEBUG_LOG_ENABLED: Lazy<bool> =
77 Lazy::new(|| log::log_enabled!(log::Level::Debug));
78
79#[derive(
81 Eq, PartialEq, Default, Debug, Clone, Copy, Deserialize, PartialOrd,
82)]
83pub enum PermissionState {
84 Granted = 0,
85 GrantedPartial = 1,
86 #[default]
87 Prompt = 2,
88 Denied = 3,
89}
90
91#[derive(Debug, Eq, PartialEq)]
99#[allow(clippy::enum_variant_names)]
100enum AllowPartial {
101 TreatAsGranted,
102 TreatAsDenied,
103 TreatAsPartialGranted,
104}
105
106impl From<bool> for AllowPartial {
107 fn from(value: bool) -> Self {
108 if value {
109 Self::TreatAsGranted
110 } else {
111 Self::TreatAsDenied
112 }
113 }
114}
115
116impl PermissionState {
117 #[inline(always)]
118 fn log_perm_access(
119 name: &'static str,
120 info: impl FnOnce() -> Option<String>,
121 ) {
122 if *DEBUG_LOG_ENABLED {
126 log::debug!(
127 "{}",
128 colors::bold(&format!(
129 "{}️ Granted {}",
130 PERMISSION_EMOJI,
131 Self::fmt_access(name, info)
132 ))
133 );
134 }
135 }
136
137 fn fmt_access(
138 name: &'static str,
139 info: impl FnOnce() -> Option<String>,
140 ) -> String {
141 format!(
142 "{} access{}",
143 name,
144 info().map(|info| format!(" to {info}")).unwrap_or_default(),
145 )
146 }
147
148 fn retryable_error(
149 name: &'static str,
150 info: impl FnOnce() -> Option<String>,
151 ) -> PermissionDeniedError {
152 PermissionDeniedError::Retryable {
153 access: Self::fmt_access(name, info),
154 name,
155 }
156 }
157
158 #[inline]
160 fn check(
161 self,
162 name: &'static str,
163 api_name: Option<&str>,
164 info: Option<&str>,
165 prompt: bool,
166 ) -> (Result<(), PermissionDeniedError>, bool, bool) {
167 self.check2(name, api_name, || info.map(|s| s.to_string()), prompt)
168 }
169
170 #[inline]
171 fn check2(
172 self,
173 name: &'static str,
174 api_name: Option<&str>,
175 info: impl Fn() -> Option<String>,
176 prompt: bool,
177 ) -> (Result<(), PermissionDeniedError>, bool, bool) {
178 match self {
179 PermissionState::Granted => {
180 Self::log_perm_access(name, info);
181 (Ok(()), false, false)
182 }
183 PermissionState::Prompt if prompt => {
184 let msg = {
185 let info = info();
186 StringBuilder::<String>::build(|builder| {
187 builder.append(name);
188 builder.append(" access");
189 if let Some(info) = &info {
190 builder.append(" to ");
191 builder.append(info);
192 }
193 })
194 .unwrap()
195 };
196 match permission_prompt(&msg, name, api_name, true) {
197 PromptResponse::Allow => {
198 Self::log_perm_access(name, info);
199 (Ok(()), true, false)
200 }
201 PromptResponse::AllowAll => {
202 Self::log_perm_access(name, info);
203 (Ok(()), true, true)
204 }
205 PromptResponse::Deny => {
206 (Err(Self::retryable_error(name, info)), true, false)
207 }
208 }
209 }
210 _ => (Err(Self::retryable_error(name, info)), false, false),
211 }
212 }
213}
214
215impl fmt::Display for PermissionState {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 match self {
218 PermissionState::Granted => f.pad("granted"),
219 PermissionState::GrantedPartial => f.pad("granted-partial"),
220 PermissionState::Prompt => f.pad("prompt"),
221 PermissionState::Denied => f.pad("denied"),
222 }
223 }
224}
225
226#[derive(Clone, Debug, Eq, PartialEq)]
227pub struct UnitPermission {
228 pub name: &'static str,
229 pub description: &'static str,
230 pub state: PermissionState,
231 pub prompt: bool,
232}
233
234impl UnitPermission {
235 pub fn query(&self) -> PermissionState {
236 self.state
237 }
238
239 pub fn request(&mut self) -> PermissionState {
240 if self.state == PermissionState::Prompt {
241 if PromptResponse::Allow
242 == permission_prompt(
243 &format!("access to {}", self.description),
244 self.name,
245 Some("Deno.permissions.query()"),
246 false,
247 )
248 {
249 self.state = PermissionState::Granted;
250 } else {
251 self.state = PermissionState::Denied;
252 }
253 }
254 self.state
255 }
256
257 pub fn revoke(&mut self) -> PermissionState {
258 if self.state == PermissionState::Granted {
259 self.state = PermissionState::Prompt;
260 }
261 self.state
262 }
263
264 pub fn check(&mut self) -> Result<(), PermissionDeniedError> {
265 let (result, prompted, _is_allow_all) =
266 self.state.check(self.name, None, None, self.prompt);
267 if prompted {
268 if result.is_ok() {
269 self.state = PermissionState::Granted;
270 } else {
271 self.state = PermissionState::Denied;
272 }
273 }
274 result
275 }
276
277 fn create_child_permissions(
278 &mut self,
279 flag: ChildUnitPermissionArg,
280 ) -> Result<Self, ChildPermissionError> {
281 let mut perm = self.clone();
282 match flag {
283 ChildUnitPermissionArg::Inherit => {
284 }
286 ChildUnitPermissionArg::Granted => {
287 if self.check().is_err() {
288 return Err(ChildPermissionError::Escalation);
289 }
290 perm.state = PermissionState::Granted;
291 }
292 ChildUnitPermissionArg::NotGranted => {
293 perm.state = PermissionState::Prompt;
294 }
295 }
296 if self.state == PermissionState::Denied {
297 perm.state = PermissionState::Denied;
298 }
299 Ok(perm)
300 }
301}
302
303#[derive(Clone, Eq, PartialEq, Hash, Debug)]
306pub struct EnvVarName {
307 inner: String,
308}
309
310impl EnvVarName {
311 pub fn new(env: impl AsRef<str>) -> Self {
312 Self {
313 inner: if cfg!(windows) {
314 env.as_ref().to_uppercase()
315 } else {
316 env.as_ref().to_string()
317 },
318 }
319 }
320}
321
322impl AsRef<str> for EnvVarName {
323 fn as_ref(&self) -> &str {
324 self.inner.as_str()
325 }
326}
327
328pub trait QueryDescriptor: Debug {
329 type AllowDesc: Debug + Eq + Clone + Hash;
330 type DenyDesc: Debug + Eq + Clone + Hash;
331
332 fn flag_name() -> &'static str;
333 fn display_name(&self) -> Cow<str>;
334
335 fn from_allow(allow: &Self::AllowDesc) -> Self;
336
337 fn as_allow(&self) -> Option<Self::AllowDesc>;
338 fn as_deny(&self) -> Self::DenyDesc;
339
340 fn check_in_permission(
342 &self,
343 perm: &mut UnaryPermission<Self>,
344 api_name: Option<&str>,
345 ) -> Result<(), PermissionDeniedError>;
346
347 fn matches_allow(&self, other: &Self::AllowDesc) -> bool;
348 fn matches_deny(&self, other: &Self::DenyDesc) -> bool;
349
350 fn revokes(&self, other: &Self::AllowDesc) -> bool;
352 fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool;
353 fn overlaps_deny(&self, other: &Self::DenyDesc) -> bool;
354}
355
356fn format_display_name(display_name: Cow<str>) -> Cow<str> {
357 if display_name.starts_with('<') && display_name.ends_with('>') {
358 display_name
359 } else {
360 Cow::Owned(format!("\"{}\"", display_name))
361 }
362}
363
364#[derive(Debug, Eq, PartialEq)]
365pub struct UnaryPermission<TQuery: QueryDescriptor + ?Sized> {
366 granted_global: bool,
367 granted_list: HashSet<TQuery::AllowDesc>,
368 flag_denied_global: bool,
369 flag_denied_list: HashSet<TQuery::DenyDesc>,
370 prompt_denied_global: bool,
371 prompt_denied_list: HashSet<TQuery::DenyDesc>,
372 prompt: bool,
373}
374
375impl<TQuery: QueryDescriptor> Default for UnaryPermission<TQuery> {
376 fn default() -> Self {
377 UnaryPermission {
378 granted_global: Default::default(),
379 granted_list: Default::default(),
380 flag_denied_global: Default::default(),
381 flag_denied_list: Default::default(),
382 prompt_denied_global: Default::default(),
383 prompt_denied_list: Default::default(),
384 prompt: Default::default(),
385 }
386 }
387}
388
389impl<TQuery: QueryDescriptor> Clone for UnaryPermission<TQuery> {
390 fn clone(&self) -> Self {
391 Self {
392 granted_global: self.granted_global,
393 granted_list: self.granted_list.clone(),
394 flag_denied_global: self.flag_denied_global,
395 flag_denied_list: self.flag_denied_list.clone(),
396 prompt_denied_global: self.prompt_denied_global,
397 prompt_denied_list: self.prompt_denied_list.clone(),
398 prompt: self.prompt,
399 }
400 }
401}
402
403impl<TQuery: QueryDescriptor> UnaryPermission<TQuery> {
404 pub fn allow_all() -> Self {
405 Self {
406 granted_global: true,
407 ..Default::default()
408 }
409 }
410
411 pub fn is_allow_all(&self) -> bool {
412 self.granted_global
413 && self.flag_denied_list.is_empty()
414 && self.prompt_denied_list.is_empty()
415 }
416
417 pub fn check_all_api(
418 &mut self,
419 api_name: Option<&str>,
420 ) -> Result<(), PermissionDeniedError> {
421 skip_check_if_is_permission_fully_granted!(self);
422 self.check_desc(None, false, api_name)
423 }
424
425 fn check_desc(
426 &mut self,
427 desc: Option<&TQuery>,
428 assert_non_partial: bool,
429 api_name: Option<&str>,
430 ) -> Result<(), PermissionDeniedError> {
431 let (result, prompted, is_allow_all) = self
432 .query_desc(desc, AllowPartial::from(!assert_non_partial))
433 .check2(
434 TQuery::flag_name(),
435 api_name,
436 || desc.map(|d| format_display_name(d.display_name()).into_owned()),
437 self.prompt,
438 );
439 if prompted {
440 if result.is_ok() {
441 if is_allow_all {
442 self.insert_granted(None);
443 } else {
444 self.insert_granted(desc);
445 }
446 } else {
447 self.insert_prompt_denied(desc.map(|d| d.as_deny()));
448 }
449 }
450 result
451 }
452
453 fn query_desc(
454 &self,
455 desc: Option<&TQuery>,
456 allow_partial: AllowPartial,
457 ) -> PermissionState {
458 if self.is_flag_denied(desc) || self.is_prompt_denied(desc) {
459 PermissionState::Denied
460 } else if self.is_granted(desc) {
461 match allow_partial {
462 AllowPartial::TreatAsGranted => PermissionState::Granted,
463 AllowPartial::TreatAsDenied => {
464 if self.is_partial_flag_denied(desc) {
465 PermissionState::Denied
466 } else {
467 PermissionState::Granted
468 }
469 }
470 AllowPartial::TreatAsPartialGranted => {
471 if self.is_partial_flag_denied(desc) {
472 PermissionState::GrantedPartial
473 } else {
474 PermissionState::Granted
475 }
476 }
477 }
478 } else if matches!(allow_partial, AllowPartial::TreatAsDenied)
479 && self.is_partial_flag_denied(desc)
480 {
481 PermissionState::Denied
482 } else {
483 PermissionState::Prompt
484 }
485 }
486
487 fn request_desc(&mut self, desc: Option<&TQuery>) -> PermissionState {
488 let state = self.query_desc(desc, AllowPartial::TreatAsPartialGranted);
489 if state == PermissionState::Granted {
490 self.insert_granted(desc);
491 return state;
492 }
493 if state != PermissionState::Prompt {
494 return state;
495 }
496 if !self.prompt {
497 return PermissionState::Denied;
498 }
499 let maybe_formatted_display_name =
500 desc.map(|d| format_display_name(d.display_name()));
501 let message = StringBuilder::<String>::build(|builder| {
502 builder.append(TQuery::flag_name());
503 builder.append(" access");
504 if let Some(display_name) = &maybe_formatted_display_name {
505 builder.append(" to ");
506 builder.append(display_name)
507 }
508 })
509 .unwrap();
510 match permission_prompt(
511 &message,
512 TQuery::flag_name(),
513 Some("Deno.permissions.request()"),
514 true,
515 ) {
516 PromptResponse::Allow => {
517 self.insert_granted(desc);
518 PermissionState::Granted
519 }
520 PromptResponse::Deny => {
521 self.insert_prompt_denied(desc.map(|d| d.as_deny()));
522 PermissionState::Denied
523 }
524 PromptResponse::AllowAll => {
525 self.insert_granted(None);
526 PermissionState::Granted
527 }
528 }
529 }
530
531 fn revoke_desc(&mut self, desc: Option<&TQuery>) -> PermissionState {
532 match desc {
533 Some(desc) => {
534 self.granted_list.retain(|v| !desc.revokes(v));
535 }
536 None => {
537 self.granted_global = false;
538 self.granted_list.clear();
542 }
543 }
544 self.query_desc(desc, AllowPartial::TreatAsPartialGranted)
545 }
546
547 fn is_granted(&self, query: Option<&TQuery>) -> bool {
548 match query {
549 Some(query) => {
550 self.granted_global
551 || self.granted_list.iter().any(|v| query.matches_allow(v))
552 }
553 None => self.granted_global,
554 }
555 }
556
557 fn is_flag_denied(&self, query: Option<&TQuery>) -> bool {
558 match query {
559 Some(query) => {
560 self.flag_denied_global
561 || self.flag_denied_list.iter().any(|v| query.matches_deny(v))
562 }
563 None => self.flag_denied_global,
564 }
565 }
566
567 fn is_prompt_denied(&self, query: Option<&TQuery>) -> bool {
568 match query {
569 Some(query) => self
570 .prompt_denied_list
571 .iter()
572 .any(|v| query.stronger_than_deny(v)),
573 None => self.prompt_denied_global || !self.prompt_denied_list.is_empty(),
574 }
575 }
576
577 fn is_partial_flag_denied(&self, query: Option<&TQuery>) -> bool {
578 match query {
579 None => !self.flag_denied_list.is_empty(),
580 Some(query) => {
581 self.flag_denied_list.iter().any(|v| query.overlaps_deny(v))
582 }
583 }
584 }
585
586 fn insert_granted(&mut self, query: Option<&TQuery>) -> bool {
587 let desc = match query.map(|q| q.as_allow()) {
588 Some(Some(allow_desc)) => Some(allow_desc),
589 Some(None) => {
590 return false;
594 }
595 None => None,
596 };
597 Self::list_insert(desc, &mut self.granted_global, &mut self.granted_list);
598 true
599 }
600
601 fn insert_prompt_denied(&mut self, desc: Option<TQuery::DenyDesc>) {
602 Self::list_insert(
603 desc,
604 &mut self.prompt_denied_global,
605 &mut self.prompt_denied_list,
606 );
607 }
608
609 fn list_insert<T: Hash + Eq>(
610 desc: Option<T>,
611 list_global: &mut bool,
612 list: &mut HashSet<T>,
613 ) {
614 match desc {
615 Some(desc) => {
616 list.insert(desc);
617 }
618 None => *list_global = true,
619 }
620 }
621
622 fn create_child_permissions<E>(
623 &mut self,
624 flag: ChildUnaryPermissionArg,
625 parse: impl Fn(&str) -> Result<Option<TQuery::AllowDesc>, E>,
626 ) -> Result<UnaryPermission<TQuery>, ChildPermissionError>
627 where
628 ChildPermissionError: From<E>,
629 {
630 let mut perms = Self::default();
631
632 match flag {
633 ChildUnaryPermissionArg::Inherit => {
634 perms.clone_from(self);
635 }
636 ChildUnaryPermissionArg::Granted => {
637 if self.check_all_api(None).is_err() {
638 return Err(ChildPermissionError::Escalation);
639 }
640 perms.granted_global = true;
641 }
642 ChildUnaryPermissionArg::NotGranted => {}
643 ChildUnaryPermissionArg::GrantedList(granted_list) => {
644 perms.granted_list = granted_list
645 .iter()
646 .filter_map(|i| parse(i).transpose())
647 .collect::<Result<_, E>>()?;
648 if !perms.granted_list.iter().all(|desc| {
649 TQuery::from_allow(desc)
650 .check_in_permission(self, None)
651 .is_ok()
652 }) {
653 return Err(ChildPermissionError::Escalation);
654 }
655 }
656 }
657 perms.flag_denied_global = self.flag_denied_global;
658 perms.prompt_denied_global = self.prompt_denied_global;
659 perms.prompt = self.prompt;
660 perms.flag_denied_list.clone_from(&self.flag_denied_list);
661 perms
662 .prompt_denied_list
663 .clone_from(&self.prompt_denied_list);
664
665 Ok(perms)
666 }
667}
668
669#[derive(Clone, Eq, PartialEq, Hash, Debug)]
670pub struct PathQueryDescriptor {
671 pub requested: String,
672 pub resolved: PathBuf,
673}
674
675impl PathQueryDescriptor {
676 pub fn into_ffi(self) -> FfiQueryDescriptor {
677 FfiQueryDescriptor(self)
678 }
679
680 pub fn into_read(self) -> ReadQueryDescriptor {
681 ReadQueryDescriptor(self)
682 }
683
684 pub fn into_write(self) -> WriteQueryDescriptor {
685 WriteQueryDescriptor(self)
686 }
687}
688
689#[derive(Clone, Eq, PartialEq, Hash, Debug)]
690pub struct ReadQueryDescriptor(pub PathQueryDescriptor);
691
692impl QueryDescriptor for ReadQueryDescriptor {
693 type AllowDesc = ReadDescriptor;
694 type DenyDesc = ReadDescriptor;
695
696 fn flag_name() -> &'static str {
697 "read"
698 }
699
700 fn display_name(&self) -> Cow<str> {
701 Cow::Borrowed(self.0.requested.as_str())
702 }
703
704 fn from_allow(allow: &Self::AllowDesc) -> Self {
705 PathQueryDescriptor {
706 requested: allow.0.to_string_lossy().into_owned(),
707 resolved: allow.0.clone(),
708 }
709 .into_read()
710 }
711
712 fn as_allow(&self) -> Option<Self::AllowDesc> {
713 Some(ReadDescriptor(self.0.resolved.clone()))
714 }
715
716 fn as_deny(&self) -> Self::DenyDesc {
717 ReadDescriptor(self.0.resolved.clone())
718 }
719
720 fn check_in_permission(
721 &self,
722 perm: &mut UnaryPermission<Self>,
723 api_name: Option<&str>,
724 ) -> Result<(), PermissionDeniedError> {
725 skip_check_if_is_permission_fully_granted!(perm);
726 perm.check_desc(Some(self), true, api_name)
727 }
728
729 fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
730 self.0.resolved.starts_with(&other.0)
731 }
732
733 fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
734 self.0.resolved.starts_with(&other.0)
735 }
736
737 fn revokes(&self, other: &Self::AllowDesc) -> bool {
738 self.matches_allow(other)
739 }
740
741 fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
742 other.0.starts_with(&self.0.resolved)
743 }
744
745 fn overlaps_deny(&self, other: &Self::DenyDesc) -> bool {
746 self.stronger_than_deny(other)
747 }
748}
749
750#[derive(Clone, Eq, PartialEq, Hash, Debug)]
751pub struct ReadDescriptor(pub PathBuf);
752
753#[derive(Clone, Eq, PartialEq, Hash, Debug)]
754pub struct WriteQueryDescriptor(pub PathQueryDescriptor);
755
756impl QueryDescriptor for WriteQueryDescriptor {
757 type AllowDesc = WriteDescriptor;
758 type DenyDesc = WriteDescriptor;
759
760 fn flag_name() -> &'static str {
761 "write"
762 }
763
764 fn display_name(&self) -> Cow<str> {
765 Cow::Borrowed(&self.0.requested)
766 }
767
768 fn from_allow(allow: &Self::AllowDesc) -> Self {
769 WriteQueryDescriptor(PathQueryDescriptor {
770 requested: allow.0.to_string_lossy().into_owned(),
771 resolved: allow.0.clone(),
772 })
773 }
774
775 fn as_allow(&self) -> Option<Self::AllowDesc> {
776 Some(WriteDescriptor(self.0.resolved.clone()))
777 }
778
779 fn as_deny(&self) -> Self::DenyDesc {
780 WriteDescriptor(self.0.resolved.clone())
781 }
782
783 fn check_in_permission(
784 &self,
785 perm: &mut UnaryPermission<Self>,
786 api_name: Option<&str>,
787 ) -> Result<(), PermissionDeniedError> {
788 skip_check_if_is_permission_fully_granted!(perm);
789 perm.check_desc(Some(self), true, api_name)
790 }
791
792 fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
793 self.0.resolved.starts_with(&other.0)
794 }
795
796 fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
797 self.0.resolved.starts_with(&other.0)
798 }
799
800 fn revokes(&self, other: &Self::AllowDesc) -> bool {
801 self.matches_allow(other)
802 }
803
804 fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
805 other.0.starts_with(&self.0.resolved)
806 }
807
808 fn overlaps_deny(&self, other: &Self::DenyDesc) -> bool {
809 self.stronger_than_deny(other)
810 }
811}
812
813#[derive(Clone, Eq, PartialEq, Hash, Debug)]
814pub struct WriteDescriptor(pub PathBuf);
815
816#[derive(Clone, Eq, PartialEq, Hash, Debug)]
817pub enum Host {
818 Fqdn(FQDN),
819 Ip(IpAddr),
820 Vsock(u32),
821}
822
823#[derive(Debug, thiserror::Error, deno_error::JsError)]
824#[class(uri)]
825pub enum HostParseError {
826 #[error("invalid IPv6 address: '{0}'")]
827 InvalidIpv6(String),
828 #[error("invalid host: '{0}'")]
829 InvalidHost(String),
830 #[error("invalid empty host: '{0}'")]
831 InvalidEmptyHost(String),
832 #[error("invalid host '{host}': {error}")]
833 Fqdn {
834 #[source]
835 error: fqdn::Error,
836 host: String,
837 },
838}
839
840impl Host {
841 fn parse(s: &str) -> Result<Self, HostParseError> {
842 if s.starts_with('[') && s.ends_with(']') {
843 let ip = s[1..s.len() - 1]
844 .parse::<Ipv6Addr>()
845 .map_err(|_| HostParseError::InvalidIpv6(s.to_string()))?;
846 return Ok(Host::Ip(IpAddr::V6(ip)));
847 }
848 let (without_trailing_dot, has_trailing_dot) =
849 s.strip_suffix('.').map_or((s, false), |s| (s, true));
850 if let Ok(ip) = without_trailing_dot.parse::<IpAddr>() {
851 if has_trailing_dot {
852 return Err(HostParseError::InvalidHost(
853 without_trailing_dot.to_string(),
854 ));
855 }
856 Ok(Host::Ip(ip))
857 } else {
858 let lower = if s.chars().all(|c| c.is_ascii_lowercase()) {
859 Cow::Borrowed(s)
860 } else {
861 Cow::Owned(s.to_ascii_lowercase())
862 };
863 let fqdn = {
864 use std::str::FromStr;
865 FQDN::from_str(&lower).map_err(|e| HostParseError::Fqdn {
866 error: e,
867 host: s.to_string(),
868 })?
869 };
870 if fqdn.is_root() {
871 return Err(HostParseError::InvalidEmptyHost(s.to_string()));
872 }
873 Ok(Host::Fqdn(fqdn))
874 }
875 }
876
877 #[cfg(test)]
878 #[track_caller]
879 fn must_parse(s: &str) -> Self {
880 Self::parse(s).unwrap()
881 }
882}
883
884#[derive(Clone, Eq, PartialEq, Hash, Debug)]
885pub struct NetDescriptor(pub Host, pub Option<u32>);
886
887impl QueryDescriptor for NetDescriptor {
888 type AllowDesc = NetDescriptor;
889 type DenyDesc = NetDescriptor;
890
891 fn flag_name() -> &'static str {
892 "net"
893 }
894
895 fn display_name(&self) -> Cow<str> {
896 Cow::from(format!("{}", self))
897 }
898
899 fn from_allow(allow: &Self::AllowDesc) -> Self {
900 allow.clone()
901 }
902
903 fn as_allow(&self) -> Option<Self::AllowDesc> {
904 Some(self.clone())
905 }
906
907 fn as_deny(&self) -> Self::DenyDesc {
908 self.clone()
909 }
910
911 fn check_in_permission(
912 &self,
913 perm: &mut UnaryPermission<Self>,
914 api_name: Option<&str>,
915 ) -> Result<(), PermissionDeniedError> {
916 skip_check_if_is_permission_fully_granted!(perm);
917 perm.check_desc(Some(self), false, api_name)
918 }
919
920 fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
921 self.0 == other.0 && (other.1.is_none() || self.1 == other.1)
922 }
923
924 fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
925 self.0 == other.0 && (other.1.is_none() || self.1 == other.1)
926 }
927
928 fn revokes(&self, other: &Self::AllowDesc) -> bool {
929 self.matches_allow(other)
930 }
931
932 fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
933 self.matches_deny(other)
934 }
935
936 fn overlaps_deny(&self, _other: &Self::DenyDesc) -> bool {
937 false
938 }
939}
940
941#[derive(Debug, thiserror::Error)]
942pub enum NetDescriptorParseError {
943 #[error("invalid value '{0}': URLs are not supported, only domains and ips")]
944 Url(String),
945 #[error("invalid IPv6 address in '{hostname}': '{ip}'")]
946 InvalidIpv6 { hostname: String, ip: String },
947 #[error("invalid port in '{hostname}': '{port}'")]
948 InvalidPort { hostname: String, port: String },
949 #[error("invalid host: '{0}'")]
950 InvalidHost(String),
951 #[error("invalid empty port in '{0}'")]
952 EmptyPort(String),
953 #[error("ipv6 addresses must be enclosed in square brackets: '{0}'")]
954 Ipv6MissingSquareBrackets(String),
955 #[error("{0}")]
956 Host(#[from] HostParseError),
957 #[error("invalid vsock: '{0}'")]
958 InvalidVsock(String),
959}
960
961#[derive(Debug, thiserror::Error, deno_error::JsError)]
962pub enum NetDescriptorFromUrlParseError {
963 #[class(type)]
964 #[error("Missing host in url: '{0}'")]
965 MissingHost(Url),
966 #[class(inherit)]
967 #[error("{0}")]
968 Host(#[from] HostParseError),
969}
970
971impl NetDescriptor {
972 pub fn parse(hostname: &str) -> Result<Self, NetDescriptorParseError> {
973 #[cfg(unix)]
974 if let Some(vsock) = hostname.strip_prefix("vsock:") {
975 let mut split = vsock.split(':');
976 let Some(cid) = split.next().and_then(|c| {
977 if c == "-1" {
978 Some(u32::MAX)
979 } else {
980 c.parse().ok()
981 }
982 }) else {
983 return Err(NetDescriptorParseError::InvalidVsock(hostname.into()));
984 };
985 let Some(port) = split.next().and_then(|p| p.parse().ok()) else {
986 return Err(NetDescriptorParseError::InvalidVsock(hostname.into()));
987 };
988 return Ok(NetDescriptor(Host::Vsock(cid), Some(port)));
989 }
990
991 if hostname.starts_with("http://") || hostname.starts_with("https://") {
992 return Err(NetDescriptorParseError::Url(hostname.to_string()));
993 }
994
995 if hostname.starts_with('[') {
997 if let Some((ip, after)) = hostname.split_once(']') {
998 let ip = ip[1..].parse::<Ipv6Addr>().map_err(|_| {
999 NetDescriptorParseError::InvalidIpv6 {
1000 hostname: hostname.to_string(),
1001 ip: ip.to_string(),
1002 }
1003 })?;
1004 let port = if let Some(port) = after.strip_prefix(':') {
1005 let port = port.parse::<u16>().map_err(|_| {
1006 NetDescriptorParseError::InvalidPort {
1007 hostname: hostname.to_string(),
1008 port: port.to_string(),
1009 }
1010 })?;
1011 Some(port)
1012 } else if after.is_empty() {
1013 None
1014 } else {
1015 return Err(NetDescriptorParseError::InvalidHost(
1016 hostname.to_string(),
1017 ));
1018 };
1019 return Ok(NetDescriptor(
1020 Host::Ip(IpAddr::V6(ip)),
1021 port.map(Into::into),
1022 ));
1023 } else {
1024 return Err(NetDescriptorParseError::InvalidHost(hostname.to_string()));
1025 }
1026 }
1027
1028 let (host, port) = match hostname.split_once(':') {
1030 Some((_, "")) => {
1031 return Err(NetDescriptorParseError::EmptyPort(hostname.to_string()));
1032 }
1033 Some((host, port)) => (host, port),
1034 None => (hostname, ""),
1035 };
1036 let host = Host::parse(host)?;
1037
1038 let port = if port.is_empty() {
1039 None
1040 } else {
1041 let port = port.parse::<u16>().map_err(|_| {
1042 if port.contains(':') {
1046 NetDescriptorParseError::Ipv6MissingSquareBrackets(
1047 hostname.to_string(),
1048 )
1049 } else {
1050 NetDescriptorParseError::InvalidPort {
1051 hostname: hostname.to_string(),
1052 port: port.to_string(),
1053 }
1054 }
1055 })?;
1056 Some(port)
1057 };
1058
1059 Ok(NetDescriptor(host, port.map(Into::into)))
1060 }
1061
1062 pub fn from_url(url: &Url) -> Result<Self, NetDescriptorFromUrlParseError> {
1063 let host = url.host_str().ok_or_else(|| {
1064 NetDescriptorFromUrlParseError::MissingHost(url.clone())
1065 })?;
1066 let host = Host::parse(host)?;
1067 let port = url.port_or_known_default();
1068 Ok(NetDescriptor(host, port.map(Into::into)))
1069 }
1070
1071 pub fn from_vsock(
1072 cid: u32,
1073 port: u32,
1074 ) -> Result<Self, NetDescriptorParseError> {
1075 Ok(NetDescriptor(Host::Vsock(cid), Some(port)))
1076 }
1077}
1078
1079impl fmt::Display for NetDescriptor {
1080 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1081 match &self.0 {
1082 Host::Fqdn(fqdn) => write!(f, "{fqdn}"),
1083 Host::Ip(IpAddr::V4(ip)) => write!(f, "{ip}"),
1084 Host::Ip(IpAddr::V6(ip)) => write!(f, "[{ip}]"),
1085 Host::Vsock(cid) => write!(f, "vsock:{cid}"),
1086 }?;
1087 if let Some(port) = self.1 {
1088 write!(f, ":{}", port)?;
1089 }
1090 Ok(())
1091 }
1092}
1093
1094#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1095pub struct ImportDescriptor(NetDescriptor);
1096
1097impl QueryDescriptor for ImportDescriptor {
1098 type AllowDesc = ImportDescriptor;
1099 type DenyDesc = ImportDescriptor;
1100
1101 fn flag_name() -> &'static str {
1102 "import"
1103 }
1104
1105 fn display_name(&self) -> Cow<str> {
1106 self.0.display_name()
1107 }
1108
1109 fn from_allow(allow: &Self::AllowDesc) -> Self {
1110 Self(NetDescriptor::from_allow(&allow.0))
1111 }
1112
1113 fn as_allow(&self) -> Option<Self::AllowDesc> {
1114 self.0.as_allow().map(ImportDescriptor)
1115 }
1116
1117 fn as_deny(&self) -> Self::DenyDesc {
1118 Self(self.0.as_deny())
1119 }
1120
1121 fn check_in_permission(
1122 &self,
1123 perm: &mut UnaryPermission<Self>,
1124 api_name: Option<&str>,
1125 ) -> Result<(), PermissionDeniedError> {
1126 skip_check_if_is_permission_fully_granted!(perm);
1127 perm.check_desc(Some(self), false, api_name)
1128 }
1129
1130 fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
1131 self.0.matches_allow(&other.0)
1132 }
1133
1134 fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
1135 self.0.matches_deny(&other.0)
1136 }
1137
1138 fn revokes(&self, other: &Self::AllowDesc) -> bool {
1139 self.0.revokes(&other.0)
1140 }
1141
1142 fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
1143 self.0.stronger_than_deny(&other.0)
1144 }
1145
1146 fn overlaps_deny(&self, other: &Self::DenyDesc) -> bool {
1147 self.0.overlaps_deny(&other.0)
1148 }
1149}
1150
1151impl ImportDescriptor {
1152 pub fn parse(specifier: &str) -> Result<Self, NetDescriptorParseError> {
1153 Ok(ImportDescriptor(NetDescriptor::parse(specifier)?))
1154 }
1155
1156 pub fn from_url(url: &Url) -> Result<Self, NetDescriptorFromUrlParseError> {
1157 Ok(ImportDescriptor(NetDescriptor::from_url(url)?))
1158 }
1159}
1160
1161#[derive(Debug, thiserror::Error)]
1162#[error("Empty env not allowed")]
1163pub struct EnvDescriptorParseError;
1164
1165#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1166pub enum EnvDescriptor {
1167 Name(EnvVarName),
1168 PrefixPattern(EnvVarName),
1169}
1170
1171impl EnvDescriptor {
1172 pub fn new(env: impl AsRef<str>) -> Self {
1173 if let Some(prefix_pattern) = env.as_ref().strip_suffix('*') {
1174 Self::PrefixPattern(EnvVarName::new(prefix_pattern))
1175 } else {
1176 Self::Name(EnvVarName::new(env))
1177 }
1178 }
1179}
1180
1181#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1182enum EnvQueryDescriptorInner {
1183 Name(EnvVarName),
1184 PrefixPattern(EnvVarName),
1185}
1186
1187#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1188pub struct EnvQueryDescriptor(EnvQueryDescriptorInner);
1189
1190impl EnvQueryDescriptor {
1191 pub fn new(env: impl AsRef<str>) -> Self {
1192 Self(EnvQueryDescriptorInner::Name(EnvVarName::new(env)))
1193 }
1194}
1195
1196impl QueryDescriptor for EnvQueryDescriptor {
1197 type AllowDesc = EnvDescriptor;
1198 type DenyDesc = EnvDescriptor;
1199
1200 fn flag_name() -> &'static str {
1201 "env"
1202 }
1203
1204 fn display_name(&self) -> Cow<str> {
1205 Cow::from(match &self.0 {
1206 EnvQueryDescriptorInner::Name(env_var_name) => env_var_name.as_ref(),
1207 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1208 env_var_name.as_ref()
1209 }
1210 })
1211 }
1212
1213 fn from_allow(allow: &Self::AllowDesc) -> Self {
1214 match allow {
1215 Self::AllowDesc::Name(s) => {
1216 Self(EnvQueryDescriptorInner::Name(s.clone()))
1217 }
1218 Self::AllowDesc::PrefixPattern(s) => {
1219 Self(EnvQueryDescriptorInner::PrefixPattern(s.clone()))
1220 }
1221 }
1222 }
1223
1224 fn as_allow(&self) -> Option<Self::AllowDesc> {
1225 Some(match &self.0 {
1226 EnvQueryDescriptorInner::Name(env_var_name) => {
1227 Self::AllowDesc::Name(env_var_name.clone())
1228 }
1229 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1230 Self::AllowDesc::PrefixPattern(env_var_name.clone())
1231 }
1232 })
1233 }
1234
1235 fn as_deny(&self) -> Self::DenyDesc {
1236 match &self.0 {
1237 EnvQueryDescriptorInner::Name(env_var_name) => {
1238 Self::DenyDesc::Name(env_var_name.clone())
1239 }
1240 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1241 Self::DenyDesc::PrefixPattern(env_var_name.clone())
1242 }
1243 }
1244 }
1245
1246 fn check_in_permission(
1247 &self,
1248 perm: &mut UnaryPermission<Self>,
1249 api_name: Option<&str>,
1250 ) -> Result<(), PermissionDeniedError> {
1251 skip_check_if_is_permission_fully_granted!(perm);
1252 perm.check_desc(Some(self), false, api_name)
1253 }
1254
1255 fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
1256 match other {
1257 Self::AllowDesc::Name(n) => match &self.0 {
1258 EnvQueryDescriptorInner::Name(env_var_name) => n == env_var_name,
1259 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1260 env_var_name.as_ref().starts_with(n.as_ref())
1261 }
1262 },
1263 Self::AllowDesc::PrefixPattern(p) => match &self.0 {
1264 EnvQueryDescriptorInner::Name(env_var_name) => {
1265 env_var_name.as_ref().starts_with(p.as_ref())
1266 }
1267 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1268 env_var_name.as_ref().starts_with(p.as_ref())
1269 }
1270 },
1271 }
1272 }
1273
1274 fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
1275 match other {
1276 Self::AllowDesc::Name(n) => match &self.0 {
1277 EnvQueryDescriptorInner::Name(env_var_name) => n == env_var_name,
1278 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1279 env_var_name.as_ref().starts_with(n.as_ref())
1280 }
1281 },
1282 Self::AllowDesc::PrefixPattern(p) => match &self.0 {
1283 EnvQueryDescriptorInner::Name(env_var_name) => {
1284 env_var_name.as_ref().starts_with(p.as_ref())
1285 }
1286 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1287 p == env_var_name
1288 }
1289 },
1290 }
1291 }
1292
1293 fn revokes(&self, other: &Self::AllowDesc) -> bool {
1294 match other {
1295 Self::AllowDesc::Name(n) => match &self.0 {
1296 EnvQueryDescriptorInner::Name(env_var_name) => n == env_var_name,
1297 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1298 env_var_name.as_ref().starts_with(n.as_ref())
1299 }
1300 },
1301 Self::AllowDesc::PrefixPattern(p) => match &self.0 {
1302 EnvQueryDescriptorInner::Name(env_var_name) => {
1303 env_var_name.as_ref().starts_with(p.as_ref())
1304 }
1305 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1306 p == env_var_name
1307 }
1308 },
1309 }
1310 }
1311
1312 fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
1313 match other {
1314 Self::AllowDesc::Name(n) => match &self.0 {
1315 EnvQueryDescriptorInner::Name(env_var_name) => n == env_var_name,
1316 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1317 env_var_name.as_ref().starts_with(n.as_ref())
1318 }
1319 },
1320 Self::AllowDesc::PrefixPattern(p) => match &self.0 {
1321 EnvQueryDescriptorInner::Name(env_var_name) => {
1322 env_var_name.as_ref().starts_with(p.as_ref())
1323 }
1324 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1325 p == env_var_name
1326 }
1327 },
1328 }
1329 }
1330
1331 fn overlaps_deny(&self, _other: &Self::DenyDesc) -> bool {
1332 false
1333 }
1334}
1335
1336impl AsRef<str> for EnvQueryDescriptor {
1337 fn as_ref(&self) -> &str {
1338 match &self.0 {
1339 EnvQueryDescriptorInner::Name(env_var_name) => env_var_name.as_ref(),
1340 EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
1341 env_var_name.as_ref()
1342 }
1343 }
1344 }
1345}
1346
1347#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
1348pub enum RunQueryDescriptor {
1349 Path {
1350 requested: String,
1351 resolved: PathBuf,
1352 },
1353 Name(String),
1360}
1361
1362#[derive(Debug, thiserror::Error, deno_error::JsError)]
1363pub enum PathResolveError {
1364 #[class(inherit)]
1365 #[error("failed resolving cwd: {0}")]
1366 CwdResolve(#[source] std::io::Error),
1367 #[class(generic)]
1368 #[error("Empty path is not allowed")]
1369 EmptyPath,
1370}
1371
1372impl RunQueryDescriptor {
1373 pub fn parse(
1374 requested: &str,
1375 ) -> Result<RunQueryDescriptor, PathResolveError> {
1376 if is_path(requested) {
1377 let path = PathBuf::from(requested);
1378 let resolved = if path.is_absolute() {
1379 normalize_path(path)
1380 } else {
1381 let cwd =
1382 std::env::current_dir().map_err(PathResolveError::CwdResolve)?;
1383 normalize_path(cwd.join(path))
1384 };
1385 Ok(RunQueryDescriptor::Path {
1386 requested: requested.to_string(),
1387 resolved,
1388 })
1389 } else {
1390 match which::which(requested) {
1391 Ok(resolved) => Ok(RunQueryDescriptor::Path {
1392 requested: requested.to_string(),
1393 resolved,
1394 }),
1395 Err(_) => Ok(RunQueryDescriptor::Name(requested.to_string())),
1396 }
1397 }
1398 }
1399}
1400
1401impl QueryDescriptor for RunQueryDescriptor {
1402 type AllowDesc = AllowRunDescriptor;
1403 type DenyDesc = DenyRunDescriptor;
1404
1405 fn flag_name() -> &'static str {
1406 "run"
1407 }
1408
1409 fn display_name(&self) -> Cow<str> {
1410 match self {
1411 RunQueryDescriptor::Path { requested, .. } => Cow::Borrowed(requested),
1412 RunQueryDescriptor::Name(name) => Cow::Borrowed(name),
1413 }
1414 }
1415
1416 fn from_allow(allow: &Self::AllowDesc) -> Self {
1417 RunQueryDescriptor::Path {
1418 requested: allow.0.to_string_lossy().into_owned(),
1419 resolved: allow.0.clone(),
1420 }
1421 }
1422
1423 fn as_allow(&self) -> Option<Self::AllowDesc> {
1424 match self {
1425 RunQueryDescriptor::Path { resolved, .. } => {
1426 Some(AllowRunDescriptor(resolved.clone()))
1427 }
1428 RunQueryDescriptor::Name(_) => None,
1429 }
1430 }
1431
1432 fn as_deny(&self) -> Self::DenyDesc {
1433 match self {
1434 RunQueryDescriptor::Path {
1435 resolved,
1436 requested,
1437 } => {
1438 if requested.contains('/')
1439 || (cfg!(windows) && requested.contains("\\"))
1440 {
1441 DenyRunDescriptor::Path(resolved.clone())
1442 } else {
1443 DenyRunDescriptor::Name(requested.clone())
1444 }
1445 }
1446 RunQueryDescriptor::Name(name) => DenyRunDescriptor::Name(name.clone()),
1447 }
1448 }
1449
1450 fn check_in_permission(
1451 &self,
1452 perm: &mut UnaryPermission<Self>,
1453 api_name: Option<&str>,
1454 ) -> Result<(), PermissionDeniedError> {
1455 skip_check_if_is_permission_fully_granted!(perm);
1456 perm.check_desc(Some(self), false, api_name)
1457 }
1458
1459 fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
1460 match self {
1461 RunQueryDescriptor::Path { resolved, .. } => *resolved == other.0,
1462 RunQueryDescriptor::Name(_) => false,
1463 }
1464 }
1465
1466 fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
1467 match other {
1468 DenyRunDescriptor::Name(deny_desc) => match self {
1469 RunQueryDescriptor::Path { resolved, .. } => {
1470 denies_run_name(deny_desc, resolved)
1471 }
1472 RunQueryDescriptor::Name(query) => query == deny_desc,
1473 },
1474 DenyRunDescriptor::Path(deny_desc) => match self {
1475 RunQueryDescriptor::Path { resolved, .. } => {
1476 resolved.starts_with(deny_desc)
1477 }
1478 RunQueryDescriptor::Name(query) => denies_run_name(query, deny_desc),
1479 },
1480 }
1481 }
1482
1483 fn revokes(&self, other: &Self::AllowDesc) -> bool {
1484 match self {
1485 RunQueryDescriptor::Path {
1486 resolved,
1487 requested,
1488 } => {
1489 if *resolved == other.0 {
1490 return true;
1491 }
1492 if is_path(requested) {
1493 false
1494 } else {
1495 denies_run_name(requested, &other.0)
1496 }
1497 }
1498 RunQueryDescriptor::Name(query) => denies_run_name(query, &other.0),
1499 }
1500 }
1501
1502 fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
1503 self.matches_deny(other)
1504 }
1505
1506 fn overlaps_deny(&self, _other: &Self::DenyDesc) -> bool {
1507 false
1508 }
1509}
1510
1511pub enum RunDescriptorArg {
1512 Name(String),
1513 Path(PathBuf),
1514}
1515
1516pub enum AllowRunDescriptorParseResult {
1517 Unresolved(Box<which::Error>),
1521 Descriptor(AllowRunDescriptor),
1522}
1523
1524#[derive(Debug, thiserror::Error, deno_error::JsError)]
1525pub enum RunDescriptorParseError {
1526 #[class(generic)]
1527 #[error("{0}")]
1528 Which(#[from] which::Error),
1529 #[class(inherit)]
1530 #[error("{0}")]
1531 PathResolve(#[from] PathResolveError),
1532 #[class(generic)]
1533 #[error("Empty run query is not allowed")]
1534 EmptyRunQuery,
1535}
1536
1537#[derive(Debug, Clone, Hash, Eq, PartialEq)]
1538pub struct AllowRunDescriptor(pub PathBuf);
1539
1540impl AllowRunDescriptor {
1541 pub fn parse(
1542 text: &str,
1543 cwd: &Path,
1544 ) -> Result<AllowRunDescriptorParseResult, which::Error> {
1545 let is_path = is_path(text);
1546 let path = if is_path {
1548 resolve_from_known_cwd(Path::new(text), cwd)
1549 } else {
1550 match which::which_in(text, std::env::var_os("PATH"), cwd) {
1551 Ok(path) => path,
1552 Err(err) => match err {
1553 which::Error::CannotGetCurrentDirAndPathListEmpty => {
1554 return Err(err);
1555 }
1556 which::Error::CannotFindBinaryPath
1557 | which::Error::CannotCanonicalize => {
1558 return Ok(AllowRunDescriptorParseResult::Unresolved(Box::new(err)))
1559 }
1560 },
1561 }
1562 };
1563 Ok(AllowRunDescriptorParseResult::Descriptor(
1564 AllowRunDescriptor(path),
1565 ))
1566 }
1567}
1568
1569#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1570pub enum DenyRunDescriptor {
1571 Name(String),
1574 Path(PathBuf),
1577}
1578
1579impl DenyRunDescriptor {
1580 pub fn parse(text: &str, cwd: &Path) -> Self {
1581 if text.contains('/') || cfg!(windows) && text.contains('\\') {
1582 let path = resolve_from_known_cwd(Path::new(&text), cwd);
1583 DenyRunDescriptor::Path(path)
1584 } else {
1585 DenyRunDescriptor::Name(text.to_string())
1586 }
1587 }
1588}
1589
1590fn is_path(text: &str) -> bool {
1591 if cfg!(windows) {
1592 text.contains('/') || text.contains('\\') || Path::new(text).is_absolute()
1593 } else {
1594 text.contains('/')
1595 }
1596}
1597
1598fn denies_run_name(name: &str, cmd_path: &Path) -> bool {
1599 let Some(file_stem) = cmd_path.file_stem() else {
1600 return false;
1601 };
1602 let Some(file_stem) = file_stem.to_str() else {
1603 return false;
1604 };
1605 if file_stem.len() < name.len() {
1606 return false;
1607 }
1608 let (prefix, suffix) = file_stem.split_at(name.len());
1609 if !prefix.eq_ignore_ascii_case(name) {
1610 return false;
1611 }
1612 suffix.is_empty() || suffix.starts_with('.')
1614}
1615
1616#[derive(Debug, thiserror::Error, deno_error::JsError)]
1617pub enum SysDescriptorParseError {
1618 #[class(type)]
1619 #[error("unknown system info kind \"{0}\"")]
1620 InvalidKind(String),
1621 #[class(generic)]
1622 #[error("Empty sys not allowed")]
1623 Empty, }
1625
1626#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1627pub struct SysDescriptor(String);
1628
1629impl SysDescriptor {
1630 pub fn parse(kind: String) -> Result<Self, SysDescriptorParseError> {
1631 match kind.as_str() {
1632 "hostname" | "inspector" | "osRelease" | "osUptime" | "loadavg"
1633 | "networkInterfaces" | "systemMemoryInfo" | "uid" | "gid" | "cpus"
1634 | "homedir" | "getegid" | "statfs" | "getPriority" | "setPriority"
1635 | "userInfo" => Ok(Self(kind)),
1636
1637 "username" => Ok(Self("userInfo".into())),
1640 _ => Err(SysDescriptorParseError::InvalidKind(kind)),
1641 }
1642 }
1643
1644 pub fn into_string(self) -> String {
1645 self.0
1646 }
1647}
1648
1649impl QueryDescriptor for SysDescriptor {
1650 type AllowDesc = SysDescriptor;
1651 type DenyDesc = SysDescriptor;
1652
1653 fn flag_name() -> &'static str {
1654 "sys"
1655 }
1656
1657 fn display_name(&self) -> Cow<str> {
1658 Cow::from(self.0.to_string())
1659 }
1660
1661 fn from_allow(allow: &Self::AllowDesc) -> Self {
1662 allow.clone()
1663 }
1664
1665 fn as_allow(&self) -> Option<Self::AllowDesc> {
1666 Some(self.clone())
1667 }
1668
1669 fn as_deny(&self) -> Self::DenyDesc {
1670 self.clone()
1671 }
1672
1673 fn check_in_permission(
1674 &self,
1675 perm: &mut UnaryPermission<Self>,
1676 api_name: Option<&str>,
1677 ) -> Result<(), PermissionDeniedError> {
1678 skip_check_if_is_permission_fully_granted!(perm);
1679 perm.check_desc(Some(self), false, api_name)
1680 }
1681
1682 fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
1683 self == other
1684 }
1685
1686 fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
1687 self == other
1688 }
1689
1690 fn revokes(&self, other: &Self::AllowDesc) -> bool {
1691 self == other
1692 }
1693
1694 fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
1695 self == other
1696 }
1697
1698 fn overlaps_deny(&self, _other: &Self::DenyDesc) -> bool {
1699 false
1700 }
1701}
1702
1703#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1704pub struct FfiQueryDescriptor(pub PathQueryDescriptor);
1705
1706impl QueryDescriptor for FfiQueryDescriptor {
1707 type AllowDesc = FfiDescriptor;
1708 type DenyDesc = FfiDescriptor;
1709
1710 fn flag_name() -> &'static str {
1711 "ffi"
1712 }
1713
1714 fn display_name(&self) -> Cow<str> {
1715 Cow::Borrowed(&self.0.requested)
1716 }
1717
1718 fn from_allow(allow: &Self::AllowDesc) -> Self {
1719 PathQueryDescriptor {
1720 requested: allow.0.to_string_lossy().into_owned(),
1721 resolved: allow.0.clone(),
1722 }
1723 .into_ffi()
1724 }
1725
1726 fn as_allow(&self) -> Option<Self::AllowDesc> {
1727 Some(FfiDescriptor(self.0.resolved.clone()))
1728 }
1729
1730 fn as_deny(&self) -> Self::DenyDesc {
1731 FfiDescriptor(self.0.resolved.clone())
1732 }
1733
1734 fn check_in_permission(
1735 &self,
1736 perm: &mut UnaryPermission<Self>,
1737 api_name: Option<&str>,
1738 ) -> Result<(), PermissionDeniedError> {
1739 skip_check_if_is_permission_fully_granted!(perm);
1740 perm.check_desc(Some(self), true, api_name)
1741 }
1742
1743 fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
1744 self.0.resolved.starts_with(&other.0)
1745 }
1746
1747 fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
1748 self.0.resolved.starts_with(&other.0)
1749 }
1750
1751 fn revokes(&self, other: &Self::AllowDesc) -> bool {
1752 self.matches_allow(other)
1753 }
1754
1755 fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
1756 other.0.starts_with(&self.0.resolved)
1757 }
1758
1759 fn overlaps_deny(&self, other: &Self::DenyDesc) -> bool {
1760 self.stronger_than_deny(other)
1761 }
1762}
1763
1764#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1765pub struct FfiDescriptor(pub PathBuf);
1766
1767impl UnaryPermission<ReadQueryDescriptor> {
1768 pub fn query(&self, desc: Option<&ReadQueryDescriptor>) -> PermissionState {
1769 self.query_desc(desc, AllowPartial::TreatAsPartialGranted)
1770 }
1771
1772 pub fn request(
1773 &mut self,
1774 path: Option<&ReadQueryDescriptor>,
1775 ) -> PermissionState {
1776 self.request_desc(path)
1777 }
1778
1779 pub fn revoke(
1780 &mut self,
1781 desc: Option<&ReadQueryDescriptor>,
1782 ) -> PermissionState {
1783 self.revoke_desc(desc)
1784 }
1785
1786 pub fn check(
1787 &mut self,
1788 desc: &ReadQueryDescriptor,
1789 api_name: Option<&str>,
1790 ) -> Result<(), PermissionDeniedError> {
1791 skip_check_if_is_permission_fully_granted!(self);
1792 self.check_desc(Some(desc), true, api_name)
1793 }
1794
1795 #[inline]
1796 pub fn check_partial(
1797 &mut self,
1798 desc: &ReadQueryDescriptor,
1799 api_name: Option<&str>,
1800 ) -> Result<(), PermissionDeniedError> {
1801 skip_check_if_is_permission_fully_granted!(self);
1802 self.check_desc(Some(desc), false, api_name)
1803 }
1804
1805 pub fn check_all(
1806 &mut self,
1807 api_name: Option<&str>,
1808 ) -> Result<(), PermissionDeniedError> {
1809 skip_check_if_is_permission_fully_granted!(self);
1810 self.check_desc(None, false, api_name)
1811 }
1812}
1813
1814impl UnaryPermission<WriteQueryDescriptor> {
1815 pub fn query(&self, path: Option<&WriteQueryDescriptor>) -> PermissionState {
1816 self.query_desc(path, AllowPartial::TreatAsPartialGranted)
1817 }
1818
1819 pub fn request(
1820 &mut self,
1821 path: Option<&WriteQueryDescriptor>,
1822 ) -> PermissionState {
1823 self.request_desc(path)
1824 }
1825
1826 pub fn revoke(
1827 &mut self,
1828 path: Option<&WriteQueryDescriptor>,
1829 ) -> PermissionState {
1830 self.revoke_desc(path)
1831 }
1832
1833 pub fn check(
1834 &mut self,
1835 path: &WriteQueryDescriptor,
1836 api_name: Option<&str>,
1837 ) -> Result<(), PermissionDeniedError> {
1838 skip_check_if_is_permission_fully_granted!(self);
1839 self.check_desc(Some(path), true, api_name)
1840 }
1841
1842 #[inline]
1843 pub fn check_partial(
1844 &mut self,
1845 path: &WriteQueryDescriptor,
1846 api_name: Option<&str>,
1847 ) -> Result<(), PermissionDeniedError> {
1848 skip_check_if_is_permission_fully_granted!(self);
1849 self.check_desc(Some(path), false, api_name)
1850 }
1851
1852 pub fn check_all(
1853 &mut self,
1854 api_name: Option<&str>,
1855 ) -> Result<(), PermissionDeniedError> {
1856 skip_check_if_is_permission_fully_granted!(self);
1857 self.check_desc(None, false, api_name)
1858 }
1859}
1860
1861impl UnaryPermission<NetDescriptor> {
1862 pub fn query(&self, host: Option<&NetDescriptor>) -> PermissionState {
1863 self.query_desc(host, AllowPartial::TreatAsPartialGranted)
1864 }
1865
1866 pub fn request(&mut self, host: Option<&NetDescriptor>) -> PermissionState {
1867 self.request_desc(host)
1868 }
1869
1870 pub fn revoke(&mut self, host: Option<&NetDescriptor>) -> PermissionState {
1871 self.revoke_desc(host)
1872 }
1873
1874 pub fn check(
1875 &mut self,
1876 host: &NetDescriptor,
1877 api_name: Option<&str>,
1878 ) -> Result<(), PermissionDeniedError> {
1879 skip_check_if_is_permission_fully_granted!(self);
1880 self.check_desc(Some(host), false, api_name)
1881 }
1882
1883 pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> {
1884 skip_check_if_is_permission_fully_granted!(self);
1885 self.check_desc(None, false, None)
1886 }
1887}
1888
1889impl UnaryPermission<ImportDescriptor> {
1890 pub fn query(&self, host: Option<&ImportDescriptor>) -> PermissionState {
1891 self.query_desc(host, AllowPartial::TreatAsPartialGranted)
1892 }
1893
1894 pub fn request(
1895 &mut self,
1896 host: Option<&ImportDescriptor>,
1897 ) -> PermissionState {
1898 self.request_desc(host)
1899 }
1900
1901 pub fn revoke(&mut self, host: Option<&ImportDescriptor>) -> PermissionState {
1902 self.revoke_desc(host)
1903 }
1904
1905 pub fn check(
1906 &mut self,
1907 host: &ImportDescriptor,
1908 api_name: Option<&str>,
1909 ) -> Result<(), PermissionDeniedError> {
1910 skip_check_if_is_permission_fully_granted!(self);
1911 self.check_desc(Some(host), false, api_name)
1912 }
1913
1914 pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> {
1915 skip_check_if_is_permission_fully_granted!(self);
1916 self.check_desc(None, false, None)
1917 }
1918}
1919
1920impl UnaryPermission<EnvQueryDescriptor> {
1921 pub fn query(&self, env: Option<&str>) -> PermissionState {
1922 self.query_desc(
1923 env.map(EnvQueryDescriptor::new).as_ref(),
1924 AllowPartial::TreatAsPartialGranted,
1925 )
1926 }
1927
1928 pub fn request(&mut self, env: Option<&str>) -> PermissionState {
1929 self.request_desc(env.map(EnvQueryDescriptor::new).as_ref())
1930 }
1931
1932 pub fn revoke(&mut self, env: Option<&str>) -> PermissionState {
1933 self.revoke_desc(env.map(EnvQueryDescriptor::new).as_ref())
1934 }
1935
1936 pub fn check(
1937 &mut self,
1938 env: &str,
1939 api_name: Option<&str>,
1940 ) -> Result<(), PermissionDeniedError> {
1941 skip_check_if_is_permission_fully_granted!(self);
1942 self.check_desc(Some(&EnvQueryDescriptor::new(env)), false, api_name)
1943 }
1944
1945 pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> {
1946 skip_check_if_is_permission_fully_granted!(self);
1947 self.check_desc(None, false, None)
1948 }
1949}
1950
1951impl UnaryPermission<SysDescriptor> {
1952 pub fn query(&self, kind: Option<&SysDescriptor>) -> PermissionState {
1953 self.query_desc(kind, AllowPartial::TreatAsPartialGranted)
1954 }
1955
1956 pub fn request(&mut self, kind: Option<&SysDescriptor>) -> PermissionState {
1957 self.request_desc(kind)
1958 }
1959
1960 pub fn revoke(&mut self, kind: Option<&SysDescriptor>) -> PermissionState {
1961 self.revoke_desc(kind)
1962 }
1963
1964 pub fn check(
1965 &mut self,
1966 kind: &SysDescriptor,
1967 api_name: Option<&str>,
1968 ) -> Result<(), PermissionDeniedError> {
1969 skip_check_if_is_permission_fully_granted!(self);
1970 self.check_desc(Some(kind), false, api_name)
1971 }
1972
1973 pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> {
1974 skip_check_if_is_permission_fully_granted!(self);
1975 self.check_desc(None, false, None)
1976 }
1977}
1978
1979impl UnaryPermission<RunQueryDescriptor> {
1980 pub fn query(&self, cmd: Option<&RunQueryDescriptor>) -> PermissionState {
1981 self.query_desc(cmd, AllowPartial::TreatAsPartialGranted)
1982 }
1983
1984 pub fn request(
1985 &mut self,
1986 cmd: Option<&RunQueryDescriptor>,
1987 ) -> PermissionState {
1988 self.request_desc(cmd)
1989 }
1990
1991 pub fn revoke(
1992 &mut self,
1993 cmd: Option<&RunQueryDescriptor>,
1994 ) -> PermissionState {
1995 self.revoke_desc(cmd)
1996 }
1997
1998 pub fn check(
1999 &mut self,
2000 cmd: &RunQueryDescriptor,
2001 api_name: Option<&str>,
2002 ) -> Result<(), PermissionDeniedError> {
2003 self.check_desc(Some(cmd), false, api_name)
2004 }
2005
2006 pub fn check_all(
2007 &mut self,
2008 api_name: Option<&str>,
2009 ) -> Result<(), PermissionDeniedError> {
2010 self.check_desc(None, false, api_name)
2011 }
2012
2013 pub fn query_all(&mut self, api_name: Option<&str>) -> bool {
2015 if self.is_allow_all() {
2016 return true;
2017 }
2018 let (result, _prompted, _is_allow_all) =
2019 self.query_desc(None, AllowPartial::TreatAsDenied).check2(
2020 RunQueryDescriptor::flag_name(),
2021 api_name,
2022 || None,
2023 false,
2024 );
2025 result.is_ok()
2026 }
2027}
2028
2029impl UnaryPermission<FfiQueryDescriptor> {
2030 pub fn query(&self, path: Option<&FfiQueryDescriptor>) -> PermissionState {
2031 self.query_desc(path, AllowPartial::TreatAsPartialGranted)
2032 }
2033
2034 pub fn request(
2035 &mut self,
2036 path: Option<&FfiQueryDescriptor>,
2037 ) -> PermissionState {
2038 self.request_desc(path)
2039 }
2040
2041 pub fn revoke(
2042 &mut self,
2043 path: Option<&FfiQueryDescriptor>,
2044 ) -> PermissionState {
2045 self.revoke_desc(path)
2046 }
2047
2048 pub fn check(
2049 &mut self,
2050 path: &FfiQueryDescriptor,
2051 api_name: Option<&str>,
2052 ) -> Result<(), PermissionDeniedError> {
2053 skip_check_if_is_permission_fully_granted!(self);
2054 self.check_desc(Some(path), true, api_name)
2055 }
2056
2057 pub fn check_partial(
2058 &mut self,
2059 path: Option<&FfiQueryDescriptor>,
2060 ) -> Result<(), PermissionDeniedError> {
2061 skip_check_if_is_permission_fully_granted!(self);
2062 self.check_desc(path, false, None)
2063 }
2064
2065 pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> {
2066 skip_check_if_is_permission_fully_granted!(self);
2067 self.check_desc(None, false, Some("all"))
2068 }
2069}
2070
2071#[derive(Clone, Debug, Eq, PartialEq)]
2072pub struct Permissions {
2073 pub read: UnaryPermission<ReadQueryDescriptor>,
2074 pub write: UnaryPermission<WriteQueryDescriptor>,
2075 pub net: UnaryPermission<NetDescriptor>,
2076 pub env: UnaryPermission<EnvQueryDescriptor>,
2077 pub sys: UnaryPermission<SysDescriptor>,
2078 pub run: UnaryPermission<RunQueryDescriptor>,
2079 pub ffi: UnaryPermission<FfiQueryDescriptor>,
2080 pub import: UnaryPermission<ImportDescriptor>,
2081 pub all: UnitPermission,
2082}
2083
2084#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
2085pub struct PermissionsOptions {
2086 pub allow_all: bool,
2087 pub allow_env: Option<Vec<String>>,
2088 pub deny_env: Option<Vec<String>>,
2089 pub allow_net: Option<Vec<String>>,
2090 pub deny_net: Option<Vec<String>>,
2091 pub allow_ffi: Option<Vec<String>>,
2092 pub deny_ffi: Option<Vec<String>>,
2093 pub allow_read: Option<Vec<String>>,
2094 pub deny_read: Option<Vec<String>>,
2095 pub allow_run: Option<Vec<String>>,
2096 pub deny_run: Option<Vec<String>>,
2097 pub allow_sys: Option<Vec<String>>,
2098 pub deny_sys: Option<Vec<String>>,
2099 pub allow_write: Option<Vec<String>>,
2100 pub deny_write: Option<Vec<String>>,
2101 pub allow_import: Option<Vec<String>>,
2102 pub prompt: bool,
2103}
2104
2105#[derive(Debug, thiserror::Error)]
2106pub enum PermissionsFromOptionsError {
2107 #[error("{0}")]
2108 PathResolve(#[from] PathResolveError),
2109 #[error("{0}")]
2110 SysDescriptorParse(#[from] SysDescriptorParseError),
2111 #[error("{0}")]
2112 NetDescriptorParse(#[from] NetDescriptorParseError),
2113 #[error("{0}")]
2114 EnvDescriptorParse(#[from] EnvDescriptorParseError),
2115 #[error("{0}")]
2116 RunDescriptorParse(#[from] RunDescriptorParseError),
2117 #[error("Empty command name not allowed in --allow-run=...")]
2118 RunEmptyCommandName,
2119}
2120
2121impl Permissions {
2122 pub fn new_unary<TQuery>(
2123 allow_list: Option<HashSet<TQuery::AllowDesc>>,
2124 deny_list: Option<HashSet<TQuery::DenyDesc>>,
2125 prompt: bool,
2126 ) -> UnaryPermission<TQuery>
2127 where
2128 TQuery: QueryDescriptor,
2129 {
2130 UnaryPermission::<TQuery> {
2131 granted_global: global_from_option(allow_list.as_ref()),
2132 granted_list: allow_list.unwrap_or_default(),
2133 flag_denied_global: global_from_option(deny_list.as_ref()),
2134 flag_denied_list: deny_list.unwrap_or_default(),
2135 prompt,
2136 ..Default::default()
2137 }
2138 }
2139
2140 pub const fn new_all(allow_state: bool) -> UnitPermission {
2141 unit_permission_from_flag_bools(
2142 allow_state,
2143 false,
2144 "all",
2145 "all",
2146 false, )
2148 }
2149
2150 pub fn from_options(
2151 parser: &dyn PermissionDescriptorParser,
2152 opts: &PermissionsOptions,
2153 ) -> Result<Self, PermissionsFromOptionsError> {
2154 fn resolve_allow_run(
2155 parser: &dyn PermissionDescriptorParser,
2156 allow_run: &[String],
2157 ) -> Result<HashSet<AllowRunDescriptor>, PermissionsFromOptionsError> {
2158 let mut new_allow_run = HashSet::with_capacity(allow_run.len());
2159 for unresolved in allow_run {
2160 if unresolved.is_empty() {
2161 return Err(PermissionsFromOptionsError::RunEmptyCommandName);
2162 }
2163 match parser.parse_allow_run_descriptor(unresolved)? {
2164 AllowRunDescriptorParseResult::Descriptor(descriptor) => {
2165 new_allow_run.insert(descriptor);
2166 }
2167 AllowRunDescriptorParseResult::Unresolved(err) => {
2168 log::info!(
2169 "{} Failed to resolve '{}' for allow-run: {}",
2170 colors::gray("Info"),
2171 unresolved,
2172 err
2173 );
2174 }
2175 }
2176 }
2177 Ok(new_allow_run)
2178 }
2179
2180 fn parse_maybe_vec<T: Eq + PartialEq + Hash, E>(
2181 items: Option<&[String]>,
2182 parse: impl Fn(&str) -> Result<T, E>,
2183 ) -> Result<Option<HashSet<T>>, PermissionsFromOptionsError>
2184 where
2185 PermissionsFromOptionsError: From<E>,
2186 {
2187 match items {
2188 Some(items) => Ok(Some(
2189 items
2190 .iter()
2191 .map(|item| parse(item))
2192 .collect::<Result<HashSet<_>, _>>()?,
2193 )),
2194 None => Ok(None),
2195 }
2196 }
2197
2198 let mut deny_write = parse_maybe_vec(opts.deny_write.as_deref(), |item| {
2199 parser.parse_write_descriptor(item)
2200 })?;
2201 let allow_run = opts
2202 .allow_run
2203 .as_ref()
2204 .and_then(|raw_allow_run| {
2205 match resolve_allow_run(parser, raw_allow_run) {
2206 Ok(resolved_allow_run) => {
2207 if resolved_allow_run.is_empty() && !raw_allow_run.is_empty() {
2208 None } else {
2210 Some(Ok(resolved_allow_run))
2211 }
2212 }
2213 Err(err) => Some(Err(err)),
2214 }
2215 })
2216 .transpose()?;
2217 if let Some(allow_run_vec) = &allow_run {
2219 if !allow_run_vec.is_empty() {
2220 let deny_write = deny_write.get_or_insert_with(Default::default);
2221 deny_write.extend(
2222 allow_run_vec
2223 .iter()
2224 .map(|item| WriteDescriptor(item.0.clone())),
2225 );
2226 }
2227 }
2228
2229 Ok(Self {
2230 read: Permissions::new_unary(
2231 parse_maybe_vec(opts.allow_read.as_deref(), |item| {
2232 parser.parse_read_descriptor(item)
2233 })?,
2234 parse_maybe_vec(opts.deny_read.as_deref(), |item| {
2235 parser.parse_read_descriptor(item)
2236 })?,
2237 opts.prompt,
2238 ),
2239 write: Permissions::new_unary(
2240 parse_maybe_vec(opts.allow_write.as_deref(), |item| {
2241 parser.parse_write_descriptor(item)
2242 })?,
2243 deny_write,
2244 opts.prompt,
2245 ),
2246 net: Permissions::new_unary(
2247 parse_maybe_vec(opts.allow_net.as_deref(), |item| {
2248 parser.parse_net_descriptor(item)
2249 })?,
2250 parse_maybe_vec(opts.deny_net.as_deref(), |item| {
2251 parser.parse_net_descriptor(item)
2252 })?,
2253 opts.prompt,
2254 ),
2255 env: Permissions::new_unary(
2256 parse_maybe_vec(opts.allow_env.as_deref(), |item| {
2257 parser.parse_env_descriptor(item)
2258 })?,
2259 parse_maybe_vec(opts.deny_env.as_deref(), |text| {
2260 parser.parse_env_descriptor(text)
2261 })?,
2262 opts.prompt,
2263 ),
2264 sys: Permissions::new_unary(
2265 parse_maybe_vec(opts.allow_sys.as_deref(), |text| {
2266 parser.parse_sys_descriptor(text)
2267 })?,
2268 parse_maybe_vec(opts.deny_sys.as_deref(), |text| {
2269 parser.parse_sys_descriptor(text)
2270 })?,
2271 opts.prompt,
2272 ),
2273 run: Permissions::new_unary(
2274 allow_run,
2275 parse_maybe_vec(opts.deny_run.as_deref(), |text| {
2276 parser.parse_deny_run_descriptor(text)
2277 })?,
2278 opts.prompt,
2279 ),
2280 ffi: Permissions::new_unary(
2281 parse_maybe_vec(opts.allow_ffi.as_deref(), |text| {
2282 parser.parse_ffi_descriptor(text)
2283 })?,
2284 parse_maybe_vec(opts.deny_ffi.as_deref(), |text| {
2285 parser.parse_ffi_descriptor(text)
2286 })?,
2287 opts.prompt,
2288 ),
2289 import: Permissions::new_unary(
2290 parse_maybe_vec(opts.allow_import.as_deref(), |item| {
2291 parser.parse_import_descriptor(item)
2292 })?,
2293 None,
2294 opts.prompt,
2295 ),
2296 all: Permissions::new_all(opts.allow_all),
2297 })
2298 }
2299
2300 pub fn allow_all() -> Self {
2302 Self {
2303 read: UnaryPermission::allow_all(),
2304 write: UnaryPermission::allow_all(),
2305 net: UnaryPermission::allow_all(),
2306 env: UnaryPermission::allow_all(),
2307 sys: UnaryPermission::allow_all(),
2308 run: UnaryPermission::allow_all(),
2309 ffi: UnaryPermission::allow_all(),
2310 import: UnaryPermission::allow_all(),
2311 all: Permissions::new_all(true),
2312 }
2313 }
2314
2315 pub fn none_with_prompt() -> Self {
2317 Self::none(true)
2318 }
2319
2320 pub fn none_without_prompt() -> Self {
2322 Self::none(false)
2323 }
2324
2325 fn none(prompt: bool) -> Self {
2326 Self {
2327 read: Permissions::new_unary(None, None, prompt),
2328 write: Permissions::new_unary(None, None, prompt),
2329 net: Permissions::new_unary(None, None, prompt),
2330 env: Permissions::new_unary(None, None, prompt),
2331 sys: Permissions::new_unary(None, None, prompt),
2332 run: Permissions::new_unary(None, None, prompt),
2333 ffi: Permissions::new_unary(None, None, prompt),
2334 import: Permissions::new_unary(None, None, prompt),
2335 all: Permissions::new_all(false),
2336 }
2337 }
2338}
2339
2340#[derive(Debug, Clone, Copy, Eq, PartialEq)]
2341pub enum CheckSpecifierKind {
2342 Static,
2343 Dynamic,
2344}
2345
2346#[derive(Debug, thiserror::Error, deno_error::JsError)]
2347pub enum ChildPermissionError {
2348 #[class("NotCapable")]
2349 #[error("Can't escalate parent thread permissions")]
2350 Escalation,
2351 #[class(inherit)]
2352 #[error("{0}")]
2353 PathResolve(#[from] PathResolveError),
2354 #[class(uri)]
2355 #[error("{0}")]
2356 NetDescriptorParse(#[from] NetDescriptorParseError),
2357 #[class(generic)]
2358 #[error("{0}")]
2359 EnvDescriptorParse(#[from] EnvDescriptorParseError),
2360 #[class(inherit)]
2361 #[error("{0}")]
2362 SysDescriptorParse(#[from] SysDescriptorParseError),
2363 #[class(inherit)]
2364 #[error("{0}")]
2365 RunDescriptorParse(#[from] RunDescriptorParseError),
2366}
2367
2368#[derive(Debug, thiserror::Error, deno_error::JsError)]
2369pub enum PermissionCheckError {
2370 #[class("NotCapable")]
2371 #[error(transparent)]
2372 PermissionDenied(#[from] PermissionDeniedError),
2373 #[class(uri)]
2374 #[error("Invalid file path.\n Specifier: {0}")]
2375 InvalidFilePath(Url),
2376 #[class(inherit)]
2377 #[error(transparent)]
2378 NetDescriptorForUrlParse(#[from] NetDescriptorFromUrlParseError),
2379 #[class(inherit)]
2380 #[error(transparent)]
2381 SysDescriptorParse(#[from] SysDescriptorParseError),
2382 #[class(inherit)]
2383 #[error(transparent)]
2384 PathResolve(#[from] PathResolveError),
2385 #[class(uri)]
2386 #[error(transparent)]
2387 HostParse(#[from] HostParseError),
2388 #[class("NotCapable")]
2389 #[error("Permission denied {0}")]
2390 NotCapable(&'static str),
2391}
2392
2393#[derive(Clone, Debug)]
2400pub struct PermissionsContainer {
2401 descriptor_parser: Arc<dyn PermissionDescriptorParser>,
2402 inner: Arc<Mutex<Permissions>>,
2403}
2404
2405impl PermissionsContainer {
2406 pub fn new(
2407 descriptor_parser: Arc<dyn PermissionDescriptorParser>,
2408 perms: Permissions,
2409 ) -> Self {
2410 Self {
2411 descriptor_parser,
2412 inner: Arc::new(Mutex::new(perms)),
2413 }
2414 }
2415
2416 pub fn allow_all(
2417 descriptor_parser: Arc<dyn PermissionDescriptorParser>,
2418 ) -> Self {
2419 Self::new(descriptor_parser, Permissions::allow_all())
2420 }
2421
2422 pub fn create_child_permissions(
2423 &self,
2424 child_permissions_arg: ChildPermissionsArg,
2425 ) -> Result<PermissionsContainer, ChildPermissionError> {
2426 fn is_granted_unary(arg: &ChildUnaryPermissionArg) -> bool {
2427 match arg {
2428 ChildUnaryPermissionArg::Inherit | ChildUnaryPermissionArg::Granted => {
2429 true
2430 }
2431 ChildUnaryPermissionArg::NotGranted
2432 | ChildUnaryPermissionArg::GrantedList(_) => false,
2433 }
2434 }
2435
2436 let mut worker_perms = Permissions::none_without_prompt();
2437
2438 let mut inner = self.inner.lock();
2439 worker_perms.all = inner
2440 .all
2441 .create_child_permissions(ChildUnitPermissionArg::Inherit)?;
2442
2443 if worker_perms.all.query() == PermissionState::Granted {
2445 let unary_perms = [
2446 &child_permissions_arg.read,
2447 &child_permissions_arg.write,
2448 &child_permissions_arg.net,
2449 &child_permissions_arg.import,
2450 &child_permissions_arg.env,
2451 &child_permissions_arg.sys,
2452 &child_permissions_arg.run,
2453 &child_permissions_arg.ffi,
2454 ];
2455 let allow_all = unary_perms.into_iter().all(is_granted_unary);
2456 if !allow_all {
2457 worker_perms.all.revoke();
2458 }
2459 }
2460
2461 worker_perms.read = inner.read.create_child_permissions(
2464 child_permissions_arg.read,
2465 |text| {
2466 Ok::<_, PathResolveError>(Some(
2467 self.descriptor_parser.parse_read_descriptor(text)?,
2468 ))
2469 },
2470 )?;
2471 worker_perms.write = inner.write.create_child_permissions(
2472 child_permissions_arg.write,
2473 |text| {
2474 Ok::<_, PathResolveError>(Some(
2475 self.descriptor_parser.parse_write_descriptor(text)?,
2476 ))
2477 },
2478 )?;
2479 worker_perms.import = inner.import.create_child_permissions(
2480 child_permissions_arg.import,
2481 |text| {
2482 Ok::<_, NetDescriptorParseError>(Some(
2483 self.descriptor_parser.parse_import_descriptor(text)?,
2484 ))
2485 },
2486 )?;
2487 worker_perms.net = inner.net.create_child_permissions(
2488 child_permissions_arg.net,
2489 |text| {
2490 Ok::<_, NetDescriptorParseError>(Some(
2491 self.descriptor_parser.parse_net_descriptor(text)?,
2492 ))
2493 },
2494 )?;
2495 worker_perms.env = inner.env.create_child_permissions(
2496 child_permissions_arg.env,
2497 |text| {
2498 Ok::<_, EnvDescriptorParseError>(Some(
2499 self.descriptor_parser.parse_env_descriptor(text)?,
2500 ))
2501 },
2502 )?;
2503 worker_perms.sys = inner.sys.create_child_permissions(
2504 child_permissions_arg.sys,
2505 |text| {
2506 Ok::<_, SysDescriptorParseError>(Some(
2507 self.descriptor_parser.parse_sys_descriptor(text)?,
2508 ))
2509 },
2510 )?;
2511 worker_perms.run = inner.run.create_child_permissions(
2512 child_permissions_arg.run,
2513 |text| match self.descriptor_parser.parse_allow_run_descriptor(text)? {
2514 AllowRunDescriptorParseResult::Unresolved(_) => {
2515 Ok::<_, RunDescriptorParseError>(None)
2516 }
2517 AllowRunDescriptorParseResult::Descriptor(desc) => Ok(Some(desc)),
2518 },
2519 )?;
2520 worker_perms.ffi = inner.ffi.create_child_permissions(
2521 child_permissions_arg.ffi,
2522 |text| {
2523 Ok::<_, PathResolveError>(Some(
2524 self.descriptor_parser.parse_ffi_descriptor(text)?,
2525 ))
2526 },
2527 )?;
2528
2529 Ok(PermissionsContainer::new(
2530 self.descriptor_parser.clone(),
2531 worker_perms,
2532 ))
2533 }
2534
2535 #[inline(always)]
2536 pub fn check_specifier(
2537 &self,
2538 specifier: &ModuleSpecifier,
2539 kind: CheckSpecifierKind,
2540 ) -> Result<(), PermissionCheckError> {
2541 let mut inner = self.inner.lock();
2542 match specifier.scheme() {
2543 "file" => {
2544 if inner.read.is_allow_all() || kind == CheckSpecifierKind::Static {
2545 return Ok(());
2546 }
2547
2548 match url_to_file_path(specifier) {
2549 Ok(path) => inner
2550 .read
2551 .check(
2552 &PathQueryDescriptor {
2553 requested: path.to_string_lossy().into_owned(),
2554 resolved: path,
2555 }
2556 .into_read(),
2557 Some("import()"),
2558 )
2559 .map_err(PermissionCheckError::PermissionDenied),
2560 Err(_) => {
2561 Err(PermissionCheckError::InvalidFilePath(specifier.clone()))
2562 }
2563 }
2564 }
2565 "data" => Ok(()),
2566 "blob" => Ok(()),
2567 _ => {
2568 if inner.import.is_allow_all() {
2569 return Ok(()); }
2571
2572 let desc = self
2573 .descriptor_parser
2574 .parse_import_descriptor_from_url(specifier)?;
2575 inner.import.check(&desc, Some("import()"))?;
2576 Ok(())
2577 }
2578 }
2579 }
2580
2581 #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
2582 #[inline(always)]
2583 pub fn check_read(
2584 &self,
2585 path: &str,
2586 api_name: &str,
2587 ) -> Result<PathBuf, PermissionCheckError> {
2588 self.check_read_with_api_name(path, Some(api_name))
2589 }
2590
2591 #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
2592 #[inline(always)]
2593 pub fn check_read_with_api_name(
2594 &self,
2595 path: &str,
2596 api_name: Option<&str>,
2597 ) -> Result<PathBuf, PermissionCheckError> {
2598 let mut inner = self.inner.lock();
2599 let inner = &mut inner.read;
2600 if inner.is_allow_all() {
2601 Ok(PathBuf::from(path))
2602 } else {
2603 let desc = self.descriptor_parser.parse_path_query(path)?.into_read();
2604 inner.check(&desc, api_name)?;
2605 Ok(desc.0.resolved)
2606 }
2607 }
2608
2609 #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
2610 #[inline(always)]
2611 pub fn check_read_path<'a>(
2612 &self,
2613 path: &'a Path,
2614 api_name: Option<&str>,
2615 ) -> Result<Cow<'a, Path>, PermissionCheckError> {
2616 let mut inner = self.inner.lock();
2617 let inner = &mut inner.read;
2618 if inner.is_allow_all() {
2619 Ok(Cow::Borrowed(path))
2620 } else {
2621 let desc = PathQueryDescriptor {
2622 requested: path.to_string_lossy().into_owned(),
2623 resolved: path.to_path_buf(),
2624 }
2625 .into_read();
2626 inner.check(&desc, api_name)?;
2627
2628 Ok(Cow::Owned(desc.0.resolved))
2629 }
2630 }
2631
2632 #[inline(always)]
2635 pub fn check_read_blind(
2636 &self,
2637 path: &Path,
2638 display: &str,
2639 api_name: &str,
2640 ) -> Result<(), PermissionCheckError> {
2641 let mut inner = self.inner.lock();
2642 let inner = &mut inner.read;
2643 skip_check_if_is_permission_fully_granted!(inner);
2644 inner.check(
2645 &PathQueryDescriptor {
2646 requested: format!("<{}>", display),
2647 resolved: path.to_path_buf(),
2648 }
2649 .into_read(),
2650 Some(api_name),
2651 )?;
2652 Ok(())
2653 }
2654
2655 #[inline(always)]
2656 pub fn check_read_all(
2657 &self,
2658 api_name: &str,
2659 ) -> Result<(), PermissionCheckError> {
2660 self.inner.lock().read.check_all(Some(api_name))?;
2661 Ok(())
2662 }
2663
2664 #[inline(always)]
2665 pub fn query_read_all(&self) -> bool {
2666 self.inner.lock().read.query(None) == PermissionState::Granted
2667 }
2668
2669 #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
2670 #[inline(always)]
2671 pub fn check_write(
2672 &self,
2673 path: &str,
2674 api_name: &str,
2675 ) -> Result<PathBuf, PermissionCheckError> {
2676 self.check_write_with_api_name(path, Some(api_name))
2677 }
2678
2679 #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
2680 #[inline(always)]
2681 pub fn check_write_with_api_name(
2682 &self,
2683 path: &str,
2684 api_name: Option<&str>,
2685 ) -> Result<PathBuf, PermissionCheckError> {
2686 let mut inner = self.inner.lock();
2687 let inner = &mut inner.write;
2688 if inner.is_allow_all() {
2689 Ok(PathBuf::from(path))
2690 } else {
2691 let desc = self.descriptor_parser.parse_path_query(path)?.into_write();
2692 inner.check(&desc, api_name)?;
2693 Ok(desc.0.resolved)
2694 }
2695 }
2696
2697 #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
2698 #[inline(always)]
2699 pub fn check_write_path<'a>(
2700 &self,
2701 path: &'a Path,
2702 api_name: &str,
2703 ) -> Result<Cow<'a, Path>, PermissionCheckError> {
2704 let mut inner = self.inner.lock();
2705 let inner = &mut inner.write;
2706 if inner.is_allow_all() {
2707 Ok(Cow::Borrowed(path))
2708 } else {
2709 let desc = PathQueryDescriptor {
2710 requested: path.to_string_lossy().into_owned(),
2711 resolved: path.to_path_buf(),
2712 }
2713 .into_write();
2714 inner.check(&desc, Some(api_name))?;
2715 Ok(Cow::Owned(desc.0.resolved))
2716 }
2717 }
2718
2719 #[inline(always)]
2720 pub fn check_write_all(
2721 &self,
2722 api_name: &str,
2723 ) -> Result<(), PermissionCheckError> {
2724 self.inner.lock().write.check_all(Some(api_name))?;
2725 Ok(())
2726 }
2727
2728 #[inline(always)]
2731 pub fn check_write_blind(
2732 &self,
2733 path: &Path,
2734 display: &str,
2735 api_name: &str,
2736 ) -> Result<(), PermissionCheckError> {
2737 let mut inner = self.inner.lock();
2738 let inner = &mut inner.write;
2739 skip_check_if_is_permission_fully_granted!(inner);
2740 inner.check(
2741 &PathQueryDescriptor {
2742 requested: format!("<{}>", display),
2743 resolved: path.to_path_buf(),
2744 }
2745 .into_write(),
2746 Some(api_name),
2747 )?;
2748 Ok(())
2749 }
2750
2751 #[inline(always)]
2752 pub fn check_write_partial(
2753 &self,
2754 path: &str,
2755 api_name: &str,
2756 ) -> Result<PathBuf, PermissionCheckError> {
2757 let mut inner = self.inner.lock();
2758 let inner = &mut inner.write;
2759 if inner.is_allow_all() {
2760 Ok(PathBuf::from(path))
2761 } else {
2762 let desc = self.descriptor_parser.parse_path_query(path)?.into_write();
2763 inner.check_partial(&desc, Some(api_name))?;
2764 Ok(desc.0.resolved)
2765 }
2766 }
2767
2768 #[inline(always)]
2769 pub fn check_run(
2770 &self,
2771 cmd: &RunQueryDescriptor,
2772 api_name: &str,
2773 ) -> Result<(), PermissionCheckError> {
2774 self.inner.lock().run.check(cmd, Some(api_name))?;
2775 Ok(())
2776 }
2777
2778 #[inline(always)]
2779 pub fn check_run_all(
2780 &mut self,
2781 api_name: &str,
2782 ) -> Result<(), PermissionCheckError> {
2783 self.inner.lock().run.check_all(Some(api_name))?;
2784 Ok(())
2785 }
2786
2787 #[inline(always)]
2788 pub fn query_run_all(&mut self, api_name: &str) -> bool {
2789 self.inner.lock().run.query_all(Some(api_name))
2790 }
2791
2792 #[inline(always)]
2793 pub fn check_sys(
2794 &self,
2795 kind: &str,
2796 api_name: &str,
2797 ) -> Result<(), PermissionCheckError> {
2798 self.inner.lock().sys.check(
2799 &self.descriptor_parser.parse_sys_descriptor(kind)?,
2800 Some(api_name),
2801 )?;
2802 Ok(())
2803 }
2804
2805 #[inline(always)]
2806 pub fn check_env(&self, var: &str) -> Result<(), PermissionCheckError> {
2807 self.inner.lock().env.check(var, None)?;
2808 Ok(())
2809 }
2810
2811 #[inline(always)]
2812 pub fn check_env_all(&self) -> Result<(), PermissionCheckError> {
2813 self.inner.lock().env.check_all()?;
2814 Ok(())
2815 }
2816
2817 #[inline(always)]
2818 pub fn check_sys_all(&self) -> Result<(), PermissionCheckError> {
2819 self.inner.lock().sys.check_all()?;
2820 Ok(())
2821 }
2822
2823 #[inline(always)]
2824 pub fn check_ffi_all(&self) -> Result<(), PermissionCheckError> {
2825 self.inner.lock().ffi.check_all()?;
2826 Ok(())
2827 }
2828
2829 #[inline(always)]
2832 pub fn check_was_allow_all_flag_passed(
2833 &self,
2834 ) -> Result<(), PermissionCheckError> {
2835 self.inner.lock().all.check()?;
2836 Ok(())
2837 }
2838
2839 pub fn check_special_file(
2842 &self,
2843 path: &Path,
2844 _api_name: &str,
2845 ) -> Result<(), &'static str> {
2846 let error_all = |_| "all";
2847
2848 if cfg!(unix)
2852 && (path == OsStr::new("/dev/random")
2853 || path == OsStr::new("/dev/urandom")
2854 || path == OsStr::new("/dev/zero")
2855 || path == OsStr::new("/dev/null"))
2856 {
2857 return Ok(());
2858 }
2859
2860 #[cfg(unix)]
2865 fn is_fd_file_is_pipe(path: &Path) -> bool {
2866 if let Some(fd) = path.file_name() {
2867 if let Ok(s) = std::str::from_utf8(fd.as_encoded_bytes()) {
2868 if let Ok(n) = s.parse::<i32>() {
2869 if n > 2 {
2870 unsafe {
2872 let mut stat = std::mem::zeroed::<libc::stat>();
2873 if libc::fstat(n, &mut stat as _) == 0
2874 && ((stat.st_mode & libc::S_IFMT) & libc::S_IFIFO) != 0
2875 {
2876 return true;
2877 }
2878 };
2879 }
2880 }
2881 }
2882 }
2883 false
2884 }
2885
2886 #[cfg(unix)]
2889 if path.starts_with("/dev/fd") && is_fd_file_is_pipe(path) {
2890 return Ok(());
2891 }
2892
2893 if cfg!(target_os = "linux") {
2894 #[cfg(unix)]
2897 if path.starts_with("/proc/self/fd") && is_fd_file_is_pipe(path) {
2898 return Ok(());
2899 }
2900 if path.starts_with("/dev")
2901 || path.starts_with("/proc")
2902 || path.starts_with("/sys")
2903 {
2904 if path.ends_with("/environ") {
2905 self.check_env_all().map_err(|_| "env")?;
2906 } else {
2907 self.check_was_allow_all_flag_passed().map_err(error_all)?;
2908 }
2909 }
2910 } else if cfg!(unix) {
2911 if path.starts_with("/dev") {
2912 self.check_was_allow_all_flag_passed().map_err(error_all)?;
2913 }
2914 } else if cfg!(target_os = "windows") {
2915 let s = path.as_os_str().as_encoded_bytes();
2917 if s.eq_ignore_ascii_case(br#"\\.\nul"#) {
2918 return Ok(());
2919 }
2920
2921 fn is_normalized_windows_drive_path(path: &Path) -> bool {
2922 let s = path.as_os_str().as_encoded_bytes();
2923 if s.len() < 7 {
2925 false
2926 } else if s.starts_with(br#"\\?\"#) {
2927 s[4].is_ascii_alphabetic() && s[5] == b':' && s[6] == b'\\'
2928 } else {
2929 false
2930 }
2931 }
2932
2933 if !is_normalized_windows_drive_path(path) {
2935 self.check_was_allow_all_flag_passed().map_err(error_all)?;
2936 }
2937 } else {
2938 unimplemented!()
2939 }
2940 Ok(())
2941 }
2942
2943 #[inline(always)]
2944 pub fn check_net_url(
2945 &mut self,
2946 url: &Url,
2947 api_name: &str,
2948 ) -> Result<(), PermissionCheckError> {
2949 let mut inner = self.inner.lock();
2950 if inner.net.is_allow_all() {
2951 return Ok(());
2952 }
2953 let desc = self.descriptor_parser.parse_net_descriptor_from_url(url)?;
2954 inner.net.check(&desc, Some(api_name))?;
2955 Ok(())
2956 }
2957
2958 #[inline(always)]
2959 pub fn check_net<T: AsRef<str>>(
2960 &mut self,
2961 host: &(T, Option<u16>),
2962 api_name: &str,
2963 ) -> Result<(), PermissionCheckError> {
2964 let mut inner = self.inner.lock();
2965 let inner = &mut inner.net;
2966 skip_check_if_is_permission_fully_granted!(inner);
2967 let hostname = Host::parse(host.0.as_ref())?;
2968 let descriptor = NetDescriptor(hostname, host.1.map(Into::into));
2969 inner.check(&descriptor, Some(api_name))?;
2970 Ok(())
2971 }
2972
2973 #[inline(always)]
2974 pub fn check_net_vsock(
2975 &mut self,
2976 cid: u32,
2977 port: u32,
2978 api_name: &str,
2979 ) -> Result<(), PermissionCheckError> {
2980 let mut inner = self.inner.lock();
2981 if inner.net.is_allow_all() {
2982 return Ok(());
2983 }
2984 let desc = NetDescriptor(Host::Vsock(cid), Some(port));
2985 inner.net.check(&desc, Some(api_name))?;
2986 Ok(())
2987 }
2988
2989 #[inline(always)]
2990 pub fn check_ffi(
2991 &mut self,
2992 path: &str,
2993 ) -> Result<PathBuf, PermissionCheckError> {
2994 let mut inner = self.inner.lock();
2995 let inner = &mut inner.ffi;
2996 if inner.is_allow_all() {
2997 Ok(PathBuf::from(path))
2998 } else {
2999 let desc = self.descriptor_parser.parse_path_query(path)?.into_ffi();
3000 inner.check(&desc, None)?;
3001 Ok(desc.0.resolved)
3002 }
3003 }
3004
3005 #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
3006 #[inline(always)]
3007 pub fn check_ffi_partial_no_path(
3008 &mut self,
3009 ) -> Result<(), PermissionCheckError> {
3010 let mut inner = self.inner.lock();
3011 let inner = &mut inner.ffi;
3012 if !inner.is_allow_all() {
3013 inner.check_partial(None)?;
3014 }
3015 Ok(())
3016 }
3017
3018 #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
3019 #[inline(always)]
3020 pub fn check_ffi_partial_with_path(
3021 &mut self,
3022 path: &str,
3023 ) -> Result<PathBuf, PermissionCheckError> {
3024 let mut inner = self.inner.lock();
3025 let inner = &mut inner.ffi;
3026 if inner.is_allow_all() {
3027 Ok(PathBuf::from(path))
3028 } else {
3029 let desc = self.descriptor_parser.parse_path_query(path)?.into_ffi();
3030 inner.check_partial(Some(&desc))?;
3031 Ok(desc.0.resolved)
3032 }
3033 }
3034
3035 #[inline(always)]
3038 pub fn query_read(
3039 &self,
3040 path: Option<&str>,
3041 ) -> Result<PermissionState, PathResolveError> {
3042 let inner = self.inner.lock();
3043 let permission = &inner.read;
3044 if permission.is_allow_all() {
3045 return Ok(PermissionState::Granted);
3046 }
3047 Ok(
3048 permission.query(
3049 path
3050 .map(|path| {
3051 Ok::<_, PathResolveError>(
3052 self.descriptor_parser.parse_path_query(path)?.into_read(),
3053 )
3054 })
3055 .transpose()?
3056 .as_ref(),
3057 ),
3058 )
3059 }
3060
3061 #[inline(always)]
3062 pub fn query_write(
3063 &self,
3064 path: Option<&str>,
3065 ) -> Result<PermissionState, PathResolveError> {
3066 let inner = self.inner.lock();
3067 let permission = &inner.write;
3068 if permission.is_allow_all() {
3069 return Ok(PermissionState::Granted);
3070 }
3071 Ok(
3072 permission.query(
3073 path
3074 .map(|path| {
3075 Ok::<_, PathResolveError>(
3076 self.descriptor_parser.parse_path_query(path)?.into_write(),
3077 )
3078 })
3079 .transpose()?
3080 .as_ref(),
3081 ),
3082 )
3083 }
3084
3085 #[inline(always)]
3086 pub fn query_net(
3087 &self,
3088 host: Option<&str>,
3089 ) -> Result<PermissionState, NetDescriptorParseError> {
3090 let inner = self.inner.lock();
3091 let permission = &inner.net;
3092 if permission.is_allow_all() {
3093 return Ok(PermissionState::Granted);
3094 }
3095 Ok(
3096 permission.query(
3097 match host {
3098 None => None,
3099 Some(h) => Some(self.descriptor_parser.parse_net_descriptor(h)?),
3100 }
3101 .as_ref(),
3102 ),
3103 )
3104 }
3105
3106 #[inline(always)]
3107 pub fn query_env(&self, var: Option<&str>) -> PermissionState {
3108 let inner = self.inner.lock();
3109 let permission = &inner.env;
3110 if permission.is_allow_all() {
3111 return PermissionState::Granted;
3112 }
3113 permission.query(var)
3114 }
3115
3116 #[inline(always)]
3117 pub fn query_sys(
3118 &self,
3119 kind: Option<&str>,
3120 ) -> Result<PermissionState, SysDescriptorParseError> {
3121 let inner = self.inner.lock();
3122 let permission = &inner.sys;
3123 if permission.is_allow_all() {
3124 return Ok(PermissionState::Granted);
3125 }
3126 Ok(
3127 permission.query(
3128 kind
3129 .map(|kind| self.descriptor_parser.parse_sys_descriptor(kind))
3130 .transpose()?
3131 .as_ref(),
3132 ),
3133 )
3134 }
3135
3136 #[inline(always)]
3137 pub fn query_run(
3138 &self,
3139 cmd: Option<&str>,
3140 ) -> Result<PermissionState, RunDescriptorParseError> {
3141 let inner = self.inner.lock();
3142 let permission = &inner.run;
3143 if permission.is_allow_all() {
3144 return Ok(PermissionState::Granted);
3145 }
3146 Ok(
3147 permission.query(
3148 cmd
3149 .map(|request| self.descriptor_parser.parse_run_query(request))
3150 .transpose()?
3151 .as_ref(),
3152 ),
3153 )
3154 }
3155
3156 #[inline(always)]
3157 pub fn query_ffi(
3158 &self,
3159 path: Option<&str>,
3160 ) -> Result<PermissionState, PathResolveError> {
3161 let inner = self.inner.lock();
3162 let permission = &inner.ffi;
3163 if permission.is_allow_all() {
3164 return Ok(PermissionState::Granted);
3165 }
3166 Ok(
3167 permission.query(
3168 path
3169 .map(|path| {
3170 Ok::<_, PathResolveError>(
3171 self.descriptor_parser.parse_path_query(path)?.into_ffi(),
3172 )
3173 })
3174 .transpose()?
3175 .as_ref(),
3176 ),
3177 )
3178 }
3179
3180 #[inline(always)]
3183 pub fn revoke_read(
3184 &self,
3185 path: Option<&str>,
3186 ) -> Result<PermissionState, PathResolveError> {
3187 Ok(
3188 self.inner.lock().read.revoke(
3189 path
3190 .map(|path| {
3191 Ok::<_, PathResolveError>(
3192 self.descriptor_parser.parse_path_query(path)?.into_read(),
3193 )
3194 })
3195 .transpose()?
3196 .as_ref(),
3197 ),
3198 )
3199 }
3200
3201 #[inline(always)]
3202 pub fn revoke_write(
3203 &self,
3204 path: Option<&str>,
3205 ) -> Result<PermissionState, PathResolveError> {
3206 Ok(
3207 self.inner.lock().write.revoke(
3208 path
3209 .map(|path| {
3210 Ok::<_, PathResolveError>(
3211 self.descriptor_parser.parse_path_query(path)?.into_write(),
3212 )
3213 })
3214 .transpose()?
3215 .as_ref(),
3216 ),
3217 )
3218 }
3219
3220 #[inline(always)]
3221 pub fn revoke_net(
3222 &self,
3223 host: Option<&str>,
3224 ) -> Result<PermissionState, NetDescriptorParseError> {
3225 Ok(
3226 self.inner.lock().net.revoke(
3227 match host {
3228 None => None,
3229 Some(h) => Some(self.descriptor_parser.parse_net_descriptor(h)?),
3230 }
3231 .as_ref(),
3232 ),
3233 )
3234 }
3235
3236 #[inline(always)]
3237 pub fn revoke_env(&self, var: Option<&str>) -> PermissionState {
3238 self.inner.lock().env.revoke(var)
3239 }
3240
3241 #[inline(always)]
3242 pub fn revoke_sys(
3243 &self,
3244 kind: Option<&str>,
3245 ) -> Result<PermissionState, SysDescriptorParseError> {
3246 Ok(
3247 self.inner.lock().sys.revoke(
3248 kind
3249 .map(|kind| self.descriptor_parser.parse_sys_descriptor(kind))
3250 .transpose()?
3251 .as_ref(),
3252 ),
3253 )
3254 }
3255
3256 #[inline(always)]
3257 pub fn revoke_run(
3258 &self,
3259 cmd: Option<&str>,
3260 ) -> Result<PermissionState, RunDescriptorParseError> {
3261 Ok(
3262 self.inner.lock().run.revoke(
3263 cmd
3264 .map(|request| self.descriptor_parser.parse_run_query(request))
3265 .transpose()?
3266 .as_ref(),
3267 ),
3268 )
3269 }
3270
3271 #[inline(always)]
3272 pub fn revoke_ffi(
3273 &self,
3274 path: Option<&str>,
3275 ) -> Result<PermissionState, PathResolveError> {
3276 Ok(
3277 self.inner.lock().ffi.revoke(
3278 path
3279 .map(|path| {
3280 Ok::<_, PathResolveError>(
3281 self.descriptor_parser.parse_path_query(path)?.into_ffi(),
3282 )
3283 })
3284 .transpose()?
3285 .as_ref(),
3286 ),
3287 )
3288 }
3289
3290 #[inline(always)]
3293 pub fn request_read(
3294 &self,
3295 path: Option<&str>,
3296 ) -> Result<PermissionState, PathResolveError> {
3297 Ok(
3298 self.inner.lock().read.request(
3299 path
3300 .map(|path| {
3301 Ok::<_, PathResolveError>(
3302 self.descriptor_parser.parse_path_query(path)?.into_read(),
3303 )
3304 })
3305 .transpose()?
3306 .as_ref(),
3307 ),
3308 )
3309 }
3310
3311 #[inline(always)]
3312 pub fn request_write(
3313 &self,
3314 path: Option<&str>,
3315 ) -> Result<PermissionState, PathResolveError> {
3316 Ok(
3317 self.inner.lock().write.request(
3318 path
3319 .map(|path| {
3320 Ok::<_, PathResolveError>(
3321 self.descriptor_parser.parse_path_query(path)?.into_write(),
3322 )
3323 })
3324 .transpose()?
3325 .as_ref(),
3326 ),
3327 )
3328 }
3329
3330 #[inline(always)]
3331 pub fn request_net(
3332 &self,
3333 host: Option<&str>,
3334 ) -> Result<PermissionState, NetDescriptorParseError> {
3335 Ok(
3336 self.inner.lock().net.request(
3337 match host {
3338 None => None,
3339 Some(h) => Some(self.descriptor_parser.parse_net_descriptor(h)?),
3340 }
3341 .as_ref(),
3342 ),
3343 )
3344 }
3345
3346 #[inline(always)]
3347 pub fn request_env(&self, var: Option<&str>) -> PermissionState {
3348 self.inner.lock().env.request(var)
3349 }
3350
3351 #[inline(always)]
3352 pub fn request_sys(
3353 &self,
3354 kind: Option<&str>,
3355 ) -> Result<PermissionState, SysDescriptorParseError> {
3356 Ok(
3357 self.inner.lock().sys.request(
3358 kind
3359 .map(|kind| self.descriptor_parser.parse_sys_descriptor(kind))
3360 .transpose()?
3361 .as_ref(),
3362 ),
3363 )
3364 }
3365
3366 #[inline(always)]
3367 pub fn request_run(
3368 &self,
3369 cmd: Option<&str>,
3370 ) -> Result<PermissionState, RunDescriptorParseError> {
3371 Ok(
3372 self.inner.lock().run.request(
3373 cmd
3374 .map(|request| self.descriptor_parser.parse_run_query(request))
3375 .transpose()?
3376 .as_ref(),
3377 ),
3378 )
3379 }
3380
3381 #[inline(always)]
3382 pub fn request_ffi(
3383 &self,
3384 path: Option<&str>,
3385 ) -> Result<PermissionState, PathResolveError> {
3386 Ok(
3387 self.inner.lock().ffi.request(
3388 path
3389 .map(|path| {
3390 Ok::<_, PathResolveError>(
3391 self.descriptor_parser.parse_path_query(path)?.into_ffi(),
3392 )
3393 })
3394 .transpose()?
3395 .as_ref(),
3396 ),
3397 )
3398 }
3399}
3400
3401const fn unit_permission_from_flag_bools(
3402 allow_flag: bool,
3403 deny_flag: bool,
3404 name: &'static str,
3405 description: &'static str,
3406 prompt: bool,
3407) -> UnitPermission {
3408 UnitPermission {
3409 name,
3410 description,
3411 state: if deny_flag {
3412 PermissionState::Denied
3413 } else if allow_flag {
3414 PermissionState::Granted
3415 } else {
3416 PermissionState::Prompt
3417 },
3418 prompt,
3419 }
3420}
3421
3422fn global_from_option<T>(flag: Option<&HashSet<T>>) -> bool {
3423 matches!(flag, Some(v) if v.is_empty())
3424}
3425
3426#[derive(Debug, Eq, PartialEq)]
3427pub enum ChildUnitPermissionArg {
3428 Inherit,
3429 Granted,
3430 NotGranted,
3431}
3432
3433impl<'de> Deserialize<'de> for ChildUnitPermissionArg {
3434 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
3435 where
3436 D: Deserializer<'de>,
3437 {
3438 struct ChildUnitPermissionArgVisitor;
3439 impl de::Visitor<'_> for ChildUnitPermissionArgVisitor {
3440 type Value = ChildUnitPermissionArg;
3441
3442 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
3443 formatter.write_str("\"inherit\" or boolean")
3444 }
3445
3446 fn visit_unit<E>(self) -> Result<ChildUnitPermissionArg, E>
3447 where
3448 E: de::Error,
3449 {
3450 Ok(ChildUnitPermissionArg::NotGranted)
3451 }
3452
3453 fn visit_str<E>(self, v: &str) -> Result<ChildUnitPermissionArg, E>
3454 where
3455 E: de::Error,
3456 {
3457 if v == "inherit" {
3458 Ok(ChildUnitPermissionArg::Inherit)
3459 } else {
3460 Err(de::Error::invalid_value(de::Unexpected::Str(v), &self))
3461 }
3462 }
3463
3464 fn visit_bool<E>(self, v: bool) -> Result<ChildUnitPermissionArg, E>
3465 where
3466 E: de::Error,
3467 {
3468 match v {
3469 true => Ok(ChildUnitPermissionArg::Granted),
3470 false => Ok(ChildUnitPermissionArg::NotGranted),
3471 }
3472 }
3473 }
3474 deserializer.deserialize_any(ChildUnitPermissionArgVisitor)
3475 }
3476}
3477
3478#[derive(Debug, Eq, PartialEq)]
3479pub enum ChildUnaryPermissionArg {
3480 Inherit,
3481 Granted,
3482 NotGranted,
3483 GrantedList(Vec<String>),
3484}
3485
3486impl<'de> Deserialize<'de> for ChildUnaryPermissionArg {
3487 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
3488 where
3489 D: Deserializer<'de>,
3490 {
3491 struct ChildUnaryPermissionArgVisitor;
3492 impl<'de> de::Visitor<'de> for ChildUnaryPermissionArgVisitor {
3493 type Value = ChildUnaryPermissionArg;
3494
3495 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
3496 formatter.write_str("\"inherit\" or boolean or string[]")
3497 }
3498
3499 fn visit_unit<E>(self) -> Result<ChildUnaryPermissionArg, E>
3500 where
3501 E: de::Error,
3502 {
3503 Ok(ChildUnaryPermissionArg::NotGranted)
3504 }
3505
3506 fn visit_str<E>(self, v: &str) -> Result<ChildUnaryPermissionArg, E>
3507 where
3508 E: de::Error,
3509 {
3510 if v == "inherit" {
3511 Ok(ChildUnaryPermissionArg::Inherit)
3512 } else {
3513 Err(de::Error::invalid_value(de::Unexpected::Str(v), &self))
3514 }
3515 }
3516
3517 fn visit_bool<E>(self, v: bool) -> Result<ChildUnaryPermissionArg, E>
3518 where
3519 E: de::Error,
3520 {
3521 match v {
3522 true => Ok(ChildUnaryPermissionArg::Granted),
3523 false => Ok(ChildUnaryPermissionArg::NotGranted),
3524 }
3525 }
3526
3527 fn visit_seq<V>(
3528 self,
3529 mut v: V,
3530 ) -> Result<ChildUnaryPermissionArg, V::Error>
3531 where
3532 V: de::SeqAccess<'de>,
3533 {
3534 let mut granted_list = vec![];
3535 while let Some(value) = v.next_element::<String>()? {
3536 granted_list.push(value);
3537 }
3538 Ok(ChildUnaryPermissionArg::GrantedList(granted_list))
3539 }
3540 }
3541 deserializer.deserialize_any(ChildUnaryPermissionArgVisitor)
3542 }
3543}
3544
3545#[derive(Debug, Eq, PartialEq)]
3547pub struct ChildPermissionsArg {
3548 env: ChildUnaryPermissionArg,
3549 net: ChildUnaryPermissionArg,
3550 ffi: ChildUnaryPermissionArg,
3551 import: ChildUnaryPermissionArg,
3552 read: ChildUnaryPermissionArg,
3553 run: ChildUnaryPermissionArg,
3554 sys: ChildUnaryPermissionArg,
3555 write: ChildUnaryPermissionArg,
3556}
3557
3558impl ChildPermissionsArg {
3559 pub fn inherit() -> Self {
3560 ChildPermissionsArg {
3561 env: ChildUnaryPermissionArg::Inherit,
3562 net: ChildUnaryPermissionArg::Inherit,
3563 ffi: ChildUnaryPermissionArg::Inherit,
3564 import: ChildUnaryPermissionArg::Inherit,
3565 read: ChildUnaryPermissionArg::Inherit,
3566 run: ChildUnaryPermissionArg::Inherit,
3567 sys: ChildUnaryPermissionArg::Inherit,
3568 write: ChildUnaryPermissionArg::Inherit,
3569 }
3570 }
3571
3572 pub fn none() -> Self {
3573 ChildPermissionsArg {
3574 env: ChildUnaryPermissionArg::NotGranted,
3575 net: ChildUnaryPermissionArg::NotGranted,
3576 ffi: ChildUnaryPermissionArg::NotGranted,
3577 import: ChildUnaryPermissionArg::NotGranted,
3578 read: ChildUnaryPermissionArg::NotGranted,
3579 run: ChildUnaryPermissionArg::NotGranted,
3580 sys: ChildUnaryPermissionArg::NotGranted,
3581 write: ChildUnaryPermissionArg::NotGranted,
3582 }
3583 }
3584}
3585
3586impl<'de> Deserialize<'de> for ChildPermissionsArg {
3587 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
3588 where
3589 D: Deserializer<'de>,
3590 {
3591 struct ChildPermissionsArgVisitor;
3592 impl<'de> de::Visitor<'de> for ChildPermissionsArgVisitor {
3593 type Value = ChildPermissionsArg;
3594
3595 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
3596 formatter.write_str("\"inherit\" or \"none\" or object")
3597 }
3598
3599 fn visit_unit<E>(self) -> Result<ChildPermissionsArg, E>
3600 where
3601 E: de::Error,
3602 {
3603 Ok(ChildPermissionsArg::inherit())
3604 }
3605
3606 fn visit_str<E>(self, v: &str) -> Result<ChildPermissionsArg, E>
3607 where
3608 E: de::Error,
3609 {
3610 if v == "inherit" {
3611 Ok(ChildPermissionsArg::inherit())
3612 } else if v == "none" {
3613 Ok(ChildPermissionsArg::none())
3614 } else {
3615 Err(de::Error::invalid_value(de::Unexpected::Str(v), &self))
3616 }
3617 }
3618
3619 fn visit_map<V>(self, mut v: V) -> Result<ChildPermissionsArg, V::Error>
3620 where
3621 V: de::MapAccess<'de>,
3622 {
3623 let mut child_permissions_arg = ChildPermissionsArg::none();
3624 while let Some((key, value)) =
3625 v.next_entry::<String, serde_json::Value>()?
3626 {
3627 if key == "env" {
3628 let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
3629 child_permissions_arg.env = arg.map_err(|e| {
3630 de::Error::custom(format!("(deno.permissions.env) {e}"))
3631 })?;
3632 } else if key == "net" {
3633 let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
3634 child_permissions_arg.net = arg.map_err(|e| {
3635 de::Error::custom(format!("(deno.permissions.net) {e}"))
3636 })?;
3637 } else if key == "ffi" {
3638 let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
3639 child_permissions_arg.ffi = arg.map_err(|e| {
3640 de::Error::custom(format!("(deno.permissions.ffi) {e}"))
3641 })?;
3642 } else if key == "import" {
3643 let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
3644 child_permissions_arg.import = arg.map_err(|e| {
3645 de::Error::custom(format!("(deno.permissions.import) {e}"))
3646 })?;
3647 } else if key == "read" {
3648 let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
3649 child_permissions_arg.read = arg.map_err(|e| {
3650 de::Error::custom(format!("(deno.permissions.read) {e}"))
3651 })?;
3652 } else if key == "run" {
3653 let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
3654 child_permissions_arg.run = arg.map_err(|e| {
3655 de::Error::custom(format!("(deno.permissions.run) {e}"))
3656 })?;
3657 } else if key == "sys" {
3658 let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
3659 child_permissions_arg.sys = arg.map_err(|e| {
3660 de::Error::custom(format!("(deno.permissions.sys) {e}"))
3661 })?;
3662 } else if key == "write" {
3663 let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
3664 child_permissions_arg.write = arg.map_err(|e| {
3665 de::Error::custom(format!("(deno.permissions.write) {e}"))
3666 })?;
3667 } else {
3668 return Err(de::Error::custom("unknown permission name"));
3669 }
3670 }
3671 Ok(child_permissions_arg)
3672 }
3673 }
3674 deserializer.deserialize_any(ChildPermissionsArgVisitor)
3675 }
3676}
3677
3678pub trait PermissionDescriptorParser: Debug + Send + Sync {
3683 fn parse_read_descriptor(
3684 &self,
3685 text: &str,
3686 ) -> Result<ReadDescriptor, PathResolveError>;
3687
3688 fn parse_write_descriptor(
3689 &self,
3690 text: &str,
3691 ) -> Result<WriteDescriptor, PathResolveError>;
3692
3693 fn parse_net_descriptor(
3694 &self,
3695 text: &str,
3696 ) -> Result<NetDescriptor, NetDescriptorParseError>;
3697
3698 fn parse_net_descriptor_from_url(
3699 &self,
3700 url: &Url,
3701 ) -> Result<NetDescriptor, NetDescriptorFromUrlParseError> {
3702 NetDescriptor::from_url(url)
3703 }
3704
3705 fn parse_import_descriptor(
3706 &self,
3707 text: &str,
3708 ) -> Result<ImportDescriptor, NetDescriptorParseError>;
3709
3710 fn parse_import_descriptor_from_url(
3711 &self,
3712 url: &Url,
3713 ) -> Result<ImportDescriptor, NetDescriptorFromUrlParseError> {
3714 ImportDescriptor::from_url(url)
3715 }
3716
3717 fn parse_env_descriptor(
3718 &self,
3719 text: &str,
3720 ) -> Result<EnvDescriptor, EnvDescriptorParseError>;
3721
3722 fn parse_sys_descriptor(
3723 &self,
3724 text: &str,
3725 ) -> Result<SysDescriptor, SysDescriptorParseError>;
3726
3727 fn parse_allow_run_descriptor(
3728 &self,
3729 text: &str,
3730 ) -> Result<AllowRunDescriptorParseResult, RunDescriptorParseError>;
3731
3732 fn parse_deny_run_descriptor(
3733 &self,
3734 text: &str,
3735 ) -> Result<DenyRunDescriptor, PathResolveError>;
3736
3737 fn parse_ffi_descriptor(
3738 &self,
3739 text: &str,
3740 ) -> Result<FfiDescriptor, PathResolveError>;
3741
3742 fn parse_path_query(
3745 &self,
3746 path: &str,
3747 ) -> Result<PathQueryDescriptor, PathResolveError>;
3748
3749 fn parse_run_query(
3750 &self,
3751 requested: &str,
3752 ) -> Result<RunQueryDescriptor, RunDescriptorParseError>;
3753}
3754
3755static IS_STANDALONE: AtomicFlag = AtomicFlag::lowered();
3756
3757pub fn mark_standalone() {
3758 IS_STANDALONE.raise();
3759}
3760
3761pub fn is_standalone() -> bool {
3762 IS_STANDALONE.is_raised()
3763}
3764
3765#[cfg(test)]
3766mod tests {
3767 use std::net::Ipv4Addr;
3768
3769 use deno_core::serde_json::json;
3770 use fqdn::fqdn;
3771 use prompter::tests::*;
3772
3773 use super::*;
3774
3775 macro_rules! svec {
3777 ($($x:expr),*) => (vec![$($x.to_string()),*]);
3778 }
3779
3780 #[derive(Debug, Clone)]
3781 struct TestPermissionDescriptorParser;
3782
3783 impl TestPermissionDescriptorParser {
3784 fn join_path_with_root(&self, path: &str) -> PathBuf {
3785 if path.starts_with("C:\\") {
3786 PathBuf::from(path)
3787 } else {
3788 PathBuf::from("/").join(path)
3789 }
3790 }
3791 }
3792
3793 impl PermissionDescriptorParser for TestPermissionDescriptorParser {
3794 fn parse_read_descriptor(
3795 &self,
3796 text: &str,
3797 ) -> Result<ReadDescriptor, PathResolveError> {
3798 Ok(ReadDescriptor(self.join_path_with_root(text)))
3799 }
3800
3801 fn parse_write_descriptor(
3802 &self,
3803 text: &str,
3804 ) -> Result<WriteDescriptor, PathResolveError> {
3805 Ok(WriteDescriptor(self.join_path_with_root(text)))
3806 }
3807
3808 fn parse_net_descriptor(
3809 &self,
3810 text: &str,
3811 ) -> Result<NetDescriptor, NetDescriptorParseError> {
3812 NetDescriptor::parse(text)
3813 }
3814
3815 fn parse_import_descriptor(
3816 &self,
3817 text: &str,
3818 ) -> Result<ImportDescriptor, NetDescriptorParseError> {
3819 ImportDescriptor::parse(text)
3820 }
3821
3822 fn parse_env_descriptor(
3823 &self,
3824 text: &str,
3825 ) -> Result<EnvDescriptor, EnvDescriptorParseError> {
3826 Ok(EnvDescriptor::new(text))
3827 }
3828
3829 fn parse_sys_descriptor(
3830 &self,
3831 text: &str,
3832 ) -> Result<SysDescriptor, SysDescriptorParseError> {
3833 SysDescriptor::parse(text.to_string())
3834 }
3835
3836 fn parse_allow_run_descriptor(
3837 &self,
3838 text: &str,
3839 ) -> Result<AllowRunDescriptorParseResult, RunDescriptorParseError> {
3840 Ok(AllowRunDescriptorParseResult::Descriptor(
3841 AllowRunDescriptor(self.join_path_with_root(text)),
3842 ))
3843 }
3844
3845 fn parse_deny_run_descriptor(
3846 &self,
3847 text: &str,
3848 ) -> Result<DenyRunDescriptor, PathResolveError> {
3849 if text.contains("/") {
3850 Ok(DenyRunDescriptor::Path(self.join_path_with_root(text)))
3851 } else {
3852 Ok(DenyRunDescriptor::Name(text.to_string()))
3853 }
3854 }
3855
3856 fn parse_ffi_descriptor(
3857 &self,
3858 text: &str,
3859 ) -> Result<FfiDescriptor, PathResolveError> {
3860 Ok(FfiDescriptor(self.join_path_with_root(text)))
3861 }
3862
3863 fn parse_path_query(
3864 &self,
3865 path: &str,
3866 ) -> Result<PathQueryDescriptor, PathResolveError> {
3867 Ok(PathQueryDescriptor {
3868 resolved: self.join_path_with_root(path),
3869 requested: path.to_string(),
3870 })
3871 }
3872
3873 fn parse_run_query(
3874 &self,
3875 requested: &str,
3876 ) -> Result<RunQueryDescriptor, RunDescriptorParseError> {
3877 RunQueryDescriptor::parse(requested).map_err(Into::into)
3878 }
3879 }
3880
3881 #[test]
3882 fn check_paths() {
3883 set_prompter(Box::new(TestPrompter));
3884 let allowlist = svec!["/a/specific/dir/name", "/a/specific", "/b/c"];
3885
3886 let parser = TestPermissionDescriptorParser;
3887 let perms = Permissions::from_options(
3888 &parser,
3889 &PermissionsOptions {
3890 allow_read: Some(allowlist.clone()),
3891 allow_write: Some(allowlist.clone()),
3892 allow_ffi: Some(allowlist),
3893 ..Default::default()
3894 },
3895 )
3896 .unwrap();
3897 let mut perms = PermissionsContainer::new(Arc::new(parser), perms);
3898
3899 let cases = [
3900 ("/a/specific/dir/name", true),
3902 ("/a/specific/dir", true),
3904 ("/a/specific/dir/name/inner", true),
3906 ("/a/specific/other/dir", true),
3908 ("/b/c", true),
3910 ("/b/c/sub/path", true),
3912 ("/b/c/sub/path/../path/.", true),
3914 ("/b/e", false),
3916 ("/a/b", false),
3918 ];
3919
3920 for (path, is_ok) in cases {
3921 assert_eq!(perms.check_read(path, "api").is_ok(), is_ok);
3922 assert_eq!(perms.check_write(path, "api").is_ok(), is_ok);
3923 assert_eq!(perms.check_ffi(path).is_ok(), is_ok);
3924 }
3925 }
3926
3927 #[test]
3928 fn test_check_net_with_values() {
3929 set_prompter(Box::new(TestPrompter));
3930 let parser = TestPermissionDescriptorParser;
3931 let mut perms = Permissions::from_options(
3932 &parser,
3933 &PermissionsOptions {
3934 allow_net: Some(svec![
3935 "localhost",
3936 "deno.land",
3937 "github.com:3000",
3938 "127.0.0.1",
3939 "172.16.0.2:8000",
3940 "www.github.com:443",
3941 "80.example.com:80",
3942 "443.example.com:443"
3943 ]),
3944 ..Default::default()
3945 },
3946 )
3947 .unwrap();
3948
3949 let domain_tests = vec![
3950 ("localhost", 1234, true),
3951 ("deno.land", 0, true),
3952 ("deno.land", 3000, true),
3953 ("deno.lands", 0, false),
3954 ("deno.lands", 3000, false),
3955 ("github.com", 3000, true),
3956 ("github.com", 0, false),
3957 ("github.com", 2000, false),
3958 ("github.net", 3000, false),
3959 ("127.0.0.1", 0, true),
3960 ("127.0.0.1", 3000, true),
3961 ("127.0.0.2", 0, false),
3962 ("127.0.0.2", 3000, false),
3963 ("172.16.0.2", 8000, true),
3964 ("172.16.0.2", 0, false),
3965 ("172.16.0.2", 6000, false),
3966 ("172.16.0.1", 8000, false),
3967 ("443.example.com", 444, false),
3968 ("80.example.com", 81, false),
3969 ("80.example.com", 80, true),
3970 ("somedomain", 0, false),
3972 ("192.168.0.1", 0, false),
3973 ];
3974
3975 for (host, port, is_ok) in domain_tests {
3976 let host = Host::parse(host).unwrap();
3977 let descriptor = NetDescriptor(host, Some(port));
3978 assert_eq!(
3979 is_ok,
3980 perms.net.check(&descriptor, None).is_ok(),
3981 "{descriptor}",
3982 );
3983 }
3984 }
3985
3986 #[test]
3987 fn test_check_net_only_flag() {
3988 set_prompter(Box::new(TestPrompter));
3989 let parser = TestPermissionDescriptorParser;
3990 let mut perms = Permissions::from_options(
3991 &parser,
3992 &PermissionsOptions {
3993 allow_net: Some(svec![]), ..Default::default()
3995 },
3996 )
3997 .unwrap();
3998
3999 let domain_tests = vec![
4000 ("localhost", 1234),
4001 ("deno.land", 0),
4002 ("deno.land", 3000),
4003 ("deno.lands", 0),
4004 ("deno.lands", 3000),
4005 ("github.com", 3000),
4006 ("github.com", 0),
4007 ("github.com", 2000),
4008 ("github.net", 3000),
4009 ("127.0.0.1", 0),
4010 ("127.0.0.1", 3000),
4011 ("127.0.0.2", 0),
4012 ("127.0.0.2", 3000),
4013 ("172.16.0.2", 8000),
4014 ("172.16.0.2", 0),
4015 ("172.16.0.2", 6000),
4016 ("172.16.0.1", 8000),
4017 ("somedomain", 0),
4018 ("192.168.0.1", 0),
4019 ];
4020
4021 for (host_str, port) in domain_tests {
4022 let host = Host::parse(host_str).unwrap();
4023 let descriptor = NetDescriptor(host, Some(port));
4024 assert!(
4025 perms.net.check(&descriptor, None).is_ok(),
4026 "expected {host_str}:{port} to pass"
4027 );
4028 }
4029 }
4030
4031 #[test]
4032 fn test_check_net_no_flag() {
4033 set_prompter(Box::new(TestPrompter));
4034 let parser = TestPermissionDescriptorParser;
4035 let mut perms = Permissions::from_options(
4036 &parser,
4037 &PermissionsOptions {
4038 allow_net: None,
4039 ..Default::default()
4040 },
4041 )
4042 .unwrap();
4043
4044 let domain_tests = vec![
4045 ("localhost", 1234),
4046 ("deno.land", 0),
4047 ("deno.land", 3000),
4048 ("deno.lands", 0),
4049 ("deno.lands", 3000),
4050 ("github.com", 3000),
4051 ("github.com", 0),
4052 ("github.com", 2000),
4053 ("github.net", 3000),
4054 ("127.0.0.1", 0),
4055 ("127.0.0.1", 3000),
4056 ("127.0.0.2", 0),
4057 ("127.0.0.2", 3000),
4058 ("172.16.0.2", 8000),
4059 ("172.16.0.2", 0),
4060 ("172.16.0.2", 6000),
4061 ("172.16.0.1", 8000),
4062 ("somedomain", 0),
4063 ("192.168.0.1", 0),
4064 ];
4065
4066 for (host_str, port) in domain_tests {
4067 let host = Host::parse(host_str).unwrap();
4068 let descriptor = NetDescriptor(host, Some(port));
4069 assert!(
4070 perms.net.check(&descriptor, None).is_err(),
4071 "expected {host_str}:{port} to fail"
4072 );
4073 }
4074 }
4075
4076 #[test]
4077 fn test_check_net_url() {
4078 let parser = TestPermissionDescriptorParser;
4079 let perms = Permissions::from_options(
4080 &parser,
4081 &PermissionsOptions {
4082 allow_net: Some(svec![
4083 "localhost",
4084 "deno.land",
4085 "github.com:3000",
4086 "127.0.0.1",
4087 "172.16.0.2:8000",
4088 "www.github.com:443"
4089 ]),
4090 ..Default::default()
4091 },
4092 )
4093 .unwrap();
4094 let mut perms = PermissionsContainer::new(Arc::new(parser), perms);
4095
4096 let url_tests = vec![
4097 ("http://localhost", true),
4099 ("https://localhost", true),
4100 ("https://localhost:4443", true),
4101 ("tcp://localhost:5000", true),
4102 ("udp://localhost:6000", true),
4103 ("https://deno.land/std/example/welcome.ts", true),
4105 ("https://deno.land:3000/std/example/welcome.ts", true),
4106 ("https://deno.lands/std/example/welcome.ts", false),
4107 ("https://deno.lands:3000/std/example/welcome.ts", false),
4108 ("https://github.com:3000/denoland/deno", true),
4110 ("https://github.com/denoland/deno", false),
4111 ("https://github.com:2000/denoland/deno", false),
4112 ("https://github.net:3000/denoland/deno", false),
4113 ("tcp://127.0.0.1", true),
4115 ("https://127.0.0.1", true),
4116 ("tcp://127.0.0.1:3000", true),
4117 ("https://127.0.0.1:3000", true),
4118 ("tcp://127.0.0.2", false),
4119 ("https://127.0.0.2", false),
4120 ("tcp://127.0.0.2:3000", false),
4121 ("https://127.0.0.2:3000", false),
4122 ("tcp://172.16.0.2:8000", true),
4124 ("https://172.16.0.2:8000", true),
4125 ("tcp://172.16.0.2", false),
4126 ("https://172.16.0.2", false),
4127 ("tcp://172.16.0.2:6000", false),
4128 ("https://172.16.0.2:6000", false),
4129 ("tcp://172.16.0.1:8000", false),
4130 ("https://172.16.0.1:8000", false),
4131 ("https://www.github.com:443/robots.txt", true),
4133 ];
4134
4135 for (url_str, is_ok) in url_tests {
4136 let u = Url::parse(url_str).unwrap();
4137 assert_eq!(is_ok, perms.check_net_url(&u, "api()").is_ok(), "{}", u);
4138 }
4139 }
4140
4141 #[test]
4142 fn check_specifiers() {
4143 set_prompter(Box::new(TestPrompter));
4144 let read_allowlist = if cfg!(target_os = "windows") {
4145 svec!["C:\\a"]
4146 } else {
4147 svec!["/a"]
4148 };
4149 let parser = TestPermissionDescriptorParser;
4150 let perms = Permissions::from_options(
4151 &parser,
4152 &PermissionsOptions {
4153 allow_read: Some(read_allowlist),
4154 allow_import: Some(svec!["localhost"]),
4155 ..Default::default()
4156 },
4157 )
4158 .unwrap();
4159 let perms = PermissionsContainer::new(Arc::new(parser), perms);
4160
4161 let mut fixtures = vec![
4162 (
4163 ModuleSpecifier::parse("http://localhost:4545/mod.ts").unwrap(),
4164 CheckSpecifierKind::Static,
4165 true,
4166 ),
4167 (
4168 ModuleSpecifier::parse("http://localhost:4545/mod.ts").unwrap(),
4169 CheckSpecifierKind::Dynamic,
4170 true,
4171 ),
4172 (
4173 ModuleSpecifier::parse("http://deno.land/x/mod.ts").unwrap(),
4174 CheckSpecifierKind::Dynamic,
4175 false,
4176 ),
4177 (
4178 ModuleSpecifier::parse("data:text/plain,Hello%2C%20Deno!").unwrap(),
4179 CheckSpecifierKind::Dynamic,
4180 true,
4181 ),
4182 ];
4183
4184 if cfg!(target_os = "windows") {
4185 fixtures.push((
4186 ModuleSpecifier::parse("file:///C:/a/mod.ts").unwrap(),
4187 CheckSpecifierKind::Dynamic,
4188 true,
4189 ));
4190 fixtures.push((
4191 ModuleSpecifier::parse("file:///C:/b/mod.ts").unwrap(),
4192 CheckSpecifierKind::Static,
4193 true,
4194 ));
4195 fixtures.push((
4196 ModuleSpecifier::parse("file:///C:/b/mod.ts").unwrap(),
4197 CheckSpecifierKind::Dynamic,
4198 false,
4199 ));
4200 } else {
4201 fixtures.push((
4202 ModuleSpecifier::parse("file:///a/mod.ts").unwrap(),
4203 CheckSpecifierKind::Dynamic,
4204 true,
4205 ));
4206 fixtures.push((
4207 ModuleSpecifier::parse("file:///b/mod.ts").unwrap(),
4208 CheckSpecifierKind::Static,
4209 true,
4210 ));
4211 fixtures.push((
4212 ModuleSpecifier::parse("file:///b/mod.ts").unwrap(),
4213 CheckSpecifierKind::Dynamic,
4214 false,
4215 ));
4216 }
4217
4218 for (specifier, kind, expected) in fixtures {
4219 assert_eq!(
4220 perms.check_specifier(&specifier, kind).is_ok(),
4221 expected,
4222 "{}",
4223 specifier,
4224 );
4225 }
4226 }
4227
4228 #[test]
4229 fn test_query() {
4230 set_prompter(Box::new(TestPrompter));
4231 let parser = TestPermissionDescriptorParser;
4232 let perms1 = Permissions::allow_all();
4233 let perms2 = Permissions::from_options(
4234 &parser,
4235 &PermissionsOptions {
4236 allow_read: Some(svec!["/foo"]),
4237 allow_write: Some(svec!["/foo"]),
4238 allow_ffi: Some(svec!["/foo"]),
4239 allow_net: Some(svec!["127.0.0.1:8000"]),
4240 allow_env: Some(svec!["HOME"]),
4241 allow_sys: Some(svec!["hostname"]),
4242 allow_run: Some(svec!["/deno"]),
4243 allow_all: false,
4244 ..Default::default()
4245 },
4246 )
4247 .unwrap();
4248 let perms3 = Permissions::from_options(
4249 &parser,
4250 &PermissionsOptions {
4251 deny_read: Some(svec!["/foo"]),
4252 deny_write: Some(svec!["/foo"]),
4253 deny_ffi: Some(svec!["/foo"]),
4254 deny_net: Some(svec!["127.0.0.1:8000"]),
4255 deny_env: Some(svec!["HOME"]),
4256 deny_sys: Some(svec!["hostname"]),
4257 deny_run: Some(svec!["deno"]),
4258 ..Default::default()
4259 },
4260 )
4261 .unwrap();
4262 let perms4 = Permissions::from_options(
4263 &parser,
4264 &PermissionsOptions {
4265 allow_read: Some(vec![]),
4266 deny_read: Some(svec!["/foo"]),
4267 allow_write: Some(vec![]),
4268 deny_write: Some(svec!["/foo"]),
4269 allow_ffi: Some(vec![]),
4270 deny_ffi: Some(svec!["/foo"]),
4271 allow_net: Some(vec![]),
4272 deny_net: Some(svec!["127.0.0.1:8000"]),
4273 allow_env: Some(vec![]),
4274 deny_env: Some(svec!["HOME"]),
4275 allow_sys: Some(vec![]),
4276 deny_sys: Some(svec!["hostname"]),
4277 allow_run: Some(vec![]),
4278 deny_run: Some(svec!["deno"]),
4279 ..Default::default()
4280 },
4281 )
4282 .unwrap();
4283 #[rustfmt::skip]
4284 {
4285 let read_query = |path: &str| parser.parse_path_query(path).unwrap().into_read();
4286 let write_query = |path: &str| parser.parse_path_query(path).unwrap().into_write();
4287 let ffi_query = |path: &str| parser.parse_path_query(path).unwrap().into_ffi();
4288 assert_eq!(perms1.read.query(None), PermissionState::Granted);
4289 assert_eq!(perms1.read.query(Some(&read_query("/foo"))), PermissionState::Granted);
4290 assert_eq!(perms2.read.query(None), PermissionState::Prompt);
4291 assert_eq!(perms2.read.query(Some(&read_query("/foo"))), PermissionState::Granted);
4292 assert_eq!(perms2.read.query(Some(&read_query("/foo/bar"))), PermissionState::Granted);
4293 assert_eq!(perms3.read.query(None), PermissionState::Prompt);
4294 assert_eq!(perms3.read.query(Some(&read_query("/foo"))), PermissionState::Denied);
4295 assert_eq!(perms3.read.query(Some(&read_query("/foo/bar"))), PermissionState::Denied);
4296 assert_eq!(perms4.read.query(None), PermissionState::GrantedPartial);
4297 assert_eq!(perms4.read.query(Some(&read_query("/foo"))), PermissionState::Denied);
4298 assert_eq!(perms4.read.query(Some(&read_query("/foo/bar"))), PermissionState::Denied);
4299 assert_eq!(perms4.read.query(Some(&read_query("/bar"))), PermissionState::Granted);
4300 assert_eq!(perms1.write.query(None), PermissionState::Granted);
4301 assert_eq!(perms1.write.query(Some(&write_query("/foo"))), PermissionState::Granted);
4302 assert_eq!(perms2.write.query(None), PermissionState::Prompt);
4303 assert_eq!(perms2.write.query(Some(&write_query("/foo"))), PermissionState::Granted);
4304 assert_eq!(perms2.write.query(Some(&write_query("/foo/bar"))), PermissionState::Granted);
4305 assert_eq!(perms3.write.query(None), PermissionState::Prompt);
4306 assert_eq!(perms3.write.query(Some(&write_query("/foo"))), PermissionState::Denied);
4307 assert_eq!(perms3.write.query(Some(&write_query("/foo/bar"))), PermissionState::Denied);
4308 assert_eq!(perms4.write.query(None), PermissionState::GrantedPartial);
4309 assert_eq!(perms4.write.query(Some(&write_query("/foo"))), PermissionState::Denied);
4310 assert_eq!(perms4.write.query(Some(&write_query("/foo/bar"))), PermissionState::Denied);
4311 assert_eq!(perms4.write.query(Some(&write_query("/bar"))), PermissionState::Granted);
4312 assert_eq!(perms1.ffi.query(None), PermissionState::Granted);
4313 assert_eq!(perms1.ffi.query(Some(&ffi_query("/foo"))), PermissionState::Granted);
4314 assert_eq!(perms2.ffi.query(None), PermissionState::Prompt);
4315 assert_eq!(perms2.ffi.query(Some(&ffi_query("/foo"))), PermissionState::Granted);
4316 assert_eq!(perms2.ffi.query(Some(&ffi_query("/foo/bar"))), PermissionState::Granted);
4317 assert_eq!(perms3.ffi.query(None), PermissionState::Prompt);
4318 assert_eq!(perms3.ffi.query(Some(&ffi_query("/foo"))), PermissionState::Denied);
4319 assert_eq!(perms3.ffi.query(Some(&ffi_query("/foo/bar"))), PermissionState::Denied);
4320 assert_eq!(perms4.ffi.query(None), PermissionState::GrantedPartial);
4321 assert_eq!(perms4.ffi.query(Some(&ffi_query("/foo"))), PermissionState::Denied);
4322 assert_eq!(perms4.ffi.query(Some(&ffi_query("/foo/bar"))), PermissionState::Denied);
4323 assert_eq!(perms4.ffi.query(Some(&ffi_query("/bar"))), PermissionState::Granted);
4324 assert_eq!(perms1.net.query(None), PermissionState::Granted);
4325 assert_eq!(perms1.net.query(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), None))), PermissionState::Granted);
4326 assert_eq!(perms2.net.query(None), PermissionState::Prompt);
4327 assert_eq!(perms2.net.query(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)))), PermissionState::Granted);
4328 assert_eq!(perms3.net.query(None), PermissionState::Prompt);
4329 assert_eq!(perms3.net.query(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)))), PermissionState::Denied);
4330 assert_eq!(perms4.net.query(None), PermissionState::GrantedPartial);
4331 assert_eq!(perms4.net.query(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)))), PermissionState::Denied);
4332 assert_eq!(perms4.net.query(Some(&NetDescriptor(Host::must_parse("192.168.0.1"), Some(8000)))), PermissionState::Granted);
4333 assert_eq!(perms1.env.query(None), PermissionState::Granted);
4334 assert_eq!(perms1.env.query(Some("HOME")), PermissionState::Granted);
4335 assert_eq!(perms2.env.query(None), PermissionState::Prompt);
4336 assert_eq!(perms2.env.query(Some("HOME")), PermissionState::Granted);
4337 assert_eq!(perms3.env.query(None), PermissionState::Prompt);
4338 assert_eq!(perms3.env.query(Some("HOME")), PermissionState::Denied);
4339 assert_eq!(perms4.env.query(None), PermissionState::GrantedPartial);
4340 assert_eq!(perms4.env.query(Some("HOME")), PermissionState::Denied);
4341 assert_eq!(perms4.env.query(Some("AWAY")), PermissionState::Granted);
4342 let sys_desc = |name: &str| SysDescriptor::parse(name.to_string()).unwrap();
4343 assert_eq!(perms1.sys.query(None), PermissionState::Granted);
4344 assert_eq!(perms1.sys.query(Some(&sys_desc("osRelease"))), PermissionState::Granted);
4345 assert_eq!(perms2.sys.query(None), PermissionState::Prompt);
4346 assert_eq!(perms2.sys.query(Some(&sys_desc("hostname"))), PermissionState::Granted);
4347 assert_eq!(perms3.sys.query(None), PermissionState::Prompt);
4348 assert_eq!(perms3.sys.query(Some(&sys_desc("hostname"))), PermissionState::Denied);
4349 assert_eq!(perms4.sys.query(None), PermissionState::GrantedPartial);
4350 assert_eq!(perms4.sys.query(Some(&sys_desc("hostname"))), PermissionState::Denied);
4351 assert_eq!(perms4.sys.query(Some(&sys_desc("uid"))), PermissionState::Granted);
4352 assert_eq!(perms1.run.query(None), PermissionState::Granted);
4353 let deno_run_query = RunQueryDescriptor::Path {
4354 requested: "deno".to_string(),
4355 resolved: PathBuf::from("/deno"),
4356 };
4357 let node_run_query = RunQueryDescriptor::Path {
4358 requested: "node".to_string(),
4359 resolved: PathBuf::from("/node"),
4360 };
4361 assert_eq!(perms1.run.query(Some(&deno_run_query)), PermissionState::Granted);
4362 assert_eq!(perms1.write.query(Some(&write_query("/deno"))), PermissionState::Granted);
4363 assert_eq!(perms2.run.query(None), PermissionState::Prompt);
4364 assert_eq!(perms2.run.query(Some(&deno_run_query)), PermissionState::Granted);
4365 assert_eq!(perms2.write.query(Some(&write_query("/deno"))), PermissionState::Denied);
4366 assert_eq!(perms3.run.query(None), PermissionState::Prompt);
4367 assert_eq!(perms3.run.query(Some(&deno_run_query)), PermissionState::Denied);
4368 assert_eq!(perms4.run.query(None), PermissionState::GrantedPartial);
4369 assert_eq!(perms4.run.query(Some(&deno_run_query)), PermissionState::Denied);
4370 assert_eq!(perms4.run.query(Some(&node_run_query)), PermissionState::Granted);
4371 };
4372 }
4373
4374 #[test]
4375 fn test_request() {
4376 set_prompter(Box::new(TestPrompter));
4377 let parser = TestPermissionDescriptorParser;
4378 let mut perms: Permissions = Permissions::none_with_prompt();
4379 let mut perms_no_prompt: Permissions = Permissions::none_without_prompt();
4380 let read_query =
4381 |path: &str| parser.parse_path_query(path).unwrap().into_read();
4382 let write_query =
4383 |path: &str| parser.parse_path_query(path).unwrap().into_write();
4384 let ffi_query =
4385 |path: &str| parser.parse_path_query(path).unwrap().into_ffi();
4386 #[rustfmt::skip]
4387 {
4388 let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
4389 prompt_value.set(true);
4390 assert_eq!(perms.read.request(Some(&read_query("/foo"))), PermissionState::Granted);
4391 assert_eq!(perms.read.query(None), PermissionState::Prompt);
4392 prompt_value.set(false);
4393 assert_eq!(perms.read.request(Some(&read_query("/foo/bar"))), PermissionState::Granted);
4394 prompt_value.set(false);
4395 assert_eq!(perms.write.request(Some(&write_query("/foo"))), PermissionState::Denied);
4396 assert_eq!(perms.write.query(Some(&write_query("/foo/bar"))), PermissionState::Prompt);
4397 prompt_value.set(true);
4398 assert_eq!(perms.write.request(None), PermissionState::Denied);
4399 prompt_value.set(false);
4400 assert_eq!(perms.ffi.request(Some(&ffi_query("/foo"))), PermissionState::Denied);
4401 assert_eq!(perms.ffi.query(Some(&ffi_query("/foo/bar"))), PermissionState::Prompt);
4402 prompt_value.set(true);
4403 assert_eq!(perms.ffi.request(None), PermissionState::Denied);
4404 prompt_value.set(true);
4405 assert_eq!(perms.net.request(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), None))), PermissionState::Granted);
4406 prompt_value.set(false);
4407 assert_eq!(perms.net.request(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)))), PermissionState::Granted);
4408 prompt_value.set(true);
4409 assert_eq!(perms.env.request(Some("HOME")), PermissionState::Granted);
4410 assert_eq!(perms.env.query(None), PermissionState::Prompt);
4411 prompt_value.set(false);
4412 assert_eq!(perms.env.request(Some("HOME")), PermissionState::Granted);
4413 prompt_value.set(true);
4414 let sys_desc = |name: &str| SysDescriptor::parse(name.to_string()).unwrap();
4415 assert_eq!(perms.sys.request(Some(&sys_desc("hostname"))), PermissionState::Granted);
4416 assert_eq!(perms.sys.query(None), PermissionState::Prompt);
4417 prompt_value.set(false);
4418 assert_eq!(perms.sys.request(Some(&sys_desc("hostname"))), PermissionState::Granted);
4419 prompt_value.set(true);
4420 let run_query = RunQueryDescriptor::Path {
4421 requested: "deno".to_string(),
4422 resolved: PathBuf::from("/deno"),
4423 };
4424 assert_eq!(perms.run.request(Some(&run_query)), PermissionState::Granted);
4425 assert_eq!(perms.run.query(None), PermissionState::Prompt);
4426 prompt_value.set(false);
4427 assert_eq!(perms.run.request(Some(&run_query)), PermissionState::Granted);
4428 assert_eq!(perms_no_prompt.read.request(Some(&read_query("/foo"))), PermissionState::Denied);
4429 };
4430 }
4431
4432 #[test]
4433 fn test_revoke() {
4434 set_prompter(Box::new(TestPrompter));
4435 let parser = TestPermissionDescriptorParser;
4436 let mut perms = Permissions::from_options(
4437 &parser,
4438 &PermissionsOptions {
4439 allow_read: Some(svec!["/foo", "/foo/baz"]),
4440 allow_write: Some(svec!["/foo", "/foo/baz"]),
4441 allow_ffi: Some(svec!["/foo", "/foo/baz"]),
4442 allow_net: Some(svec!["127.0.0.1", "127.0.0.1:8000"]),
4443 allow_env: Some(svec!["HOME"]),
4444 allow_sys: Some(svec!["hostname"]),
4445 allow_run: Some(svec!["/deno"]),
4446 ..Default::default()
4447 },
4448 )
4449 .unwrap();
4450 let read_query =
4451 |path: &str| parser.parse_path_query(path).unwrap().into_read();
4452 let write_query =
4453 |path: &str| parser.parse_path_query(path).unwrap().into_write();
4454 let ffi_query =
4455 |path: &str| parser.parse_path_query(path).unwrap().into_ffi();
4456 #[rustfmt::skip]
4457 {
4458 assert_eq!(perms.read.revoke(Some(&read_query("/foo/bar"))), PermissionState::Prompt);
4459 assert_eq!(perms.read.query(Some(&read_query("/foo"))), PermissionState::Prompt);
4460 assert_eq!(perms.read.query(Some(&read_query("/foo/baz"))), PermissionState::Granted);
4461 assert_eq!(perms.write.revoke(Some(&write_query("/foo/bar"))), PermissionState::Prompt);
4462 assert_eq!(perms.write.query(Some(&write_query("/foo"))), PermissionState::Prompt);
4463 assert_eq!(perms.write.query(Some(&write_query("/foo/baz"))), PermissionState::Granted);
4464 assert_eq!(perms.ffi.revoke(Some(&ffi_query("/foo/bar"))), PermissionState::Prompt);
4465 assert_eq!(perms.ffi.query(Some(&ffi_query("/foo"))), PermissionState::Prompt);
4466 assert_eq!(perms.ffi.query(Some(&ffi_query("/foo/baz"))), PermissionState::Granted);
4467 assert_eq!(perms.net.revoke(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), Some(9000)))), PermissionState::Prompt);
4468 assert_eq!(perms.net.query(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), None))), PermissionState::Prompt);
4469 assert_eq!(perms.net.query(Some(&NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)))), PermissionState::Granted);
4470 assert_eq!(perms.env.revoke(Some("HOME")), PermissionState::Prompt);
4471 assert_eq!(perms.env.revoke(Some("hostname")), PermissionState::Prompt);
4472 let run_query = RunQueryDescriptor::Path {
4473 requested: "deno".to_string(),
4474 resolved: PathBuf::from("/deno"),
4475 };
4476 assert_eq!(perms.run.revoke(Some(&run_query)), PermissionState::Prompt);
4477 };
4478 }
4479
4480 #[test]
4481 fn test_check() {
4482 set_prompter(Box::new(TestPrompter));
4483 let mut perms = Permissions::none_with_prompt();
4484 let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
4485 let parser = TestPermissionDescriptorParser;
4486 let read_query =
4487 |path: &str| parser.parse_path_query(path).unwrap().into_read();
4488 let write_query =
4489 |path: &str| parser.parse_path_query(path).unwrap().into_write();
4490 let ffi_query =
4491 |path: &str| parser.parse_path_query(path).unwrap().into_ffi();
4492
4493 prompt_value.set(true);
4494 assert!(perms.read.check(&read_query("/foo"), None).is_ok());
4495 prompt_value.set(false);
4496 assert!(perms.read.check(&read_query("/foo"), None).is_ok());
4497 assert!(perms.read.check(&read_query("/bar"), None).is_err());
4498
4499 prompt_value.set(true);
4500 assert!(perms.write.check(&write_query("/foo"), None).is_ok());
4501 prompt_value.set(false);
4502 assert!(perms.write.check(&write_query("/foo"), None).is_ok());
4503 assert!(perms.write.check(&write_query("/bar"), None).is_err());
4504
4505 prompt_value.set(true);
4506 assert!(perms.ffi.check(&ffi_query("/foo"), None).is_ok());
4507 prompt_value.set(false);
4508 assert!(perms.ffi.check(&ffi_query("/foo"), None).is_ok());
4509 assert!(perms.ffi.check(&ffi_query("/bar"), None).is_err());
4510
4511 prompt_value.set(true);
4512 assert!(perms
4513 .net
4514 .check(
4515 &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)),
4516 None
4517 )
4518 .is_ok());
4519 prompt_value.set(false);
4520 assert!(perms
4521 .net
4522 .check(
4523 &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)),
4524 None
4525 )
4526 .is_ok());
4527 assert!(perms
4528 .net
4529 .check(
4530 &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8001)),
4531 None
4532 )
4533 .is_err());
4534 assert!(perms
4535 .net
4536 .check(&NetDescriptor(Host::must_parse("127.0.0.1"), None), None)
4537 .is_err());
4538 assert!(perms
4539 .net
4540 .check(
4541 &NetDescriptor(Host::must_parse("deno.land"), Some(8000)),
4542 None
4543 )
4544 .is_err());
4545 assert!(perms
4546 .net
4547 .check(&NetDescriptor(Host::must_parse("deno.land"), None), None)
4548 .is_err());
4549
4550 #[allow(clippy::disallowed_methods)]
4551 let cwd = std::env::current_dir().unwrap();
4552 prompt_value.set(true);
4553 assert!(perms
4554 .run
4555 .check(
4556 &RunQueryDescriptor::Path {
4557 requested: "cat".to_string(),
4558 resolved: cwd.join("cat")
4559 },
4560 None
4561 )
4562 .is_ok());
4563 prompt_value.set(false);
4564 assert!(perms
4565 .run
4566 .check(
4567 &RunQueryDescriptor::Path {
4568 requested: "cat".to_string(),
4569 resolved: cwd.join("cat")
4570 },
4571 None
4572 )
4573 .is_ok());
4574 assert!(perms
4575 .run
4576 .check(
4577 &RunQueryDescriptor::Path {
4578 requested: "ls".to_string(),
4579 resolved: cwd.join("ls")
4580 },
4581 None
4582 )
4583 .is_err());
4584
4585 prompt_value.set(true);
4586 assert!(perms.env.check("HOME", None).is_ok());
4587 prompt_value.set(false);
4588 assert!(perms.env.check("HOME", None).is_ok());
4589 assert!(perms.env.check("PATH", None).is_err());
4590
4591 prompt_value.set(true);
4592 assert!(perms.env.check("hostname", None).is_ok());
4593 prompt_value.set(false);
4594 assert!(perms.env.check("hostname", None).is_ok());
4595 assert!(perms.env.check("osRelease", None).is_err());
4596 }
4597
4598 #[test]
4599 fn test_check_fail() {
4600 set_prompter(Box::new(TestPrompter));
4601 let mut perms = Permissions::none_with_prompt();
4602 let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
4603 let parser = TestPermissionDescriptorParser;
4604 let read_query =
4605 |path: &str| parser.parse_path_query(path).unwrap().into_read();
4606 let write_query =
4607 |path: &str| parser.parse_path_query(path).unwrap().into_write();
4608 let ffi_query =
4609 |path: &str| parser.parse_path_query(path).unwrap().into_ffi();
4610
4611 prompt_value.set(false);
4612 assert!(perms.read.check(&read_query("/foo"), None).is_err());
4613 prompt_value.set(true);
4614 assert!(perms.read.check(&read_query("/foo"), None).is_err());
4615 assert!(perms.read.check(&read_query("/bar"), None).is_ok());
4616 prompt_value.set(false);
4617 assert!(perms.read.check(&read_query("/bar"), None).is_ok());
4618
4619 prompt_value.set(false);
4620 assert!(perms.write.check(&write_query("/foo"), None).is_err());
4621 prompt_value.set(true);
4622 assert!(perms.write.check(&write_query("/foo"), None).is_err());
4623 assert!(perms.write.check(&write_query("/bar"), None).is_ok());
4624 prompt_value.set(false);
4625 assert!(perms.write.check(&write_query("/bar"), None).is_ok());
4626
4627 prompt_value.set(false);
4628 assert!(perms.ffi.check(&ffi_query("/foo"), None).is_err());
4629 prompt_value.set(true);
4630 assert!(perms.ffi.check(&ffi_query("/foo"), None).is_err());
4631 assert!(perms.ffi.check(&ffi_query("/bar"), None).is_ok());
4632 prompt_value.set(false);
4633 assert!(perms.ffi.check(&ffi_query("/bar"), None).is_ok());
4634
4635 prompt_value.set(false);
4636 assert!(perms
4637 .net
4638 .check(
4639 &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)),
4640 None
4641 )
4642 .is_err());
4643 prompt_value.set(true);
4644 assert!(perms
4645 .net
4646 .check(
4647 &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8000)),
4648 None
4649 )
4650 .is_err());
4651 assert!(perms
4652 .net
4653 .check(
4654 &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8001)),
4655 None
4656 )
4657 .is_ok());
4658 assert!(perms
4659 .net
4660 .check(
4661 &NetDescriptor(Host::must_parse("deno.land"), Some(8000)),
4662 None
4663 )
4664 .is_ok());
4665 prompt_value.set(false);
4666 assert!(perms
4667 .net
4668 .check(
4669 &NetDescriptor(Host::must_parse("127.0.0.1"), Some(8001)),
4670 None
4671 )
4672 .is_ok());
4673 assert!(perms
4674 .net
4675 .check(
4676 &NetDescriptor(Host::must_parse("deno.land"), Some(8000)),
4677 None
4678 )
4679 .is_ok());
4680
4681 prompt_value.set(false);
4682 #[allow(clippy::disallowed_methods)]
4683 let cwd = std::env::current_dir().unwrap();
4684 assert!(perms
4685 .run
4686 .check(
4687 &RunQueryDescriptor::Path {
4688 requested: "cat".to_string(),
4689 resolved: cwd.join("cat")
4690 },
4691 None
4692 )
4693 .is_err());
4694 prompt_value.set(true);
4695 assert!(perms
4696 .run
4697 .check(
4698 &RunQueryDescriptor::Path {
4699 requested: "cat".to_string(),
4700 resolved: cwd.join("cat")
4701 },
4702 None
4703 )
4704 .is_err());
4705 assert!(perms
4706 .run
4707 .check(
4708 &RunQueryDescriptor::Path {
4709 requested: "ls".to_string(),
4710 resolved: cwd.join("ls")
4711 },
4712 None
4713 )
4714 .is_ok());
4715 prompt_value.set(false);
4716 assert!(perms
4717 .run
4718 .check(
4719 &RunQueryDescriptor::Path {
4720 requested: "ls".to_string(),
4721 resolved: cwd.join("ls")
4722 },
4723 None
4724 )
4725 .is_ok());
4726
4727 prompt_value.set(false);
4728 assert!(perms.env.check("HOME", None).is_err());
4729 prompt_value.set(true);
4730 assert!(perms.env.check("HOME", None).is_err());
4731 assert!(perms.env.check("PATH", None).is_ok());
4732 prompt_value.set(false);
4733 assert!(perms.env.check("PATH", None).is_ok());
4734
4735 prompt_value.set(false);
4736 let sys_desc = |name: &str| SysDescriptor::parse(name.to_string()).unwrap();
4737 assert!(perms.sys.check(&sys_desc("hostname"), None).is_err());
4738 prompt_value.set(true);
4739 assert!(perms.sys.check(&sys_desc("hostname"), None).is_err());
4740 assert!(perms.sys.check(&sys_desc("osRelease"), None).is_ok());
4741 prompt_value.set(false);
4742 assert!(perms.sys.check(&sys_desc("osRelease"), None).is_ok());
4743 }
4744
4745 #[test]
4746 #[cfg(windows)]
4747 fn test_env_windows() {
4748 set_prompter(Box::new(TestPrompter));
4749 let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
4750 let mut perms = Permissions::allow_all();
4751 perms.env = UnaryPermission {
4752 granted_global: false,
4753 ..Permissions::new_unary(
4754 Some(HashSet::from([EnvDescriptor::new("HOME")])),
4755 None,
4756 false,
4757 )
4758 };
4759
4760 prompt_value.set(true);
4761 assert!(perms.env.check("HOME", None).is_ok());
4762 prompt_value.set(false);
4763 assert!(perms.env.check("HOME", None).is_ok());
4764 assert!(perms.env.check("hOmE", None).is_ok());
4765
4766 assert_eq!(perms.env.revoke(Some("HomE")), PermissionState::Prompt);
4767 }
4768
4769 #[test]
4770 fn test_env_wildcards() {
4771 set_prompter(Box::new(TestPrompter));
4772 let _prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
4773 let mut perms = Permissions::allow_all();
4774 perms.env = UnaryPermission {
4775 granted_global: false,
4776 ..Permissions::new_unary(
4777 Some(HashSet::from([EnvDescriptor::new("HOME_*")])),
4778 None,
4779 false,
4780 )
4781 };
4782 assert_eq!(perms.env.query(Some("HOME")), PermissionState::Prompt);
4783 assert_eq!(perms.env.query(Some("HOME_")), PermissionState::Granted);
4784 assert_eq!(perms.env.query(Some("HOME_TEST")), PermissionState::Granted);
4785
4786 let parser = TestPermissionDescriptorParser;
4788 assert!(perms
4789 .env
4790 .create_child_permissions(
4791 ChildUnaryPermissionArg::GrantedList(vec!["HOME_SUB".to_string()]),
4792 |value| parser.parse_env_descriptor(value).map(Some),
4793 )
4794 .is_ok());
4795 assert!(perms
4796 .env
4797 .create_child_permissions(
4798 ChildUnaryPermissionArg::GrantedList(vec!["HOME*".to_string()]),
4799 |value| parser.parse_env_descriptor(value).map(Some),
4800 )
4801 .is_err());
4802 assert!(perms
4803 .env
4804 .create_child_permissions(
4805 ChildUnaryPermissionArg::GrantedList(vec!["OUTSIDE".to_string()]),
4806 |value| parser.parse_env_descriptor(value).map(Some),
4807 )
4808 .is_err());
4809 assert!(perms
4810 .env
4811 .create_child_permissions(
4812 ChildUnaryPermissionArg::GrantedList(vec!["HOME_S*".to_string()]),
4814 |value| parser.parse_env_descriptor(value).map(Some),
4815 )
4816 .is_ok());
4817 }
4818
4819 #[test]
4820 fn test_check_partial_denied() {
4821 let parser = TestPermissionDescriptorParser;
4822 let mut perms = Permissions::from_options(
4823 &parser,
4824 &PermissionsOptions {
4825 allow_read: Some(vec![]),
4826 deny_read: Some(svec!["/foo/bar"]),
4827 allow_write: Some(vec![]),
4828 deny_write: Some(svec!["/foo/bar"]),
4829 ..Default::default()
4830 },
4831 )
4832 .unwrap();
4833
4834 let read_query = parser.parse_path_query("/foo").unwrap().into_read();
4835 perms.read.check_partial(&read_query, None).unwrap();
4836 assert!(perms.read.check(&read_query, None).is_err());
4837
4838 let write_query = parser.parse_path_query("/foo").unwrap().into_write();
4839 perms.write.check_partial(&write_query, None).unwrap();
4840 assert!(perms.write.check(&write_query, None).is_err());
4841 }
4842
4843 #[test]
4844 fn test_net_fully_qualified_domain_name() {
4845 set_prompter(Box::new(TestPrompter));
4846 let parser = TestPermissionDescriptorParser;
4847 let perms = Permissions::from_options(
4848 &parser,
4849 &PermissionsOptions {
4850 allow_net: Some(svec!["allowed.domain", "1.1.1.1"]),
4851 deny_net: Some(svec!["denied.domain", "2.2.2.2"]),
4852 ..Default::default()
4853 },
4854 )
4855 .unwrap();
4856 let mut perms = PermissionsContainer::new(Arc::new(parser), perms);
4857 let cases = [
4858 ("allowed.domain.", true),
4859 ("1.1.1.1", true),
4860 ("denied.domain.", false),
4861 ("2.2.2.2", false),
4862 ];
4863
4864 for (host, is_ok) in cases {
4865 assert_eq!(perms.check_net(&(host, None), "api").is_ok(), is_ok);
4866 }
4867 }
4868
4869 #[test]
4870 fn test_deserialize_child_permissions_arg() {
4871 set_prompter(Box::new(TestPrompter));
4872 assert_eq!(
4873 ChildPermissionsArg::inherit(),
4874 ChildPermissionsArg {
4875 env: ChildUnaryPermissionArg::Inherit,
4876 net: ChildUnaryPermissionArg::Inherit,
4877 ffi: ChildUnaryPermissionArg::Inherit,
4878 import: ChildUnaryPermissionArg::Inherit,
4879 read: ChildUnaryPermissionArg::Inherit,
4880 run: ChildUnaryPermissionArg::Inherit,
4881 sys: ChildUnaryPermissionArg::Inherit,
4882 write: ChildUnaryPermissionArg::Inherit,
4883 }
4884 );
4885 assert_eq!(
4886 ChildPermissionsArg::none(),
4887 ChildPermissionsArg {
4888 env: ChildUnaryPermissionArg::NotGranted,
4889 net: ChildUnaryPermissionArg::NotGranted,
4890 ffi: ChildUnaryPermissionArg::NotGranted,
4891 import: ChildUnaryPermissionArg::NotGranted,
4892 read: ChildUnaryPermissionArg::NotGranted,
4893 run: ChildUnaryPermissionArg::NotGranted,
4894 sys: ChildUnaryPermissionArg::NotGranted,
4895 write: ChildUnaryPermissionArg::NotGranted,
4896 }
4897 );
4898 assert_eq!(
4899 serde_json::from_value::<ChildPermissionsArg>(json!("inherit")).unwrap(),
4900 ChildPermissionsArg::inherit()
4901 );
4902 assert_eq!(
4903 serde_json::from_value::<ChildPermissionsArg>(json!("none")).unwrap(),
4904 ChildPermissionsArg::none()
4905 );
4906 assert_eq!(
4907 serde_json::from_value::<ChildPermissionsArg>(json!({})).unwrap(),
4908 ChildPermissionsArg::none()
4909 );
4910 assert_eq!(
4911 serde_json::from_value::<ChildPermissionsArg>(json!({
4912 "env": ["foo", "bar"],
4913 }))
4914 .unwrap(),
4915 ChildPermissionsArg {
4916 env: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar"]),
4917 ..ChildPermissionsArg::none()
4918 }
4919 );
4920 assert_eq!(
4921 serde_json::from_value::<ChildPermissionsArg>(json!({
4922 "env": true,
4923 "net": true,
4924 "ffi": true,
4925 "import": true,
4926 "read": true,
4927 "run": true,
4928 "sys": true,
4929 "write": true,
4930 }))
4931 .unwrap(),
4932 ChildPermissionsArg {
4933 env: ChildUnaryPermissionArg::Granted,
4934 net: ChildUnaryPermissionArg::Granted,
4935 ffi: ChildUnaryPermissionArg::Granted,
4936 import: ChildUnaryPermissionArg::Granted,
4937 read: ChildUnaryPermissionArg::Granted,
4938 run: ChildUnaryPermissionArg::Granted,
4939 sys: ChildUnaryPermissionArg::Granted,
4940 write: ChildUnaryPermissionArg::Granted,
4941 }
4942 );
4943 assert_eq!(
4944 serde_json::from_value::<ChildPermissionsArg>(json!({
4945 "env": false,
4946 "net": false,
4947 "ffi": false,
4948 "import": false,
4949 "read": false,
4950 "run": false,
4951 "sys": false,
4952 "write": false,
4953 }))
4954 .unwrap(),
4955 ChildPermissionsArg {
4956 env: ChildUnaryPermissionArg::NotGranted,
4957 net: ChildUnaryPermissionArg::NotGranted,
4958 ffi: ChildUnaryPermissionArg::NotGranted,
4959 import: ChildUnaryPermissionArg::NotGranted,
4960 read: ChildUnaryPermissionArg::NotGranted,
4961 run: ChildUnaryPermissionArg::NotGranted,
4962 sys: ChildUnaryPermissionArg::NotGranted,
4963 write: ChildUnaryPermissionArg::NotGranted,
4964 }
4965 );
4966 assert_eq!(
4967 serde_json::from_value::<ChildPermissionsArg>(json!({
4968 "env": ["foo", "bar"],
4969 "net": ["foo", "bar:8000"],
4970 "ffi": ["foo", "file:///bar/baz"],
4971 "import": ["example.com"],
4972 "read": ["foo", "file:///bar/baz"],
4973 "run": ["foo", "file:///bar/baz", "./qux"],
4974 "sys": ["hostname", "osRelease"],
4975 "write": ["foo", "file:///bar/baz"],
4976 }))
4977 .unwrap(),
4978 ChildPermissionsArg {
4979 env: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar"]),
4980 net: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar:8000"]),
4981 ffi: ChildUnaryPermissionArg::GrantedList(svec![
4982 "foo",
4983 "file:///bar/baz"
4984 ]),
4985 import: ChildUnaryPermissionArg::GrantedList(svec!["example.com"]),
4986 read: ChildUnaryPermissionArg::GrantedList(svec![
4987 "foo",
4988 "file:///bar/baz"
4989 ]),
4990 run: ChildUnaryPermissionArg::GrantedList(svec![
4991 "foo",
4992 "file:///bar/baz",
4993 "./qux"
4994 ]),
4995 sys: ChildUnaryPermissionArg::GrantedList(svec![
4996 "hostname",
4997 "osRelease"
4998 ]),
4999 write: ChildUnaryPermissionArg::GrantedList(svec![
5000 "foo",
5001 "file:///bar/baz"
5002 ]),
5003 }
5004 );
5005 }
5006
5007 #[test]
5008 fn test_create_child_permissions() {
5009 set_prompter(Box::new(TestPrompter));
5010 let parser = TestPermissionDescriptorParser;
5011 let main_perms = Permissions::from_options(
5012 &parser,
5013 &PermissionsOptions {
5014 allow_env: Some(vec![]),
5015 allow_net: Some(svec!["foo", "bar"]),
5016 ..Default::default()
5017 },
5018 )
5019 .unwrap();
5020 let main_perms = PermissionsContainer::new(Arc::new(parser), main_perms);
5021 assert_eq!(
5022 main_perms
5023 .create_child_permissions(ChildPermissionsArg {
5024 env: ChildUnaryPermissionArg::Inherit,
5025 net: ChildUnaryPermissionArg::GrantedList(svec!["foo"]),
5026 ffi: ChildUnaryPermissionArg::NotGranted,
5027 ..ChildPermissionsArg::none()
5028 })
5029 .unwrap()
5030 .inner
5031 .lock()
5032 .clone(),
5033 Permissions {
5034 env: Permissions::new_unary(Some(HashSet::new()), None, false),
5035 net: Permissions::new_unary(
5036 Some(HashSet::from([NetDescriptor::parse("foo").unwrap()])),
5037 None,
5038 false
5039 ),
5040 ..Permissions::none_without_prompt()
5041 }
5042 );
5043 assert!(main_perms
5044 .create_child_permissions(ChildPermissionsArg {
5045 net: ChildUnaryPermissionArg::Granted,
5046 ..ChildPermissionsArg::none()
5047 })
5048 .is_err());
5049 assert!(main_perms
5050 .create_child_permissions(ChildPermissionsArg {
5051 net: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar", "baz"]),
5052 ..ChildPermissionsArg::none()
5053 })
5054 .is_err());
5055 assert!(main_perms
5056 .create_child_permissions(ChildPermissionsArg {
5057 ffi: ChildUnaryPermissionArg::GrantedList(svec!["foo"]),
5058 ..ChildPermissionsArg::none()
5059 })
5060 .is_err());
5061 }
5062
5063 #[test]
5064 fn test_create_child_permissions_with_prompt() {
5065 set_prompter(Box::new(TestPrompter));
5066 let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
5067 let main_perms = Permissions::from_options(
5068 &TestPermissionDescriptorParser,
5069 &PermissionsOptions {
5070 prompt: true,
5071 ..Default::default()
5072 },
5073 )
5074 .unwrap();
5075 let main_perms = PermissionsContainer::new(
5076 Arc::new(TestPermissionDescriptorParser),
5077 main_perms,
5078 );
5079 prompt_value.set(true);
5080 let worker_perms = main_perms
5081 .create_child_permissions(ChildPermissionsArg {
5082 read: ChildUnaryPermissionArg::Granted,
5083 run: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar"]),
5084 ..ChildPermissionsArg::none()
5085 })
5086 .unwrap();
5087 assert_eq!(
5088 main_perms.inner.lock().clone(),
5089 worker_perms.inner.lock().clone()
5090 );
5091 assert_eq!(
5092 main_perms.inner.lock().run.granted_list,
5093 HashSet::from([
5094 AllowRunDescriptor(PathBuf::from("/bar")),
5095 AllowRunDescriptor(PathBuf::from("/foo")),
5096 ])
5097 );
5098 }
5099
5100 #[test]
5101 fn test_create_child_permissions_with_inherited_denied_list() {
5102 set_prompter(Box::new(TestPrompter));
5103 let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
5104 let parser = TestPermissionDescriptorParser;
5105 let main_perms = Permissions::from_options(
5106 &parser,
5107 &PermissionsOptions {
5108 prompt: true,
5109 ..Default::default()
5110 },
5111 )
5112 .unwrap();
5113 let main_perms =
5114 PermissionsContainer::new(Arc::new(parser.clone()), main_perms);
5115 prompt_value.set(false);
5116 assert!(main_perms
5117 .inner
5118 .lock()
5119 .write
5120 .check(&parser.parse_path_query("foo").unwrap().into_write(), None)
5121 .is_err());
5122 let worker_perms = main_perms
5123 .create_child_permissions(ChildPermissionsArg::none())
5124 .unwrap();
5125 assert_eq!(
5126 worker_perms.inner.lock().write.flag_denied_list.clone(),
5127 main_perms.inner.lock().write.flag_denied_list
5128 );
5129 }
5130
5131 #[test]
5132 fn test_host_parse() {
5133 let hosts = &[
5134 ("deno.land", Some(Host::Fqdn(fqdn!("deno.land")))),
5135 ("DENO.land", Some(Host::Fqdn(fqdn!("deno.land")))),
5136 ("deno.land.", Some(Host::Fqdn(fqdn!("deno.land")))),
5137 (
5138 "1.1.1.1",
5139 Some(Host::Ip(IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)))),
5140 ),
5141 (
5142 "::1",
5143 Some(Host::Ip(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)))),
5144 ),
5145 (
5146 "[::1]",
5147 Some(Host::Ip(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)))),
5148 ),
5149 ("[::1", None),
5150 ("::1]", None),
5151 ("deno. land", None),
5152 ("1. 1.1.1", None),
5153 ("1.1.1.1.", None),
5154 ("1::1.", None),
5155 ("deno.land.", Some(Host::Fqdn(fqdn!("deno.land")))),
5156 (".deno.land", None),
5157 (
5158 "::ffff:1.1.1.1",
5159 Some(Host::Ip(IpAddr::V6(Ipv6Addr::new(
5160 0, 0, 0, 0, 0, 0xffff, 0x0101, 0x0101,
5161 )))),
5162 ),
5163 ];
5164
5165 for (host_str, expected) in hosts {
5166 assert_eq!(Host::parse(host_str).ok(), *expected, "{host_str}");
5167 }
5168 }
5169
5170 #[test]
5171 fn test_net_descriptor_parse() {
5172 let cases = &[
5173 (
5174 "deno.land",
5175 Some(NetDescriptor(Host::Fqdn(fqdn!("deno.land")), None)),
5176 ),
5177 (
5178 "DENO.land",
5179 Some(NetDescriptor(Host::Fqdn(fqdn!("deno.land")), None)),
5180 ),
5181 (
5182 "deno.land:8000",
5183 Some(NetDescriptor(Host::Fqdn(fqdn!("deno.land")), Some(8000))),
5184 ),
5185 ("deno.land:", None),
5186 ("deno.land:a", None),
5187 ("deno. land:a", None),
5188 ("deno.land.: a", None),
5189 (
5190 "1.1.1.1",
5191 Some(NetDescriptor(
5192 Host::Ip(IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1))),
5193 None,
5194 )),
5195 ),
5196 ("1.1.1.1.", None),
5197 ("1.1.1.1..", None),
5198 (
5199 "1.1.1.1:8000",
5200 Some(NetDescriptor(
5201 Host::Ip(IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1))),
5202 Some(8000),
5203 )),
5204 ),
5205 ("::", None),
5206 (":::80", None),
5207 ("::80", None),
5208 (
5209 "[::]",
5210 Some(NetDescriptor(
5211 Host::Ip(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0))),
5212 None,
5213 )),
5214 ),
5215 ("[::1", None),
5216 ("::1]", None),
5217 ("::1]", None),
5218 ("[::1]:", None),
5219 ("[::1]:a", None),
5220 (
5221 "[::1]:443",
5222 Some(NetDescriptor(
5223 Host::Ip(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))),
5224 Some(443),
5225 )),
5226 ),
5227 ("", None),
5228 ("deno.land..", None),
5229 ];
5230
5231 for (input, expected) in cases {
5232 assert_eq!(NetDescriptor::parse(input).ok(), *expected, "'{input}'");
5233 }
5234 }
5235
5236 #[test]
5237 fn test_denies_run_name() {
5238 let cases = [
5239 #[cfg(windows)]
5240 ("deno", "C:\\deno.exe", true),
5241 #[cfg(windows)]
5242 ("deno", "C:\\sub\\deno.cmd", true),
5243 #[cfg(windows)]
5244 ("deno", "C:\\sub\\DeNO.cmd", true),
5245 #[cfg(windows)]
5246 ("DEno", "C:\\sub\\deno.cmd", true),
5247 #[cfg(windows)]
5248 ("deno", "C:\\other\\sub\\deno.batch", true),
5249 #[cfg(windows)]
5250 ("deno", "C:\\other\\sub\\deno", true),
5251 #[cfg(windows)]
5252 ("denort", "C:\\other\\sub\\deno.exe", false),
5253 ("deno", "/home/test/deno", true),
5254 ("deno", "/home/test/denot", false),
5255 ];
5256 for (name, cmd_path, denies) in cases {
5257 assert_eq!(
5258 denies_run_name(name, &PathBuf::from(cmd_path)),
5259 denies,
5260 "{} {}",
5261 name,
5262 cmd_path
5263 );
5264 }
5265 }
5266}