From 7e2d8d115a0a1c60a5f9a97581dee93d19d148a1 Mon Sep 17 00:00:00 2001 From: BitterPanda Date: Tue, 10 Mar 2026 19:36:13 +0100 Subject: [PATCH] vscode rule: report version --- .../src/http/firewall/rule/vscode/mod.rs | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/proxy-lib/src/http/firewall/rule/vscode/mod.rs b/proxy-lib/src/http/firewall/rule/vscode/mod.rs index 62cf9d01..6001bbab 100644 --- a/proxy-lib/src/http/firewall/rule/vscode/mod.rs +++ b/proxy-lib/src/http/firewall/rule/vscode/mod.rs @@ -19,7 +19,7 @@ use crate::{ domain_matcher::DomainMatcher, events::{BlockReason, BlockedArtifact}, }, - package::malware_list::{LowerCaseEntryFormatter, RemoteMalwareList}, + package::{malware_list::{LowerCaseEntryFormatter, RemoteMalwareList}, version::PackageVersion}, storage::SyncCompactDataStorage, }; @@ -182,7 +182,7 @@ impl RuleVSCode { product: arcstr!("vscode"), identifier: ArcStr::from(vscode_extension.extension_id.as_str()), display_name: None, - version: None, + version: vscode_extension.version.clone(), } } @@ -206,7 +206,7 @@ impl RuleVSCode { ) } - /// Parse extension ID (publisher.name) from .vsix download URL path. + /// Parse extension ID (publisher.name) and version from .vsix download URL path. fn parse_extension_id_from_path(path: &str) -> Option { let mut it = path.trim_start_matches('/').split('/'); @@ -216,18 +216,19 @@ impl RuleVSCode { if first.eq_ignore_ascii_case("files") { let publisher = it.next()?; let extension = it.next()?; - let _ = it.next()?; // we require at least a fourth path - return Some(VsCodeExtensionId::new(publisher, extension)); + let version = it.next()?; // we require at least a fourth path segment + return Some(VsCodeExtensionId::new(publisher, extension, Some(version))); } - // Pattern: extensions///... + // Pattern: extensions////... if first.eq_ignore_ascii_case("extensions") { let publisher = it.next()?; let extension = it.next()?; - return Some(VsCodeExtensionId::new(publisher, extension)); + let version = it.next(); + return Some(VsCodeExtensionId::new(publisher, extension, version)); } - // Pattern: _apis/public/gallery/publishers//vsextensions//... + // Pattern: _apis/public/gallery/publishers//vsextensions///... if first.eq_ignore_ascii_case("_apis") { let second = it.next()?; let third = it.next()?; @@ -243,12 +244,13 @@ impl RuleVSCode { || fifth.eq_ignore_ascii_case("extensions") { let extension = it.next()?; - return Some(VsCodeExtensionId::new(publisher, extension)); + let version = it.next(); + return Some(VsCodeExtensionId::new(publisher, extension, version)); } } // Pattern: _apis/public/gallery/publisher///... - // Pattern: _apis/public/gallery/publisher//extension//... + // Pattern: _apis/public/gallery/publisher//extension///... if second.eq_ignore_ascii_case("public") && third.eq_ignore_ascii_case("gallery") && fourth.eq_ignore_ascii_case("publisher") @@ -258,10 +260,12 @@ impl RuleVSCode { if next.eq_ignore_ascii_case("extension") { let extension = it.next()?; - return Some(VsCodeExtensionId::new(publisher, extension)); + let version = it.next(); + return Some(VsCodeExtensionId::new(publisher, extension, version)); } - return Some(VsCodeExtensionId::new(publisher, next)); + let version = it.next(); + return Some(VsCodeExtensionId::new(publisher, next, version)); } } @@ -271,12 +275,14 @@ impl RuleVSCode { struct VsCodeExtensionId { extension_id: String, + version: Option, } impl VsCodeExtensionId { - fn new(publisher: &str, extension: &str) -> VsCodeExtensionId { + fn new(publisher: &str, extension: &str, version: Option<&str>) -> VsCodeExtensionId { Self { extension_id: format!("{publisher}.{extension}").to_lowercase(), + version: version.map(|v| v.parse().unwrap()), } } }