mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-20 03:28:04 +01:00
Celebrate the diversity of UA strings when generating tags for metrics.
This commit is contained in:
committed by
Jon Chambers
parent
9ba5ee8043
commit
06c82ee87d
@@ -5,6 +5,7 @@ import org.whispersystems.textsecuregcm.util.Pair;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -14,39 +15,73 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class UserAgentTagUtil {
|
||||
|
||||
static final int MAX_VERSIONS = 10_000;
|
||||
static final int MAX_VERSIONS = 10_000;
|
||||
|
||||
public static final String PLATFORM_TAG = "platform";
|
||||
public static final String VERSION_TAG = "clientVersion";
|
||||
public static final String PLATFORM_TAG = "platform";
|
||||
public static final String VERSION_TAG = "clientVersion";
|
||||
|
||||
static final List<Tag> OVERFLOW_TAGS = List.of(Tag.of(PLATFORM_TAG, "overflow"), Tag.of(VERSION_TAG, "overflow"));
|
||||
static final List<Tag> UNRECOGNIZED_TAGS = List.of(Tag.of(PLATFORM_TAG, "unrecognized"), Tag.of(VERSION_TAG, "unrecognized"));
|
||||
static final List<Tag> OVERFLOW_TAGS = List.of(Tag.of(PLATFORM_TAG, "overflow"), Tag.of(VERSION_TAG, "overflow"));
|
||||
static final List<Tag> UNRECOGNIZED_TAGS = List.of(Tag.of(PLATFORM_TAG, "unrecognized"), Tag.of(VERSION_TAG, "unrecognized"));
|
||||
|
||||
private static final Pattern USER_AGENT_PATTERN = Pattern.compile("Signal-([^ ]+) ([^ ]+).*$", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern USER_AGENT_PATTERN = Pattern.compile("^Signal[ \\-]([^ ]+) ([^ ]+).*$", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern IOS_USER_AGENT_PATTERN = Pattern.compile("^Signal/([^ ]+) \\(.*ios.*\\)$", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private static final Set<Pair<String, String>> SEEN_VERSIONS = new HashSet<>();
|
||||
private static final Set<Pair<String, String>> SEEN_VERSIONS = new HashSet<>();
|
||||
|
||||
private UserAgentTagUtil() {
|
||||
}
|
||||
|
||||
public static List<Tag> getUserAgentTags(final String userAgent) {
|
||||
final Matcher matcher = USER_AGENT_PATTERN.matcher(userAgent);
|
||||
final List<Tag> tags;
|
||||
|
||||
if (matcher.matches()) {
|
||||
final Pair<String, String> platformAndVersion = new Pair<>(matcher.group(1).toLowerCase(), matcher.group(2));
|
||||
|
||||
final boolean allowVersion;
|
||||
|
||||
synchronized (SEEN_VERSIONS) {
|
||||
allowVersion = SEEN_VERSIONS.contains(platformAndVersion) || (SEEN_VERSIONS.size() < MAX_VERSIONS && SEEN_VERSIONS.add(platformAndVersion));
|
||||
}
|
||||
|
||||
tags = allowVersion ? List.of(Tag.of(PLATFORM_TAG, platformAndVersion.first()), Tag.of(VERSION_TAG, platformAndVersion.second())) : OVERFLOW_TAGS;
|
||||
} else {
|
||||
if (userAgent == null) {
|
||||
tags = UNRECOGNIZED_TAGS;
|
||||
} else {
|
||||
tags = getAndroidOrDesktopUserAgentTags(userAgent)
|
||||
.orElseGet(() -> getIOSUserAgentTags(userAgent)
|
||||
.orElse(UNRECOGNIZED_TAGS));
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
private static Optional<List<Tag>> getAndroidOrDesktopUserAgentTags(final String userAgent) {
|
||||
final Matcher matcher = USER_AGENT_PATTERN.matcher(userAgent);
|
||||
final Optional<List<Tag>> maybeTags;
|
||||
|
||||
if (matcher.matches()) {
|
||||
final String platform = matcher.group(1).toLowerCase();
|
||||
final String version = matcher.group(2);
|
||||
|
||||
maybeTags = Optional.of(allowVersion(platform, version) ? List.of(Tag.of(PLATFORM_TAG, platform), Tag.of(VERSION_TAG, version)) : OVERFLOW_TAGS);
|
||||
} else {
|
||||
maybeTags = Optional.empty();
|
||||
}
|
||||
|
||||
return maybeTags;
|
||||
}
|
||||
|
||||
private static Optional<List<Tag>> getIOSUserAgentTags(final String userAgent) {
|
||||
final Matcher matcher = IOS_USER_AGENT_PATTERN.matcher(userAgent);
|
||||
final Optional<List<Tag>> maybeTags;
|
||||
|
||||
if (matcher.matches()) {
|
||||
final String platform = "ios";
|
||||
final String version = matcher.group(1);
|
||||
|
||||
maybeTags = Optional.of(allowVersion(platform, version) ? List.of(Tag.of(PLATFORM_TAG, platform), Tag.of(VERSION_TAG, version)) : OVERFLOW_TAGS);
|
||||
} else {
|
||||
maybeTags = Optional.empty();
|
||||
}
|
||||
|
||||
return maybeTags;
|
||||
}
|
||||
|
||||
private static boolean allowVersion(final String platform, final String version) {
|
||||
final Pair<String, String> platformAndVersion = new Pair<>(platform, version);
|
||||
|
||||
synchronized (SEEN_VERSIONS) {
|
||||
return SEEN_VERSIONS.contains(platformAndVersion) || (SEEN_VERSIONS.size() < MAX_VERSIONS && SEEN_VERSIONS.add(platformAndVersion));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user