Merge branch '7-create-output-formatter' into 'master'
Resolve "Create output formatter" Closes #7 See merge request bartlomiej.pluta/esa-tool!8
This commit is contained in:
@@ -6,7 +6,7 @@ plugins {
|
|||||||
group 'com.bartek'
|
group 'com.bartek'
|
||||||
version '1.0-SNAPSHOT'
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.12
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -22,6 +22,8 @@ dependencies {
|
|||||||
compile "io.vavr:vavr:${vavrVersion}"
|
compile "io.vavr:vavr:${vavrVersion}"
|
||||||
compile "com.github.javaparser:javaparser-core:${javaParserVersion}"
|
compile "com.github.javaparser:javaparser-core:${javaParserVersion}"
|
||||||
compile "commons-io:commons-io:${commonsIoVersion}"
|
compile "commons-io:commons-io:${commonsIoVersion}"
|
||||||
|
compile "org.fusesource.jansi:jansi:${jansiVersion}"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ ext {
|
|||||||
vavrVersion = '1.0.0-alpha-2'
|
vavrVersion = '1.0.0-alpha-2'
|
||||||
javaParserVersion = '3.13.4'
|
javaParserVersion = '3.13.4'
|
||||||
commonsIoVersion = '2.6'
|
commonsIoVersion = '2.6'
|
||||||
|
jansiVersion = '1.17.1'
|
||||||
}
|
}
|
||||||
@@ -4,10 +4,12 @@ import com.bartek.esa.analyser.apk.ApkAnalyser;
|
|||||||
import com.bartek.esa.analyser.source.SourceAnalyser;
|
import com.bartek.esa.analyser.source.SourceAnalyser;
|
||||||
import com.bartek.esa.cli.model.CliArgsOptions;
|
import com.bartek.esa.cli.model.CliArgsOptions;
|
||||||
import com.bartek.esa.cli.parser.CliArgsParser;
|
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.core.model.object.Issue;
|
||||||
import com.bartek.esa.di.DaggerDependencyInjector;
|
import com.bartek.esa.di.DaggerDependencyInjector;
|
||||||
import com.bartek.esa.dispatcher.dispatcher.MethodDispatcher;
|
import com.bartek.esa.dispatcher.dispatcher.MethodDispatcher;
|
||||||
import com.bartek.esa.dispatcher.model.DispatcherActions;
|
import com.bartek.esa.dispatcher.model.DispatcherActions;
|
||||||
|
import com.bartek.esa.formatter.provider.FormatterProvider;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -17,13 +19,15 @@ public class EsaMain {
|
|||||||
private final MethodDispatcher methodDispatcher;
|
private final MethodDispatcher methodDispatcher;
|
||||||
private final SourceAnalyser sourceAnalyser;
|
private final SourceAnalyser sourceAnalyser;
|
||||||
private final ApkAnalyser apkAnalyser;
|
private final ApkAnalyser apkAnalyser;
|
||||||
|
private final FormatterProvider formatterProvider;
|
||||||
|
|
||||||
@Inject
|
@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.cliArgsParser = cliArgsParser;
|
||||||
this.methodDispatcher = methodDispatcher;
|
this.methodDispatcher = methodDispatcher;
|
||||||
this.sourceAnalyser = sourceAnalyser;
|
this.sourceAnalyser = sourceAnalyser;
|
||||||
this.apkAnalyser = apkAnalyser;
|
this.apkAnalyser = apkAnalyser;
|
||||||
|
this.formatterProvider = formatterProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void run(String[] args) {
|
private void run(String[] args) {
|
||||||
@@ -33,8 +37,16 @@ public class EsaMain {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
CliArgsOptions options = cliArgsParser.parse(args);
|
CliArgsOptions options = cliArgsParser.parse(args);
|
||||||
|
|
||||||
List<Issue> issues = methodDispatcher.dispatchMethod(options, dispatcherActions);
|
List<Issue> issues = methodDispatcher.dispatchMethod(options, dispatcherActions);
|
||||||
|
formatterProvider.provide(options).format(issues);
|
||||||
|
|
||||||
|
exitWithErrorIfAnyIssueIsAnError(issues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exitWithErrorIfAnyIssueIsAnError(List<Issue> issues) {
|
||||||
|
if(issues.stream().anyMatch(i -> i.getSeverity() == Severity.ERROR)) {
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public class CliArgsOptions {
|
|||||||
private String apkAuditFile;
|
private String apkAuditFile;
|
||||||
private Set<String> excludes;
|
private Set<String> excludes;
|
||||||
private Set<String> plugins;
|
private Set<String> plugins;
|
||||||
|
private boolean color;
|
||||||
|
|
||||||
public boolean isSourceAnalysis() {
|
public boolean isSourceAnalysis() {
|
||||||
return sourceAnalysisDirectory != null;
|
return sourceAnalysisDirectory != null;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public class CliArgsParser {
|
|||||||
private static final String EXCLUDE_OPT = "exclude";
|
private static final String EXCLUDE_OPT = "exclude";
|
||||||
private static final String HELP_OPT = "help";
|
private static final String HELP_OPT = "help";
|
||||||
private static final String PLUGINS_OPT = "plugins";
|
private static final String PLUGINS_OPT = "plugins";
|
||||||
|
private static final String COLOR_OPT = "color";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CliArgsParser() {}
|
public CliArgsParser() {}
|
||||||
@@ -47,6 +48,7 @@ public class CliArgsParser {
|
|||||||
.apkAuditFile(command.hasOption(APK_OPT) ? command.getOptionValue(APK_OPT) : null)
|
.apkAuditFile(command.hasOption(APK_OPT) ? command.getOptionValue(APK_OPT) : null)
|
||||||
.plugins(command.hasOption(PLUGINS_OPT) ? new HashSet<>(asList(command.getOptionValues(PLUGINS_OPT))) : emptySet())
|
.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())
|
.excludes(command.hasOption(EXCLUDE_OPT) ? new HashSet<>(asList(command.getOptionValues(EXCLUDE_OPT))) : emptySet())
|
||||||
|
.color(command.hasOption(COLOR_OPT))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +64,7 @@ public class CliArgsParser {
|
|||||||
options.addOption(exclude());
|
options.addOption(exclude());
|
||||||
options.addOption(plugins());
|
options.addOption(plugins());
|
||||||
options.addOption(help());
|
options.addOption(help());
|
||||||
|
options.addOption(color());
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,4 +110,11 @@ public class CliArgsParser {
|
|||||||
.desc("use only selected security checks for audit/analysis")
|
.desc("use only selected security checks for audit/analysis")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Option color() {
|
||||||
|
return Option.builder()
|
||||||
|
.longOpt(COLOR_OPT)
|
||||||
|
.desc("enable colored output")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.bartek.esa.core.di.PluginModule;
|
|||||||
import com.bartek.esa.decompiler.di.DecompilerModule;
|
import com.bartek.esa.decompiler.di.DecompilerModule;
|
||||||
import com.bartek.esa.dispatcher.di.DispatcherModule;
|
import com.bartek.esa.dispatcher.di.DispatcherModule;
|
||||||
import com.bartek.esa.file.di.FileModule;
|
import com.bartek.esa.file.di.FileModule;
|
||||||
|
import com.bartek.esa.formatter.di.FormatterModule;
|
||||||
import dagger.Component;
|
import dagger.Component;
|
||||||
|
|
||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
@@ -17,7 +18,8 @@ import dagger.Component;
|
|||||||
DecompilerModule.class,
|
DecompilerModule.class,
|
||||||
CoreModule.class,
|
CoreModule.class,
|
||||||
PluginModule.class,
|
PluginModule.class,
|
||||||
AnalyserModule.class
|
AnalyserModule.class,
|
||||||
|
FormatterModule.class
|
||||||
})
|
})
|
||||||
public interface DependencyInjector {
|
public interface DependencyInjector {
|
||||||
EsaMain esa();
|
EsaMain esa();
|
||||||
|
|||||||
@@ -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<Issue> issues);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class FormatterModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
public SimpleFormatter simpleFormatter(DescriptionProvider descriptionProvider) {
|
||||||
|
return new SimpleFormatter(descriptionProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
public ColorFormatter colorFormatter(DescriptionProvider descriptionProvider) {
|
||||||
|
return new ColorFormatter(descriptionProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
public FormatterProvider formatterProvider(SimpleFormatter simpleFormatter, ColorFormatter colorFormatter) {
|
||||||
|
return new FormatterProvider(simpleFormatter, colorFormatter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
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<Issue> 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());
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
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<Issue> issues) {
|
||||||
|
if(issues.isEmpty()) {
|
||||||
|
System.out.println("No issues found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user