diff options
24 files changed, 232 insertions, 311 deletions
diff --git a/.classpath b/.classpath deleted file mode 100644 index 746962e..0000000 --- a/.classpath +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <classpath> | ||
3 | <classpathentry kind="src" output="target/classes" path="src/main/java"> | ||
4 | <attributes> | ||
5 | <attribute name="optional" value="true"/> | ||
6 | <attribute name="maven.pomderived" value="true"/> | ||
7 | </attributes> | ||
8 | </classpathentry> | ||
9 | <classpathentry kind="src" output="target/test-classes" path="src/test/java"> | ||
10 | <attributes> | ||
11 | <attribute name="test" value="true"/> | ||
12 | <attribute name="optional" value="true"/> | ||
13 | <attribute name="maven.pomderived" value="true"/> | ||
14 | </attributes> | ||
15 | </classpathentry> | ||
16 | <classpathentry kind="src" path="example/src/main/java"/> | ||
17 | <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> | ||
18 | <attributes> | ||
19 | <attribute name="maven.pomderived" value="true"/> | ||
20 | <attribute name="org.eclipse.jst.component.nondependency" value=""/> | ||
21 | </attributes> | ||
22 | </classpathentry> | ||
23 | <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> | ||
24 | <attributes> | ||
25 | <attribute name="maven.pomderived" value="true"/> | ||
26 | <attribute name="test" value="true"/> | ||
27 | </attributes> | ||
28 | </classpathentry> | ||
29 | <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"> | ||
30 | <attributes> | ||
31 | <attribute name="maven.pomderived" value="true"/> | ||
32 | </attributes> | ||
33 | </classpathentry> | ||
34 | <classpathentry kind="output" path="target/classes"/> | ||
35 | </classpath> | ||
@@ -22,3 +22,8 @@ | |||
22 | hs_err_pid* | 22 | hs_err_pid* |
23 | /target/ | 23 | /target/ |
24 | /repository/ | 24 | /repository/ |
25 | |||
26 | # IDE files | ||
27 | /.project | ||
28 | /.classpath | ||
29 | /.settings/ \ No newline at end of file | ||
diff --git a/.project b/.project deleted file mode 100644 index dcd6357..0000000 --- a/.project +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <projectDescription> | ||
3 | <name>Akiwrapper</name> | ||
4 | <comment></comment> | ||
5 | <projects> | ||
6 | </projects> | ||
7 | <buildSpec> | ||
8 | <buildCommand> | ||
9 | <name>org.eclipse.jdt.core.javabuilder</name> | ||
10 | <arguments> | ||
11 | </arguments> | ||
12 | </buildCommand> | ||
13 | <buildCommand> | ||
14 | <name>org.eclipse.wst.validation.validationbuilder</name> | ||
15 | <arguments> | ||
16 | </arguments> | ||
17 | </buildCommand> | ||
18 | <buildCommand> | ||
19 | <name>org.eclipse.m2e.core.maven2Builder</name> | ||
20 | <arguments> | ||
21 | </arguments> | ||
22 | </buildCommand> | ||
23 | </buildSpec> | ||
24 | <natures> | ||
25 | <nature>org.eclipse.m2e.core.maven2Nature</nature> | ||
26 | <nature>org.eclipse.jdt.core.javanature</nature> | ||
27 | </natures> | ||
28 | </projectDescription> | ||
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index cdfe4f1..0000000 --- a/.settings/org.eclipse.core.resources.prefs +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | eclipse.preferences.version=1 | ||
2 | encoding//src/main/java=UTF-8 | ||
3 | encoding//src/test/java=UTF-8 | ||
4 | encoding//src/test/resources=UTF-8 | ||
5 | encoding/<project>=UTF-8 | ||
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 76e3512..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null | |||
@@ -1,133 +0,0 @@ | |||
1 | eclipse.preferences.version=1 | ||
2 | org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled | ||
3 | org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled | ||
4 | org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore | ||
5 | org.eclipse.jdt.core.compiler.annotation.nonnull=javax.annotation.Nonnull | ||
6 | org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=,edu.umd.cs.findbugs.annotations.NonNull,org.eclipse.jdt.annotation.NonNull | ||
7 | org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault | ||
8 | org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= | ||
9 | org.eclipse.jdt.core.compiler.annotation.nullable=javax.annotation.Nullable | ||
10 | org.eclipse.jdt.core.compiler.annotation.nullable.secondary=,edu.umd.cs.findbugs.annotations.Nullable,org.eclipse.jdt.annotation.Nullable | ||
11 | org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled | ||
12 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled | ||
13 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate | ||
14 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 | ||
15 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve | ||
16 | org.eclipse.jdt.core.compiler.compliance=11 | ||
17 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate | ||
18 | org.eclipse.jdt.core.compiler.debug.localVariable=generate | ||
19 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate | ||
20 | org.eclipse.jdt.core.compiler.doc.comment.support=enabled | ||
21 | org.eclipse.jdt.core.compiler.problem.APILeak=warning | ||
22 | org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info | ||
23 | org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning | ||
24 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error | ||
25 | org.eclipse.jdt.core.compiler.problem.autoboxing=ignore | ||
26 | org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning | ||
27 | org.eclipse.jdt.core.compiler.problem.deadCode=warning | ||
28 | org.eclipse.jdt.core.compiler.problem.deprecation=warning | ||
29 | org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled | ||
30 | org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled | ||
31 | org.eclipse.jdt.core.compiler.problem.discouragedReference=warning | ||
32 | org.eclipse.jdt.core.compiler.problem.emptyStatement=info | ||
33 | org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled | ||
34 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error | ||
35 | org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=info | ||
36 | org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning | ||
37 | org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled | ||
38 | org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore | ||
39 | org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning | ||
40 | org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning | ||
41 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning | ||
42 | org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning | ||
43 | org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled | ||
44 | org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning | ||
45 | org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning | ||
46 | org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=info | ||
47 | org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error | ||
48 | org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled | ||
49 | org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled | ||
50 | org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled | ||
51 | org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private | ||
52 | org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore | ||
53 | org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning | ||
54 | org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore | ||
55 | org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=info | ||
56 | org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled | ||
57 | org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning | ||
58 | org.eclipse.jdt.core.compiler.problem.missingJavadocComments=info | ||
59 | org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled | ||
60 | org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public | ||
61 | org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag | ||
62 | org.eclipse.jdt.core.compiler.problem.missingJavadocTags=info | ||
63 | org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled | ||
64 | org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled | ||
65 | org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public | ||
66 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=info | ||
67 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled | ||
68 | org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore | ||
69 | org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning | ||
70 | org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning | ||
71 | org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning | ||
72 | org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore | ||
73 | org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning | ||
74 | org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning | ||
75 | org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error | ||
76 | org.eclipse.jdt.core.compiler.problem.nullReference=error | ||
77 | org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error | ||
78 | org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning | ||
79 | org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning | ||
80 | org.eclipse.jdt.core.compiler.problem.parameterAssignment=info | ||
81 | org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning | ||
82 | org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning | ||
83 | org.eclipse.jdt.core.compiler.problem.potentialNullReference=error | ||
84 | org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning | ||
85 | org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning | ||
86 | org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning | ||
87 | org.eclipse.jdt.core.compiler.problem.redundantNullCheck=error | ||
88 | org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=info | ||
89 | org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=info | ||
90 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore | ||
91 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=info | ||
92 | org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning | ||
93 | org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled | ||
94 | org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning | ||
95 | org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled | ||
96 | org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled | ||
97 | org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info | ||
98 | org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=enabled | ||
99 | org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning | ||
100 | org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning | ||
101 | org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning | ||
102 | org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled | ||
103 | org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning | ||
104 | org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning | ||
105 | org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore | ||
106 | org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning | ||
107 | org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=error | ||
108 | org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled | ||
109 | org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=error | ||
110 | org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore | ||
111 | org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=info | ||
112 | org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=info | ||
113 | org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning | ||
114 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=info | ||
115 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled | ||
116 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=disabled | ||
117 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled | ||
118 | org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore | ||
119 | org.eclipse.jdt.core.compiler.problem.unusedImport=info | ||
120 | org.eclipse.jdt.core.compiler.problem.unusedLabel=info | ||
121 | org.eclipse.jdt.core.compiler.problem.unusedLocal=info | ||
122 | org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning | ||
123 | org.eclipse.jdt.core.compiler.problem.unusedParameter=info | ||
124 | org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=disabled | ||
125 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled | ||
126 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled | ||
127 | org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=info | ||
128 | org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=info | ||
129 | org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning | ||
130 | org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning | ||
131 | org.eclipse.jdt.core.compiler.release=disabled | ||
132 | org.eclipse.jdt.core.compiler.source=11 | ||
133 | org.eclipse.objectteams.otdt.compiler.option.pure_java=enabled | ||
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/.settings/org.eclipse.m2e.core.prefs +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | activeProfiles= | ||
2 | eclipse.preferences.version=1 | ||
3 | resolveWorkspaceProjects=true | ||
4 | version=1 | ||
diff --git a/.settings/org.sonarlint.eclipse.core.prefs b/.settings/org.sonarlint.eclipse.core.prefs deleted file mode 100644 index 55537ed..0000000 --- a/.settings/org.sonarlint.eclipse.core.prefs +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | autoEnabled=true | ||
2 | eclipse.preferences.version=1 | ||
3 | extraProperties= | ||
4 | fileExclusions=DIRECTORY\:target\r\nGLOB\:src/main/java/com/markozajc/akiwrapper/listbuilder/*.*\r\nDIRECTORY\:example | ||
diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c0327db..0000000 --- a/.travis.yml +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | language: java | ||
2 | jdk: | ||
3 | - openjdk11 | ||
4 | os: linux | ||
5 | arch: | ||
6 | - arm64 | ||
7 | - ppc64le | ||
8 | - s390x | ||
9 | script: mvn clean verify -Dmaven.javadoc.skip=true | ||
10 | dist: xenial | ||
11 | cache: | ||
12 | directories: | ||
13 | - "$HOME/.m2/repository" | ||
14 | - "$HOME/apache-maven-3.8.1" | ||
15 | before_install: | ||
16 | - export M2_HOME=$HOME/apache-maven-3.8.1 | ||
17 | - if [ ! -d $M2_HOME/bin ]; then curl https://archive.apache.org/dist/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.tar.gz | tar zxf - -C $HOME; fi | ||
18 | - export PATH=$M2_HOME/bin:$PATH | ||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | <groupId>com.github.markozajc</groupId> | 4 | <groupId>com.github.markozajc</groupId> |
5 | <artifactId>akiwrapper</artifactId> | 5 | <artifactId>akiwrapper</artifactId> |
6 | <version>1.5.2</version> | 6 | <version>1.5.2-2</version> |
7 | 7 | ||
8 | <name>Akiwrapper</name> | 8 | <name>Akiwrapper</name> |
9 | <description>A Java API wrapper for Akinator</description> | 9 | <description>A Java API wrapper for Akinator</description> |
@@ -35,8 +35,8 @@ | |||
35 | <properties> | 35 | <properties> |
36 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | 36 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
37 | <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | 37 | <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
38 | <junit.version>5.8.2</junit.version> | 38 | <junit.version>5.9.3</junit.version> |
39 | <slf4j.version>1.7.36</slf4j.version> | 39 | <slf4j.version>2.0.7</slf4j.version> |
40 | <maven.compiler.source>11</maven.compiler.source> | 40 | <maven.compiler.source>11</maven.compiler.source> |
41 | <maven.compiler.target>11</maven.compiler.target> | 41 | <maven.compiler.target>11</maven.compiler.target> |
42 | </properties> | 42 | </properties> |
@@ -47,7 +47,7 @@ | |||
47 | <dependency> | 47 | <dependency> |
48 | <groupId>com.jcabi</groupId> | 48 | <groupId>com.jcabi</groupId> |
49 | <artifactId>jcabi-xml</artifactId> | 49 | <artifactId>jcabi-xml</artifactId> |
50 | <version>0.23.2</version> | 50 | <version>0.27.2</version> |
51 | </dependency> | 51 | </dependency> |
52 | 52 | ||
53 | <!-- JSON parsing --> | 53 | <!-- JSON parsing --> |
@@ -61,7 +61,7 @@ | |||
61 | <dependency> | 61 | <dependency> |
62 | <groupId>com.konghq</groupId> | 62 | <groupId>com.konghq</groupId> |
63 | <artifactId>unirest-java</artifactId> | 63 | <artifactId>unirest-java</artifactId> |
64 | <version>3.13.8</version> | 64 | <version>3.14.2</version> |
65 | </dependency> | 65 | </dependency> |
66 | 66 | ||
67 | <!-- Logging --> | 67 | <!-- Logging --> |
@@ -101,7 +101,7 @@ | |||
101 | <dependency> | 101 | <dependency> |
102 | <groupId>com.github.spotbugs</groupId> | 102 | <groupId>com.github.spotbugs</groupId> |
103 | <artifactId>spotbugs-annotations</artifactId> | 103 | <artifactId>spotbugs-annotations</artifactId> |
104 | <version>4.6.0</version> | 104 | <version>4.7.3</version> |
105 | <scope>provided</scope> | 105 | <scope>provided</scope> |
106 | <optional>true</optional> | 106 | <optional>true</optional> |
107 | </dependency> | 107 | </dependency> |
@@ -119,6 +119,28 @@ | |||
119 | <build> | 119 | <build> |
120 | <plugins> | 120 | <plugins> |
121 | 121 | ||
122 | <!-- Version enforcer --> | ||
123 | <plugin> | ||
124 | <groupId>org.apache.maven.plugins</groupId> | ||
125 | <artifactId>maven-enforcer-plugin</artifactId> | ||
126 | <version>3.1.0</version> | ||
127 | <executions> | ||
128 | <execution> | ||
129 | <id>enforce-maven</id> | ||
130 | <goals> | ||
131 | <goal>enforce</goal> | ||
132 | </goals> | ||
133 | <configuration> | ||
134 | <rules> | ||
135 | <requireMavenVersion> | ||
136 | <version>3.2.5</version> | ||
137 | </requireMavenVersion> | ||
138 | </rules> | ||
139 | </configuration> | ||
140 | </execution> | ||
141 | </executions> | ||
142 | </plugin> | ||
143 | |||
122 | <!-- Javadoc --> | 144 | <!-- Javadoc --> |
123 | <plugin> | 145 | <plugin> |
124 | <artifactId>maven-javadoc-plugin</artifactId> | 146 | <artifactId>maven-javadoc-plugin</artifactId> |
@@ -154,7 +176,7 @@ | |||
154 | <plugin> | 176 | <plugin> |
155 | <groupId>org.codehaus.mojo</groupId> | 177 | <groupId>org.codehaus.mojo</groupId> |
156 | <artifactId>versions-maven-plugin</artifactId> | 178 | <artifactId>versions-maven-plugin</artifactId> |
157 | <version>2.10.0</version> | 179 | <version>2.11.0</version> |
158 | <configuration> | 180 | <configuration> |
159 | <rulesUri>file://${project.basedir}/versions-ruleset.xml</rulesUri> | 181 | <rulesUri>file://${project.basedir}/versions-ruleset.xml</rulesUri> |
160 | </configuration> | 182 | </configuration> |
@@ -218,4 +240,4 @@ | |||
218 | </profile> | 240 | </profile> |
219 | </profiles> | 241 | </profiles> |
220 | 242 | ||
221 | </project> \ No newline at end of file | 243 | </project> |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/AkiwrapperBuilder.java b/src/main/java/com/github/markozajc/akiwrapper/AkiwrapperBuilder.java index d11fe05..e13b31a 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/AkiwrapperBuilder.java +++ b/src/main/java/com/github/markozajc/akiwrapper/AkiwrapperBuilder.java | |||
@@ -32,15 +32,11 @@ public class AkiwrapperBuilder { | |||
32 | 32 | ||
33 | private static final Logger LOG = LoggerFactory.getLogger(AkiwrapperBuilder.class); | 33 | private static final Logger LOG = LoggerFactory.getLogger(AkiwrapperBuilder.class); |
34 | 34 | ||
35 | @Nullable | 35 | @Nullable private UnirestInstance unirest; |
36 | private UnirestInstance unirest; | 36 | @Nullable private Server server; |
37 | @Nullable | ||
38 | private Server server; | ||
39 | private boolean filterProfanity; | 37 | private boolean filterProfanity; |
40 | @Nonnull | 38 | @Nonnull private Language language; |
41 | private Language language; | 39 | @Nonnull private GuessType guessType; |
42 | @Nonnull | ||
43 | private GuessType guessType; | ||
44 | 40 | ||
45 | /** | 41 | /** |
46 | * The default profanity filter preference for new {@link Akiwrapper} instances. | 42 | * The default profanity filter preference for new {@link Akiwrapper} instances. |
@@ -50,14 +46,12 @@ public class AkiwrapperBuilder { | |||
50 | /** | 46 | /** |
51 | * The default {@link Language} for new {@link Akiwrapper} instances. | 47 | * The default {@link Language} for new {@link Akiwrapper} instances. |
52 | */ | 48 | */ |
53 | @Nonnull | 49 | @Nonnull public static final Language DEFAULT_LOCALIZATION = ENGLISH; |
54 | public static final Language DEFAULT_LOCALIZATION = ENGLISH; | ||
55 | 50 | ||
56 | /** | 51 | /** |
57 | * The default {@link GuessType} for new {@link Akiwrapper} instances. | 52 | * The default {@link GuessType} for new {@link Akiwrapper} instances. |
58 | */ | 53 | */ |
59 | @Nonnull | 54 | @Nonnull public static final GuessType DEFAULT_GUESS_TYPE = CHARACTER; |
60 | public static final GuessType DEFAULT_GUESS_TYPE = CHARACTER; | ||
61 | 55 | ||
62 | private AkiwrapperBuilder(@Nullable UnirestInstance unirest, @Nullable Server server, boolean filterProfanity, | 56 | private AkiwrapperBuilder(@Nullable UnirestInstance unirest, @Nullable Server server, boolean filterProfanity, |
63 | @Nonnull Language language, @Nonnull GuessType guessType) { | 57 | @Nonnull Language language, @Nonnull GuessType guessType) { |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/Route.java b/src/main/java/com/github/markozajc/akiwrapper/core/Route.java index 5b64def..309e297 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/Route.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/Route.java | |||
@@ -34,8 +34,7 @@ public final class Route { | |||
34 | * to false may result in unpredicted exceptions! <b>You usually don't need to alter | 34 | * to false may result in unpredicted exceptions! <b>You usually don't need to alter |
35 | * this value</b> | 35 | * this value</b> |
36 | */ | 36 | */ |
37 | @SuppressFBWarnings("MS_SHOULD_BE_FINAL") | 37 | @SuppressFBWarnings("MS_SHOULD_BE_FINAL") public static boolean defaultRunChecks = true; // NOSONAR |
38 | public static boolean defaultRunChecks = true; // NOSONAR | ||
39 | 38 | ||
40 | /** | 39 | /** |
41 | * Creates a new session for further gameplay.<br> | 40 | * Creates a new session for further gameplay.<br> |
@@ -81,10 +80,8 @@ public final class Route { | |||
81 | */ | 80 | */ |
82 | public static final Route LIST = new Route(1, "/list?mode_question=0&step=%s"); | 81 | public static final Route LIST = new Route(1, "/list?mode_question=0&step=%s"); |
83 | 82 | ||
84 | @Nonnull | 83 | @Nonnull private final String path; |
85 | private final String path; | 84 | @Nonnull private final String[] filterArguments; |
86 | @Nonnull | ||
87 | private final String[] filterArguments; | ||
88 | 85 | ||
89 | private final int parametersQuantity; | 86 | private final int parametersQuantity; |
90 | 87 | ||
@@ -182,10 +179,8 @@ public final class Route { | |||
182 | 179 | ||
183 | private static final Logger LOG = LoggerFactory.getLogger(Route.Request.class); | 180 | private static final Logger LOG = LoggerFactory.getLogger(Route.Request.class); |
184 | 181 | ||
185 | @Nonnull | 182 | @Nonnull private final UnirestInstance unirest; |
186 | private final UnirestInstance unirest; | 183 | @Nonnull private final String url; |
187 | @Nonnull | ||
188 | private final String url; | ||
189 | private final int jQueryCallbackLength; | 184 | private final int jQueryCallbackLength; |
190 | 185 | ||
191 | Request(@Nonnull UnirestInstance unirest, @Nonnull String url, int jQueryCallbackLength) { | 186 | Request(@Nonnull UnirestInstance unirest, @Nonnull String url, int jQueryCallbackLength) { |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ApiKey.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ApiKey.java index d7af25e..5447ab4 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ApiKey.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ApiKey.java | |||
@@ -24,10 +24,8 @@ public class ApiKey { | |||
24 | 24 | ||
25 | private static final String FORMAT = "frontaddr=%s&uid_ext_session=%s"; | 25 | private static final String FORMAT = "frontaddr=%s&uid_ext_session=%s"; |
26 | 26 | ||
27 | @Nonnull | 27 | @Nonnull private final String sessionUid; |
28 | private final String sessionUid; | 28 | @Nonnull private final String frontAddress; |
29 | @Nonnull | ||
30 | private final String frontAddress; | ||
31 | 29 | ||
32 | ApiKey(@Nonnull String sessionUid, @Nonnull String frontAddress) { | 30 | ApiKey(@Nonnull String sessionUid, @Nonnull String frontAddress) { |
33 | this.sessionUid = sessionUid; | 31 | this.sessionUid = sessionUid; |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/GuessImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/GuessImpl.java index d6a9012..f2afa77 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/GuessImpl.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/GuessImpl.java | |||
@@ -13,16 +13,11 @@ import com.github.markozajc.akiwrapper.core.entities.Guess; | |||
13 | 13 | ||
14 | public class GuessImpl implements Guess { | 14 | public class GuessImpl implements Guess { |
15 | 15 | ||
16 | @Nonnull | 16 | @Nonnull private final String id; |
17 | private final String id; | 17 | @Nonnull private final String name; |
18 | @Nonnull | 18 | @Nullable private final String description; |
19 | private final String name; | 19 | @Nullable private final URL image; |
20 | @Nullable | 20 | @Nonnegative private final double probability; |
21 | private final String description; | ||
22 | @Nullable | ||
23 | private final URL image; | ||
24 | @Nonnegative | ||
25 | private final double probability; | ||
26 | 21 | ||
27 | public GuessImpl(@Nonnull String id, @Nonnull String name, @Nullable String description, @Nullable URL image, | 22 | public GuessImpl(@Nonnull String id, @Nonnull String name, @Nullable String description, @Nullable URL image, |
28 | @Nonnegative double probability) { | 23 | @Nonnegative double probability) { |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/QuestionImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/QuestionImpl.java index abea006..c5b77cf 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/QuestionImpl.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/QuestionImpl.java | |||
@@ -14,16 +14,11 @@ public class QuestionImpl implements Question { | |||
14 | 14 | ||
15 | private static final String REASON_OUT_OF_QUESTIONS = "no question"; | 15 | private static final String REASON_OUT_OF_QUESTIONS = "no question"; |
16 | 16 | ||
17 | @Nonnull | 17 | @Nonnull private final String id; |
18 | private final String id; | 18 | @Nonnull private final String question; |
19 | @Nonnull | 19 | @Nonnegative private final int step; |
20 | private final String question; | 20 | @Nonnegative private final double gain; |
21 | @Nonnegative | 21 | @Nonnegative private final double progression; |
22 | private final int step; | ||
23 | @Nonnegative | ||
24 | private final double gain; | ||
25 | @Nonnegative | ||
26 | private final double progression; | ||
27 | 22 | ||
28 | public QuestionImpl(@Nonnull String id, @Nonnull String question, @Nonnegative int step, @Nonnegative double gain, | 23 | public QuestionImpl(@Nonnull String id, @Nonnull String question, @Nonnegative int step, @Nonnegative double gain, |
29 | @Nonnegative double progression, @Nonnull Status status) { | 24 | @Nonnegative double progression, @Nonnull Status status) { |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerImpl.java index 3354706..7af6db8 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerImpl.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerImpl.java | |||
@@ -13,12 +13,9 @@ public class ServerImpl implements Server { | |||
13 | private static final String LANGUAGE_ID_XPATH = "LANGUAGE/LANG_ID/text()"; // NOSONAR not a URL | 13 | private static final String LANGUAGE_ID_XPATH = "LANGUAGE/LANG_ID/text()"; // NOSONAR not a URL |
14 | private static final String SUBJECT_ID_XPATH = "SUBJECT/SUBJ_ID/text()"; // NOSONAR not a URL | 14 | private static final String SUBJECT_ID_XPATH = "SUBJECT/SUBJ_ID/text()"; // NOSONAR not a URL |
15 | private static final String CANDIDATE_URLS_XPATH = "CANDIDATS/*/text()"; // sic | 15 | private static final String CANDIDATE_URLS_XPATH = "CANDIDATS/*/text()"; // sic |
16 | @Nonnull | 16 | @Nonnull private final String url; |
17 | private final String url; | 17 | @Nonnull private final Language localization; |
18 | @Nonnull | 18 | @Nonnull private final GuessType guessType; |
19 | private final Language localization; | ||
20 | @Nonnull | ||
21 | private final GuessType guessType; | ||
22 | 19 | ||
23 | public ServerImpl(@Nonnull String url, @Nonnull Language localization, @Nonnull GuessType guessType) { | 20 | public ServerImpl(@Nonnull String url, @Nonnull Language localization, @Nonnull GuessType guessType) { |
24 | this.url = url; | 21 | this.url = url; |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerListImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerListImpl.java index cd4f540..2a3114c 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerListImpl.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerListImpl.java | |||
@@ -10,10 +10,8 @@ import com.github.markozajc.akiwrapper.core.entities.*; | |||
10 | 10 | ||
11 | public class ServerListImpl implements ServerList { | 11 | public class ServerListImpl implements ServerList { |
12 | 12 | ||
13 | @Nonnull | 13 | @Nonnull private Server currentServer; |
14 | private Server currentServer; | 14 | @Nonnull private final Queue<Server> candidateServers; |
15 | @Nonnull | ||
16 | private final Queue<Server> candidateServers; | ||
17 | 15 | ||
18 | @SuppressWarnings("null") | 16 | @SuppressWarnings("null") |
19 | public ServerListImpl(@Nonnull Server first, @Nonnull Server... candidates) { | 17 | public ServerListImpl(@Nonnull Server first, @Nonnull Server... candidates) { |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/StatusImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/StatusImpl.java index 0f3e520..b3c2381 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/StatusImpl.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/StatusImpl.java | |||
@@ -15,10 +15,8 @@ public class StatusImpl implements Status { | |||
15 | 15 | ||
16 | public static final StatusImpl STATUS_OK = new StatusImpl(Level.OK, null); | 16 | public static final StatusImpl STATUS_OK = new StatusImpl(Level.OK, null); |
17 | 17 | ||
18 | @Nullable | 18 | @Nullable private final String reason; |
19 | private final String reason; | 19 | @Nonnull private final Level level; |
20 | @Nonnull | ||
21 | private final Level level; | ||
22 | 20 | ||
23 | private StatusImpl(@Nonnull Level level, @Nullable String reason) { | 21 | private StatusImpl(@Nonnull Level level, @Nullable String reason) { |
24 | this.level = level; | 22 | this.level = level; |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/impl/AkiwrapperImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/impl/AkiwrapperImpl.java index 6c85422..7609cdb 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/impl/AkiwrapperImpl.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/impl/AkiwrapperImpl.java | |||
@@ -54,17 +54,12 @@ public class AkiwrapperImpl implements Akiwrapper { | |||
54 | } | 54 | } |
55 | } | 55 | } |
56 | 56 | ||
57 | @Nonnull | 57 | @Nonnull private final Server server; |
58 | private final Server server; | 58 | @Nonnull private final UnirestInstance unirest; |
59 | @Nonnull | ||
60 | private final UnirestInstance unirest; | ||
61 | private final boolean filterProfanity; | 59 | private final boolean filterProfanity; |
62 | @Nonnull | 60 | @Nonnull private final Session session; |
63 | private final Session session; | 61 | @Nonnegative private int currentStep; |
64 | @Nonnegative | 62 | @Nullable private Question question; |
65 | private int currentStep; | ||
66 | @Nullable | ||
67 | private Question question; | ||
68 | private List<Guess> guessCache; | 63 | private List<Guess> guessCache; |
69 | 64 | ||
70 | @SuppressWarnings("null") | 65 | @SuppressWarnings("null") |
@@ -115,7 +110,7 @@ public class AkiwrapperImpl implements Akiwrapper { | |||
115 | this.guessCache = null; | 110 | this.guessCache = null; |
116 | 111 | ||
117 | Question current = getQuestion(); | 112 | Question current = getQuestion(); |
118 | if ((current == null) || (current.getStep() < 1)) | 113 | if (current == null || current.getStep() < 1) |
119 | return null; | 114 | return null; |
120 | 115 | ||
121 | var questionJson = CANCEL_ANSWER | 116 | var questionJson = CANCEL_ANSWER |
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/utils/Servers.java b/src/main/java/com/github/markozajc/akiwrapper/core/utils/Servers.java index fb8d8c4..6f74a9b 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/utils/Servers.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/utils/Servers.java | |||
@@ -24,9 +24,8 @@ import kong.unirest.UnirestInstance; | |||
24 | @SuppressFBWarnings("REC_CATCH_EXCEPTION") | 24 | @SuppressFBWarnings("REC_CATCH_EXCEPTION") |
25 | public final class Servers { | 25 | public final class Servers { |
26 | 26 | ||
27 | private static final String FOOTPRINT = "cd8e6509f3420878e18d75b9831b317f"; | ||
28 | private static final String LIST_URL = | 27 | private static final String LIST_URL = |
29 | "https://global3.akinator.com/ws/instances_v2.php?media_id=14" + "&mode=https&footprint=" + FOOTPRINT; | 28 | "https://global3.akinator.com/ws/instances_v2.php?media_id=14&mode=https&footprint=cd8e6509f3420878e18d75b9831b317f"; |
30 | 29 | ||
31 | private Servers() {} | 30 | private Servers() {} |
32 | 31 | ||
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/utils/UnirestUtils.java b/src/main/java/com/github/markozajc/akiwrapper/core/utils/UnirestUtils.java index f361249..f418cb9 100644 --- a/src/main/java/com/github/markozajc/akiwrapper/core/utils/UnirestUtils.java +++ b/src/main/java/com/github/markozajc/akiwrapper/core/utils/UnirestUtils.java | |||
@@ -1,5 +1,6 @@ | |||
1 | package com.github.markozajc.akiwrapper.core.utils; | 1 | package com.github.markozajc.akiwrapper.core.utils; |
2 | 2 | ||
3 | import static com.github.markozajc.akiwrapper.core.utils.WorkaroundUtils.workaroundIncompleteChain; | ||
3 | import static kong.unirest.Unirest.spawnInstance; | 4 | import static kong.unirest.Unirest.spawnInstance; |
4 | 5 | ||
5 | import javax.annotation.Nonnull; | 6 | import javax.annotation.Nonnull; |
@@ -50,7 +51,9 @@ public class UnirestUtils { | |||
50 | * Configures a new {@link UnirestInstance} for use by Akiwrapper. Akinator's API | 51 | * Configures a new {@link UnirestInstance} for use by Akiwrapper. Akinator's API |
51 | * servers are quite picky about the headers you send to them so if you supply | 52 | * servers are quite picky about the headers you send to them so if you supply |
52 | * {@link AkiwrapperBuilder} with your own {@link UnirestInstance} you should either | 53 | * {@link AkiwrapperBuilder} with your own {@link UnirestInstance} you should either |
53 | * pass it through this or configure it accordingly yourself.<br> | 54 | * pass it through this or configure it accordingly yourself. This also applies the |
55 | * workaround to Akinator's incomplete SSL chain from | ||
56 | * {@link WorkaroundUtils#workaroundIncompleteChain(kong.unirest.Config)} .<br> | ||
54 | * Note: even though this method returns a {@link UnirestInstance}, the instance you | 57 | * Note: even though this method returns a {@link UnirestInstance}, the instance you |
55 | * pass to it is itself mutated and returned. The return value is only there for ease | 58 | * pass to it is itself mutated and returned. The return value is only there for ease |
56 | * of chaining. | 59 | * of chaining. |
@@ -61,6 +64,7 @@ public class UnirestUtils { | |||
61 | * @return the {@link UnirestInstance} you passed, used for chaining | 64 | * @return the {@link UnirestInstance} you passed, used for chaining |
62 | */ | 65 | */ |
63 | @Nonnull | 66 | @Nonnull |
67 | @SuppressWarnings("null") | ||
64 | public static UnirestInstance configureInstance(@Nonnull UnirestInstance unirest) { | 68 | public static UnirestInstance configureInstance(@Nonnull UnirestInstance unirest) { |
65 | unirest.config() | 69 | unirest.config() |
66 | .addDefaultHeader("Accept", | 70 | .addDefaultHeader("Accept", |
@@ -76,6 +80,8 @@ public class UnirestUtils { | |||
76 | "(KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36") | 80 | "(KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36") |
77 | .addDefaultHeader("Referer", "https://en.akinator.com/game") | 81 | .addDefaultHeader("Referer", "https://en.akinator.com/game") |
78 | .cookieSpec("ignore"); | 82 | .cookieSpec("ignore"); |
83 | workaroundIncompleteChain(unirest.config()); | ||
84 | |||
79 | return unirest; | 85 | return unirest; |
80 | } | 86 | } |
81 | 87 | ||
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/utils/WorkaroundUtils.java b/src/main/java/com/github/markozajc/akiwrapper/core/utils/WorkaroundUtils.java new file mode 100644 index 0000000..0cc1427 --- /dev/null +++ b/src/main/java/com/github/markozajc/akiwrapper/core/utils/WorkaroundUtils.java | |||
@@ -0,0 +1,149 @@ | |||
1 | package com.github.markozajc.akiwrapper.core.utils; | ||
2 | |||
3 | import static java.util.Arrays.stream; | ||
4 | |||
5 | import java.io.IOException; | ||
6 | import java.security.*; | ||
7 | import java.security.cert.*; | ||
8 | |||
9 | import javax.annotation.Nonnull; | ||
10 | import javax.net.ssl.*; | ||
11 | |||
12 | import kong.unirest.Config; | ||
13 | |||
14 | /** | ||
15 | * A utility class with workarounds for problems with Akinator's infrastructure. | ||
16 | * | ||
17 | * @author Marko Zajc | ||
18 | */ | ||
19 | public class WorkaroundUtils { | ||
20 | |||
21 | /** | ||
22 | * Applies a workaround for the {@code PKIX path building failed} exception to a | ||
23 | * Unirest {@link Config}.<br> | ||
24 | * Note: even though this method returns a {@link Config}, the instance you pass to | ||
25 | * it is itself mutated and returned. The return value is only there for ease of | ||
26 | * chaining. | ||
27 | * | ||
28 | * @param config | ||
29 | * the {@link Config} to apply the workaround to | ||
30 | * | ||
31 | * @return the {@link Config} for chaining | ||
32 | * | ||
33 | * @implNote it seems that Akinator sysadmins have misconfigured the en.akinator.com | ||
34 | * server such that it fails to send the intermediate SSL certificate. | ||
35 | * Because we only trust the root certificate, the local certificate chain | ||
36 | * resolution fails and an exception is thrown. This workaround manually | ||
37 | * trusts the intermediate certificate such that the resolution succeeds | ||
38 | * without having to completely disable certificate validation. You can get | ||
39 | * the modified {@link SSLContext} to apply yourself with | ||
40 | * {@link #getIncompleteChainWorkaroundSSLContext()} or if you're using | ||
41 | * your own {@link SSLContext} and you want to add the | ||
42 | * {@link TrustManager}, you can get it from | ||
43 | * {@link #getIncompleteChainWorkaroundCustomTrustManager()}. | ||
44 | */ | ||
45 | @Nonnull | ||
46 | @SuppressWarnings("null") | ||
47 | public static Config workaroundIncompleteChain(@Nonnull Config config) { | ||
48 | return config.sslContext(getIncompleteChainWorkaroundSSLContext()); | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * @return the {@link SSLContext} used to workaround the | ||
53 | * {@code PKIX path building failed} exception. | ||
54 | * | ||
55 | * @see #workaroundIncompleteChain(Config) | ||
56 | */ | ||
57 | @Nonnull | ||
58 | public static SSLContext getIncompleteChainWorkaroundSSLContext() { | ||
59 | try { | ||
60 | var defaultTrust = getDefaultTrustManager(); | ||
61 | var customTrust = getIncompleteChainWorkaroundCustomTrustManager(); | ||
62 | var combinedTrust = getCombinedTrust(defaultTrust, customTrust); | ||
63 | |||
64 | var sslContext = SSLContext.getInstance("TLS"); | ||
65 | sslContext.init(null, new TrustManager[] { combinedTrust }, null); | ||
66 | return sslContext; | ||
67 | } catch (GeneralSecurityException | IOException e) { | ||
68 | throw new RuntimeException("Could not create a workaround SSLContext", e); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | @Nonnull | ||
73 | private static X509TrustManager getCombinedTrust(@Nonnull X509TrustManager defaultTrust, | ||
74 | @Nonnull X509TrustManager customTrust) { | ||
75 | return new X509TrustManager() { | ||
76 | |||
77 | @Override | ||
78 | public X509Certificate[] getAcceptedIssuers() { | ||
79 | // merging isn't necessary | ||
80 | return defaultTrust.getAcceptedIssuers(); | ||
81 | } | ||
82 | |||
83 | @Override | ||
84 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { | ||
85 | try { | ||
86 | defaultTrust.checkServerTrusted(chain, authType); | ||
87 | } catch (CertificateException e) { | ||
88 | customTrust.checkServerTrusted(chain, authType); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | @Override | ||
93 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { | ||
94 | // merging isn't necessary | ||
95 | defaultTrust.checkClientTrusted(chain, authType); | ||
96 | } | ||
97 | }; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * @return the {@link X509TrustManager} used to workaround the | ||
102 | * {@code PKIX path building failed} exception. | ||
103 | * | ||
104 | * @throws KeyStoreException | ||
105 | * @throws IOException | ||
106 | * @throws NoSuchAlgorithmException | ||
107 | * @throws CertificateException | ||
108 | * | ||
109 | * @see #workaroundIncompleteChain(Config) | ||
110 | */ | ||
111 | @Nonnull | ||
112 | @SuppressWarnings("null") | ||
113 | public static X509TrustManager getIncompleteChainWorkaroundCustomTrustManager() throws KeyStoreException, | ||
114 | IOException, | ||
115 | NoSuchAlgorithmException, | ||
116 | CertificateException { | ||
117 | KeyStore store; | ||
118 | try (var is = WorkaroundUtils.class.getResourceAsStream("/intermediate.jks")) { | ||
119 | store = KeyStore.getInstance(KeyStore.getDefaultType()); | ||
120 | store.load(is, "thingamabob".toCharArray()); // NOSONAR not a secure credential | ||
121 | } | ||
122 | |||
123 | if (store.size() != 1) | ||
124 | throw new IOException("The intermediate keystore does not contain exactly one entry (did loading fail?)"); | ||
125 | |||
126 | var tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
127 | tmf.init(store); | ||
128 | |||
129 | return stream(tmf.getTrustManagers()).filter(X509TrustManager.class::isInstance) | ||
130 | .map(X509TrustManager.class::cast) | ||
131 | .findAny() | ||
132 | .orElseThrow(); | ||
133 | } | ||
134 | |||
135 | @Nonnull | ||
136 | @SuppressWarnings("null") | ||
137 | private static X509TrustManager getDefaultTrustManager() throws NoSuchAlgorithmException, KeyStoreException { | ||
138 | var tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
139 | tmf.init((KeyStore) null); | ||
140 | |||
141 | return stream(tmf.getTrustManagers()).filter(X509TrustManager.class::isInstance) | ||
142 | .map(X509TrustManager.class::cast) | ||
143 | .findAny() | ||
144 | .orElseThrow(); | ||
145 | } | ||
146 | |||
147 | private WorkaroundUtils() {} | ||
148 | |||
149 | } | ||
diff --git a/src/main/resources/intermediate.jks b/src/main/resources/intermediate.jks new file mode 100644 index 0000000..b29b21b --- /dev/null +++ b/src/main/resources/intermediate.jks | |||
Binary files differ | |||
diff --git a/src/main/resources/intermediate.jks.txt b/src/main/resources/intermediate.jks.txt new file mode 100644 index 0000000..a272934 --- /dev/null +++ b/src/main/resources/intermediate.jks.txt | |||
@@ -0,0 +1,2 @@ | |||
1 | This keystore contains the intermediate "Go Daddy Secure Certificate Authority - G2" key used by Akinator's server (because they're too incompetent to send it) | ||
2 | Password: thingamabob (because JKS requires a password) | ||
diff --git a/src/test/java/com/github/markozajc/akiwrapper/IntegrationTest.java b/src/test/java/com/github/markozajc/akiwrapper/IntegrationTest.java index 5c09f6d..0bd9ec9 100644 --- a/src/test/java/com/github/markozajc/akiwrapper/IntegrationTest.java +++ b/src/test/java/com/github/markozajc/akiwrapper/IntegrationTest.java | |||
@@ -1,6 +1,7 @@ | |||
1 | package com.github.markozajc.akiwrapper; | 1 | package com.github.markozajc.akiwrapper; |
2 | 2 | ||
3 | import static java.lang.String.format; | 3 | import static java.lang.String.format; |
4 | import static org.junit.jupiter.api.Assumptions.abort; | ||
4 | import static org.slf4j.LoggerFactory.getLogger; | 5 | import static org.slf4j.LoggerFactory.getLogger; |
5 | 6 | ||
6 | import java.util.List; | 7 | import java.util.List; |
@@ -41,8 +42,7 @@ class IntegrationTest { | |||
41 | try { | 42 | try { |
42 | api = new AkiwrapperBuilder().setLanguage(language).setGuessType(guessType).build(); | 43 | api = new AkiwrapperBuilder().setLanguage(language).setGuessType(guessType).build(); |
43 | } catch (ServerNotFoundException e) { | 44 | } catch (ServerNotFoundException e) { |
44 | log.warn("Current combination not supported, server wasn't found."); | 45 | abort("Current combination not supported, server wasn't found."); |
45 | log.trace("", e); | ||
46 | return; | 46 | return; |
47 | } | 47 | } |
48 | 48 | ||