From 5334d247fc31bdae947bbf28a65ecdddd01f3c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Wed, 3 Apr 2019 11:42:19 +0200 Subject: [PATCH 1/5] 7: Create Formatters --- build.gradle | 4 +- dependency-versions.gradle | 1 + .../esa/formatter/archetype/Formatter.java | 9 ++ .../esa/formatter/di/FormatterModule.java | 21 +++++ .../formatter/formatter/ColorFormatter.java | 90 +++++++++++++++++++ .../formatter/formatter/SimpleFormatter.java | 65 ++++++++++++++ 6 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/bartek/esa/formatter/archetype/Formatter.java create mode 100644 src/main/java/com/bartek/esa/formatter/di/FormatterModule.java create mode 100644 src/main/java/com/bartek/esa/formatter/formatter/ColorFormatter.java create mode 100644 src/main/java/com/bartek/esa/formatter/formatter/SimpleFormatter.java diff --git a/build.gradle b/build.gradle index b04e14e..b72d0a5 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { group 'com.bartek' version '1.0-SNAPSHOT' -sourceCompatibility = 1.8 +sourceCompatibility = 1.12 repositories { mavenCentral() @@ -22,6 +22,8 @@ dependencies { compile "io.vavr:vavr:${vavrVersion}" compile "com.github.javaparser:javaparser-core:${javaParserVersion}" compile "commons-io:commons-io:${commonsIoVersion}" + compile "org.fusesource.jansi:jansi:${jansiVersion}" + } jar { diff --git a/dependency-versions.gradle b/dependency-versions.gradle index 7faffed..0114d4f 100644 --- a/dependency-versions.gradle +++ b/dependency-versions.gradle @@ -5,4 +5,5 @@ ext { vavrVersion = '1.0.0-alpha-2' javaParserVersion = '3.13.4' commonsIoVersion = '2.6' + jansiVersion = '1.17.1' } \ No newline at end of file diff --git a/src/main/java/com/bartek/esa/formatter/archetype/Formatter.java b/src/main/java/com/bartek/esa/formatter/archetype/Formatter.java new file mode 100644 index 0000000..cac7e43 --- /dev/null +++ b/src/main/java/com/bartek/esa/formatter/archetype/Formatter.java @@ -0,0 +1,9 @@ +package com.bartek.esa.formatter.archetype; + +import com.bartek.esa.core.model.object.Issue; + +import java.util.List; + +public interface Formatter { + void format(List issues); +} diff --git a/src/main/java/com/bartek/esa/formatter/di/FormatterModule.java b/src/main/java/com/bartek/esa/formatter/di/FormatterModule.java new file mode 100644 index 0000000..e91db50 --- /dev/null +++ b/src/main/java/com/bartek/esa/formatter/di/FormatterModule.java @@ -0,0 +1,21 @@ +package com.bartek.esa.formatter.di; + +import com.bartek.esa.core.desc.provider.DescriptionProvider; +import com.bartek.esa.formatter.formatter.ColorFormatter; +import com.bartek.esa.formatter.formatter.SimpleFormatter; +import dagger.Module; +import dagger.Provides; + +@Module +public class FormatterModule { + + @Provides + public SimpleFormatter simpleFormatter(DescriptionProvider descriptionProvider) { + return new SimpleFormatter(descriptionProvider); + } + + @Provides + public ColorFormatter colorFormatter(DescriptionProvider descriptionProvider) { + return new ColorFormatter(descriptionProvider); + } +} diff --git a/src/main/java/com/bartek/esa/formatter/formatter/ColorFormatter.java b/src/main/java/com/bartek/esa/formatter/formatter/ColorFormatter.java new file mode 100644 index 0000000..daa71ed --- /dev/null +++ b/src/main/java/com/bartek/esa/formatter/formatter/ColorFormatter.java @@ -0,0 +1,90 @@ +package com.bartek.esa.formatter.formatter; + +import com.bartek.esa.core.desc.provider.DescriptionProvider; +import com.bartek.esa.core.model.object.Issue; +import com.bartek.esa.formatter.archetype.Formatter; +import org.fusesource.jansi.Ansi; +import org.fusesource.jansi.AnsiConsole; + +import javax.inject.Inject; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.fusesource.jansi.Ansi.Color.*; +import static org.fusesource.jansi.Ansi.ansi; + +public class ColorFormatter implements Formatter { + + private final DescriptionProvider descriptionProvider; + + @Inject + public ColorFormatter(DescriptionProvider descriptionProvider) { + this.descriptionProvider = descriptionProvider; + } + + @Override + public void format(List issues) { + AnsiConsole.systemInstall(); + String format = issues.stream() + .map(this::format) + .collect(Collectors.joining()); + + System.out.println(format.substring(0, format.length() - 2)); + AnsiConsole.systemUninstall(); + } + + private String format(Issue issue) { + Ansi ansi = ansi(); + ansi = appendDescription(issue, ansi); + ansi = appendFile(issue, ansi); + ansi = appendLine(issue, ansi); + ansi.a("\n"); + + return ansi.toString(); + } + + private Ansi appendDescription(Issue issue, Ansi ansi) { + String description = descriptionProvider.getDescriptionForIssue(issue); + + return ansi + .fg(getColorForSeverity(issue)) + .a(issue.getSeverity().name()) + .reset() + .a(": ").a(description) + .a("\n"); + } + + private Ansi appendFile(Issue issue, Ansi ansi) { + return ansi + .fg(GREEN) + .a("File: ") + .reset() + .a(issue.getFile().getAbsolutePath()) + .a("\n"); + } + + private Ansi appendLine(Issue issue, Ansi ansi) { + Optional.ofNullable(issue.getLine()) + .ifPresent(line -> { + ansi + .fg(BLUE) + .a("Line"); + Optional.ofNullable(issue.getLineNumber()).ifPresentOrElse( + number -> ansi.a(" ").a(number).a(": "), + () -> ansi.a(": ") + ); + ansi.reset().a(line).a("\n"); + }); + return ansi; + } + + private Ansi.Color getColorForSeverity(Issue issue) { + switch(issue.getSeverity()) { + case WARNING: return YELLOW; + case ERROR: return RED; + } + + return RED; + } +} diff --git a/src/main/java/com/bartek/esa/formatter/formatter/SimpleFormatter.java b/src/main/java/com/bartek/esa/formatter/formatter/SimpleFormatter.java new file mode 100644 index 0000000..d9e2933 --- /dev/null +++ b/src/main/java/com/bartek/esa/formatter/formatter/SimpleFormatter.java @@ -0,0 +1,65 @@ +package com.bartek.esa.formatter.formatter; + +import com.bartek.esa.core.desc.provider.DescriptionProvider; +import com.bartek.esa.core.model.object.Issue; +import com.bartek.esa.formatter.archetype.Formatter; + +import javax.inject.Inject; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class SimpleFormatter implements Formatter { + private final DescriptionProvider descriptionProvider; + + @Inject + public SimpleFormatter(DescriptionProvider descriptionProvider) { + this.descriptionProvider = descriptionProvider; + } + + @Override + public void format(List issues) { + String format = issues.stream() + .map(this::format) + .collect(Collectors.joining()); + + System.out.println(format.substring(0, format.length() - 2)); + } + + private String format(Issue issue) { + StringBuilder format = new StringBuilder(); + appendDescription(issue, format); + appendFile(issue, format); + appendLine(issue, format); + format.append("\n"); + + return format.toString(); + } + + private void appendDescription(Issue issue, StringBuilder format) { + String description = descriptionProvider.getDescriptionForIssue(issue); + format + .append(issue.getSeverity().name()) + .append(": ").append(description) + .append("\n"); + } + + private void appendFile(Issue issue, StringBuilder format) { + format + .append("File: ") + .append(issue.getFile().getAbsolutePath()) + .append("\n"); + } + + private void appendLine(Issue issue, StringBuilder format) { + Optional.ofNullable(issue.getLine()) + .ifPresent(line -> { + format.append("Line"); + Optional.ofNullable(issue.getLineNumber()).ifPresentOrElse( + number -> format.append(" ").append(number).append(": "), + () -> format.append(": ") + ); + format.append(line).append("\n"); + }); + } +} From ccf0c2fbf96477951f075e4578daae337e31feb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Wed, 3 Apr 2019 12:16:39 +0200 Subject: [PATCH 2/5] 7: Add --color option to CLI --- .../java/com/bartek/esa/cli/model/CliArgsOptions.java | 1 + .../java/com/bartek/esa/cli/parser/CliArgsParser.java | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/com/bartek/esa/cli/model/CliArgsOptions.java b/src/main/java/com/bartek/esa/cli/model/CliArgsOptions.java index ddcb5a9..1280bdb 100644 --- a/src/main/java/com/bartek/esa/cli/model/CliArgsOptions.java +++ b/src/main/java/com/bartek/esa/cli/model/CliArgsOptions.java @@ -14,6 +14,7 @@ public class CliArgsOptions { private String apkAuditFile; private Set excludes; private Set plugins; + private boolean color; public boolean isSourceAnalysis() { return sourceAnalysisDirectory != null; diff --git a/src/main/java/com/bartek/esa/cli/parser/CliArgsParser.java b/src/main/java/com/bartek/esa/cli/parser/CliArgsParser.java index dd23a4d..f98c873 100644 --- a/src/main/java/com/bartek/esa/cli/parser/CliArgsParser.java +++ b/src/main/java/com/bartek/esa/cli/parser/CliArgsParser.java @@ -15,6 +15,7 @@ public class CliArgsParser { private static final String EXCLUDE_OPT = "exclude"; private static final String HELP_OPT = "help"; private static final String PLUGINS_OPT = "plugins"; + private static final String COLOR_OPT = "color"; @Inject public CliArgsParser() {} @@ -47,6 +48,7 @@ public class CliArgsParser { .apkAuditFile(command.hasOption(APK_OPT) ? command.getOptionValue(APK_OPT) : null) .plugins(command.hasOption(PLUGINS_OPT) ? new HashSet<>(asList(command.getOptionValues(PLUGINS_OPT))) : emptySet()) .excludes(command.hasOption(EXCLUDE_OPT) ? new HashSet<>(asList(command.getOptionValues(EXCLUDE_OPT))) : emptySet()) + .color(command.hasOption(COLOR_OPT)) .build(); } @@ -62,6 +64,7 @@ public class CliArgsParser { options.addOption(exclude()); options.addOption(plugins()); options.addOption(help()); + options.addOption(color()); return options; } @@ -107,4 +110,11 @@ public class CliArgsParser { .desc("use only selected security checks for audit/analysis") .build(); } + + private Option color() { + return Option.builder() + .longOpt(COLOR_OPT) + .desc("enable colored output") + .build(); + } } From ff3f696b248682b771afe796aad369c8b5b0b9bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Wed, 3 Apr 2019 12:20:07 +0200 Subject: [PATCH 3/5] 7: Create FormatterProvider --- .../com/bartek/esa/di/DependencyInjector.java | 4 +++- .../esa/formatter/di/FormatterModule.java | 6 +++++ .../formatter/provider/FormatterProvider.java | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/bartek/esa/formatter/provider/FormatterProvider.java diff --git a/src/main/java/com/bartek/esa/di/DependencyInjector.java b/src/main/java/com/bartek/esa/di/DependencyInjector.java index 2c78ba4..da0baaa 100644 --- a/src/main/java/com/bartek/esa/di/DependencyInjector.java +++ b/src/main/java/com/bartek/esa/di/DependencyInjector.java @@ -8,6 +8,7 @@ import com.bartek.esa.core.di.PluginModule; import com.bartek.esa.decompiler.di.DecompilerModule; import com.bartek.esa.dispatcher.di.DispatcherModule; import com.bartek.esa.file.di.FileModule; +import com.bartek.esa.formatter.di.FormatterModule; import dagger.Component; @Component(modules = { @@ -17,7 +18,8 @@ import dagger.Component; DecompilerModule.class, CoreModule.class, PluginModule.class, - AnalyserModule.class + AnalyserModule.class, + FormatterModule.class }) public interface DependencyInjector { EsaMain esa(); diff --git a/src/main/java/com/bartek/esa/formatter/di/FormatterModule.java b/src/main/java/com/bartek/esa/formatter/di/FormatterModule.java index e91db50..b7741aa 100644 --- a/src/main/java/com/bartek/esa/formatter/di/FormatterModule.java +++ b/src/main/java/com/bartek/esa/formatter/di/FormatterModule.java @@ -3,6 +3,7 @@ package com.bartek.esa.formatter.di; import com.bartek.esa.core.desc.provider.DescriptionProvider; import com.bartek.esa.formatter.formatter.ColorFormatter; import com.bartek.esa.formatter.formatter.SimpleFormatter; +import com.bartek.esa.formatter.provider.FormatterProvider; import dagger.Module; import dagger.Provides; @@ -18,4 +19,9 @@ public class FormatterModule { public ColorFormatter colorFormatter(DescriptionProvider descriptionProvider) { return new ColorFormatter(descriptionProvider); } + + @Provides + public FormatterProvider formatterProvider(SimpleFormatter simpleFormatter, ColorFormatter colorFormatter) { + return new FormatterProvider(simpleFormatter, colorFormatter); + } } diff --git a/src/main/java/com/bartek/esa/formatter/provider/FormatterProvider.java b/src/main/java/com/bartek/esa/formatter/provider/FormatterProvider.java new file mode 100644 index 0000000..16a31ce --- /dev/null +++ b/src/main/java/com/bartek/esa/formatter/provider/FormatterProvider.java @@ -0,0 +1,23 @@ +package com.bartek.esa.formatter.provider; + +import com.bartek.esa.cli.model.CliArgsOptions; +import com.bartek.esa.formatter.archetype.Formatter; +import com.bartek.esa.formatter.formatter.ColorFormatter; +import com.bartek.esa.formatter.formatter.SimpleFormatter; + +import javax.inject.Inject; + +public class FormatterProvider { + private final SimpleFormatter simpleFormatter; + private final ColorFormatter colorFormatter; + + @Inject + public FormatterProvider(SimpleFormatter simpleFormatter, ColorFormatter colorFormatter) { + this.simpleFormatter = simpleFormatter; + this.colorFormatter = colorFormatter; + } + + public Formatter provide(CliArgsOptions options) { + return options.isColor() ? colorFormatter : simpleFormatter; + } +} From 0ca1fcdc3a50483d1df55f20f20d233301dff5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Wed, 3 Apr 2019 12:23:43 +0200 Subject: [PATCH 4/5] 7: Make EsaMain to use formatters and checks errors in issues --- src/main/java/com/bartek/esa/EsaMain.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bartek/esa/EsaMain.java b/src/main/java/com/bartek/esa/EsaMain.java index 704a32b..c9ea10c 100644 --- a/src/main/java/com/bartek/esa/EsaMain.java +++ b/src/main/java/com/bartek/esa/EsaMain.java @@ -4,10 +4,12 @@ import com.bartek.esa.analyser.apk.ApkAnalyser; import com.bartek.esa.analyser.source.SourceAnalyser; import com.bartek.esa.cli.model.CliArgsOptions; import com.bartek.esa.cli.parser.CliArgsParser; +import com.bartek.esa.core.model.enumeration.Severity; import com.bartek.esa.core.model.object.Issue; import com.bartek.esa.di.DaggerDependencyInjector; import com.bartek.esa.dispatcher.dispatcher.MethodDispatcher; import com.bartek.esa.dispatcher.model.DispatcherActions; +import com.bartek.esa.formatter.provider.FormatterProvider; import javax.inject.Inject; import java.util.List; @@ -17,13 +19,15 @@ public class EsaMain { private final MethodDispatcher methodDispatcher; private final SourceAnalyser sourceAnalyser; private final ApkAnalyser apkAnalyser; + private final FormatterProvider formatterProvider; @Inject - EsaMain(CliArgsParser cliArgsParser, MethodDispatcher methodDispatcher, SourceAnalyser sourceAnalyser, ApkAnalyser apkAnalyser) { + EsaMain(CliArgsParser cliArgsParser, MethodDispatcher methodDispatcher, SourceAnalyser sourceAnalyser, ApkAnalyser apkAnalyser, FormatterProvider formatterProvider) { this.cliArgsParser = cliArgsParser; this.methodDispatcher = methodDispatcher; this.sourceAnalyser = sourceAnalyser; this.apkAnalyser = apkAnalyser; + this.formatterProvider = formatterProvider; } private void run(String[] args) { @@ -33,8 +37,16 @@ public class EsaMain { .build(); CliArgsOptions options = cliArgsParser.parse(args); - List issues = methodDispatcher.dispatchMethod(options, dispatcherActions); + formatterProvider.provide(options).format(issues); + + exitWithErrorIfAnyIssueIsAnError(issues); + } + + private void exitWithErrorIfAnyIssueIsAnError(List issues) { + if(issues.stream().anyMatch(i -> i.getSeverity() == Severity.ERROR)) { + System.exit(1); + } } public static void main(String[] args) { From 39fba8d23828b928581b9587bd37bbdb6ca296a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Wed, 3 Apr 2019 12:28:39 +0200 Subject: [PATCH 5/5] 7: Add message on empty issues list --- .../com/bartek/esa/formatter/formatter/ColorFormatter.java | 6 ++++++ .../com/bartek/esa/formatter/formatter/SimpleFormatter.java | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/com/bartek/esa/formatter/formatter/ColorFormatter.java b/src/main/java/com/bartek/esa/formatter/formatter/ColorFormatter.java index daa71ed..fdae927 100644 --- a/src/main/java/com/bartek/esa/formatter/formatter/ColorFormatter.java +++ b/src/main/java/com/bartek/esa/formatter/formatter/ColorFormatter.java @@ -26,6 +26,12 @@ public class ColorFormatter implements Formatter { @Override public void format(List issues) { AnsiConsole.systemInstall(); + if(issues.isEmpty()) { + Ansi noIssuesFound = ansi().fg(GREEN).a("No issues found.").reset(); + System.out.println(noIssuesFound); + return; + } + String format = issues.stream() .map(this::format) .collect(Collectors.joining()); diff --git a/src/main/java/com/bartek/esa/formatter/formatter/SimpleFormatter.java b/src/main/java/com/bartek/esa/formatter/formatter/SimpleFormatter.java index d9e2933..606da51 100644 --- a/src/main/java/com/bartek/esa/formatter/formatter/SimpleFormatter.java +++ b/src/main/java/com/bartek/esa/formatter/formatter/SimpleFormatter.java @@ -19,6 +19,11 @@ public class SimpleFormatter implements Formatter { @Override public void format(List issues) { + if(issues.isEmpty()) { + System.out.println("No issues found."); + return; + } + String format = issues.stream() .map(this::format) .collect(Collectors.joining());