Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2020-06-20 13:55:36 +0300
committerStefan Niedermann <info@niedermann.it>2020-06-20 13:55:36 +0300
commit7ca8fe14a3d63c0ab0f733a79ba1a3c87a47dd59 (patch)
tree03bbaf67ba097d27fa55c2238e2f42d2b526e4a3 /glide-sso-integration
parenta914ff3a32f2c5e81178fc60bd29b4c04053609b (diff)
Move SSO Glide integration into own module
Diffstat (limited to 'glide-sso-integration')
-rw-r--r--glide-sso-integration/.gitignore1
-rw-r--r--glide-sso-integration/build.gradle34
-rw-r--r--glide-sso-integration/consumer-rules.pro0
-rw-r--r--glide-sso-integration/proguard-rules.pro21
-rw-r--r--glide-sso-integration/src/main/AndroidManifest.xml4
-rw-r--r--glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnLibraryGlideModule.java33
-rw-r--r--glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnStreamFetcher.java145
-rw-r--r--glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnUrl.java88
-rw-r--r--glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnUrlLoader.java66
9 files changed, 392 insertions, 0 deletions
diff --git a/glide-sso-integration/.gitignore b/glide-sso-integration/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/glide-sso-integration/.gitignore
@@ -0,0 +1 @@
+/build \ No newline at end of file
diff --git a/glide-sso-integration/build.gradle b/glide-sso-integration/build.gradle
new file mode 100644
index 000000000..1f8cddf59
--- /dev/null
+++ b/glide-sso-integration/build.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.3"
+
+ defaultConfig {
+ minSdkVersion 14
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ // Nextcloud SSO
+ implementation "com.github.nextcloud:Android-SingleSignOn:0.5.1"
+
+ // Glide
+ implementation 'com.github.bumptech.glide:glide:4.11.0'
+ annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
+
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+} \ No newline at end of file
diff --git a/glide-sso-integration/consumer-rules.pro b/glide-sso-integration/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/glide-sso-integration/consumer-rules.pro
diff --git a/glide-sso-integration/proguard-rules.pro b/glide-sso-integration/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/glide-sso-integration/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile \ No newline at end of file
diff --git a/glide-sso-integration/src/main/AndroidManifest.xml b/glide-sso-integration/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..88728afb3
--- /dev/null
+++ b/glide-sso-integration/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+<manifest package="it.niedermann.android.glidesso">
+
+ /
+</manifest> \ No newline at end of file
diff --git a/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnLibraryGlideModule.java b/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnLibraryGlideModule.java
new file mode 100644
index 000000000..6669d5da1
--- /dev/null
+++ b/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnLibraryGlideModule.java
@@ -0,0 +1,33 @@
+package it.niedermann.android.glidesso;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.Registry;
+import com.bumptech.glide.annotation.GlideModule;
+import com.bumptech.glide.load.model.GlideUrl;
+import com.bumptech.glide.module.LibraryGlideModule;
+
+import java.io.InputStream;
+
+/**
+ * Registers OkHttp related classes via Glide's annotation processor.
+ *
+ * <p>For Applications that depend on this library and include an {@link LibraryGlideModule} and Glide's
+ * annotation processor, this class will be automatically included.
+ */
+@GlideModule
+public final class SingleSignOnLibraryGlideModule extends LibraryGlideModule {
+
+ private static final String TAG = SingleSignOnLibraryGlideModule.class.getSimpleName();
+
+ @Override
+ public void registerComponents(
+ @NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
+ Log.v(TAG, "Replacing default implementation for " + GlideUrl.class.getSimpleName() + ".");
+ registry.replace(GlideUrl.class, InputStream.class, new SingleSignOnUrlLoader.Factory(context));
+ }
+}
diff --git a/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnStreamFetcher.java b/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnStreamFetcher.java
new file mode 100644
index 000000000..10f708890
--- /dev/null
+++ b/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnStreamFetcher.java
@@ -0,0 +1,145 @@
+package it.niedermann.android.glidesso;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.bumptech.glide.Priority;
+import com.bumptech.glide.load.DataSource;
+import com.bumptech.glide.load.data.DataFetcher;
+import com.bumptech.glide.load.model.GlideUrl;
+import com.google.gson.GsonBuilder;
+import com.nextcloud.android.sso.AccountImporter;
+import com.nextcloud.android.sso.aidl.NextcloudRequest;
+import com.nextcloud.android.sso.api.NextcloudAPI;
+import com.nextcloud.android.sso.api.Response;
+import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
+import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException;
+import com.nextcloud.android.sso.exceptions.TokenMismatchException;
+import com.nextcloud.android.sso.helper.SingleAccountHelper;
+import com.nextcloud.android.sso.model.SingleSignOnAccount;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Fetches an {@link InputStream} using the Nextcloud SSO library.
+ */
+public class SingleSignOnStreamFetcher implements DataFetcher<InputStream> {
+
+ /**
+ * Use this header and set the {@link SingleSignOnAccount} name property as value
+ * Format of the value needs to be
+ */
+ public static final String X_HEADER_SSO_ACCOUNT_NAME = "X-SSO-Account-Name";
+
+ private static final String TAG = SingleSignOnStreamFetcher.class.getSimpleName();
+ private static final String METHOD_GET = "GET";
+
+ private static final Map<String, NextcloudAPI> INITIALIZED_APIs = new HashMap<>();
+
+ private final Context context;
+ private final GlideUrl url;
+
+ // Public API.
+ @SuppressWarnings("WeakerAccess")
+ public SingleSignOnStreamFetcher(Context context, GlideUrl url) {
+ this.context = context;
+ this.url = url;
+ }
+
+ @Override
+ public void loadData(@NonNull Priority priority, @NonNull final DataCallback<? super InputStream> callback) {
+ NextcloudAPI client;
+ try {
+ final SingleSignOnAccount ssoAccount;
+ if (url.getHeaders().containsKey(X_HEADER_SSO_ACCOUNT_NAME)) {
+ ssoAccount = AccountImporter.getSingleSignOnAccount(context, url.getHeaders().get(X_HEADER_SSO_ACCOUNT_NAME));
+ } else {
+ ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context);
+ }
+ client = INITIALIZED_APIs.get(ssoAccount.name);
+ boolean didInitialize = false;
+ if (client == null) {
+ client = new NextcloudAPI(context, ssoAccount, new GsonBuilder().create(), new NextcloudAPI.ApiConnectedListener() {
+ @Override
+ public void onConnected() {
+ Log.v(TAG, "SSO API successfully initialized");
+ }
+
+ @Override
+ public void onError(Exception ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ }
+ });
+ INITIALIZED_APIs.put(ssoAccount.name, client);
+ didInitialize = true;
+ }
+
+ NextcloudRequest.Builder requestBuilder;
+ try {
+ requestBuilder = new NextcloudRequest.Builder()
+ .setMethod(METHOD_GET)
+ .setUrl(url.toURL().getPath());
+ Map<String, List<String>> header = new HashMap<>();
+ for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
+ if (!X_HEADER_SSO_ACCOUNT_NAME.equals(headerEntry.getKey())) {
+ header.put(headerEntry.getKey(), Collections.singletonList(headerEntry.getValue()));
+ }
+ }
+ requestBuilder.setHeader(header);
+ NextcloudRequest nextcloudRequest = requestBuilder.build();
+ Log.v(TAG, nextcloudRequest.toString());
+ Response response = client.performNetworkRequestV2(nextcloudRequest);
+ callback.onDataReady(response.getBody());
+ } catch (MalformedURLException e) {
+ callback.onLoadFailed(e);
+ } catch (TokenMismatchException e) {
+ if (!didInitialize) {
+ Log.w(TAG, "SSO Glide loader failed with TokenMismatchException, trying to re-initialize...");
+ client.stop();
+ INITIALIZED_APIs.remove(ssoAccount.name);
+ loadData(priority, callback);
+ } else {
+ e.printStackTrace();
+ callback.onLoadFailed(e);
+ }
+ } catch (Exception e) {
+ callback.onLoadFailed(e);
+ }
+
+ } catch (NextcloudFilesAppAccountNotFoundException e) {
+ e.printStackTrace();
+ } catch (NoCurrentAccountSelectedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void cleanup() {
+
+ }
+
+ @Override
+ public void cancel() {
+
+ }
+
+ @NonNull
+ @Override
+ public Class<InputStream> getDataClass() {
+ return InputStream.class;
+ }
+
+ @NonNull
+ @Override
+ public DataSource getDataSource() {
+ return DataSource.REMOTE;
+ }
+}
diff --git a/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnUrl.java b/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnUrl.java
new file mode 100644
index 000000000..b8f359757
--- /dev/null
+++ b/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnUrl.java
@@ -0,0 +1,88 @@
+package it.niedermann.android.glidesso;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.model.GlideUrl;
+import com.bumptech.glide.load.model.Headers;
+import com.bumptech.glide.load.model.LazyHeaders;
+import com.nextcloud.android.sso.helper.SingleAccountHelper;
+import com.nextcloud.android.sso.model.SingleSignOnAccount;
+
+import java.net.URL;
+import java.util.Map;
+
+import static it.niedermann.android.glidesso.SingleSignOnStreamFetcher.X_HEADER_SSO_ACCOUNT_NAME;
+
+/**
+ * Use this as kind of {@link GlideUrl} if you want to do a {@link Glide} request from a {@link SingleSignOnAccount} which is not set by {@link SingleAccountHelper#setCurrentAccount(Context, String)}.
+ */
+public class SingleSignOnUrl extends GlideUrl {
+
+ public SingleSignOnUrl(@NonNull SingleSignOnAccount ssoAccount, @NonNull String url) {
+ this(ssoAccount.name, url);
+ }
+
+ public SingleSignOnUrl(@NonNull SingleSignOnAccount ssoAccount, @NonNull URL url) {
+ this(ssoAccount.name, url);
+ }
+
+ public SingleSignOnUrl(@NonNull SingleSignOnAccount ssoAccount, @NonNull String url, @NonNull Headers headers) {
+ this(ssoAccount.name, url, headers);
+ }
+
+ public SingleSignOnUrl(@NonNull SingleSignOnAccount ssoAccount, @NonNull URL url, @NonNull Headers headers) {
+ this(ssoAccount.name, url, headers);
+ }
+
+ public SingleSignOnUrl(@NonNull String ssoAccountName, @NonNull String url) {
+ super(url, new SingleSignOnOriginHeader(ssoAccountName));
+ }
+
+ public SingleSignOnUrl(@NonNull String ssoAccountName, @NonNull URL url) {
+ super(url, new SingleSignOnOriginHeader(ssoAccountName));
+ }
+
+ public SingleSignOnUrl(@NonNull String ssoAccountName, @NonNull String url, @NonNull Headers headers) {
+ super(url, new SingleSignOnOriginHeader(ssoAccountName, headers));
+ }
+
+ public SingleSignOnUrl(@NonNull String ssoAccountName, @NonNull URL url, @NonNull Headers headers) {
+ super(url, new SingleSignOnOriginHeader(ssoAccountName, headers));
+ }
+
+ private static class SingleSignOnOriginHeader implements Headers {
+
+ private Headers headers;
+
+ /**
+ * Use this as {@link Headers} if you want to do a {@link Glide} request for an {@link SingleSignOnAccount} which is not set by {@link SingleAccountHelper} as current {@link SingleSignOnAccount}.
+ *
+ * @param ssoAccountName Account name from which host the request should be fired (needs to match {@link SingleSignOnAccount#name})
+ */
+ public SingleSignOnOriginHeader(@NonNull String ssoAccountName) {
+ this.headers = new LazyHeaders.Builder().addHeader(X_HEADER_SSO_ACCOUNT_NAME, ssoAccountName).build();
+ }
+
+ /**
+ * Use this as {@link Headers} if you want to do a {@link Glide} request for an {@link SingleSignOnAccount} which is not set by {@link SingleAccountHelper} as current {@link SingleSignOnAccount}.
+ *
+ * @param ssoAccountName Account name from which host the request should be fired (needs to match {@link SingleSignOnAccount#name})
+ */
+ public SingleSignOnOriginHeader(@NonNull String ssoAccountName, Headers headers) {
+ LazyHeaders.Builder builder = new LazyHeaders.Builder();
+ for (Map.Entry<String, String> entry : headers.getHeaders().entrySet()) {
+ builder.addHeader(entry.getKey(), entry.getValue());
+ }
+ builder.addHeader(X_HEADER_SSO_ACCOUNT_NAME, ssoAccountName).build();
+ this.headers = builder.build();
+ }
+
+ @Override
+ public Map<String, String> getHeaders() {
+ return this.headers.getHeaders();
+ }
+ }
+}
diff --git a/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnUrlLoader.java b/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnUrlLoader.java
new file mode 100644
index 000000000..10f990b3e
--- /dev/null
+++ b/glide-sso-integration/src/main/java/it/niedermann/android/glidesso/SingleSignOnUrlLoader.java
@@ -0,0 +1,66 @@
+package it.niedermann.android.glidesso;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.bumptech.glide.load.Options;
+import com.bumptech.glide.load.model.GlideUrl;
+import com.bumptech.glide.load.model.ModelLoader;
+import com.bumptech.glide.load.model.ModelLoaderFactory;
+import com.bumptech.glide.load.model.MultiModelLoaderFactory;
+
+import java.io.InputStream;
+
+/**
+ * A simple model loader for fetching media over http/https using OkHttp.
+ */
+public class SingleSignOnUrlLoader implements ModelLoader<GlideUrl, InputStream> {
+
+ private static final String TAG = SingleSignOnUrlLoader.class.getSimpleName();
+ private final Context context;
+
+ // Public API.
+ @SuppressWarnings("WeakerAccess")
+ public SingleSignOnUrlLoader(@NonNull Context context) {
+ this.context = context;
+ }
+
+ @Override
+ public boolean handles(@NonNull GlideUrl url) {
+ return true;
+ }
+
+ @Override
+ public LoadData<InputStream> buildLoadData(
+ @NonNull GlideUrl model, int width, int height, @NonNull Options options) {
+ return new LoadData<>(model, new SingleSignOnStreamFetcher(context, model));
+ }
+
+ /**
+ * The default factory for {@link SingleSignOnUrlLoader}s.
+ */
+ // Public API.
+ @SuppressWarnings("WeakerAccess")
+ public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
+ private SingleSignOnUrlLoader loader;
+
+ /**
+ * Constructor for a new Factory that runs requests using given client.
+ */
+ public Factory(@NonNull Context context) {
+ loader = new SingleSignOnUrlLoader(context);
+ }
+
+ @NonNull
+ @Override
+ public ModelLoader<GlideUrl, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
+ return loader;
+ }
+
+ @Override
+ public void teardown() {
+ // Do nothing, this instance doesn't own the client.
+ }
+ }
+}