140 lines
5.4 KiB
Java
140 lines
5.4 KiB
Java
package com.novitechie.scan;
|
|
|
|
import com.janetfilter.core.commons.DebugInfo;
|
|
import com.janetfilter.core.enums.RuleType;
|
|
import com.janetfilter.core.models.FilterRule;
|
|
import com.janetfilter.core.plugin.PluginConfig;
|
|
|
|
import java.io.File;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
public class CanaryAutoScanner {
|
|
|
|
private static final List<FilterRule> DEFAULT_SCAN_PLUGINS = Arrays.asList(
|
|
new FilterRule(RuleType.EQUAL, "izhangzhihao.rainbow.brackets"));
|
|
private static final List<FilterRule> DEFAULT_SCAN_PACKAGES = Arrays.asList(
|
|
new FilterRule(RuleType.PREFIX, "com.janetfilter."),
|
|
new FilterRule(RuleType.PREFIX, "com.novitechie."));
|
|
|
|
private CanaryAutoScanner() {
|
|
}
|
|
|
|
public static List<FilterRule> scan(PluginConfig config) {
|
|
return scanWithResult(config).getClassRules();
|
|
}
|
|
|
|
public static AutoScanResult scanWithResult(PluginConfig config) {
|
|
try {
|
|
return doScan(config);
|
|
} catch (Exception e) {
|
|
DebugInfo.warn("[PRIVACY-SCAN] Auto scan failed; continue without generated rules", e);
|
|
return AutoScanResult.empty();
|
|
} catch (LinkageError e) {
|
|
DebugInfo.warn("[PRIVACY-SCAN] Auto scan unavailable; continue without generated rules", e);
|
|
return AutoScanResult.empty();
|
|
}
|
|
}
|
|
|
|
private static AutoScanResult doScan(PluginConfig config) {
|
|
List<FilterRule> pluginRules = rules(config, "Auto_Scan_Plugin", DEFAULT_SCAN_PLUGINS);
|
|
List<FilterRule> packageRules = rules(config, "Auto_Scan_Package", DEFAULT_SCAN_PACKAGES);
|
|
List<FilterRule> excludeRules = emptyIfNull(config.getBySection("Auto_Scan_Exclude"));
|
|
|
|
if (pluginRules.isEmpty() || packageRules.isEmpty()) {
|
|
DebugInfo.warn("[PRIVACY-SCAN] Auto scan disabled: plugin or package rules are empty");
|
|
return AutoScanResult.empty();
|
|
}
|
|
|
|
List<File> scanTargets = JbDirectoryScanner.getPluginDir(config);
|
|
if (scanTargets.isEmpty()) {
|
|
DebugInfo.warn("[PRIVACY-SCAN] No plugin scan targets found");
|
|
return AutoScanResult.empty();
|
|
}
|
|
|
|
DebugInfo.output("[PRIVACY-SCAN] Plugin targets: " + fileSummary(scanTargets));
|
|
DebugInfo.output("[PRIVACY-SCAN] Scan_Plugin: " + ruleSummary(pluginRules));
|
|
DebugInfo.output("[PRIVACY-SCAN] Scan_Package: " + ruleSummary(packageRules));
|
|
DebugInfo.output("[PRIVACY-SCAN] Exclude_Package: " + ruleSummary(excludeRules));
|
|
|
|
CanaryScanner.ScanResult result = CanaryScanner.scan(scanTargets, pluginRules, packageRules, excludeRules);
|
|
List<String> classNames = result.getClassNames();
|
|
List<FilterRule> classRules = new ArrayList<>(classNames.size());
|
|
DebugInfo.output("[PRIVACY-SCAN] Found " + classNames.size() + " canary classes");
|
|
for (String className : classNames) {
|
|
classRules.add(FilterRule.of("EQUAL", className));
|
|
DebugInfo.output("[PRIVACY-SCAN] - " + className);
|
|
}
|
|
DebugInfo.output("[PRIVACY-SCAN] Marker resource exists: " + result.isMarkerResourceExists());
|
|
return new AutoScanResult(classRules, result.isMarkerResourceExists());
|
|
}
|
|
|
|
private static List<FilterRule> rules(PluginConfig config, String section, List<FilterRule> defaultValue) {
|
|
List<FilterRule> configRules = config.getBySection(section);
|
|
if (hasSection(config, section)) {
|
|
return emptyIfNull(configRules);
|
|
}
|
|
if (defaultValue == null) {
|
|
return Collections.emptyList();
|
|
}
|
|
return defaultValue;
|
|
}
|
|
|
|
private static boolean hasSection(PluginConfig config, String section) {
|
|
return config.getData() != null && config.getData().containsKey(section);
|
|
}
|
|
|
|
private static List<FilterRule> emptyIfNull(List<FilterRule> rules) {
|
|
return rules == null ? Collections.emptyList() : rules;
|
|
}
|
|
|
|
private static String fileSummary(List<File> files) {
|
|
StringBuilder summary = new StringBuilder();
|
|
for (File file : files) {
|
|
if (summary.length() > 0) {
|
|
summary.append(", ");
|
|
}
|
|
summary.append(file.getAbsolutePath());
|
|
}
|
|
return summary.toString();
|
|
}
|
|
|
|
private static String ruleSummary(List<FilterRule> rules) {
|
|
if (rules == null || rules.isEmpty()) {
|
|
return "(none)";
|
|
}
|
|
StringBuilder summary = new StringBuilder();
|
|
for (FilterRule rule : rules) {
|
|
if (summary.length() > 0) {
|
|
summary.append(", ");
|
|
}
|
|
summary.append(rule);
|
|
}
|
|
return summary.toString();
|
|
}
|
|
|
|
public static class AutoScanResult {
|
|
private final List<FilterRule> classRules;
|
|
private final boolean markerResourceExists;
|
|
|
|
private AutoScanResult(List<FilterRule> classRules, boolean markerResourceExists) {
|
|
this.classRules = classRules == null ? Collections.emptyList() : classRules;
|
|
this.markerResourceExists = markerResourceExists;
|
|
}
|
|
|
|
public static AutoScanResult empty() {
|
|
return new AutoScanResult(Collections.emptyList(), false);
|
|
}
|
|
|
|
public List<FilterRule> getClassRules() {
|
|
return new ArrayList<>(classRules);
|
|
}
|
|
|
|
public boolean isMarkerResourceExists() {
|
|
return markerResourceExists;
|
|
}
|
|
}
|
|
}
|