use crate::context::LintContext;
use crate::diagnostic::Severity;
use crate::rule::{Rule, RuleCategory, RuleMeta};
use vize_relief::ast::{DirectiveNode, ElementNode, ExpressionNode};
static META: RuleMeta = RuleMeta {
name: "vue/no-unsafe-url",
description: "Warn about potentially unsafe URL bindings",
category: RuleCategory::Recommended,
fixable: false,
default_severity: Severity::Warning,
};
#[derive(Default)]
pub struct NoUnsafeUrl;
const UNSAFE_URL_ATTRS: &[&str] = &["href", "src", "srcset", "action", "formaction"];
impl Rule for NoUnsafeUrl {
fn meta(&self) -> &'static RuleMeta {
&META
}
fn check_directive<'a>(
&self,
ctx: &mut LintContext<'a>,
element: &ElementNode<'a>,
directive: &DirectiveNode<'a>,
) {
if directive.name != "bind" {
return;
}
let attr_name = match &directive.arg {
Some(ExpressionNode::Simple(s)) => s.content.as_str(),
_ => return,
};
if !UNSAFE_URL_ATTRS.contains(&attr_name) {
return;
}
let tag = element.tag.as_str();
if tag == "router-link" || tag == "RouterLink" || tag == "nuxt-link" || tag == "NuxtLink" {
return;
}
let help_message = if attr_name == "href" {
ctx.t("vue/no-unsafe-url.help_href")
} else {
ctx.t("vue/no-unsafe-url.help")
};
ctx.warn_with_help(
ctx.t("vue/no-unsafe-url.message"),
&directive.loc,
help_message,
);
}
}
#[cfg(test)]
mod tests {
use super::NoUnsafeUrl;
use crate::linter::Linter;
use crate::rule::RuleRegistry;
fn create_linter() -> Linter {
let mut registry = RuleRegistry::new();
registry.register(Box::new(NoUnsafeUrl));
Linter::with_registry(registry)
}
#[test]
fn test_valid_static_href() {
let linter = create_linter();
let result = linter.lint_template(r#"<a href="/about">About</a>"#, "test.vue");
assert_eq!(result.warning_count, 0);
}
#[test]
fn test_valid_router_link() {
let linter = create_linter();
let result = linter.lint_template(
r#"<router-link :to="{ name: 'profile' }">Profile</router-link>"#,
"test.vue",
);
assert_eq!(result.warning_count, 0);
}
#[test]
fn test_warns_dynamic_href() {
let linter = create_linter();
let result = linter.lint_template(r#"<a :href="userUrl">Link</a>"#, "test.vue");
assert_eq!(result.warning_count, 1);
}
#[test]
fn test_warns_dynamic_src() {
let linter = create_linter();
let result = linter.lint_template(r#"<iframe :src="url"></iframe>"#, "test.vue");
assert_eq!(result.warning_count, 1);
}
#[test]
fn test_valid_class_binding() {
let linter = create_linter();
let result = linter.lint_template(r#"<div :class="classes"></div>"#, "test.vue");
assert_eq!(result.warning_count, 0);
}
}