@@ -0,0 +1,666 @@
|
||||
use proxywarden_lib::component_detection::{
|
||||
proxyfier_component_from_inventory, singbox_component_from_inventory,
|
||||
};
|
||||
use proxywarden_lib::component_inventory::{
|
||||
authorize_component_action, classify_component_candidates,
|
||||
component_inventory_fingerprint_for_cutover, legacy_proxifyre_topshelf_path_matches,
|
||||
prove_legacy_cutover, BinaryIdentityEvidence, CandidateRole, ComponentCandidateProbe,
|
||||
ComponentClassification, InventoryAction, InventoryIssue, LegacyCutoverEvidence,
|
||||
LegacyCutoverProof, LegacyProxifyreScmProfile, MarkerEvidence, ServiceEvidence,
|
||||
AMBIGUOUS_LEGACY, MANUAL_MIGRATION_REQUIRED, OWNERSHIP_MISMATCH,
|
||||
};
|
||||
use proxywarden_lib::component_status::resolve_component_statuses_with_inventories;
|
||||
use proxywarden_lib::models::{ComponentId, ComponentState};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[test]
|
||||
fn managed_current_requires_marker_files_and_exact_service_path() {
|
||||
let root = PathBuf::from(r"C:\Program Files\ProxyWarden\components\ProxiFyre");
|
||||
let inventory = classify_component_candidates(
|
||||
ComponentId::Proxyfier,
|
||||
vec![probe(
|
||||
ComponentId::Proxyfier,
|
||||
CandidateRole::Current,
|
||||
&root,
|
||||
true,
|
||||
MarkerEvidence::Valid,
|
||||
BinaryIdentityEvidence::Unknown,
|
||||
Some(service(&root.join("ProxiFyre.exe"), true)),
|
||||
)],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
inventory.classification(),
|
||||
ComponentClassification::ManagedCurrent
|
||||
);
|
||||
assert_eq!(
|
||||
inventory
|
||||
.selected_candidate()
|
||||
.expect("selected current")
|
||||
.binary_version,
|
||||
Some("2.4.0.0".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_service_name_with_foreign_path_is_ownership_mismatch() {
|
||||
let root = PathBuf::from(r"C:\Program Files\ProxyWarden\components\ProxiFyre");
|
||||
let inventory = classify_component_candidates(
|
||||
ComponentId::Proxyfier,
|
||||
vec![probe(
|
||||
ComponentId::Proxyfier,
|
||||
CandidateRole::Current,
|
||||
&root,
|
||||
true,
|
||||
MarkerEvidence::Valid,
|
||||
BinaryIdentityEvidence::KnownPackage,
|
||||
Some(service(
|
||||
PathBuf::from(r"C:\Foreign\ProxiFyre.exe").as_path(),
|
||||
false,
|
||||
)),
|
||||
)],
|
||||
);
|
||||
|
||||
let candidate = inventory
|
||||
.selected_candidate()
|
||||
.expect("foreign current candidate");
|
||||
assert_eq!(candidate.classification, ComponentClassification::Foreign);
|
||||
assert_eq!(candidate.issues[0].code, OWNERSHIP_MISMATCH);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tools_proxifyre_is_legacy_and_never_current() {
|
||||
let root = PathBuf::from(r"C:\Tools\ProxiFyre");
|
||||
let inventory = classify_component_candidates(
|
||||
ComponentId::Proxyfier,
|
||||
vec![probe(
|
||||
ComponentId::Proxyfier,
|
||||
CandidateRole::Legacy,
|
||||
&root,
|
||||
false,
|
||||
MarkerEvidence::NotRequired,
|
||||
BinaryIdentityEvidence::KnownPackage,
|
||||
Some(service(&root.join("ProxiFyre.exe"), true)),
|
||||
)],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
inventory.classification(),
|
||||
ComponentClassification::ManagedLegacy
|
||||
);
|
||||
let component = proxyfier_component_from_inventory(&inventory);
|
||||
assert_eq!(component.actions, vec!["Перенести ProxiFyre"]);
|
||||
assert!(component
|
||||
.problems
|
||||
.iter()
|
||||
.any(|problem| problem.contains("явного переноса")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bare_singbox_root_stays_foreign_without_complete_identity() {
|
||||
let root = PathBuf::from(r"C:\Program Files\sing-box");
|
||||
let mut candidate = probe(
|
||||
ComponentId::Singbox,
|
||||
CandidateRole::ForeignByDefault,
|
||||
&root,
|
||||
false,
|
||||
MarkerEvidence::NotRequired,
|
||||
BinaryIdentityEvidence::Unknown,
|
||||
Some(service(&root.join("ProxyWardenSingBox.exe"), true)),
|
||||
);
|
||||
candidate.legacy_identity_complete = false;
|
||||
let inventory = classify_component_candidates(ComponentId::Singbox, vec![candidate]);
|
||||
|
||||
assert_eq!(inventory.classification(), ComponentClassification::Foreign);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn current_root_without_required_marker_is_incomplete() {
|
||||
let root = PathBuf::from(r"C:\Program Files\ProxyWarden\components\ProxiFyre");
|
||||
let inventory = classify_component_candidates(
|
||||
ComponentId::Proxyfier,
|
||||
vec![probe(
|
||||
ComponentId::Proxyfier,
|
||||
CandidateRole::Current,
|
||||
&root,
|
||||
true,
|
||||
MarkerEvidence::Missing,
|
||||
BinaryIdentityEvidence::KnownPackage,
|
||||
Some(service(&root.join("ProxiFyre.exe"), true)),
|
||||
)],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
inventory.classification(),
|
||||
ComponentClassification::Incomplete
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn startup_status_preserves_foreign_and_incomplete_inventory_errors() {
|
||||
let proxyfier_root = PathBuf::from(r"C:\Program Files\ProxyWarden\components\ProxiFyre");
|
||||
let foreign_proxyfier = classify_component_candidates(
|
||||
ComponentId::Proxyfier,
|
||||
vec![probe(
|
||||
ComponentId::Proxyfier,
|
||||
CandidateRole::Current,
|
||||
&proxyfier_root,
|
||||
true,
|
||||
MarkerEvidence::Valid,
|
||||
BinaryIdentityEvidence::KnownPackage,
|
||||
Some(service(
|
||||
PathBuf::from(r"C:\Foreign\ProxiFyre.exe").as_path(),
|
||||
false,
|
||||
)),
|
||||
)],
|
||||
);
|
||||
let singbox_root = PathBuf::from(r"C:\Program Files\ProxyWarden\components\sing-box");
|
||||
let mut incomplete_singbox_probe = probe(
|
||||
ComponentId::Singbox,
|
||||
CandidateRole::Current,
|
||||
&singbox_root,
|
||||
false,
|
||||
MarkerEvidence::NotRequired,
|
||||
BinaryIdentityEvidence::KnownPackage,
|
||||
Some(service(&singbox_root.join("ProxyWardenSingBox.exe"), true)),
|
||||
);
|
||||
incomplete_singbox_probe
|
||||
.missing_files
|
||||
.push(singbox_root.join("ProxyWardenSingBox.xml"));
|
||||
let incomplete_singbox =
|
||||
classify_component_candidates(ComponentId::Singbox, vec![incomplete_singbox_probe]);
|
||||
|
||||
let statuses =
|
||||
resolve_component_statuses_with_inventories(&foreign_proxyfier, &incomplete_singbox);
|
||||
let proxyfier = statuses
|
||||
.iter()
|
||||
.find(|status| status.id == ComponentId::Proxyfier)
|
||||
.expect("ProxiFyre status");
|
||||
let singbox = statuses
|
||||
.iter()
|
||||
.find(|status| status.id == ComponentId::Singbox)
|
||||
.expect("sing-box status");
|
||||
|
||||
assert_eq!(proxyfier.state, ComponentState::Error);
|
||||
assert_eq!(singbox.state, ComponentState::Error);
|
||||
assert!(!proxyfier.problems.is_empty());
|
||||
assert!(!singbox.problems.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn current_candidate_wins_but_legacy_remains_visible() {
|
||||
let current_root = PathBuf::from(r"C:\Program Files\ProxyWarden\components\ProxiFyre");
|
||||
let legacy_root = PathBuf::from(r"C:\Tools\ProxiFyre");
|
||||
let inventory = classify_component_candidates(
|
||||
ComponentId::Proxyfier,
|
||||
vec![
|
||||
probe(
|
||||
ComponentId::Proxyfier,
|
||||
CandidateRole::Legacy,
|
||||
&legacy_root,
|
||||
false,
|
||||
MarkerEvidence::NotRequired,
|
||||
BinaryIdentityEvidence::KnownPackage,
|
||||
Some(service(&legacy_root.join("ProxiFyre.exe"), true)),
|
||||
),
|
||||
probe(
|
||||
ComponentId::Proxyfier,
|
||||
CandidateRole::Current,
|
||||
¤t_root,
|
||||
true,
|
||||
MarkerEvidence::Valid,
|
||||
BinaryIdentityEvidence::KnownPackage,
|
||||
Some(service(¤t_root.join("ProxiFyre.exe"), true)),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(inventory.candidates.len(), 2);
|
||||
assert_eq!(
|
||||
inventory.classification(),
|
||||
ComponentClassification::ManagedCurrent
|
||||
);
|
||||
assert_eq!(
|
||||
inventory
|
||||
.selected_candidate()
|
||||
.expect("selected current")
|
||||
.root,
|
||||
current_root
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_managed_legacy_candidates_block_selection() {
|
||||
let roots = [
|
||||
PathBuf::from(r"C:\Tools\ProxiFyre"),
|
||||
PathBuf::from(r"C:\Program Files\ProxiFyre"),
|
||||
];
|
||||
let probes = roots
|
||||
.iter()
|
||||
.map(|root| {
|
||||
probe(
|
||||
ComponentId::Proxyfier,
|
||||
CandidateRole::Legacy,
|
||||
root,
|
||||
false,
|
||||
MarkerEvidence::NotRequired,
|
||||
BinaryIdentityEvidence::KnownPackage,
|
||||
Some(service(&root.join("ProxiFyre.exe"), true)),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let inventory = classify_component_candidates(ComponentId::Proxyfier, probes);
|
||||
|
||||
assert!(inventory.selected_candidate().is_none());
|
||||
assert_eq!(inventory.issues[0].code, AMBIGUOUS_LEGACY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reparse_point_is_never_managed() {
|
||||
let root = PathBuf::from(r"C:\Program Files\ProxyWarden\components\sing-box");
|
||||
let mut candidate = probe(
|
||||
ComponentId::Singbox,
|
||||
CandidateRole::Current,
|
||||
&root,
|
||||
false,
|
||||
MarkerEvidence::NotRequired,
|
||||
BinaryIdentityEvidence::KnownPackage,
|
||||
Some(service(&root.join("ProxyWardenSingBox.exe"), true)),
|
||||
);
|
||||
candidate.has_reparse_point = true;
|
||||
let inventory = classify_component_candidates(ComponentId::Singbox, vec![candidate]);
|
||||
|
||||
assert_eq!(inventory.classification(), ComponentClassification::Foreign);
|
||||
assert_eq!(
|
||||
inventory.selected_candidate().unwrap().issues[0].code,
|
||||
OWNERSHIP_MISMATCH
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_frozen_proxifyre_identity_is_the_only_automatic_cutover() {
|
||||
let root = PathBuf::from(r"C:\Tools\ProxiFyre");
|
||||
let inventory = legacy_inventory(
|
||||
ComponentId::Proxyfier,
|
||||
&root,
|
||||
"ProxiFyreService",
|
||||
&topshelf_path(&root),
|
||||
"2.2.1.0",
|
||||
);
|
||||
|
||||
let proof = prove_legacy_cutover(&inventory, &exact_cutover_evidence())
|
||||
.expect("exact identity must produce an opaque proof");
|
||||
assert_eq!(proof.fingerprint().len(), 64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn discovery_evidence_never_substitutes_for_cutover_identity() {
|
||||
let auto_root = PathBuf::from(r"C:\Tools\ProxiFyre");
|
||||
let cases = [
|
||||
legacy_inventory(
|
||||
ComponentId::Proxyfier,
|
||||
Path::new(r"C:\Program Files\ProxiFyre"),
|
||||
"ProxiFyreService",
|
||||
&topshelf_path(Path::new(r"C:\Program Files\ProxiFyre")),
|
||||
"2.2.1.0",
|
||||
),
|
||||
legacy_inventory(
|
||||
ComponentId::Proxyfier,
|
||||
&auto_root,
|
||||
"ProxiFyre",
|
||||
&topshelf_path(&auto_root),
|
||||
"2.2.1.0",
|
||||
),
|
||||
legacy_inventory(
|
||||
ComponentId::Proxyfier,
|
||||
&auto_root,
|
||||
"ProxiFyreService",
|
||||
&format!(
|
||||
r#""{}" --service"#,
|
||||
auto_root.join("ProxiFyre.exe").display()
|
||||
),
|
||||
"2.2.1.0",
|
||||
),
|
||||
legacy_inventory(
|
||||
ComponentId::Proxyfier,
|
||||
&auto_root,
|
||||
"ProxiFyreService",
|
||||
&topshelf_path(&auto_root),
|
||||
"2.4.0.0",
|
||||
),
|
||||
];
|
||||
|
||||
for inventory in cases {
|
||||
assert_eq!(
|
||||
inventory.classification(),
|
||||
ComponentClassification::ManagedLegacy
|
||||
);
|
||||
assert_manual_without_mutation(prove_legacy_cutover(&inventory, &exact_cutover_evidence()));
|
||||
}
|
||||
|
||||
let inventory = legacy_inventory(
|
||||
ComponentId::Proxyfier,
|
||||
&auto_root,
|
||||
"ProxiFyreService",
|
||||
&topshelf_path(&auto_root),
|
||||
"2.2.1.0",
|
||||
);
|
||||
let mut bad_manifest = exact_cutover_evidence();
|
||||
bad_manifest.proxifyre_manifest_matches = false;
|
||||
assert_manual_without_mutation(prove_legacy_cutover(&inventory, &bad_manifest));
|
||||
|
||||
let mut bad_snapshot_fingerprint = exact_cutover_evidence();
|
||||
bad_snapshot_fingerprint
|
||||
.proxifyre_scm_snapshot_fingerprint
|
||||
.clear();
|
||||
assert_manual_without_mutation(prove_legacy_cutover(&inventory, &bad_snapshot_fingerprint));
|
||||
|
||||
let mut bad_profile = exact_cutover_evidence();
|
||||
bad_profile
|
||||
.proxifyre_scm_profile
|
||||
.as_mut()
|
||||
.expect("profile")
|
||||
.delayed_auto_start = true;
|
||||
assert_manual_without_mutation(prove_legacy_cutover(&inventory, &bad_profile));
|
||||
|
||||
let mut extra_candidate = inventory.clone();
|
||||
extra_candidate
|
||||
.candidates
|
||||
.push(extra_candidate.candidates[0].clone());
|
||||
assert_manual_without_mutation(prove_legacy_cutover(
|
||||
&extra_candidate,
|
||||
&exact_cutover_evidence(),
|
||||
));
|
||||
|
||||
let mut alias_collision = exact_cutover_evidence();
|
||||
alias_collision.additional_matching_service = true;
|
||||
assert_manual_without_mutation(prove_legacy_cutover(&inventory, &alias_collision));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_singbox_is_always_manual_and_has_zero_mutation_authority() {
|
||||
let root = PathBuf::from(r"C:\Program Files\ProxyWarden\sing-box");
|
||||
let inventory = legacy_inventory(
|
||||
ComponentId::Singbox,
|
||||
&root,
|
||||
"ProxyWardenSingBox",
|
||||
&format!(r#""{}""#, root.join("ProxyWardenSingBox.exe").display()),
|
||||
"1.13.19",
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
inventory.classification(),
|
||||
ComponentClassification::ManagedLegacy
|
||||
);
|
||||
let component = singbox_component_from_inventory(&inventory);
|
||||
assert!(component.actions.is_empty());
|
||||
assert!(component
|
||||
.problems
|
||||
.iter()
|
||||
.any(|problem| problem.contains("ручного переноса")));
|
||||
assert_manual_without_mutation(prove_legacy_cutover(&inventory, &exact_cutover_evidence()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generic_inventory_authorization_never_grants_cutover() {
|
||||
let root = PathBuf::from(r"C:\Tools\ProxiFyre");
|
||||
let inventory = legacy_inventory(
|
||||
ComponentId::Proxyfier,
|
||||
&root,
|
||||
"ProxiFyreService",
|
||||
&topshelf_path(&root),
|
||||
"2.2.1.0",
|
||||
);
|
||||
|
||||
let error = authorize_component_action(&inventory, InventoryAction::Cutover)
|
||||
.expect_err("generic lifecycle authorization must not grant cutover");
|
||||
assert_eq!(error.code, "legacy_cutover_required");
|
||||
let mut current = inventory.clone();
|
||||
current.candidates[0].classification = ComponentClassification::ManagedCurrent;
|
||||
let missing =
|
||||
proxywarden_lib::component_inventory::ComponentInventory::missing(ComponentId::Proxyfier);
|
||||
for inventory in [¤t, &missing] {
|
||||
assert!(authorize_component_action(inventory, InventoryAction::Cutover).is_err());
|
||||
}
|
||||
prove_legacy_cutover(&inventory, &exact_cutover_evidence())
|
||||
.expect("strict gate remains the only proof constructor");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generic_inventory_authorization_never_writes_legacy_runtime_config() {
|
||||
let root = PathBuf::from(r"C:\Tools\ProxiFyre");
|
||||
let inventory = legacy_inventory(
|
||||
ComponentId::Proxyfier,
|
||||
&root,
|
||||
"ProxiFyreService",
|
||||
&topshelf_path(&root),
|
||||
"2.2.1.0",
|
||||
);
|
||||
|
||||
for action in [
|
||||
InventoryAction::Apply,
|
||||
InventoryAction::Start,
|
||||
InventoryAction::Stop,
|
||||
] {
|
||||
let error = authorize_component_action(&inventory, action)
|
||||
.expect_err("legacy runtime actions require explicit cutover");
|
||||
assert_eq!(error.code, "legacy_cutover_required");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cutover_inventory_fingerprint_is_stable_and_binds_live_service_state() {
|
||||
let root = PathBuf::from(r"C:\Tools\ProxiFyre");
|
||||
let inventory = legacy_inventory(
|
||||
ComponentId::Proxyfier,
|
||||
&root,
|
||||
"ProxiFyreService",
|
||||
&topshelf_path(&root),
|
||||
"2.2.1.0",
|
||||
);
|
||||
let first = component_inventory_fingerprint_for_cutover(&inventory);
|
||||
assert_eq!(
|
||||
first,
|
||||
component_inventory_fingerprint_for_cutover(&inventory)
|
||||
);
|
||||
|
||||
let mut changed = inventory.clone();
|
||||
changed.candidates[0]
|
||||
.service
|
||||
.as_mut()
|
||||
.expect("service")
|
||||
.status = "running".to_string();
|
||||
assert_ne!(first, component_inventory_fingerprint_for_cutover(&changed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frozen_scm_profile_rejects_each_unsafe_or_unknown_field() {
|
||||
let mutations: [fn(&mut LegacyProxifyreScmProfile); 15] = [
|
||||
|profile| profile.service_type = 0x20,
|
||||
|profile| profile.start_type = 3,
|
||||
|profile| profile.error_control = 0,
|
||||
|profile| profile.account_name = "NetworkService".to_string(),
|
||||
|profile| profile.display_name = "ProxiFyre".to_string(),
|
||||
|profile| profile.description.clear(),
|
||||
|profile| profile.dependencies.push("Tcpip".to_string()),
|
||||
|profile| profile.load_order_group = Some("Network".to_string()),
|
||||
|profile| profile.has_failure_actions = true,
|
||||
|profile| profile.failure_actions_on_non_crash = true,
|
||||
|profile| profile.delayed_auto_start = true,
|
||||
|profile| profile.sid_type = 1,
|
||||
|profile| {
|
||||
profile
|
||||
.required_privileges
|
||||
.push("SeDebugPrivilege".to_string())
|
||||
},
|
||||
|profile| profile.has_triggers = true,
|
||||
|profile| profile.untrusted_mutation_rights = true,
|
||||
];
|
||||
|
||||
assert!(exact_scm_profile().matches_frozen_2_2_1_profile());
|
||||
for mutate in mutations {
|
||||
let mut profile = exact_scm_profile();
|
||||
mutate(&mut profile);
|
||||
assert!(!profile.matches_frozen_2_2_1_profile());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn topshelf_cutover_path_is_token_exact_and_pair_order_independent() {
|
||||
let executable = Path::new(r"C:\Tools\ProxiFyre\ProxiFyre.exe");
|
||||
for path_name in [
|
||||
r#""C:\Tools\ProxiFyre\ProxiFyre.exe" -displayname "ProxiFyre Service" -servicename "ProxiFyreService""#,
|
||||
r#"C:\Tools\ProxiFyre\ProxiFyre.exe -servicename ProxiFyreService -displayname "ProxiFyre Service""#,
|
||||
] {
|
||||
assert!(legacy_proxifyre_topshelf_path_matches(
|
||||
path_name, executable
|
||||
));
|
||||
}
|
||||
for path_name in [
|
||||
r#""C:\Tools\ProxiFyre\ProxiFyre.exe" --service"#,
|
||||
r#""C:\Tools\ProxiFyre\ProxiFyre.exe" -displayname "ProxiFyre Service" -servicename ProxiFyreService --run"#,
|
||||
r#""C:\Tools\ProxiFyre\ProxiFyre.exe" -displayname "Foreign" -servicename ProxiFyreService"#,
|
||||
r#""C:\Tools\ProxiFyre\ProxiFyre.exe" -displayname "ProxiFyre Service" -servicename ProxiFyre"#,
|
||||
r#""C:\Tools\ProxiFyre\ProxiFyre.exe -displayname "ProxiFyre Service" -servicename ProxiFyreService"#,
|
||||
] {
|
||||
assert!(!legacy_proxifyre_topshelf_path_matches(
|
||||
path_name, executable
|
||||
));
|
||||
}
|
||||
assert!(!legacy_proxifyre_topshelf_path_matches(
|
||||
r#""C:\Program Files\ProxiFyre\ProxiFyre.exe" -displayname "ProxiFyre Service" -servicename ProxiFyreService"#,
|
||||
Path::new(r"C:\Program Files\ProxiFyre\ProxiFyre.exe"),
|
||||
));
|
||||
}
|
||||
|
||||
fn assert_manual_without_mutation(result: Result<LegacyCutoverProof, InventoryIssue>) {
|
||||
assert_eq!(
|
||||
result
|
||||
.expect_err("manual identity must not yield a proof")
|
||||
.code,
|
||||
MANUAL_MIGRATION_REQUIRED
|
||||
);
|
||||
}
|
||||
|
||||
fn exact_cutover_evidence() -> LegacyCutoverEvidence {
|
||||
LegacyCutoverEvidence {
|
||||
proxifyre_manifest_matches: true,
|
||||
proxifyre_scm_profile: Some(exact_scm_profile()),
|
||||
proxifyre_scm_snapshot_fingerprint: "9".repeat(64),
|
||||
additional_matching_service: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn exact_scm_profile() -> LegacyProxifyreScmProfile {
|
||||
LegacyProxifyreScmProfile {
|
||||
service_type: 0x10,
|
||||
start_type: 2,
|
||||
error_control: 1,
|
||||
account_name: "LocalSystem".to_string(),
|
||||
display_name: "ProxiFyre Service".to_string(),
|
||||
description: "ProxiFyre - SOCKS5 ProxiFyre Service".to_string(),
|
||||
dependencies: Vec::new(),
|
||||
load_order_group: None,
|
||||
has_failure_actions: false,
|
||||
failure_actions_on_non_crash: false,
|
||||
delayed_auto_start: false,
|
||||
sid_type: 0,
|
||||
required_privileges: Vec::new(),
|
||||
has_triggers: false,
|
||||
untrusted_mutation_rights: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn legacy_inventory(
|
||||
component_id: ComponentId,
|
||||
root: &Path,
|
||||
service_name: &str,
|
||||
path_name: &str,
|
||||
version: &str,
|
||||
) -> proxywarden_lib::component_inventory::ComponentInventory {
|
||||
let executable_name = match component_id {
|
||||
ComponentId::Proxyfier => "ProxiFyre.exe",
|
||||
ComponentId::Singbox => "sing-box.exe",
|
||||
ComponentId::ControlApp => "ProxyWarden.exe",
|
||||
};
|
||||
let service_executable = match component_id {
|
||||
ComponentId::Singbox => root.join("ProxyWardenSingBox.exe"),
|
||||
ComponentId::Proxyfier | ComponentId::ControlApp => root.join(executable_name),
|
||||
};
|
||||
classify_component_candidates(
|
||||
component_id.clone(),
|
||||
vec![ComponentCandidateProbe {
|
||||
component_id,
|
||||
role: CandidateRole::Legacy,
|
||||
root: root.to_path_buf(),
|
||||
root_exists: true,
|
||||
has_reparse_point: false,
|
||||
executable_path: Some(root.join(executable_name)),
|
||||
missing_files: Vec::new(),
|
||||
marker: MarkerEvidence::NotRequired,
|
||||
marker_required: false,
|
||||
binary_identity: BinaryIdentityEvidence::KnownPackage,
|
||||
binary_version: Some(version.to_string()),
|
||||
service: Some(ServiceEvidence {
|
||||
name: service_name.to_string(),
|
||||
status: "stopped".to_string(),
|
||||
path_name: Some(path_name.to_string()),
|
||||
executable_path: Some(service_executable),
|
||||
path_matches_candidate: true,
|
||||
binary_version: Some(version.to_string()),
|
||||
}),
|
||||
service_required: true,
|
||||
legacy_identity_complete: true,
|
||||
}],
|
||||
)
|
||||
}
|
||||
|
||||
fn topshelf_path(root: &Path) -> String {
|
||||
format!(
|
||||
r#""{}" -displayname "ProxiFyre Service" -servicename "ProxiFyreService""#,
|
||||
root.join("ProxiFyre.exe").display()
|
||||
)
|
||||
}
|
||||
|
||||
fn probe(
|
||||
component_id: ComponentId,
|
||||
role: CandidateRole,
|
||||
root: &Path,
|
||||
marker_required: bool,
|
||||
marker: MarkerEvidence,
|
||||
binary_identity: BinaryIdentityEvidence,
|
||||
service: Option<ServiceEvidence>,
|
||||
) -> ComponentCandidateProbe {
|
||||
let executable_name = match component_id {
|
||||
ComponentId::Proxyfier => "ProxiFyre.exe",
|
||||
ComponentId::Singbox => "sing-box.exe",
|
||||
ComponentId::ControlApp => "ProxyWarden.exe",
|
||||
};
|
||||
ComponentCandidateProbe {
|
||||
component_id,
|
||||
role,
|
||||
root: root.to_path_buf(),
|
||||
root_exists: true,
|
||||
has_reparse_point: false,
|
||||
executable_path: Some(root.join(executable_name)),
|
||||
missing_files: Vec::new(),
|
||||
marker,
|
||||
marker_required,
|
||||
binary_identity,
|
||||
binary_version: Some("2.4.0.0".to_string()),
|
||||
service,
|
||||
service_required: true,
|
||||
legacy_identity_complete: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn service(executable: &std::path::Path, matches: bool) -> ServiceEvidence {
|
||||
ServiceEvidence {
|
||||
name: "ProxiFyreService".to_string(),
|
||||
status: "stopped".to_string(),
|
||||
path_name: Some(format!(r#""{}" --service"#, executable.display())),
|
||||
executable_path: Some(executable.to_path_buf()),
|
||||
path_matches_candidate: matches,
|
||||
binary_version: Some("2.4.0.0".to_string()),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user