From 454874a42d9997771545233b957b72bbc92ae328 Mon Sep 17 00:00:00 2001 From: Radu Baston <65868820+radu2147@users.noreply.github.com> Date: Thu, 10 Oct 2024 22:17:29 +0300 Subject: [PATCH 01/24] feat(linter): Implement `react/iframe-missing-sandbox` (#6383) https://github.com/oxc-project/oxc/issues/1022 --------- Co-authored-by: Don Isaac --- crates/oxc_linter/src/rules.rs | 2 + .../src/rules/react/iframe_missing_sandbox.rs | 233 ++++++++++++++++++ .../src/snapshots/iframe_missing_sandbox.snap | 93 +++++++ 3 files changed, 328 insertions(+) create mode 100644 crates/oxc_linter/src/rules/react/iframe_missing_sandbox.rs create mode 100644 crates/oxc_linter/src/snapshots/iframe_missing_sandbox.snap diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index a347787b1b0d1..ffe855e5f884f 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -234,6 +234,7 @@ mod jest { mod react { pub mod button_has_type; pub mod checked_requires_onchange_or_readonly; + pub mod iframe_missing_sandbox; pub mod jsx_boolean_value; pub mod jsx_curly_brace_presence; pub mod jsx_key; @@ -771,6 +772,7 @@ oxc_macros::declare_all_lint_rules! { promise::valid_params, react::button_has_type, react::checked_requires_onchange_or_readonly, + react::iframe_missing_sandbox, react::jsx_boolean_value, react::jsx_curly_brace_presence, react::jsx_key, diff --git a/crates/oxc_linter/src/rules/react/iframe_missing_sandbox.rs b/crates/oxc_linter/src/rules/react/iframe_missing_sandbox.rs new file mode 100644 index 0000000000000..0fcd3f4300beb --- /dev/null +++ b/crates/oxc_linter/src/rules/react/iframe_missing_sandbox.rs @@ -0,0 +1,233 @@ +use oxc_ast::ast::{ + Argument, Expression, JSXAttributeItem, JSXAttributeValue, JSXElementName, ObjectProperty, + ObjectPropertyKind, StringLiteral, +}; +use oxc_ast::AstKind; +use oxc_diagnostics::OxcDiagnostic; +use oxc_macros::declare_oxc_lint; +use oxc_span::Span; +use phf::{phf_set, Set}; + +use crate::utils::{get_prop_value, has_jsx_prop_ignore_case, is_create_element_call}; +use crate::{context::LintContext, rule::Rule, AstNode}; + +fn missing_sandbox_prop(span: Span) -> OxcDiagnostic { + OxcDiagnostic::warn("An iframe element is missing a sandbox attribute") + .with_help("Add a `sandbox` attribute to the `iframe` element.") + .with_label(span) +} + +fn invalid_sandbox_prop(span: Span, value: &str) -> OxcDiagnostic { + OxcDiagnostic::warn(format!("An iframe element defines a sandbox attribute with invalid value: {value}")) + .with_help("Check this link for the valid values of `sandbox` attribute: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox.") + .with_label(span) +} + +fn invalid_sandbox_combination_prop(span: Span) -> OxcDiagnostic { + OxcDiagnostic::warn("An `iframe` element defines a sandbox attribute with both allow-scripts and allow-same-origin which is invalid") + .with_help("Remove `allow-scripts` or `allow-same-origin`.") + .with_label(span) +} + +const ALLOWED_VALUES: Set<&'static str> = phf_set! { + "", + "allow-downloads-without-user-activation", + "allow-downloads", + "allow-forms", + "allow-modals", + "allow-orientation-lock", + "allow-pointer-lock", + "allow-popups", + "allow-popups-to-escape-sandbox", + "allow-presentation", + "allow-same-origin", + "allow-scripts", + "allow-storage-access-by-user-activation", + "allow-top-navigation", + "allow-top-navigation-by-user-activation" +}; + +#[derive(Debug, Default, Clone)] +pub struct IframeMissingSandbox; + +declare_oxc_lint!( + /// ### What it does + /// + /// Enforce sandbox attribute on iframe elements + /// + /// ### Why is this bad? + /// + /// The sandbox attribute enables an extra set of restrictions for the content in the iframe. Using sandbox attribute is considered a good security practice. + /// To learn more about sandboxing, see [MDN's documentation on the `sandbox` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox). + + /// + /// This rule checks all React `"#, + r#"React.createElement("iframe", { src: "foo.htm", sandbox: true })"#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#""#, + r#"React.createElement("iframe", { sandbox: "allow-forms" })"#, + r#"React.createElement("iframe", { sandbox: "allow-modals" })"#, + r#"React.createElement("iframe", { sandbox: "allow-orientation-lock" })"#, + r#"React.createElement("iframe", { sandbox: "allow-pointer-lock" })"#, + r#"React.createElement("iframe", { sandbox: "allow-popups" })"#, + r#"React.createElement("iframe", { sandbox: "allow-popups-to-escape-sandbox" })"#, + r#"React.createElement("iframe", { sandbox: "allow-presentation" })"#, + r#"React.createElement("iframe", { sandbox: "allow-same-origin" })"#, + r#"React.createElement("iframe", { sandbox: "allow-scripts" })"#, + r#"React.createElement("iframe", { sandbox: "allow-top-navigation" })"#, + r#"React.createElement("iframe", { sandbox: "allow-top-navigation-by-user-activation" })"#, + r#"React.createElement("iframe", { sandbox: "allow-forms allow-modals" })"#, + r#"React.createElement("iframe", { sandbox: "allow-popups allow-popups-to-escape-sandbox allow-pointer-lock allow-same-origin allow-top-navigation" })"#, + ]; + + let fail = vec![ + ";", + ""#, + r#"React.createElement("iframe", { sandbox: "__unknown__" })"#, + r#";"#, + r#"; + · ────── + ╰──── + help: Add a `sandbox` attribute to the `iframe` element. + + ⚠ eslint-plugin-react(iframe-missing-sandbox): An iframe element is missing a sandbox attribute + ╭─[iframe_missing_sandbox.tsx:1:2] + 1 │ + · ───────────── + ╰──── + help: Check this link for the valid values of `sandbox` attribute: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox. + + ⚠ eslint-plugin-react(iframe-missing-sandbox): An iframe element defines a sandbox attribute with invalid value: __unknown__ + ╭─[iframe_missing_sandbox.tsx:1:42] + 1 │ React.createElement("iframe", { sandbox: "__unknown__" }) + · ───────────── + ╰──── + help: Check this link for the valid values of `sandbox` attribute: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox. + + ⚠ eslint-plugin-react(iframe-missing-sandbox): An iframe element defines a sandbox attribute with invalid value: __unknown__ + ╭─[iframe_missing_sandbox.tsx:1:17] + 1 │ ; + · ───────────────────────────────── + ╰──── + help: Remove `allow-scripts` or `allow-same-origin`. + + ⚠ eslint-plugin-react(iframe-missing-sandbox): An `iframe` element defines a sandbox attribute with both allow-scripts and allow-same-origin which is invalid + ╭─[iframe_missing_sandbox.tsx:1:17] + 1 │