From 561cff8157ebd5904d877eac7999088040b7cb0f Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 16 Feb 2021 13:31:33 +0100 Subject: [PATCH 1/6] SSO: support of parameter v2, which allows to have multiple values for same key Signed-off-by: tobiasKaminsky --- .../nextcloud/sso/InputStreamBinderTest.kt | 61 +++++++++++++++++++ .../android/sso/InputStreamBinder.java | 31 +++++++++- .../android/sso/aidl/NextcloudRequest.java | 31 ++++++++++ 3 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 src/androidTest/java/com/nextcloud/sso/InputStreamBinderTest.kt diff --git a/src/androidTest/java/com/nextcloud/sso/InputStreamBinderTest.kt b/src/androidTest/java/com/nextcloud/sso/InputStreamBinderTest.kt new file mode 100644 index 0000000000..27d5413b64 --- /dev/null +++ b/src/androidTest/java/com/nextcloud/sso/InputStreamBinderTest.kt @@ -0,0 +1,61 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2021 Tobias Kaminsky + * Copyright (C) 2021 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.nextcloud.sso + +import com.nextcloud.android.sso.InputStreamBinder +import junit.framework.Assert.assertEquals +import org.junit.Test + +class InputStreamBinderTest { + @Test + fun convertMapToNVP() { + val source = mutableMapOf() + source["quality"] = "1024p" + source["someOtherParameter"] = "parameterValue" + source["duplicate"] = "1" + source["duplicate"] = "2" // this overwrites previous parameter + + val output = InputStreamBinder.convertMapToNVP(source) + + assertEquals(source.size, output.size) + assertEquals("1024p", output[0].value) + assertEquals("parameterValue", output[1].value) + assertEquals("2", output[2].value) + } + + @Test + fun convertListToNVP() { + val source = mutableListOf>() + source.add(android.util.Pair("quality", "1024p")) + source.add(android.util.Pair("someOtherParameter", "parameterValue")) + source.add(android.util.Pair("duplicate", "1")) + source.add(android.util.Pair("duplicate", "2")) // here we can have same parameter multiple times + + val output = InputStreamBinder.convertListToNVP(source) + + assertEquals(source.size, output.size) + assertEquals("1024p", output[0].value) + assertEquals("parameterValue", output[1].value) + assertEquals("1", output[2].value) + assertEquals("2", output[3].value) + } +} diff --git a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java index 2f83ac9706..6198785233 100644 --- a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java +++ b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java @@ -32,6 +32,7 @@ import android.os.Binder; import android.os.ParcelFileDescriptor; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import com.nextcloud.android.sso.aidl.IInputStreamService; import com.nextcloud.android.sso.aidl.NextcloudRequest; @@ -70,9 +71,12 @@ import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.Collection; import java.util.List; import java.util.Map; +import androidx.annotation.VisibleForTesting; + import static com.nextcloud.android.sso.Constants.DELIMITER; import static com.nextcloud.android.sso.Constants.EXCEPTION_ACCOUNT_NOT_FOUND; import static com.nextcloud.android.sso.Constants.EXCEPTION_HTTP_REQUEST_FAILED; @@ -331,7 +335,11 @@ public class InputStreamBinder extends IInputStreamService.Stub { HttpMethodBase method = buildMethod(request, client.getBaseUri(), requestBodyInputStream); - method.setQueryString(convertMapToNVP(request.getParameter())); + if (!request.getParameterV2().isEmpty()) { + method.setQueryString(convertListToNVP(request.getParameterV2())); + } else { + method.setQueryString(convertMapToNVP(request.getParameter())); + } method.addRequestHeader("OCS-APIREQUEST", "true"); for (Map.Entry> header : request.getHeader().entrySet()) { @@ -394,7 +402,12 @@ public class InputStreamBinder extends IInputStreamService.Stub { HttpMethodBase method = buildMethod(request, client.getBaseUri(), requestBodyInputStream); - method.setQueryString(convertMapToNVP(request.getParameter())); + if (!request.getParameterV2().isEmpty()) { + method.setQueryString(convertListToNVP(request.getParameterV2())); + } else { + method.setQueryString(convertMapToNVP(request.getParameter())); + } + method.addRequestHeader("OCS-APIREQUEST", "true"); for (Map.Entry> header : request.getHeader().entrySet()) { @@ -482,7 +495,8 @@ public class InputStreamBinder extends IInputStreamService.Stub { } } - private static NameValuePair[] convertMapToNVP(Map map) { + @VisibleForTesting + public static NameValuePair[] convertMapToNVP(Map map) { NameValuePair[] nvp = new NameValuePair[map.size()]; int i = 0; for (String key : map.keySet()) { @@ -491,4 +505,15 @@ public class InputStreamBinder extends IInputStreamService.Stub { } return nvp; } + + @VisibleForTesting + public static NameValuePair[] convertListToNVP(Collection> list) { + NameValuePair[] nvp = new NameValuePair[list.size()]; + int i = 0; + for (Pair pair : list) { + nvp[i] = new NameValuePair(pair.first, pair.second); + i++; + } + return nvp; + } } diff --git a/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java b/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java index 467e875a33..a83ffe021e 100644 --- a/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java +++ b/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java @@ -1,3 +1,25 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2021 Tobias Kaminsky + * Copyright (C) 2021 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + /* * Nextcloud SingleSignOn * @@ -19,8 +41,12 @@ package com.nextcloud.android.sso.aidl; +import android.util.Pair; + import java.io.Serializable; +import java.util.Collection; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -31,6 +57,7 @@ public class NextcloudRequest implements Serializable { private String method; private Map> header = new HashMap<>(); private Map parameter = new HashMap<>(); + private final Collection> parameterV2 = new LinkedList<>(); private String requestBody; private String url; private String token; @@ -144,4 +171,8 @@ public class NextcloudRequest implements Serializable { public boolean isFollowRedirects() { return this.followRedirects; } + + public Collection> getParameterV2() { + return parameterV2; + } } From e7bc146524beae93a295eeaec443283525ff8628 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Thu, 18 Mar 2021 12:58:51 +0100 Subject: [PATCH 2/6] fix possible NPE Signed-off-by: tobiasKaminsky --- src/main/java/com/nextcloud/android/sso/InputStreamBinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java index 6198785233..24113418a3 100644 --- a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java +++ b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java @@ -335,7 +335,7 @@ public class InputStreamBinder extends IInputStreamService.Stub { HttpMethodBase method = buildMethod(request, client.getBaseUri(), requestBodyInputStream); - if (!request.getParameterV2().isEmpty()) { + if (request.getParameterV2() != null && !request.getParameterV2().isEmpty()) { method.setQueryString(convertListToNVP(request.getParameterV2())); } else { method.setQueryString(convertMapToNVP(request.getParameter())); From 59a2187447782657b9bf6e46a6f3193fa99d78e0 Mon Sep 17 00:00:00 2001 From: Stefan Niedermann Date: Thu, 18 Mar 2021 20:30:16 +0100 Subject: [PATCH 3/6] Fix another NPE when parameterV2 is null --- src/main/java/com/nextcloud/android/sso/InputStreamBinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java index 24113418a3..0cebf0dbdc 100644 --- a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java +++ b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java @@ -402,7 +402,7 @@ public class InputStreamBinder extends IInputStreamService.Stub { HttpMethodBase method = buildMethod(request, client.getBaseUri(), requestBodyInputStream); - if (!request.getParameterV2().isEmpty()) { + if (request.getParameterV2() != null && !request.getParameterV2().isEmpty()) { method.setQueryString(convertListToNVP(request.getParameterV2())); } else { method.setQueryString(convertMapToNVP(request.getParameter())); From 4875b20c6cfed49ff12ed689bbe72000ba78a1ed Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 4 May 2021 09:19:16 +0200 Subject: [PATCH 4/6] Use own QueryPair implementation that supports serializable Signed-off-by: tobiasKaminsky --- .../android/sso/InputStreamBinder.java | 5 ++- .../com/nextcloud/android/sso/QueryPair.java | 35 +++++++++++++++++++ .../android/sso/aidl/NextcloudRequest.java | 6 ++-- 3 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/nextcloud/android/sso/QueryPair.java diff --git a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java index 24113418a3..d6dcc576bc 100644 --- a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java +++ b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java @@ -32,7 +32,6 @@ import android.os.Binder; import android.os.ParcelFileDescriptor; import android.text.TextUtils; import android.util.Log; -import android.util.Pair; import com.nextcloud.android.sso.aidl.IInputStreamService; import com.nextcloud.android.sso.aidl.NextcloudRequest; @@ -507,10 +506,10 @@ public class InputStreamBinder extends IInputStreamService.Stub { } @VisibleForTesting - public static NameValuePair[] convertListToNVP(Collection> list) { + public static NameValuePair[] convertListToNVP(Collection list) { NameValuePair[] nvp = new NameValuePair[list.size()]; int i = 0; - for (Pair pair : list) { + for (com.nextcloud.android.sso.api.QueryPair pair : list) { nvp[i] = new NameValuePair(pair.first, pair.second); i++; } diff --git a/src/main/java/com/nextcloud/android/sso/QueryPair.java b/src/main/java/com/nextcloud/android/sso/QueryPair.java new file mode 100644 index 0000000000..7d6948aee2 --- /dev/null +++ b/src/main/java/com/nextcloud/android/sso/QueryPair.java @@ -0,0 +1,35 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2021 Tobias Kaminsky + * Copyright (C) 2021 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.android.sso.api; + +import java.io.Serializable; + +public class QueryPair implements Serializable { + public String first; + public String second; + + public QueryPair(String first, String second) { + this.first = first; + this.second = second; + } +} diff --git a/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java b/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java index a83ffe021e..1fb41f0c78 100644 --- a/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java +++ b/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java @@ -41,8 +41,6 @@ package com.nextcloud.android.sso.aidl; -import android.util.Pair; - import java.io.Serializable; import java.util.Collection; import java.util.HashMap; @@ -57,7 +55,7 @@ public class NextcloudRequest implements Serializable { private String method; private Map> header = new HashMap<>(); private Map parameter = new HashMap<>(); - private final Collection> parameterV2 = new LinkedList<>(); + private final Collection parameterV2 = new LinkedList<>(); private String requestBody; private String url; private String token; @@ -172,7 +170,7 @@ public class NextcloudRequest implements Serializable { return this.followRedirects; } - public Collection> getParameterV2() { + public Collection getParameterV2() { return parameterV2; } } From 9a464ca5c57d1c84387e14a162e51025ff832a70 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 25 May 2021 09:32:18 +0200 Subject: [PATCH 5/6] Renamed QueryPair Signed-off-by: tobiasKaminsky --- .../sso/{QueryPair.java => QueryParam.java} | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) rename src/main/java/com/nextcloud/android/sso/{QueryPair.java => QueryParam.java} (77%) diff --git a/src/main/java/com/nextcloud/android/sso/QueryPair.java b/src/main/java/com/nextcloud/android/sso/QueryParam.java similarity index 77% rename from src/main/java/com/nextcloud/android/sso/QueryPair.java rename to src/main/java/com/nextcloud/android/sso/QueryParam.java index 7d6948aee2..c3d39157b8 100644 --- a/src/main/java/com/nextcloud/android/sso/QueryPair.java +++ b/src/main/java/com/nextcloud/android/sso/QueryParam.java @@ -20,16 +20,16 @@ * along with this program. If not, see . */ -package com.nextcloud.android.sso.api; +package com.nextcloud.android.sso; import java.io.Serializable; -public class QueryPair implements Serializable { - public String first; - public String second; +public class QueryParam implements Serializable { + public String key; + public String value; - public QueryPair(String first, String second) { - this.first = first; - this.second = second; + public QueryParam(String key, String value) { + this.key = key; + this.value = value; } } From 61cef4979f018783e0a3c5b3b911becc77f24a75 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 25 May 2021 09:34:05 +0200 Subject: [PATCH 6/6] Renamed QueryPair Signed-off-by: tobiasKaminsky --- .../java/com/nextcloud/android/sso/InputStreamBinder.java | 6 +++--- .../com/nextcloud/android/sso/aidl/NextcloudRequest.java | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java index cca20364b4..386b497faa 100644 --- a/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java +++ b/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java @@ -506,11 +506,11 @@ public class InputStreamBinder extends IInputStreamService.Stub { } @VisibleForTesting - public static NameValuePair[] convertListToNVP(Collection list) { + public static NameValuePair[] convertListToNVP(Collection list) { NameValuePair[] nvp = new NameValuePair[list.size()]; int i = 0; - for (com.nextcloud.android.sso.api.QueryPair pair : list) { - nvp[i] = new NameValuePair(pair.first, pair.second); + for (QueryParam pair : list) { + nvp[i] = new NameValuePair(pair.key, pair.value); i++; } return nvp; diff --git a/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java b/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java index 1fb41f0c78..23905521c2 100644 --- a/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java +++ b/src/main/java/com/nextcloud/android/sso/aidl/NextcloudRequest.java @@ -41,6 +41,8 @@ package com.nextcloud.android.sso.aidl; +import com.nextcloud.android.sso.QueryParam; + import java.io.Serializable; import java.util.Collection; import java.util.HashMap; @@ -55,7 +57,7 @@ public class NextcloudRequest implements Serializable { private String method; private Map> header = new HashMap<>(); private Map parameter = new HashMap<>(); - private final Collection parameterV2 = new LinkedList<>(); + private final Collection parameterV2 = new LinkedList<>(); private String requestBody; private String url; private String token; @@ -170,7 +172,7 @@ public class NextcloudRequest implements Serializable { return this.followRedirects; } - public Collection getParameterV2() { + public Collection getParameterV2() { return parameterV2; } }