Skip to content

Commit

Permalink
[CUSTENG-2059-backport] sanitize malformed locales in audience checks
Browse files Browse the repository at this point in the history
  • Loading branch information
rlepinski committed Dec 13, 2019
1 parent dd5241b commit b730519
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@
import android.support.v4.os.ConfigurationCompat;
import android.support.v4.os.LocaleListCompat;

import com.urbanairship.Logger;
import com.urbanairship.UAirship;
import com.urbanairship.location.UALocationManager;
import com.urbanairship.push.PushManager;
import com.urbanairship.util.UAStringUtil;
import com.urbanairship.util.VersionUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -139,6 +143,26 @@ private static boolean isAppVersionConditionMet(@NonNull Audience audience) {
return audience.getVersionPredicate().apply(VersionUtils.createVersionObject());
}

private static Set<String> sanitizeLanguageTags(List<String> languageTags) {
HashSet<String> sanitizedLanguageTags = new HashSet<>();

for (String languageTag : languageTags) {
// Remove trailing dashes and underscores
if (!UAStringUtil.isEmpty(languageTag)) {
if (languageTag.endsWith("_") || languageTag.endsWith("-")) {
Logger.debug("Sanitizing malformed language tag: " + languageTag);
sanitizedLanguageTags.add(languageTag.substring(0, languageTag.length() - 1));
} else {
sanitizedLanguageTags.add(languageTag);
}
}
}

// Remove duplicates
return sanitizedLanguageTags;
}


/**
* Helper method to check the locales.
*
Expand All @@ -162,23 +186,29 @@ private static boolean isLocaleConditionMet(@NonNull Context context, @NonNull A
// getFirstMatch will return the default language if none of the specified locales are found,
// so we still have to verify the locale exists in the audience conditions

String tags = UAStringUtil.join(audience.getLanguageTags(), ",");
LocaleListCompat audienceLocales = LocaleListCompat.forLanguageTags(tags);
for (int i = 0; i < audienceLocales.size(); i++) {
Locale audienceLocale = audienceLocales.get(i);
// Sanitize language tags in case any happen to be malformed
Set<String> languageTags = sanitizeLanguageTags(audience.getLanguageTags());

if (!locale.getLanguage().equals(audienceLocale.getLanguage())) {
continue;
}
try {
String joinedTags = UAStringUtil.join(languageTags, ",");
LocaleListCompat audienceLocales = LocaleListCompat.forLanguageTags(joinedTags);
for (int i = 0; i < audienceLocales.size(); i++) {
Locale audienceLocale = audienceLocales.get(i);

if (!UAStringUtil.isEmpty(audienceLocale.getCountry()) && !audienceLocale.getCountry().equals(locale.getCountry())) {
continue;
}
if (!locale.getLanguage().equals(audienceLocale.getLanguage())) {
continue;
}

return true;
if (!UAStringUtil.isEmpty(audienceLocale.getCountry()) && !audienceLocale.getCountry().equals(locale.getCountry())) {
continue;
}

return true;
}
} catch (Exception e) {
Logger.error("Unable to construct locale list: ", e);
}

return false;
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* Copyright Airship and Contributors */
/* Copyright 2018 Urban Airship and Contributors */

package com.urbanairship.iam;


import android.content.Context;
import android.util.Base64;

Expand All @@ -26,6 +27,7 @@
import java.util.Set;

import static com.urbanairship.iam.tags.TestUtils.tagSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -120,19 +122,21 @@ public void testTestDevices() {
String testDevice = Base64.encodeToString(bytes, Base64.DEFAULT);

Audience testDeviceAudience = Audience.newBuilder()
.addTestDevice(testDevice)
.build();
.addTestDevice(testDevice)
.build();

Audience someOtherTestDeviceAudience = Audience.newBuilder()
.addTestDevice(UAStringUtil.sha256("some other channel"))
.build();
.addTestDevice(UAStringUtil.sha256("some other channel"))
.build();

when(pushManager.getChannelId()).thenReturn("test channel");


assertTrue(AudienceChecks.checkAudienceForScheduling(context, testDeviceAudience, false));
assertFalse(AudienceChecks.checkAudienceForScheduling(context, someOtherTestDeviceAudience, false));
}


@Test
public void testTagSelector() {
final Set<String> tags = new HashSet<>();
Expand Down Expand Up @@ -163,10 +167,12 @@ public Set<String> answer(InvocationOnMock invocation) throws Throwable {
}
});


Audience audience = Audience.newBuilder()
.setTagSelector(TagSelector.tag("expected tag", "expected group"))
.build();


Map<String, Set<String>> tagGroups = new HashMap<>();

assertFalse(AudienceChecks.checkAudience(context, audience, tagGroups));
Expand Down Expand Up @@ -207,6 +213,7 @@ public void testAppVersion() {
.setVersionMatcher(ValueMatcher.newNumberRangeMatcher(1.0, 2.0))
.build();


when(applicationMetrics.getCurrentAppVersion()).thenReturn(1);
assertTrue(AudienceChecks.checkAudience(context, audience));

Expand All @@ -217,4 +224,17 @@ public void testAppVersion() {
assertFalse(AudienceChecks.checkAudience(context, audience));
}

@Test
public void testSanitizeLocalesInChecks() {
Audience audience = Audience.newBuilder()
.addLanguageTag("en-")
.addLanguageTag("en_")
.addLanguageTag("en")
.addLanguageTag("-")
.addLanguageTag("_")
.addLanguageTag("")
.build();

assertTrue(AudienceChecks.checkAudience(context, audience));
}
}

0 comments on commit b730519

Please sign in to comment.