Loading app/build.gradle +4 −2 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ plugins { id 'dagger.hilt.android.plugin' id 'kotlin-android' id 'kotlin-kapt' // remove as soon as Hilt supports KSP [https://issuetracker.google.com/179057202] id 'kotlin-parcelize' } // Android configuration Loading @@ -28,7 +29,7 @@ android { minSdkVersion 24 // Android 7.0 targetSdkVersion 33 // Android 13 buildConfigField "String", "userAgent", "\"DAVx5\"" buildConfigField "String", "userAgent", "\"AccountManager\"" testInstrumentationRunner "at.bitfire.davdroid.CustomTestRunner" } Loading Loading @@ -146,6 +147,7 @@ configurations { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3' testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' implementation "com.google.dagger:hilt-android:${versions.hilt}" Loading Loading @@ -217,7 +219,7 @@ dependencies { implementation "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2 implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5' // remove after entire switch to lib v2 implementation 'com.google.code.gson:gson:2.10.1' implementation("com.github.nextcloud:android-library:2.14.0") { implementation("foundation.e:Nextcloud-Android-Library:1.0.5-release") { exclude group: 'com.gitlab.bitfireAT', module: 'dav4jvm' exclude group: 'org.ogce', module: 'xpp3' // unused in Android and brings wrong Junit version exclude group: 'com.squareup.okhttp3' Loading app/src/main/AndroidManifest.xml +10 −1 Original line number Diff line number Diff line Loading @@ -684,13 +684,22 @@ <receiver android:name=".BootCompletedReceiver" android:name=".receiver.BootCompletedReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <receiver android:name=".receiver.AccountRemovedReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.accounts.action.ACCOUNT_REMOVED"/> </intent-filter> </receiver> <!-- provider to share debug info/logs --> <provider android:name="androidx.core.content.FileProvider" Loading app/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java +20 −15 Original line number Diff line number Diff line Loading @@ -26,7 +26,6 @@ import static com.nextcloud.android.sso.Constants.EXCEPTION_UNSUPPORTED_METHOD; import static com.nextcloud.android.sso.Constants.SSO_SHARED_PREFERENCE; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; Loading @@ -43,10 +42,10 @@ import com.nextcloud.android.sso.aidl.NextcloudRequest; import com.nextcloud.android.sso.aidl.ParcelFileDescriptorUtil; import com.nextcloud.android.utils.AccountManagerUtils; import com.nextcloud.android.utils.EncryptionUtils; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.OwnCloudClientManager; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import org.apache.commons.httpclient.HttpConnection; import org.apache.commons.httpclient.HttpMethodBase; Loading Loading @@ -79,6 +78,7 @@ import java.util.List; import java.util.Map; import java.util.logging.Level; import at.bitfire.davdroid.BuildConfig; import at.bitfire.davdroid.log.Logger; public class InputStreamBinder extends IInputStreamService.Stub { Loading Loading @@ -333,9 +333,10 @@ public class InputStreamBinder extends IInputStreamService.Stub { new IllegalStateException("URL need to start with a /")); } Uri serverUri = Uri.parse(AccountUtils.getBaseUrlForAccount(context, account)); OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(serverUri, context, true); client.setCredentials(OwnCloudCredentialsFactory.newBasicCredentials(account.name, getAcountPwd(account, context))); OwnCloudClientManagerFactory.setUserAgent(getUserAgent()); final OwnCloudClientManager ownCloudClientManager = OwnCloudClientManagerFactory.getDefaultSingleton(); final OwnCloudAccount ownCloudAccount = new OwnCloudAccount(account, context); final OwnCloudClient client = ownCloudClientManager.getClientFor(ownCloudAccount, context); HttpMethodBase method = buildMethod(request, client.getBaseUri(), requestBodyInputStream); Loading @@ -360,6 +361,8 @@ public class InputStreamBinder extends IInputStreamService.Stub { client.setFollowRedirects(true); int status = client.executeMethod(method); ownCloudClientManager.saveAllClients(context, account.type); // Check if status code is 2xx --> https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success if (status >= HTTP_STATUS_CODE_OK && status < HTTP_STATUS_CODE_MULTIPLE_CHOICES) { return method; Loading @@ -380,6 +383,10 @@ public class InputStreamBinder extends IInputStreamService.Stub { } } private static String getUserAgent() { return "AccountManager-SSO(" + BuildConfig.VERSION_NAME + ")"; } private Response processRequestV2(final NextcloudRequest request, final InputStream requestBodyInputStream) throws UnsupportedOperationException, com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException, Loading @@ -400,9 +407,10 @@ public class InputStreamBinder extends IInputStreamService.Stub { new IllegalStateException("URL need to start with a /")); } Uri serverUri = Uri.parse(AccountUtils.getBaseUrlForAccount(context, account)); OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(serverUri, context, true); client.setCredentials(OwnCloudCredentialsFactory.newBasicCredentials(account.name, getAcountPwd(account, context))); OwnCloudClientManagerFactory.setUserAgent(getUserAgent()); final OwnCloudClientManager ownCloudClientManager = OwnCloudClientManagerFactory.getDefaultSingleton(); final OwnCloudAccount ownCloudAccount = new OwnCloudAccount(account, context); final OwnCloudClient client = ownCloudClientManager.getClientFor(ownCloudAccount, context); HttpMethodBase method = buildMethod(request, client.getBaseUri(), requestBodyInputStream); Loading @@ -428,6 +436,8 @@ public class InputStreamBinder extends IInputStreamService.Stub { client.setFollowRedirects(true); int status = client.executeMethod(method); ownCloudClientManager.saveAllClients(context, account.type); // Check if status code is 2xx --> https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success if (status >= HTTP_STATUS_CODE_OK && status < HTTP_STATUS_CODE_MULTIPLE_CHOICES) { return new Response(method); Loading @@ -447,11 +457,6 @@ public class InputStreamBinder extends IInputStreamService.Stub { } } private static String getAcountPwd(Account account, Context ctx) throws AccountUtils.AccountNotFoundException { return AccountManager.get(ctx).getPassword(account); } private boolean isValid(NextcloudRequest request) { String callingPackageName = context.getPackageManager().getNameForUid(Binder.getCallingUid()); Loading app/src/main/java/com/owncloud/android/ui/activity/SsoGrantPermissionActivity.java +2 −19 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; Loading @@ -49,6 +48,7 @@ import java.util.logging.Level; import at.bitfire.davdroid.R; import at.bitfire.davdroid.log.Logger; import at.bitfire.davdroid.util.SsoUtils; public class SsoGrantPermissionActivity extends AppCompatActivity { Loading Loading @@ -115,7 +115,7 @@ public class SsoGrantPermissionActivity extends AppCompatActivity { // create token String token = UUID.randomUUID().toString().replaceAll("-", ""); String userId = sanitizeUserId(account.name); String userId = SsoUtils.INSTANCE.sanitizeUserId(account.name); saveToken(token, account.name); setResultData(token, userId, serverUrl); Loading @@ -136,23 +136,6 @@ public class SsoGrantPermissionActivity extends AppCompatActivity { setResult(RESULT_OK, data); } /** * Murena account's userId is set same as it's email address. * For old accounts (@e.email) userId = email. * For new accounts (@murena.io) userId is first part of email (ex: for email abc@murena.io, userId is abc). * For api requests, we needed to pass the actual userId. This method remove the unwanted part (@murena.io) from the userId */ @NonNull private static String sanitizeUserId(@NonNull String userId) { final String murenaMailEndPart = "@murena.io"; if (!userId.endsWith(murenaMailEndPart)) { return userId; } return userId.split(murenaMailEndPart)[0]; } @Nullable private String getServerUrl() { try { Loading app/src/main/kotlin/at/bitfire/davdroid/network/CookieParser.kt 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * Copyright MURENA SAS 2024 * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ package at.bitfire.davdroid.network interface CookieParser { fun cookiesAsString(): String } No newline at end of file Loading
app/build.gradle +4 −2 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ plugins { id 'dagger.hilt.android.plugin' id 'kotlin-android' id 'kotlin-kapt' // remove as soon as Hilt supports KSP [https://issuetracker.google.com/179057202] id 'kotlin-parcelize' } // Android configuration Loading @@ -28,7 +29,7 @@ android { minSdkVersion 24 // Android 7.0 targetSdkVersion 33 // Android 13 buildConfigField "String", "userAgent", "\"DAVx5\"" buildConfigField "String", "userAgent", "\"AccountManager\"" testInstrumentationRunner "at.bitfire.davdroid.CustomTestRunner" } Loading Loading @@ -146,6 +147,7 @@ configurations { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3' testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' implementation "com.google.dagger:hilt-android:${versions.hilt}" Loading Loading @@ -217,7 +219,7 @@ dependencies { implementation "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2 implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5' // remove after entire switch to lib v2 implementation 'com.google.code.gson:gson:2.10.1' implementation("com.github.nextcloud:android-library:2.14.0") { implementation("foundation.e:Nextcloud-Android-Library:1.0.5-release") { exclude group: 'com.gitlab.bitfireAT', module: 'dav4jvm' exclude group: 'org.ogce', module: 'xpp3' // unused in Android and brings wrong Junit version exclude group: 'com.squareup.okhttp3' Loading
app/src/main/AndroidManifest.xml +10 −1 Original line number Diff line number Diff line Loading @@ -684,13 +684,22 @@ <receiver android:name=".BootCompletedReceiver" android:name=".receiver.BootCompletedReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <receiver android:name=".receiver.AccountRemovedReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.accounts.action.ACCOUNT_REMOVED"/> </intent-filter> </receiver> <!-- provider to share debug info/logs --> <provider android:name="androidx.core.content.FileProvider" Loading
app/src/main/java/com/nextcloud/android/sso/InputStreamBinder.java +20 −15 Original line number Diff line number Diff line Loading @@ -26,7 +26,6 @@ import static com.nextcloud.android.sso.Constants.EXCEPTION_UNSUPPORTED_METHOD; import static com.nextcloud.android.sso.Constants.SSO_SHARED_PREFERENCE; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; Loading @@ -43,10 +42,10 @@ import com.nextcloud.android.sso.aidl.NextcloudRequest; import com.nextcloud.android.sso.aidl.ParcelFileDescriptorUtil; import com.nextcloud.android.utils.AccountManagerUtils; import com.nextcloud.android.utils.EncryptionUtils; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.OwnCloudClientManager; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import org.apache.commons.httpclient.HttpConnection; import org.apache.commons.httpclient.HttpMethodBase; Loading Loading @@ -79,6 +78,7 @@ import java.util.List; import java.util.Map; import java.util.logging.Level; import at.bitfire.davdroid.BuildConfig; import at.bitfire.davdroid.log.Logger; public class InputStreamBinder extends IInputStreamService.Stub { Loading Loading @@ -333,9 +333,10 @@ public class InputStreamBinder extends IInputStreamService.Stub { new IllegalStateException("URL need to start with a /")); } Uri serverUri = Uri.parse(AccountUtils.getBaseUrlForAccount(context, account)); OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(serverUri, context, true); client.setCredentials(OwnCloudCredentialsFactory.newBasicCredentials(account.name, getAcountPwd(account, context))); OwnCloudClientManagerFactory.setUserAgent(getUserAgent()); final OwnCloudClientManager ownCloudClientManager = OwnCloudClientManagerFactory.getDefaultSingleton(); final OwnCloudAccount ownCloudAccount = new OwnCloudAccount(account, context); final OwnCloudClient client = ownCloudClientManager.getClientFor(ownCloudAccount, context); HttpMethodBase method = buildMethod(request, client.getBaseUri(), requestBodyInputStream); Loading @@ -360,6 +361,8 @@ public class InputStreamBinder extends IInputStreamService.Stub { client.setFollowRedirects(true); int status = client.executeMethod(method); ownCloudClientManager.saveAllClients(context, account.type); // Check if status code is 2xx --> https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success if (status >= HTTP_STATUS_CODE_OK && status < HTTP_STATUS_CODE_MULTIPLE_CHOICES) { return method; Loading @@ -380,6 +383,10 @@ public class InputStreamBinder extends IInputStreamService.Stub { } } private static String getUserAgent() { return "AccountManager-SSO(" + BuildConfig.VERSION_NAME + ")"; } private Response processRequestV2(final NextcloudRequest request, final InputStream requestBodyInputStream) throws UnsupportedOperationException, com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException, Loading @@ -400,9 +407,10 @@ public class InputStreamBinder extends IInputStreamService.Stub { new IllegalStateException("URL need to start with a /")); } Uri serverUri = Uri.parse(AccountUtils.getBaseUrlForAccount(context, account)); OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(serverUri, context, true); client.setCredentials(OwnCloudCredentialsFactory.newBasicCredentials(account.name, getAcountPwd(account, context))); OwnCloudClientManagerFactory.setUserAgent(getUserAgent()); final OwnCloudClientManager ownCloudClientManager = OwnCloudClientManagerFactory.getDefaultSingleton(); final OwnCloudAccount ownCloudAccount = new OwnCloudAccount(account, context); final OwnCloudClient client = ownCloudClientManager.getClientFor(ownCloudAccount, context); HttpMethodBase method = buildMethod(request, client.getBaseUri(), requestBodyInputStream); Loading @@ -428,6 +436,8 @@ public class InputStreamBinder extends IInputStreamService.Stub { client.setFollowRedirects(true); int status = client.executeMethod(method); ownCloudClientManager.saveAllClients(context, account.type); // Check if status code is 2xx --> https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success if (status >= HTTP_STATUS_CODE_OK && status < HTTP_STATUS_CODE_MULTIPLE_CHOICES) { return new Response(method); Loading @@ -447,11 +457,6 @@ public class InputStreamBinder extends IInputStreamService.Stub { } } private static String getAcountPwd(Account account, Context ctx) throws AccountUtils.AccountNotFoundException { return AccountManager.get(ctx).getPassword(account); } private boolean isValid(NextcloudRequest request) { String callingPackageName = context.getPackageManager().getNameForUid(Binder.getCallingUid()); Loading
app/src/main/java/com/owncloud/android/ui/activity/SsoGrantPermissionActivity.java +2 −19 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; Loading @@ -49,6 +48,7 @@ import java.util.logging.Level; import at.bitfire.davdroid.R; import at.bitfire.davdroid.log.Logger; import at.bitfire.davdroid.util.SsoUtils; public class SsoGrantPermissionActivity extends AppCompatActivity { Loading Loading @@ -115,7 +115,7 @@ public class SsoGrantPermissionActivity extends AppCompatActivity { // create token String token = UUID.randomUUID().toString().replaceAll("-", ""); String userId = sanitizeUserId(account.name); String userId = SsoUtils.INSTANCE.sanitizeUserId(account.name); saveToken(token, account.name); setResultData(token, userId, serverUrl); Loading @@ -136,23 +136,6 @@ public class SsoGrantPermissionActivity extends AppCompatActivity { setResult(RESULT_OK, data); } /** * Murena account's userId is set same as it's email address. * For old accounts (@e.email) userId = email. * For new accounts (@murena.io) userId is first part of email (ex: for email abc@murena.io, userId is abc). * For api requests, we needed to pass the actual userId. This method remove the unwanted part (@murena.io) from the userId */ @NonNull private static String sanitizeUserId(@NonNull String userId) { final String murenaMailEndPart = "@murena.io"; if (!userId.endsWith(murenaMailEndPart)) { return userId; } return userId.split(murenaMailEndPart)[0]; } @Nullable private String getServerUrl() { try { Loading
app/src/main/kotlin/at/bitfire/davdroid/network/CookieParser.kt 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * Copyright MURENA SAS 2024 * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ package at.bitfire.davdroid.network interface CookieParser { fun cookiesAsString(): String } No newline at end of file