Skip to content

Commit

Permalink
feat: add no_danger rule
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinhagemeister committed Nov 22, 2024
1 parent 5a7ce21 commit fde4446
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 0 deletions.
14 changes: 14 additions & 0 deletions docs/rules/no_danger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Prevent the use of `dangerouslySetInnerHTML` which can lead to XSS
vulnerabilities if used incorrectly.

### Invalid:

```tsx
const hello = <div dangerouslySetInnerHTML={{ __html: "Hello World!" }} />;
```

### Valid:

```tsx
const hello = <div>Hello World!</div>;
```
2 changes: 2 additions & 0 deletions src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub mod no_console;
pub mod no_const_assign;
pub mod no_constant_condition;
pub mod no_control_regex;
pub mod no_danger;
pub mod no_debugger;
pub mod no_delete_var;
pub mod no_deprecated_deno_api;
Expand Down Expand Up @@ -268,6 +269,7 @@ fn get_all_rules_raw() -> Vec<Box<dyn LintRule>> {
Box::new(no_const_assign::NoConstAssign),
Box::new(no_constant_condition::NoConstantCondition),
Box::new(no_control_regex::NoControlRegex),
Box::new(no_danger::NoDanger),
Box::new(no_debugger::NoDebugger),
Box::new(no_delete_var::NoDeleteVar),
Box::new(no_deprecated_deno_api::NoDeprecatedDenoApi),
Expand Down
96 changes: 96 additions & 0 deletions src/rules/no_danger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use super::{Context, LintRule};
use crate::handler::{Handler, Traverse};
use crate::Program;
use deno_ast::view::{JSXAttr, JSXAttrName};
use deno_ast::SourceRanged;

#[derive(Debug)]
pub struct NoDanger;

const CODE: &str = "no-danger";

impl LintRule for NoDanger {
fn tags(&self) -> &'static [&'static str] {
&["react", "jsx"]
}

fn code(&self) -> &'static str {
CODE
}

fn lint_program_with_ast_view(
&self,
context: &mut Context,
program: Program,
) {
NoDangerHandler.traverse(program, context);
}

#[cfg(feature = "docs")]
fn docs(&self) -> &'static str {
include_str!("../../docs/rules/no_danger.md")
}
}

const MESSAGE: &str = "Do not use `dangerouslySetInnerHTML`";
const HINT: &str = "Remove this attribute";

struct NoDangerHandler;

impl Handler for NoDangerHandler {
fn jsx_attr(&mut self, node: &JSXAttr, ctx: &mut Context) {
if let JSXAttrName::Ident(name) = node.name {
if name.sym() == "dangerouslySetInnerHTML" {
ctx.add_diagnostic_with_hint(node.range(), CODE, MESSAGE, HINT);
}
}
}
}

// most tests are taken from ESlint, commenting those
// requiring code path support
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn no_danger_valid() {
assert_lint_ok! {
NoDanger,
filename: "file:///foo.jsx",
// non derived classes.
r#"<div />"#,
};
}

#[test]
fn no_danger_invalid() {
assert_lint_err! {
NoDanger,
filename: "file:///foo.jsx",
"<div dangerouslySetInnerHTML />": [
{
col: 5,
message: MESSAGE,
hint: HINT,
}
],
r#"<div dangerouslySetInnerHTML="" />"#: [
{
col: 5,
message: MESSAGE,
hint: HINT,
}
],
"<div dangerouslySetInnerHTML={{}} />": [
{
col: 5,
message: MESSAGE,
hint: HINT,
}
]
};
}
}
8 changes: 8 additions & 0 deletions www/static/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@
"recommended"
]
},
{
"code": "no-danger",
"docs": "Prevent the use of `dangerouslySetInnerHTML` which can lead to XSS\nvulnerabilities if used incorrectly.\n\n### Invalid:\n\n```tsx\nconst hello = <div dangerouslySetInnerHTML={{ __html: \"Hello World!\" }} />;\n```\n\n### Valid:\n\n```tsx\nconst hello = <div>Hello World!</div>;\n```\n",
"tags": [
"react",
"jsx"
]
},
{
"code": "no-debugger",
"docs": "Disallows the use of the `debugger` statement\n\n`debugger` is a statement which is meant for stopping the javascript execution\nenvironment and start the debugger at the statement. Modern debuggers and\ntooling no longer need this statement and leaving it in can cause the execution\nof your code to stop in production.\n\n### Invalid:\n\n```typescript\nfunction isLongString(x: string) {\n debugger;\n return x.length > 100;\n}\n```\n\n### Valid:\n\n```typescript\nfunction isLongString(x: string) {\n return x.length > 100; // set breakpoint here instead\n}\n```\n",
Expand Down

0 comments on commit fde4446

Please sign in to comment.