diff --git a/src/main/java/com/bartek/esa/context/constructor/ContextConstructor.java b/src/main/java/com/bartek/esa/context/constructor/ContextConstructor.java index 47030fc..a95f182 100644 --- a/src/main/java/com/bartek/esa/context/constructor/ContextConstructor.java +++ b/src/main/java/com/bartek/esa/context/constructor/ContextConstructor.java @@ -4,7 +4,7 @@ import com.bartek.esa.context.model.Context; import com.bartek.esa.context.model.Source; import com.bartek.esa.core.xml.XmlHelper; import com.bartek.esa.error.EsaException; -import com.bartek.esa.file.matcher.GlobMatcher; +import com.bartek.esa.file.matcher.PackageNameMatcher; import com.github.javaparser.ParseProblemException; import com.github.javaparser.Problem; import com.github.javaparser.StaticJavaParser; @@ -18,19 +18,18 @@ import javax.xml.xpath.XPathConstants; import java.io.File; import java.util.Optional; import java.util.Set; -import java.util.function.Predicate; import static java.lang.String.format; import static java.util.stream.Collectors.toSet; public class ContextConstructor { private final XmlHelper xmlHelper; - private final GlobMatcher globMatcher; + private final PackageNameMatcher packageNameMatcher; @Inject - public ContextConstructor(XmlHelper xmlHelper, GlobMatcher globMatcher) { + public ContextConstructor(XmlHelper xmlHelper, PackageNameMatcher packageNameMatcher) { this.xmlHelper = xmlHelper; - this.globMatcher = globMatcher; + this.packageNameMatcher = packageNameMatcher; } public Context construct(File androidManifestFile, Set javaFiles, Set layoutFiles) { @@ -76,19 +75,12 @@ public class ContextConstructor { private Set> parseJavaFiles(Set javaFiles, String packageName) { return javaFiles.stream() - .filter(isApplicationPackageFile(packageName)) + .filter(file -> packageNameMatcher.doesFileMatchPackageName(file, packageName)) .map(file -> new Source<>(file, parseJava(file))) .filter(s -> s.getModel() != null) .collect(toSet()); } - private Predicate isApplicationPackageFile(String packageName) { - return file -> { - String path = packageName.replaceAll("\\.", "/"); - return globMatcher.fileMatchesGlobPattern(file, format("**/%s/**", path)); - }; - } - private CompilationUnit parseJava(File javaFile) { try { return StaticJavaParser.parse(javaFile); diff --git a/src/main/java/com/bartek/esa/context/di/ContextModule.java b/src/main/java/com/bartek/esa/context/di/ContextModule.java index 5015333..83e403c 100644 --- a/src/main/java/com/bartek/esa/context/di/ContextModule.java +++ b/src/main/java/com/bartek/esa/context/di/ContextModule.java @@ -2,14 +2,14 @@ package com.bartek.esa.context.di; import com.bartek.esa.context.constructor.ContextConstructor; import com.bartek.esa.core.xml.XmlHelper; -import com.bartek.esa.file.matcher.GlobMatcher; +import com.bartek.esa.file.matcher.PackageNameMatcher; import dagger.Module; @Module public class ContextModule { - public ContextConstructor contextConstructor(XmlHelper xmlHelper, GlobMatcher globMatcher) { - return new ContextConstructor(xmlHelper, globMatcher); + public ContextConstructor contextConstructor(XmlHelper xmlHelper, PackageNameMatcher packageNameMatcher) { + return new ContextConstructor(xmlHelper, packageNameMatcher); } } diff --git a/src/main/java/com/bartek/esa/core/di/PluginModule.java b/src/main/java/com/bartek/esa/core/di/PluginModule.java index 01c3ed8..e6f09ae 100644 --- a/src/main/java/com/bartek/esa/core/di/PluginModule.java +++ b/src/main/java/com/bartek/esa/core/di/PluginModule.java @@ -7,6 +7,7 @@ import com.bartek.esa.core.helper.StringConcatenationChecker; import com.bartek.esa.core.java.JavaSyntaxRegexProvider; import com.bartek.esa.core.plugin.*; import com.bartek.esa.core.xml.XmlHelper; +import com.bartek.esa.file.matcher.PackageNameMatcher; import dagger.Module; import dagger.Provides; import dagger.multibindings.ElementsIntoSet; @@ -98,8 +99,8 @@ public class PluginModule { @Provides @IntoSet - public Plugin exportedComponentsPlugin(XmlHelper xmlHelper) { - return new ExportedComponentsPlugin(xmlHelper); + public Plugin exportedComponentsPlugin(XmlHelper xmlHelper, PackageNameMatcher packageNameMatcher) { + return new ExportedComponentsPlugin(xmlHelper, packageNameMatcher); } @Provides @@ -116,8 +117,8 @@ public class PluginModule { @Provides @IntoSet - public Plugin intentFilterPlugin(XmlHelper xmlHelper) { - return new IntentFilterPlugin(xmlHelper); + public Plugin intentFilterPlugin(XmlHelper xmlHelper, PackageNameMatcher packageNameMatcher) { + return new IntentFilterPlugin(xmlHelper, packageNameMatcher); } @Provides diff --git a/src/main/java/com/bartek/esa/core/plugin/ExportedComponentsPlugin.java b/src/main/java/com/bartek/esa/core/plugin/ExportedComponentsPlugin.java index f464c17..db15f47 100644 --- a/src/main/java/com/bartek/esa/core/plugin/ExportedComponentsPlugin.java +++ b/src/main/java/com/bartek/esa/core/plugin/ExportedComponentsPlugin.java @@ -1,11 +1,10 @@ package com.bartek.esa.core.plugin; import com.bartek.esa.context.model.Context; -import com.bartek.esa.context.model.Source; import com.bartek.esa.core.archetype.BasePlugin; import com.bartek.esa.core.model.enumeration.Severity; import com.bartek.esa.core.xml.XmlHelper; -import com.github.javaparser.ast.CompilationUnit; +import com.bartek.esa.file.matcher.PackageNameMatcher; import com.github.javaparser.ast.expr.MethodCallExpr; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -14,16 +13,17 @@ import javax.inject.Inject; import javax.xml.xpath.XPathConstants; import java.util.Map; import java.util.Optional; -import java.util.function.Predicate; import static java.lang.String.format; public class ExportedComponentsPlugin extends BasePlugin { private final XmlHelper xmlHelper; + private final PackageNameMatcher packageNameMatcher; @Inject - public ExportedComponentsPlugin(XmlHelper xmlHelper) { + public ExportedComponentsPlugin(XmlHelper xmlHelper, PackageNameMatcher packageNameMatcher) { this.xmlHelper = xmlHelper; + this.packageNameMatcher = packageNameMatcher; } @Override @@ -52,7 +52,7 @@ public class ExportedComponentsPlugin extends BasePlugin { private boolean isIntentDataBeingUsedInsideComponent(Context context, String componentCanonicalName) { return context.getJavaSources().stream() - .filter(doesMatchCanonicalName(componentCanonicalName)) + .filter(java -> packageNameMatcher.doesFileMatchPackageName(java.getFile(), componentCanonicalName)) .flatMap(java -> java.getModel().findAll(MethodCallExpr.class).stream()) .filter(expr -> expr.getName().getIdentifier().equals("getIntent")) .anyMatch(expr -> expr.getArguments().isEmpty()); @@ -88,8 +88,4 @@ public class ExportedComponentsPlugin extends BasePlugin { .map(v -> v.equals("true")) .orElse(false); } - - private Predicate> doesMatchCanonicalName(String canonicalName) { - return source -> source.getFile().getAbsolutePath().replaceAll("/", ".").contains(canonicalName); - } } diff --git a/src/main/java/com/bartek/esa/core/plugin/IntentFilterPlugin.java b/src/main/java/com/bartek/esa/core/plugin/IntentFilterPlugin.java index 69ed261..68cfe9b 100644 --- a/src/main/java/com/bartek/esa/core/plugin/IntentFilterPlugin.java +++ b/src/main/java/com/bartek/esa/core/plugin/IntentFilterPlugin.java @@ -1,31 +1,51 @@ package com.bartek.esa.core.plugin; -import com.bartek.esa.context.model.Source; -import com.bartek.esa.core.archetype.AndroidManifestPlugin; +import com.bartek.esa.context.model.Context; +import com.bartek.esa.core.archetype.BasePlugin; import com.bartek.esa.core.model.enumeration.Severity; import com.bartek.esa.core.xml.XmlHelper; -import org.w3c.dom.Document; +import com.bartek.esa.file.matcher.PackageNameMatcher; +import com.github.javaparser.ast.expr.MethodCallExpr; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.inject.Inject; import java.util.Map; +import java.util.Optional; -public class IntentFilterPlugin extends AndroidManifestPlugin { +public class IntentFilterPlugin extends BasePlugin { private final XmlHelper xmlHelper; + private final PackageNameMatcher packageNameMatcher; @Inject - public IntentFilterPlugin(XmlHelper xmlHelper) { + public IntentFilterPlugin(XmlHelper xmlHelper, PackageNameMatcher packageNameMatcher) { this.xmlHelper = xmlHelper; + this.packageNameMatcher = packageNameMatcher; } @Override - protected void run(Source manifest) { - NodeList filters = manifest.getModel().getElementsByTagName("intent-filter"); + protected void run(Context context) { + NodeList filters = context.getManifest().getModel().getElementsByTagName("intent-filter"); xmlHelper.stream(filters) .filter(this::isNotMainActivity) + .filter(this::isNotExported) .map(Node::getParentNode) - .forEach(n -> addIssue(Severity.INFO, getModel(n), manifest.getFile(), null, null)); + .forEach(node -> { + String componentName = node.getAttributes().getNamedItem("android:name").getNodeValue(); + String canonicalName = context.getPackageName() + componentName; + if (isIntentDataBeingUsedInsideComponent(context, canonicalName)) { + addIssue(Severity.WARNING, ".DATA_USAGE", getModel(node), context.getManifest().getFile(), null, null); + } else { + addIssue(Severity.WARNING, getModel(node), context.getManifest().getFile(), null, null); + } + }); + } + + private boolean isNotExported(Node component) { + return !Optional.ofNullable(component.getAttributes().getNamedItem("android:exported")) + .map(Node::getNodeValue) + .map(Boolean::parseBoolean) + .orElse(false); } private Map getModel(Node node) { @@ -37,16 +57,24 @@ public class IntentFilterPlugin extends AndroidManifestPlugin { private boolean isNotMainActivity(Node filter) { long mainActivityIntentFilters = xmlHelper.stream(filter.getChildNodes()) - .filter(n -> n.getNodeName().matches("action|category")) + .filter(n -> n.getNodeName().matches("action|category|data")) .map(n -> n.getAttributes().getNamedItem("android:name")) .map(Node::getNodeValue) .filter(v -> v.equals("android.intent.action.MAIN") || v.equals("android.intent.category.LAUNCHER")) .count(); long currentIntentFilters = xmlHelper.stream(filter.getChildNodes()) - .filter(n -> n.getNodeName().matches("action|category")) + .filter(n -> n.getNodeName().matches("action|category|data")) .count(); return mainActivityIntentFilters != currentIntentFilters; } + + private boolean isIntentDataBeingUsedInsideComponent(Context context, String componentCanonicalName) { + return context.getJavaSources().stream() + .filter(java -> packageNameMatcher.doesFileMatchPackageName(java.getFile(), componentCanonicalName)) + .flatMap(java -> java.getModel().findAll(MethodCallExpr.class).stream()) + .filter(expr -> expr.getName().getIdentifier().equals("getIntent")) + .anyMatch(expr -> expr.getArguments().isEmpty()); + } } diff --git a/src/main/java/com/bartek/esa/file/di/FileModule.java b/src/main/java/com/bartek/esa/file/di/FileModule.java index 8d927cc..2c81e3b 100644 --- a/src/main/java/com/bartek/esa/file/di/FileModule.java +++ b/src/main/java/com/bartek/esa/file/di/FileModule.java @@ -2,6 +2,7 @@ package com.bartek.esa.file.di; import com.bartek.esa.file.cleaner.FileCleaner; import com.bartek.esa.file.matcher.GlobMatcher; +import com.bartek.esa.file.matcher.PackageNameMatcher; import com.bartek.esa.file.provider.FileContentProvider; import com.bartek.esa.file.provider.FileProvider; import com.bartek.esa.file.zip.ZipTool; @@ -35,4 +36,9 @@ public class FileModule { public FileCleaner fileCleaner() { return new FileCleaner(); } + + @Provides + public PackageNameMatcher packageNameMatcher() { + return new PackageNameMatcher(); + } } diff --git a/src/main/java/com/bartek/esa/file/matcher/PackageNameMatcher.java b/src/main/java/com/bartek/esa/file/matcher/PackageNameMatcher.java new file mode 100644 index 0000000..e5b712b --- /dev/null +++ b/src/main/java/com/bartek/esa/file/matcher/PackageNameMatcher.java @@ -0,0 +1,16 @@ +package com.bartek.esa.file.matcher; + +import javax.inject.Inject; +import java.io.File; + +public class PackageNameMatcher { + + @Inject + public PackageNameMatcher() { + + } + + public boolean doesFileMatchPackageName(File file, String packageName) { + return file.getAbsolutePath().replaceAll(File.separator, ".").contains(packageName); + } +} diff --git a/src/main/resources/description.properties b/src/main/resources/description.properties index 1fa44d7..d916ca2 100644 --- a/src/main/resources/description.properties +++ b/src/main/resources/description.properties @@ -110,12 +110,22 @@ com.bartek.esa.core.plugin.TextInputValidationPlugin=Input type is no selected.\ Consider associating a input type with this view.\n\ For example: