diff --git a/ls/src/configuration.rs b/ls/src/configuration.rs index 93f584211..5d33ad68b 100644 --- a/ls/src/configuration.rs +++ b/ls/src/configuration.rs @@ -53,4 +53,7 @@ pub struct MetadataValidationRule { pub ty: Option, /// Format of the metadata entry, if type is "date". pub format: Option, + /// Regex pattern to validate the metadata entry, if type is "string". + #[serde(default)] + pub regex: Option, } diff --git a/ls/src/features/diagnostics.rs b/ls/src/features/diagnostics.rs index d1316885b..43feee612 100644 --- a/ls/src/features/diagnostics.rs +++ b/ls/src/features/diagnostics.rs @@ -9,9 +9,10 @@ use async_lsp::lsp_types::{ use dashmap::mapref::one::Ref; use serde::{Deserialize, Serialize}; -use crate::configuration::MetadataValidationRule; use chrono::NaiveDate; +use regex::Regex; +use crate::configuration::MetadataValidationRule; #[cfg(feature = "full-compiler")] use crate::documents::document::Document; use crate::documents::storage::DocumentStorage; @@ -95,18 +96,37 @@ pub fn compiler_diagnostics( if let Some(ty) = &validation_rule.ty { match ty.as_str() { "string" => { - compiler.add_linter(linter.validator( - |meta| { - matches!( - meta.value, - yara_x_parser::ast::MetaValue::String(_) - ) - }, - format!( - "`{}` must be a `string`", - validation_rule.identifier - ), - )); + if let Some(pattern) = &validation_rule.regex { + compiler.add_linter(linter.validator( + |meta| { + if let yara_x_parser::ast::MetaValue::String( + value, + ) = &meta.value + { + Regex::new(pattern).unwrap().is_match(value.0) + } else { + false + } + }, + format!( + "`{}` must be a string and match the pattern `{}`", + validation_rule.identifier, pattern + ), + )); + } else { + compiler.add_linter(linter.validator( + |meta| { + matches!( + meta.value, + yara_x_parser::ast::MetaValue::String(_) + ) + }, + format!( + "`{}` must be a `string`", + validation_rule.identifier + ), + )); + } } "integer" => { compiler.add_linter(linter.validator( diff --git a/ls/src/server.rs b/ls/src/server.rs index ca4f5944e..6bd940996 100644 --- a/ls/src/server.rs +++ b/ls/src/server.rs @@ -704,6 +704,23 @@ impl YARALanguageServer { ), }); } + + for rule in &config.metadata_validation { + if let Some(pattern) = &rule.regex + && let Err(err) = regex::Regex::new(pattern) + { + let _ = client.show_message(ShowMessageParams { + typ: MessageType::ERROR, + message: format!( + "YARA: invalid regex for metadata '{}': {} ({})", + rule.identifier, + pattern, + err + ), + }); + } + } + let _ = client.emit(UpdateConfig(config)); } None => {