1use super::core_traits::Plugin;
9use super::security::{DigitalSignature, Permission, PublisherInfo, SecurityPolicy};
10use super::types_config::PluginMetadata;
11use crate::error::Result;
12use std::collections::HashMap;
13
14#[derive(Debug)]
39pub struct PluginValidator {
40 security_policy: SecurityPolicy,
42 dependency_resolver: DependencyResolver,
44 #[allow(dead_code)]
46 code_analyzer: CodeAnalyzer,
47 trust_store: TrustStore,
49}
50
51impl PluginValidator {
52 pub fn new() -> Self {
57 Self {
58 security_policy: SecurityPolicy::default(),
59 dependency_resolver: DependencyResolver::new(),
60 code_analyzer: CodeAnalyzer::new(),
61 trust_store: TrustStore::new(),
62 }
63 }
64
65 pub fn with_security_policy(security_policy: SecurityPolicy) -> Self {
71 Self {
72 security_policy,
73 dependency_resolver: DependencyResolver::new(),
74 code_analyzer: CodeAnalyzer::new(),
75 trust_store: TrustStore::new(),
76 }
77 }
78
79 pub fn validate_comprehensive(
94 &self,
95 plugin: &dyn Plugin,
96 manifest: &PluginManifest,
97 ) -> Result<ValidationReport> {
98 let mut report = ValidationReport::new();
99
100 self.validate_basic(plugin, &mut report)?;
102
103 self.validate_security(manifest, &mut report)?;
105
106 self.validate_dependencies(manifest, &mut report)?;
108
109 self.validate_code_safety(manifest, &mut report)?;
111
112 self.validate_trust(manifest, &mut report)?;
114
115 Ok(report)
116 }
117
118 fn validate_basic(&self, plugin: &dyn Plugin, report: &mut ValidationReport) -> Result<()> {
122 let metadata = plugin.metadata();
123
124 if metadata.name.is_empty() {
125 report.add_error(ValidationError::InvalidMetadata(
126 "Plugin name cannot be empty".to_string(),
127 ));
128 }
129
130 if metadata.version.is_empty() {
131 report.add_error(ValidationError::InvalidMetadata(
132 "Plugin version cannot be empty".to_string(),
133 ));
134 }
135
136 if metadata.author.is_empty() {
137 report.add_error(ValidationError::InvalidMetadata(
138 "Plugin author cannot be empty".to_string(),
139 ));
140 }
141
142 if !self.is_valid_version(&metadata.version) {
144 report.add_error(ValidationError::InvalidVersion(metadata.version.clone()));
145 }
146
147 if !self.is_compatible_sdk_version(&metadata.min_sdk_version) {
149 report.add_error(ValidationError::IncompatibleSdkVersion(
150 metadata.min_sdk_version.clone(),
151 ));
152 }
153
154 report.add_check(ValidationCheck::BasicMetadata, ValidationResult::Passed);
155 Ok(())
156 }
157
158 fn validate_security(
163 &self,
164 manifest: &PluginManifest,
165 report: &mut ValidationReport,
166 ) -> Result<()> {
167 for permission in &manifest.permissions {
169 if self.security_policy.is_dangerous_permission(permission) {
170 report.add_warning(ValidationWarning::DangerousPermission(permission.clone()));
171 }
172 }
173
174 if let Some(ref api_usage) = manifest.api_usage {
176 for api_call in &api_usage.calls {
177 if self.security_policy.is_restricted_api(api_call) {
178 report.add_error(ValidationError::RestrictedApiUsage(api_call.clone()));
179 }
180 }
181 }
182
183 if manifest.contains_unsafe_code {
185 if !self.security_policy.allow_unsafe_code {
186 report.add_error(ValidationError::UnsafeCodeNotAllowed);
187 } else {
188 report.add_warning(ValidationWarning::UnsafeCodeDetected);
189 }
190 }
191
192 report.add_check(ValidationCheck::Security, ValidationResult::Passed);
193 Ok(())
194 }
195
196 fn validate_dependencies(
201 &self,
202 manifest: &PluginManifest,
203 report: &mut ValidationReport,
204 ) -> Result<()> {
205 for dependency in &manifest.dependencies {
206 if !self.dependency_resolver.is_available(dependency) {
208 report.add_error(ValidationError::MissingDependency(dependency.clone()));
209 continue;
210 }
211
212 if !self.dependency_resolver.is_compatible_version(dependency) {
214 report.add_error(ValidationError::IncompatibleDependency(dependency.clone()));
215 continue;
216 }
217
218 if let Some(vulnerabilities) =
220 self.dependency_resolver.check_vulnerabilities(dependency)
221 {
222 for vuln in vulnerabilities {
223 report.add_error(ValidationError::VulnerableDependency(
224 dependency.clone(),
225 vuln,
226 ));
227 }
228 }
229 }
230
231 report.add_check(ValidationCheck::Dependencies, ValidationResult::Passed);
232 Ok(())
233 }
234
235 fn validate_code_safety(
240 &self,
241 manifest: &PluginManifest,
242 report: &mut ValidationReport,
243 ) -> Result<()> {
244 if let Some(ref code_info) = manifest.code_analysis {
245 if code_info.cyclomatic_complexity > self.security_policy.max_complexity as usize {
247 report.add_warning(ValidationWarning::HighComplexity(
248 code_info.cyclomatic_complexity,
249 ));
250 }
251
252 for pattern in &code_info.suspicious_patterns {
254 report.add_warning(ValidationWarning::SuspiciousPattern(pattern.clone()));
255 }
256
257 if code_info.potential_memory_issues > 0 {
259 report.add_error(ValidationError::MemorySafetyIssue(
260 code_info.potential_memory_issues,
261 ));
262 }
263 }
264
265 report.add_check(ValidationCheck::CodeSafety, ValidationResult::Passed);
266 Ok(())
267 }
268
269 fn validate_trust(
273 &self,
274 manifest: &PluginManifest,
275 report: &mut ValidationReport,
276 ) -> Result<()> {
277 if let Some(ref signature) = manifest.signature {
279 match self
280 .trust_store
281 .verify_signature(&manifest.content_hash, signature)
282 {
283 Ok(true) => report.add_check(ValidationCheck::Signature, ValidationResult::Passed),
284 Ok(false) => report.add_error(ValidationError::InvalidSignature),
285 Err(e) => {
286 report.add_error(ValidationError::SignatureVerificationFailed(e.to_string()))
287 }
288 }
289 } else if self.security_policy.require_signatures {
290 report.add_error(ValidationError::MissingSignature);
291 }
292
293 let trust_level = self.trust_store.get_publisher_trust(&manifest.publisher);
295 if trust_level < self.security_policy.min_trust_level as f32 {
296 report.add_warning(ValidationWarning::LowTrustPublisher(trust_level));
297 }
298
299 report.add_check(ValidationCheck::Trust, ValidationResult::Passed);
300 Ok(())
301 }
302
303 fn is_valid_version(&self, version: &str) -> bool {
305 let parts: Vec<&str> = version.split('.').collect();
306 parts.len() >= 2 && parts.len() <= 3 && parts.iter().all(|p| p.parse::<u32>().is_ok())
307 }
308
309 fn is_compatible_sdk_version(&self, min_version: &str) -> bool {
311 !min_version.is_empty()
314 }
315}
316
317impl Default for PluginValidator {
318 fn default() -> Self {
319 Self::new()
320 }
321}
322
323#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
328pub struct PluginManifest {
329 pub metadata: PluginMetadata,
331 pub permissions: Vec<Permission>,
333 pub api_usage: Option<ApiUsageInfo>,
335 pub contains_unsafe_code: bool,
337 pub dependencies: Vec<Dependency>,
339 pub code_analysis: Option<CodeAnalysisInfo>,
341 pub signature: Option<DigitalSignature>,
343 pub content_hash: String,
345 pub publisher: PublisherInfo,
347 pub marketplace: MarketplaceInfo,
349}
350
351#[derive(Debug, Clone)]
353pub struct ValidationReport {
354 pub errors: Vec<ValidationError>,
356 pub warnings: Vec<ValidationWarning>,
358 pub checks: HashMap<ValidationCheck, ValidationResult>,
360 pub status: ValidationStatus,
362}
363
364impl ValidationReport {
365 pub fn new() -> Self {
367 Self {
368 errors: Vec::new(),
369 warnings: Vec::new(),
370 checks: HashMap::new(),
371 status: ValidationStatus::Pending,
372 }
373 }
374
375 pub fn add_error(&mut self, error: ValidationError) {
377 self.errors.push(error);
378 self.status = ValidationStatus::Failed;
379 }
380
381 pub fn add_warning(&mut self, warning: ValidationWarning) {
383 self.warnings.push(warning);
384 }
385
386 pub fn add_check(&mut self, check: ValidationCheck, result: ValidationResult) {
388 self.checks.insert(check, result);
389 if self.status == ValidationStatus::Pending && self.errors.is_empty() {
390 self.status = ValidationStatus::Passed;
391 }
392 }
393
394 pub fn has_errors(&self) -> bool {
396 !self.errors.is_empty()
397 }
398
399 pub fn has_warnings(&self) -> bool {
401 !self.warnings.is_empty()
402 }
403
404 pub fn get_errors(&self) -> &[ValidationError] {
406 &self.errors
407 }
408
409 pub fn get_warnings(&self) -> &[ValidationWarning] {
411 &self.warnings
412 }
413
414 pub fn status(&self) -> ValidationStatus {
416 self.status
417 }
418
419 pub fn get_checks(&self) -> &HashMap<ValidationCheck, ValidationResult> {
421 &self.checks
422 }
423}
424
425#[derive(Debug, Clone)]
427pub enum ValidationError {
428 InvalidMetadata(String),
430 InvalidVersion(String),
432 IncompatibleSdkVersion(String),
434 MissingDependency(Dependency),
436 IncompatibleDependency(Dependency),
438 VulnerableDependency(Dependency, String),
440 RestrictedApiUsage(String),
442 UnsafeCodeNotAllowed,
444 MemorySafetyIssue(usize),
446 InvalidSignature,
448 MissingSignature,
450 SignatureVerificationFailed(String),
452}
453
454#[derive(Debug, Clone)]
456pub enum ValidationWarning {
457 DangerousPermission(Permission),
459 UnsafeCodeDetected,
461 HighComplexity(usize),
463 SuspiciousPattern(String),
465 LowTrustPublisher(f32),
467}
468
469#[derive(Debug, Clone, PartialEq, Eq, Hash)]
471pub enum ValidationCheck {
472 BasicMetadata,
474 Security,
476 Dependencies,
478 CodeSafety,
480 Trust,
482 Signature,
484}
485
486#[derive(Debug, Clone, PartialEq, Eq)]
488pub enum ValidationResult {
489 Passed,
491 Failed,
493 Skipped,
495}
496
497#[derive(Debug, Clone, Copy, PartialEq, Eq)]
499pub enum ValidationStatus {
500 Pending,
502 Passed,
504 Failed,
506}
507
508#[derive(Debug, Clone)]
510pub struct Vulnerability {
511 pub id: String,
513 pub severity: VulnerabilitySeverity,
515 pub description: String,
517 pub affected_versions: Vec<String>,
519}
520
521#[derive(Debug, Clone, PartialEq, Eq)]
523pub enum VulnerabilitySeverity {
524 Low,
525 Medium,
526 High,
527 Critical,
528}
529
530#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
532pub struct ApiUsageInfo {
533 pub calls: Vec<String>,
535 pub network_access: Vec<String>,
537 pub filesystem_access: Vec<String>,
539}
540
541#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
543pub struct CodeAnalysisInfo {
544 pub cyclomatic_complexity: usize,
546 pub suspicious_patterns: Vec<String>,
548 pub potential_memory_issues: usize,
550 pub lines_of_code: usize,
552 pub test_coverage: f32,
554}
555
556#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
558pub struct Dependency {
559 pub name: String,
561 pub version: String,
563 pub optional: bool,
565 pub features: Vec<String>,
567}
568
569#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
571pub struct MarketplaceInfo {
572 pub url: String,
574 pub downloads: u64,
576 pub rating: f32,
578 pub reviews: u32,
580 pub last_updated: String,
582}
583
584#[derive(Debug)]
586pub struct DependencyResolver {
587 available_deps: HashMap<String, String>,
589}
590
591impl Default for DependencyResolver {
592 fn default() -> Self {
593 Self::new()
594 }
595}
596
597impl DependencyResolver {
598 pub fn new() -> Self {
600 Self {
601 available_deps: HashMap::new(),
602 }
603 }
604
605 pub fn is_available(&self, dependency: &Dependency) -> bool {
607 self.available_deps.contains_key(&dependency.name)
608 }
609
610 pub fn is_compatible_version(&self, _dependency: &Dependency) -> bool {
612 true
614 }
615
616 pub fn check_vulnerabilities(&self, _dependency: &Dependency) -> Option<Vec<String>> {
618 None
620 }
621}
622
623#[derive(Debug)]
625pub struct CodeAnalyzer {
626 #[allow(dead_code)]
628 rules: Vec<AnalysisRule>,
629}
630
631impl Default for CodeAnalyzer {
632 fn default() -> Self {
633 Self::new()
634 }
635}
636
637impl CodeAnalyzer {
638 pub fn new() -> Self {
640 Self { rules: Vec::new() }
641 }
642}
643
644#[derive(Debug)]
646pub struct TrustStore {
647 trusted_publishers: HashMap<String, f32>,
649}
650
651impl Default for TrustStore {
652 fn default() -> Self {
653 Self::new()
654 }
655}
656
657impl TrustStore {
658 pub fn new() -> Self {
660 Self {
661 trusted_publishers: HashMap::new(),
662 }
663 }
664
665 pub fn verify_signature(
667 &self,
668 _content_hash: &str,
669 _signature: &DigitalSignature,
670 ) -> Result<bool> {
671 Ok(true)
673 }
674
675 pub fn get_publisher_trust(&self, publisher: &PublisherInfo) -> f32 {
677 self.trusted_publishers
678 .get(&publisher.name)
679 .copied()
680 .unwrap_or(0.5)
681 }
682}
683
684#[derive(Debug, Clone)]
686pub struct AnalysisRule {
687 pub name: String,
689 pub description: String,
691 pub pattern: String,
693}
694
695impl Default for ValidationReport {
696 fn default() -> Self {
697 Self::new()
698 }
699}