Skip to content

Commit

Permalink
Merge branch 'master' into 395-e2e-test
Browse files Browse the repository at this point in the history
# Conflicts:
#	lib/build.gradle
  • Loading branch information
stefan-niedermann committed Jan 17, 2024
2 parents 71f88ef + 4e872e8 commit 90bfdb6
Show file tree
Hide file tree
Showing 82 changed files with 1,725 additions and 1,284 deletions.
4 changes: 4 additions & 0 deletions .drone.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---
kind: pipeline
type: docker
name: tests
Expand Down Expand Up @@ -88,3 +89,6 @@ trigger:
event:
- push
- pull_request
---
kind: signature
hmac: 8f74ead1e56e65775aeee6ea0fcc43f1587f345e468d13e8432adf50fa46cd1e
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This library allows you to use accounts as well as the network stack provided by
- [5.2) Without Retrofit](#52-without-retrofit)
- [5.3) WebDAV](#53-webdav)
- [Additional info](#additional-info)
- [R8/ProGuard](#r8proguard)
- [Security](#security)
- [Media](#media)
- [Talks at the Nextcloud Conference](#talks-at-the-nextcloud-conference)
Expand Down Expand Up @@ -75,7 +76,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
// As this library supports multiple accounts we created some helper methods if you only want to use one.
// The following line stores the selected account as the "default" account which can be queried by using
// the SingleAccountHelper.getCurrentSingleSignOnAccount(context) method
SingleAccountHelper.setCurrentAccount(context, account.name);
SingleAccountHelper.commitCurrentAccount(context, account.name);

// Get the "default" account
SingleSignOnAccount ssoAccount = null;
Expand Down Expand Up @@ -108,6 +109,9 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
// If you stored the "default" account using setCurrentAccount(…) you can get the account by using the following line:
final var ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context);

// It is also possible to get the "default" account as a LiveData object:
final var ssoAccount$ = SingleAccountHelper.getCurrentSingleSignOnAccount$(context);

// Otherwise (for multi-account support you'll have to keep track of the account names yourself. Note: this has to be the name of SingleSignOnAccount.name)
AccountImporter.getSingleSignOnAccount(context, accountName);

Expand Down Expand Up @@ -215,7 +219,7 @@ public class MyActivity extends AppCompatActivity {
super.onStop();
// Close Service Connection to Nextcloud Files App and
// disconnect API from Context (prevent Memory Leak)
mNextcloudAPI.stop();
mNextcloudAPI.close();
}

private void downloadFile() {
Expand Down Expand Up @@ -272,6 +276,30 @@ if (VersionCheckHelper.verifyMinVersion(context, MIN_NEXTCLOUD_FILES_APP_VERSION
}
```

## R8/ProGuard

R8 and ProGuard rules are bundled into [SSO](lib/consumer-proguard-rules.pro).
The bundled rules do **not** cover enabled obfuscation.
Therefore it is **recommended** to add `-dontobfuscate` to your app-specific proguard rules.

With [R8 full mode](https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md#r8-full-mode) being enabled by default since [AGP 8.0](https://developer.android.com/build/releases/gradle-plugin#default-changes), you will probably need to handle following app-specific rules yourself (or disable full mode):

### gson
According to [gson's sample rules](https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg#L14), you still need to configure rules for your gson-handled classes.
> ```
> # Application classes that will be serialized/deserialized over Gson
> -keep class com.google.gson.examples.android.model.** { <fields>; }
> ```
### Retrofit
The same applies to classes which you're using in the api from step [5.1.1](#511-before-using-this-single-sign-on-library-your-interface-for-your-retrofit-api-might-look-like-this)
```
# Application classes that will be serialized/deserialized by retrofit
-keep class com.google.gson.examples.android.model.**
```

If you find working less broad rules, contributions to these rules are welcome!

## Security

Once the user clicks on "Allow" in the login dialog, the Nextcloud Files App will generate a token for your app. Only your app is allowed to use that token. Even if another app will get a hold of that token, it won't be able to make any requests to the nextcloud server as the nextcloud files app matches that token against the namespace of your app.
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
buildscript {
ext {
kotlin_version = '1.8.20'
kotlin_version = '1.9.22'
}
repositories {
google()
Expand All @@ -13,7 +13,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.7.5'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.22.0"
classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.4"
}
}

Expand Down
29 changes: 17 additions & 12 deletions lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 33
consumerProguardFiles 'consumer-proguard-rules.pro'
}

buildFeatures {
aidl true
}

buildTypes {
Expand Down Expand Up @@ -90,37 +95,37 @@ detekt {
}

dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'

implementation "androidx.appcompat:appcompat:1.6.1"
implementation 'androidx.annotation:annotation:1.5.0'
implementation 'androidx.core:core:1.9.0'
implementation 'androidx.fragment:fragment:1.5.6'
implementation 'androidx.annotation:annotation:1.7.1'
implementation 'androidx.core:core:1.10.1'
implementation 'androidx.fragment:fragment:1.6.2'

implementation 'com.google.android.material:material:1.8.0'
implementation 'com.google.android.material:material:1.9.0'

compileOnly "org.projectlombok:lombok:1.18.26"
annotationProcessor "org.projectlombok:lombok:1.18.24"
compileOnly "org.projectlombok:lombok:1.18.30"
annotationProcessor "org.projectlombok:lombok:1.18.30"

api 'com.google.code.gson:gson:2.10.1'

implementation 'io.reactivex.rxjava2:rxjava:2.2.21'
implementation 'io.reactivex.rxjava3:rxjava:3.1.6'
implementation 'io.reactivex.rxjava3:rxjava:3.1.8'

implementation 'commons-io:commons-io:2.11.0'
implementation 'commons-io:commons-io:2.14.0'

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:3.14.9'

spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.12.0'
spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.0'
spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4'

ktlint "com.pinterest:ktlint:0.48.2"
ktlint "com.pinterest:ktlint:0.51.0-FINAL"

// Required for local unit tests (JUnit 4 framework)
testImplementation 'junit:junit:4.13.2'
// required if you want to use Mockito for unit tests
testImplementation 'org.mockito:mockito-core:5.3.0'
testImplementation 'org.mockito:mockito-core:5.7.0'
}

afterEvaluate {
Expand Down
71 changes: 71 additions & 0 deletions lib/consumer-proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# from https://www.guardsquare.com/manual/configuration/examples#serializable
-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}

##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.nextcloud.android.sso.model.** { <fields>; }

# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}

# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

##---------------End: proguard configuration for Gson ----------

# Retrofit rules, remove once upgraded to 2.10.0
# Keep generic signature of RxJava2 (R8 full mode strips signatures from non-kept items).
-keep,allowobfuscation,allowshrinking class io.reactivex.Single
-keep,allowobfuscation,allowshrinking class io.reactivex.Flowable
-keep,allowobfuscation,allowshrinking class io.reactivex.Observable
-keep,allowobfuscation,allowshrinking class io.reactivex.Completable

# Keep inherited services.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>

# Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items).
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response

# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

# Keep generic signature of RxJava3 (R8 full mode strips signatures from non-kept items).
-keep,allowobfuscation,allowshrinking class io.reactivex.rxjava3.core.Flowable
-keep,allowobfuscation,allowshrinking class io.reactivex.rxjava3.core.Maybe
-keep,allowobfuscation,allowshrinking class io.reactivex.rxjava3.core.Observable
-keep,allowobfuscation,allowshrinking class io.reactivex.rxjava3.core.Single
Loading

0 comments on commit 90bfdb6

Please sign in to comment.