diff --git a/audit-base/pom.xml b/audit-base/pom.xml
index f767ab6..7cbfd22 100644
--- a/audit-base/pom.xml
+++ b/audit-base/pom.xml
@@ -59,8 +59,8 @@
+ org.apache.maven.plugins
maven-surefire-plugin
- 3.2.2
diff --git a/http-common/pom.xml b/http-common/pom.xml
index c53e75b..9e1b483 100644
--- a/http-common/pom.xml
+++ b/http-common/pom.xml
@@ -29,6 +29,20 @@
spring-boot-starter-test
test
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ test
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+
+
\ No newline at end of file
diff --git a/http-common/src/main/java/com/wultra/core/http/common/headers/UserAgent.java b/http-common/src/main/java/com/wultra/core/http/common/headers/UserAgent.java
index 9935ff5..08d328b 100644
--- a/http-common/src/main/java/com/wultra/core/http/common/headers/UserAgent.java
+++ b/http-common/src/main/java/com/wultra/core/http/common/headers/UserAgent.java
@@ -26,6 +26,7 @@
* Utility class for processing our standard user agent strings.
*
* @author Petr Dvorak, petr@wultra.com
+ * @author Lubos Racansky, lubos.racansky@wultra.com
*/
@Slf4j
public final class UserAgent {
@@ -43,15 +44,18 @@ public static class Device {
private String model;
}
+ private static final String PREFIX = "((^PowerAuthNetworking)|.*PowerAuth2)/(?\\d+\\.\\d+\\.\\d+)";
+ private static final Pattern PATTERN_PREFIX = Pattern.compile(PREFIX + ".*");
+
+ private static final String LANGUAGE_AND_CONNECTION = "(\\((?[a-zA-Z]{2}); (?[a-zA-Z0-9]+)\\) )?";
+ private static final String PRODUCT_AND_VERSION = "((?[a-zA-Z0-9-_.]+)/(?[0-9.]+(-[^ ]*)?) )?";
+ private static final String PLATFORM_OS_VERSION_MODEL = "(\\(((?[^;]+); )?(?[^/ ]+)[/ ](?[^;,]+)[;,] (?[^)]+)\\))?";
+ private static final Pattern PATTERN_V1 = Pattern.compile(PREFIX + " " + LANGUAGE_AND_CONNECTION + PRODUCT_AND_VERSION + PLATFORM_OS_VERSION_MODEL + ".*");
+
private UserAgent() {
+ throw new IllegalStateException("Should not be instantiated");
}
- private static final Pattern patternPrefix = Pattern.compile("^PowerAuthNetworking/(?[0-9]+\\.[0-9]+\\.[0-9]+).*");
- private static final Pattern patternV1 = Pattern.compile("^PowerAuthNetworking/(?[0-9]+\\.[0-9]+\\.[0-9]+) " +
- "\\((?[a-zA-Z]{2}); (?[a-zA-Z0-9]+)\\) " +
- "(?[a-zA-Z0-9-_.]+)/(?[0-9.]+) .*" +
- "\\((?[^;]+); (?[^/]+)/(?[^;]+); (?[^)]+)\\)$");
-
/**
* Parse client user from the HTTP header value.
*
@@ -61,7 +65,7 @@ private UserAgent() {
public static Optional parse(String userAgent) {
// Identify if the user agent is ours and in what version
logger.debug("Parsing user agent value: {}", userAgent);
- final Matcher matcherPrefix = patternPrefix.matcher(userAgent);
+ final Matcher matcherPrefix = PATTERN_PREFIX.matcher(userAgent);
if (!matcherPrefix.matches()) {
return Optional.empty();
}
@@ -83,7 +87,7 @@ public static Optional parse(String userAgent) {
* @return Parsed device info, or empty if the user agent header cannot be parsed.
*/
private static Optional parseUserAgentV1(String userAgent) {
- final Matcher matcher = patternV1.matcher(userAgent);
+ final Matcher matcher = PATTERN_V1.matcher(userAgent);
if (matcher.matches()) {
final Device device = new Device();
device.setNetworkVersion(matcher.group("networkVersion"));
diff --git a/http-common/src/test/java/com/wultra/core/http/common/headers/UserAgentTest.java b/http-common/src/test/java/com/wultra/core/http/common/headers/UserAgentTest.java
index 9696c94..3796254 100644
--- a/http-common/src/test/java/com/wultra/core/http/common/headers/UserAgentTest.java
+++ b/http-common/src/test/java/com/wultra/core/http/common/headers/UserAgentTest.java
@@ -15,7 +15,13 @@
*/
package com.wultra.core.http.common.headers;
-import org.junit.jupiter.api.Test;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
import java.util.Optional;
@@ -23,27 +29,106 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
- * Test for the user agent parser.
+ * Test for {@link UserAgent}.
*
* @author Petr Dvorak, petr@wultra.com
+ * @author Lubos Racansky, lubos.racansky@wultra.com
*/
class UserAgentTest {
- @Test
- void parse() {
- final String sample = "PowerAuthNetworking/1.1.7 (en; cellular) com.wultra.app.Mobile-Token.wultra_test/2.0.0 (Apple; iOS/16.6.1; iphone12,3)";
- final Optional deviceOptional = UserAgent.parse(sample);
- assertTrue(deviceOptional.isPresent());
-
- final UserAgent.Device device = deviceOptional.get();
- assertEquals("1.1.7", device.getNetworkVersion());
- assertEquals("en", device.getLanguage());
- assertEquals("cellular", device.getConnection());
- assertEquals("com.wultra.app.Mobile-Token.wultra_test", device.getProduct());
- assertEquals("2.0.0", device.getVersion());
- assertEquals("Apple", device.getPlatform());
- assertEquals("iOS", device.getOs());
- assertEquals("16.6.1", device.getOsVersion());
- assertEquals("iphone12,3", device.getModel());
+ @ParameterizedTest
+ @MethodSource("provideUserAgents")
+ void testParse(final String userAgent, final UserAgent.Device expectedDevice) {
+ final Optional deviceOptional = UserAgent.parse(userAgent);
+ assertTrue(deviceOptional.isPresent(), "Unable to parse user-agent: " + userAgent);
+ assertEquals(expectedDevice, deviceOptional.get());
+ }
+
+ private static Stream provideUserAgents() throws JsonProcessingException {
+ return Stream.of(
+ Arguments.of("PowerAuthNetworking/1.1.7 (en; cellular) com.wultra.app.Mobile-Token.wultra_test/2.0.0 (Apple; iOS/16.6.1; iphone12,3)", readDevice("""
+ {
+ "networkVersion": "1.1.7",
+ "language": "en",
+ "connection": "cellular",
+ "product": "com.wultra.app.Mobile-Token.wultra_test",
+ "version": "2.0.0",
+ "platform": "Apple",
+ "os": "iOS",
+ "osVersion": "16.6.1",
+ "model": "iphone12,3"
+ }
+ """)),
+ Arguments.of("PowerAuthNetworking/1.2.1 (uk; wifi) com.wultra.android.mtoken.gdnexttest/1.0.0-gdnexttest (samsung; Android/13; SM-A047F)", readDevice("""
+ {
+ "networkVersion": "1.2.1",
+ "language": "uk",
+ "connection": "wifi",
+ "product": "com.wultra.android.mtoken.gdnexttest",
+ "version": "1.0.0-gdnexttest",
+ "platform": "samsung",
+ "os": "Android",
+ "osVersion": "13",
+ "model": "SM-A047F"
+ }
+ """)),
+ Arguments.of("PowerAuthNetworking/1.1.7 (en; unknown) com.wultra.app.MobileToken.wtest/2.0.0 (Apple; iOS/16.6.1; iphone10,6)", readDevice("""
+ {
+ "networkVersion": "1.1.7",
+ "language": "en",
+ "connection": "unknown",
+ "product": "com.wultra.app.MobileToken.wtest",
+ "version": "2.0.0",
+ "platform": "Apple",
+ "os": "iOS",
+ "osVersion": "16.6.1",
+ "model": "iphone10,6"
+ }
+ """)),
+ Arguments.of("PowerAuthNetworking/1.1.7 (en; wifi) com.wultra.app.MobileToken.wtest/2.0.0 (Apple; iOS/16.7.1; iphone10,6)", readDevice("""
+ {
+ "networkVersion": "1.1.7",
+ "language": "en",
+ "connection": "wifi",
+ "product": "com.wultra.app.MobileToken.wtest",
+ "version": "2.0.0",
+ "platform": "Apple",
+ "os": "iOS",
+ "osVersion": "16.7.1",
+ "model": "iphone10,6"
+ }
+ """)),
+ // MainBundle/Version PowerAuth2/Version (iOS Version, deviceString)
+ Arguments.of("PowerAuth2TestsHostApp-ios/1.0 PowerAuth2/1.7.8 (iOS 17.0, simulator)", readDevice("""
+ {
+ "networkVersion": "1.7.8",
+ "os": "iOS",
+ "osVersion": "17.0",
+ "model": "simulator"
+ }
+ """)),
+ // PowerAuth2/Version (Android Version, Build.MANUFACTURER Build.MODEL)
+ Arguments.of("PowerAuth2/1.7.8 (Android 13, Google Pixel 4)", readDevice("""
+ {
+ "networkVersion": "1.7.8",
+ "os": "Android",
+ "osVersion": "13",
+ "model": "Google Pixel 4"
+ }
+ """)),
+ Arguments.of("MobileToken/1.2.0 PowerAuth2/1.7.8 (iOS 15.7.9, iPhone9,3)", readDevice("""
+ {
+ "networkVersion": "1.7.8",
+ "os": "iOS",
+ "osVersion": "15.7.9",
+ "model": "iPhone9,3"
+ }
+ """))
+ );
}
-}
\ No newline at end of file
+
+ private static UserAgent.Device readDevice(final String json) throws JsonProcessingException {
+ return new ObjectMapper().readValue(json, UserAgent.Device.class);
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index ba93e64..71db424 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,6 +55,7 @@
UTF-8
17
17
+ 3.2.2
3.1.6
@@ -96,6 +97,16 @@
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+
+
org.apache.maven.plugins
diff --git a/rest-client-base/pom.xml b/rest-client-base/pom.xml
index 2773afd..4e58e14 100644
--- a/rest-client-base/pom.xml
+++ b/rest-client-base/pom.xml
@@ -66,8 +66,8 @@
+ org.apache.maven.plugins
maven-surefire-plugin
- 3.2.2