Skip to content

Commit 873708f

Browse files
authored
Merge pull request #411 from Iterable/jay/MOB-3769-allowed-protocols
[MOB-3769] allowed protocols
2 parents f0a694a + c3d5543 commit 873708f

13 files changed

+67
-26
lines changed

iterableapi/src/androidTest/java/com/iterable/iterableapi/IterableApiDeeplinkTest.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
@RunWith(AndroidJUnit4.class)
1818
public class IterableApiDeeplinkTest {
19-
2019
@Before
2120
public void setUp() {
21+
2222
}
2323

2424
@After
@@ -30,7 +30,7 @@ public void tearDown() throws Exception {
3030
public void testUniversalDeepLinkNoRewrite() throws Exception {
3131
final CountDownLatch signal = new CountDownLatch(1);
3232
try {
33-
final String requestString = "http://links.iterable.com/u/60402396fbd5433eb35397b47ab2fb83?_e=joneng%40iterable.com&_m=93125f33ba814b13a882358f8e0852e0";
33+
final String requestString = "https://links.iterable.com/u/60402396fbd5433eb35397b47ab2fb83?_e=joneng%40iterable.com&_m=93125f33ba814b13a882358f8e0852e0";
3434
IterableHelper.IterableActionHandler clickCallback = new IterableHelper.IterableActionHandler() {
3535
@Override
3636
public void execute(String result) {
@@ -39,7 +39,7 @@ public void execute(String result) {
3939
}
4040
};
4141

42-
IterableApi.getAndTrackDeeplink(requestString, clickCallback);
42+
IterableApi.getInstance().getAndTrackDeepLink(requestString, clickCallback);
4343
assertTrue("callback is called", signal.await(5, TimeUnit.SECONDS));
4444
} catch (InterruptedException e) {
4545
e.printStackTrace();
@@ -61,7 +61,7 @@ public void execute(String result) {
6161
}
6262
};
6363

64-
IterableApi.getAndTrackDeeplink(requestString, clickCallback);
64+
IterableApi.getInstance().getAndTrackDeepLink(requestString, clickCallback);
6565
assertTrue("callback is called", signal.await(5, TimeUnit.SECONDS));
6666
} catch (InterruptedException e) {
6767
e.printStackTrace();
@@ -72,15 +72,15 @@ public void execute(String result) {
7272
public void testEmptyRedirect() throws Exception {
7373
final CountDownLatch signal = new CountDownLatch(1);
7474
try {
75-
final String requestString = "";
75+
final String requestString = "https";
7676
IterableHelper.IterableActionHandler clickCallback = new IterableHelper.IterableActionHandler() {
7777
@Override
7878
public void execute(String result) {
7979
assertEquals(requestString, result);
8080
signal.countDown();
8181
}
8282
};
83-
IterableApi.getAndTrackDeeplink(requestString, clickCallback);
83+
IterableApi.getInstance().getAndTrackDeepLink(requestString, clickCallback);
8484
signal.await();
8585
} catch (InterruptedException e) {
8686
e.printStackTrace();
@@ -99,7 +99,7 @@ public void execute(String result) {
9999
signal.countDown();
100100
}
101101
};
102-
IterableApi.getAndTrackDeeplink(requestString, clickCallback);
102+
IterableApi.getInstance().getAndTrackDeepLink(requestString, clickCallback);
103103
assertTrue("callback is called", signal.await(5, TimeUnit.SECONDS));
104104
} catch (InterruptedException e) {
105105
e.printStackTrace();
@@ -119,7 +119,7 @@ public void execute(String result) {
119119
signal.countDown();
120120
}
121121
};
122-
IterableApi.getAndTrackDeeplink(requestString, clickCallback);
122+
IterableApi.getInstance().getAndTrackDeepLink(requestString, clickCallback);
123123
signal.await();
124124
} catch (InterruptedException e) {
125125
e.printStackTrace();

iterableapi/src/androidTest/resources/push_payload_action_buttons.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"openApp": true,
1010
"action": {
1111
"type": "openUrl",
12-
"data": "http://maps.apple.com/?ll=37.7828,-122.3984"
12+
"data": "https://maps.apple.com/?ll=37.7828,-122.3984"
1313
}
1414
},
1515
{

iterableapi/src/main/java/com/iterable/iterableapi/IterableActionRunner.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ boolean executeAction(@NonNull Context context, @Nullable IterableAction action,
5858
* `false` if the handler did not handle this URL and no activity was found to open it with
5959
*/
6060
private boolean openUri(@NonNull Context context, @NonNull Uri uri, @NonNull IterableActionContext actionContext) {
61+
// Handle URL: check for deep links within the app
62+
if (!IterableUtil.isUrlOpenAllowed(uri.toString())) {
63+
return false;
64+
}
65+
6166
if (IterableApi.sharedInstance.config.urlHandler != null) {
6267
if (IterableApi.sharedInstance.config.urlHandler.handleIterableURL(uri, actionContext)) {
6368
return true;
@@ -107,5 +112,4 @@ private boolean callCustomActionIfSpecified(@NonNull IterableAction action, @Non
107112
return false;
108113
}
109114
}
110-
111115
}

iterableapi/src/main/java/com/iterable/iterableapi/IterableApi.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ public class IterableApi {
7777
//---------------------------------------------------------------------------------------
7878
//endregion
7979

80-
8180
//region Getters/Setters
8281
//---------------------------------------------------------------------------------------
8382

@@ -105,7 +104,6 @@ public String getPayloadData(@NonNull String key) {
105104
* Retrieves all of the payload as a single Bundle Object
106105
* @return Bundle
107106
*/
108-
109107
@Nullable
110108
public Bundle getPayloadData() {
111109
return _payloadData;
@@ -252,8 +250,6 @@ public void removeDeviceAttribute(String key) {
252250
//---------------------------------------------------------------------------------------
253251
//endregion
254252

255-
256-
257253
//region Public Functions
258254
//---------------------------------------------------------------------------------------
259255

@@ -295,14 +291,17 @@ public static void initialize(@NonNull Context context, @NonNull String apiKey,
295291
if (sharedInstance.config == null) {
296292
sharedInstance.config = new IterableConfig.Builder().build();
297293
}
294+
298295
sharedInstance.retrieveEmailAndUserId();
299296

300297
IterableActivityMonitor.getInstance().registerLifecycleCallbacks(context);
301298
IterableActivityMonitor.getInstance().addCallback(sharedInstance.activityMonitorListener);
299+
302300
if (sharedInstance.inAppManager == null) {
303301
sharedInstance.inAppManager = new IterableInAppManager(sharedInstance, sharedInstance.config.inAppHandler,
304302
sharedInstance.config.inAppDisplayInterval);
305303
}
304+
306305
loadLastSavedConfiguration(context);
307306
IterablePushActionReceiver.processPendingAction(context);
308307
}
@@ -402,7 +401,7 @@ public void setUserId(@Nullable String userId) {
402401
* @param onCallback Calls the callback handler with the destination location
403402
* or the original url if it is not an Iterable link.
404403
*/
405-
public static void getAndTrackDeeplink(@NonNull String uri, @NonNull IterableHelper.IterableActionHandler onCallback) {
404+
public void getAndTrackDeepLink(@NonNull String uri, @NonNull IterableHelper.IterableActionHandler onCallback) {
406405
IterableDeeplinkManager.getAndTrackDeeplink(uri, onCallback);
407406
}
408407

@@ -418,8 +417,9 @@ public static void getAndTrackDeeplink(@NonNull String uri, @NonNull IterableHel
418417
* handler activity
419418
* @return whether or not the app link was handled
420419
*/
421-
public static boolean handleAppLink(@NonNull String uri) {
420+
public boolean handleAppLink(@NonNull String uri) {
422421
IterableLogger.printInfo();
422+
423423
if (IterableDeeplinkManager.isIterableDeeplink(uri)) {
424424
IterableDeeplinkManager.getAndTrackDeeplink(uri, new IterableHelper.IterableActionHandler() {
425425
@Override
@@ -880,7 +880,6 @@ void trackInAppClose(@NonNull String messageId, @NonNull String clickedURL, @Non
880880
//---------------------------------------------------------------------------------------
881881
//endregion
882882

883-
884883
//region Package-Protected Functions
885884
//---------------------------------------------------------------------------------------
886885

iterableapi/src/main/java/com/iterable/iterableapi/IterableConfig.java

+18
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ public class IterableConfig {
6464
*/
6565
final long expiringAuthTokenRefreshPeriod;
6666

67+
/**
68+
* By default, the SDK allows navigation/calls to URLs with the `https` protocol (e.g. deep links or external links)
69+
* If you'd like to allow other protocols like `http`, `tel`, etc., add them to the `allowedProtocols` array
70+
*/
71+
final String[] allowedProtocols;
72+
6773
private IterableConfig(Builder builder) {
6874
pushIntegrationName = builder.pushIntegrationName;
6975
urlHandler = builder.urlHandler;
@@ -75,6 +81,7 @@ private IterableConfig(Builder builder) {
7581
inAppDisplayInterval = builder.inAppDisplayInterval;
7682
authHandler = builder.authHandler;
7783
expiringAuthTokenRefreshPeriod = builder.expiringAuthTokenRefreshPeriod;
84+
allowedProtocols = builder.allowedProtocols;
7885
}
7986

8087
public static class Builder {
@@ -88,6 +95,7 @@ public static class Builder {
8895
private double inAppDisplayInterval = 30.0;
8996
private IterableAuthHandler authHandler;
9097
private long expiringAuthTokenRefreshPeriod = 60000L;
98+
private String[] allowedProtocols = new String[0];
9199
public Builder() {}
92100

93101
/**
@@ -198,6 +206,16 @@ public Builder setExpiringAuthTokenRefreshPeriod(@NonNull Long period) {
198206
return this;
199207
}
200208

209+
/**
210+
* Set what URLs the SDK should allow to open (in addition to `https`)
211+
* @param allowedProtocols an array/list of protocols (e.g. `http`, `tel`)
212+
*/
213+
@NonNull
214+
public Builder setAllowedProtocols(@NonNull String[] allowedProtocols) {
215+
this.allowedProtocols = allowedProtocols;
216+
return this;
217+
}
218+
201219
@NonNull
202220
public IterableConfig build() {
203221
return new IterableConfig(this);

iterableapi/src/main/java/com/iterable/iterableapi/IterableDeeplinkManager.java

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ class IterableDeeplinkManager {
2323
*/
2424
static void getAndTrackDeeplink(@Nullable String url, @NonNull IterableHelper.IterableActionHandler callback) {
2525
if (url != null) {
26+
if (!IterableUtil.isUrlOpenAllowed(url)) {
27+
return;
28+
}
2629
if (isIterableDeeplink(url)) {
2730
new RedirectTask(callback).execute(url);
2831
} else {

iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java

-2
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ public static IterableInAppFragmentHTMLNotification createInstance(@NonNull Stri
8080
}
8181

8282
public static IterableInAppFragmentHTMLNotification createInstance(@NonNull String htmlString, boolean callbackOnCancel, @NonNull IterableHelper.IterableUrlCallback clickCallback, @NonNull IterableInAppLocation location, @NonNull String messageId, @NonNull Double backgroundAlpha, @NonNull Rect padding, @NonNull boolean shouldAnimate, IterableInAppMessage.InAppBgColor inAppBgColor) {
83-
8483
notification = new IterableInAppFragmentHTMLNotification();
8584
Bundle args = new Bundle();
8685
args.putString(HTML_STRING, htmlString);
@@ -163,7 +162,6 @@ public void onCancel(DialogInterface dialog) {
163162
return dialog;
164163
}
165164

166-
167165
@Nullable
168166
@Override
169167
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppManager.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public interface Listener {
7474
this.displayer = displayer;
7575
this.activityMonitor = activityMonitor;
7676
this.activityMonitor.addCallback(this);
77+
7778
syncInApp();
7879
}
7980

@@ -136,7 +137,6 @@ public synchronized void setRead(@NonNull IterableInAppMessage message, boolean
136137
notifyOnChange();
137138
}
138139

139-
140140
boolean isAutoDisplayPaused() {
141141
return autoDisplayPaused;
142142
}
@@ -232,6 +232,7 @@ public void execute(Uri url) {
232232
if (clickCallback != null) {
233233
clickCallback.execute(url);
234234
}
235+
235236
handleInAppClick(message, url);
236237
lastInAppShown = IterableUtil.currentTimeMillis();
237238
scheduleProcessing();
@@ -264,6 +265,7 @@ public synchronized void removeMessage(@NonNull IterableInAppMessage message, @N
264265
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
265266
public void handleInAppClick(@NonNull IterableInAppMessage message, @Nullable Uri url) {
266267
IterableLogger.printInfo();
268+
267269
if (url != null && !url.toString().isEmpty()) {
268270
String urlString = url.toString();
269271
if (urlString.startsWith(IterableConstants.URL_SCHEME_ACTION)) {

iterableapi/src/main/java/com/iterable/iterableapi/IterableNotificationBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public void createNotificationActionButton(Context context, IterableNotification
119119
buttonIntent.putExtra(IterableConstants.ACTION_IDENTIFIER, button.identifier);
120120

121121
PendingIntent pendingButtonIntent = PendingIntent.getBroadcast(context, buttonIntent.hashCode(),
122-
buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
122+
buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
123123

124124
NotificationCompat.Action.Builder actionBuilder = new NotificationCompat.Action
125125
.Builder(NotificationCompat.BADGE_ICON_NONE, button.title, pendingButtonIntent);

iterableapi/src/main/java/com/iterable/iterableapi/IterableNotificationHelper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public IterableNotificationBuilder createNotification(Context context, Bundle ex
193193
}
194194

195195
PendingIntent notificationClickedIntent = PendingIntent.getBroadcast(context, notificationBuilder.requestCode,
196-
pushContentIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
196+
pushContentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
197197

198198
notificationBuilder.setContentIntent(notificationClickedIntent);
199199
notificationBuilder.setIsGhostPush(isGhostPush(extras));

iterableapi/src/main/java/com/iterable/iterableapi/IterableUtil.java

+17
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.content.pm.PackageInfo;
66
import android.content.pm.PackageManager;
77

8+
import androidx.annotation.NonNull;
89
import androidx.annotation.Nullable;
910
import androidx.annotation.VisibleForTesting;
1011

@@ -277,4 +278,20 @@ boolean writeFile(File file, String content) {
277278
return false;
278279
}
279280
}
281+
282+
static boolean isUrlOpenAllowed(@NonNull String url) {
283+
String urlProtocol = url.split("://")[0];
284+
if (urlProtocol.equals("https")) {
285+
return true;
286+
}
287+
288+
for (String allowedProtocol : IterableApi.getInstance().config.allowedProtocols) {
289+
if (urlProtocol.equals(allowedProtocol)) {
290+
return true;
291+
}
292+
}
293+
294+
IterableLogger.d(TAG, urlProtocol + " is not in the allowed protocols");
295+
return false;
296+
}
280297
}

iterableapi/src/test/java/com/iterable/iterableapi/IterableApiTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,9 @@ public void testHandleUniversalLinkRewrite() throws Exception {
198198
when(urlHandlerMock.handleIterableURL(any(Uri.class), any(IterableActionContext.class))).thenReturn(true);
199199
IterableApi.initialize(getContext(), "fake_key", new IterableConfig.Builder().setUrlHandler(urlHandlerMock).build());
200200

201-
String url = "http://iterable.com";
202-
IterableApi.handleAppLink(
203-
"http://links.iterable.com/a/60402396fbd5433eb35397b47ab2fb83?_e=joneng%40iterable.com&_m=93125f33ba814b13a882358f8e0852e0");
201+
String url = "https://iterable.com";
202+
IterableApi.getInstance().handleAppLink(
203+
"https://links.iterable.com/a/60402396fbd5433eb35397b47ab2fb83?_e=joneng%40iterable.com&_m=93125f33ba814b13a882358f8e0852e0");
204204

205205
ArgumentCaptor<Uri> capturedUri = ArgumentCaptor.forClass(Uri.class);
206206
ArgumentCaptor<IterableActionContext> capturedActionContext = ArgumentCaptor.forClass(IterableActionContext.class);

iterableapi/src/test/resources/push_payload_action_buttons.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"openApp": true,
1010
"action": {
1111
"type": "openUrl",
12-
"data": "http://maps.apple.com/?ll=37.7828,-122.3984"
12+
"data": "https://maps.apple.com/?ll=37.7828,-122.3984"
1313
}
1414
},
1515
{

0 commit comments

Comments
 (0)