1
0
mirror of https://github.com/owncloud/android-library.git synced 2025-06-10 17:36:12 +00:00

Merge pull request #323 from owncloud/master

1.0.5 stable
This commit is contained in:
Abel García de Prada 2020-06-04 09:03:56 +02:00 committed by GitHub
commit 8f5f821113
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
120 changed files with 1508 additions and 3489 deletions

View File

@ -0,0 +1,10 @@
name: "Validate Gradle Wrapper"
on: [pull_request]
jobs:
validation:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1

5
.gitignore vendored
View File

@ -19,11 +19,6 @@ gen/
# Local configuration files (sdk path, etc)
.gradle/
local.properties
sample_client/local.properties
# Mac .DS_Store files
.DS_Store
# Proguard README
proguard-project.txt
sample_client/proguard-project.txt

View File

@ -2,7 +2,7 @@
ownCloud Android Library is available under MIT license
Copyright (C) 2019 ownCloud GmbH.
Copyright (C) 2020 ownCloud GmbH.
Copyright (C) 2012 Bartek Przybylski
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@ -1,7 +1,7 @@
buildscript {
ext {
// Libraries
kotlinVersion = '1.3.50'
kotlinVersion = '1.3.72'
moshiVersion = "1.9.2"
}
repositories {
@ -9,7 +9,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath 'com.android.tools.build:gradle:3.6.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion"
}

3
gradle.properties Normal file
View File

@ -0,0 +1,3 @@
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip

View File

@ -7,7 +7,14 @@ dependencies {
api 'com.squareup.okhttp3:okhttp:3.12.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
api 'com.gitlab.ownclouders:dav4android:oc_support_1.0.1'
api 'com.github.hannesa2:Logcat:1.5.6'
api 'com.github.hannesa2:Logcat:1.6.0'
api 'net.openid:appauth:0.7.1'
// Moshi
implementation ("com.squareup.moshi:moshi-kotlin:$moshiVersion") {
exclude module: "kotlin-reflect"
}
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion"
}
allOpen {
@ -19,11 +26,15 @@ android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 19
minSdkVersion 21
targetSdkVersion 28
versionCode = 10000400
versionName = "1.0.4"
versionCode = 10000500
versionName = "1.0.5"
// This is pretty ugly but manifest placeholders don't seem to work very well when using different modules
// See https://github.com/openid/AppAuth-Android/issues/325
manifestPlaceholders = [appAuthRedirectScheme: '']
}
lintOptions {

View File

@ -1,63 +0,0 @@
package com.owncloud.android.lib.common;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import java.io.IOException;
/**
* Dynamic implementation of {@link OwnCloudClientManager}.
*
* Wraps instances of {@link SingleSessionManager} and {@link SimpleFactoryManager} and delegates on one
* or the other depending on the known version of the server corresponding to the {@link OwnCloudAccount}
*
* @author David A. Velasco
*/
public class DynamicSessionManager implements OwnCloudClientManager {
private SimpleFactoryManager mSimpleFactoryManager = new SimpleFactoryManager();
private SingleSessionManager mSingleSessionManager = new SingleSessionManager();
@Override
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context)
throws AccountUtils.AccountNotFoundException,
OperationCanceledException, AuthenticatorException, IOException {
OwnCloudVersion ownCloudVersion = null;
if (account.getSavedAccount() != null) {
ownCloudVersion = AccountUtils.getServerVersionForAccount(
account.getSavedAccount(), context
);
}
if (ownCloudVersion != null && ownCloudVersion.isSessionMonitoringSupported()) {
return mSingleSessionManager.getClientFor(account, context);
} else {
return mSimpleFactoryManager.getClientFor(account, context);
}
}
@Override
public OwnCloudClient removeClientFor(OwnCloudAccount account) {
OwnCloudClient clientRemovedFromFactoryManager = mSimpleFactoryManager.removeClientFor(account);
OwnCloudClient clientRemovedFromSingleSessionManager = mSingleSessionManager.removeClientFor(account);
if (clientRemovedFromSingleSessionManager != null) {
return clientRemovedFromSingleSessionManager;
} else {
return clientRemovedFromFactoryManager;
}
// clientRemoved and clientRemoved2 should not be != null at the same time
}
@Override
public void saveAllClients(Context context, String accountType) {
mSimpleFactoryManager.saveAllClients(context, accountType);
mSingleSessionManager.saveAllClients(context, accountType);
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@ -38,12 +38,11 @@ import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.common.utils.RandomUtils;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import okhttp3.Cookie;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import timber.log.Timber;
import java.io.IOException;
import java.io.InputStream;
@ -54,11 +53,10 @@ import static com.owncloud.android.lib.common.http.HttpConstants.OC_X_REQUEST_ID
public class OwnCloudClient extends HttpClient {
public static final String WEBDAV_FILES_PATH_4_0 = "/remote.php/dav/files/";
public static final String WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
public static final String WEBDAV_PATH_4_0_AND_LATER = "/remote.php/dav";
private static final String WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
public static final String STATUS_PATH = "/status.php";
public static final String FILES_WEB_PATH = "/index.php/apps/files";
private static final String TAG = OwnCloudClient.class.getSimpleName();
private static final int MAX_REDIRECTIONS_COUNT = 3;
private static final int MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS = 1;
@ -70,13 +68,8 @@ public class OwnCloudClient extends HttpClient {
private OwnCloudVersion mVersion = null;
private OwnCloudAccount mAccount;
/**
* {@link @OwnCloudClientManager} holding a reference to this object and delivering it to callers; might be
* NULL
*/
private OwnCloudClientManager mOwnCloudClientManager = null;
private SingleSessionManager mSingleSessionManager = null;
private String mRedirectedLocation;
private boolean mFollowRedirects;
public OwnCloudClient(Uri baseUri) {
@ -86,7 +79,7 @@ public class OwnCloudClient extends HttpClient {
mBaseUri = baseUri;
mInstanceNumber = sIntanceCounter++;
Log_OC.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient");
Timber.d("#" + mInstanceNumber + "Creating OwnCloudClient");
clearCredentials();
clearCookies();
@ -99,7 +92,7 @@ public class OwnCloudClient extends HttpClient {
mCredentials.applyTo(this);
}
public void applyCredentials() {
void applyCredentials() {
mCredentials.applyTo(this);
}
@ -112,7 +105,6 @@ public class OwnCloudClient extends HttpClient {
setRequestId(method);
status = method.execute();
checkFirstRedirection(method);
if (mFollowRedirects) {
status = followRedirection(method).getLastStatus();
@ -127,13 +119,6 @@ public class OwnCloudClient extends HttpClient {
return status;
}
private void checkFirstRedirection(HttpBaseMethod method) {
final String location = method.getResponseHeader(HttpConstants.LOCATION_HEADER_LOWER);
if (location != null && !location.isEmpty()) {
mRedirectedLocation = location;
}
}
private int executeRedirectedHttpMethod(HttpBaseMethod method) throws Exception {
boolean repeatWithFreshCredentials;
int repeatCounter = 0;
@ -163,7 +148,7 @@ public class OwnCloudClient extends HttpClient {
// Header to allow tracing requests in apache and ownCloud logs
addHeaderForAllRequests(OC_X_REQUEST_ID, requestId);
Log_OC.d(TAG, "Executing " + method.getClass().getSimpleName() + " in request with id " + requestId);
Timber.d("Executing in request with id %s", requestId);
}
public RedirectionPath followRedirection(HttpBaseMethod method) throws Exception {
@ -175,15 +160,14 @@ public class OwnCloudClient extends HttpClient {
(status == HttpConstants.HTTP_MOVED_PERMANENTLY ||
status == HttpConstants.HTTP_MOVED_TEMPORARILY ||
status == HttpConstants.HTTP_TEMPORARY_REDIRECT)
) {
) {
final String location = method.getResponseHeader(HttpConstants.LOCATION_HEADER) != null
? method.getResponseHeader(HttpConstants.LOCATION_HEADER)
: method.getResponseHeader(HttpConstants.LOCATION_HEADER_LOWER);
if (location != null) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Location to redirect: " + location);
Timber.d("#" + mInstanceNumber + "Location to redirect: " + location);
redirectionPath.addLocation(location);
@ -216,7 +200,7 @@ public class OwnCloudClient extends HttpClient {
redirectionsCount++;
} else {
Log_OC.d(TAG + " #" + mInstanceNumber, "No location to redirect!");
Timber.d(" #" + mInstanceNumber + "No location to redirect!");
status = HttpConstants.HTTP_NOT_FOUND;
}
}
@ -237,8 +221,7 @@ public class OwnCloudClient extends HttpClient {
responseBodyAsStream.close();
} catch (IOException io) {
Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response;" +
" will be IGNORED", io);
Timber.e(io, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED");
}
}
}
@ -248,7 +231,7 @@ public class OwnCloudClient extends HttpClient {
}
public Uri getUserFilesWebDavUri() {
return mCredentials instanceof OwnCloudAnonymousCredentials
return (mCredentials instanceof OwnCloudAnonymousCredentials || mAccount == null)
? Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0)
: Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0 + AccountUtils.getUserId(
mAccount.getSavedAccount(), getContext()
@ -296,38 +279,6 @@ public class OwnCloudClient extends HttpClient {
}
}
private void logCookie(Cookie cookie) {
Log_OC.d(TAG, "Cookie name: " + cookie.name());
Log_OC.d(TAG, " value: " + cookie.value());
Log_OC.d(TAG, " domain: " + cookie.domain());
Log_OC.d(TAG, " path: " + cookie.path());
Log_OC.d(TAG, " expiryDate: " + cookie.expiresAt());
Log_OC.d(TAG, " secure: " + cookie.secure());
}
private void logCookiesAtRequest(Headers headers, String when) {
int counter = 0;
for (final String cookieHeader : headers.toMultimap().get("cookie")) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Cookies at request (" + when + ") (" + counter++ + "): "
+ cookieHeader);
}
if (counter == 0) {
Log_OC.d(TAG + " #" + mInstanceNumber, "No cookie at request before");
}
}
private void logSetCookiesAtResponse(Headers headers) {
int counter = 0;
for (final String cookieHeader : headers.toMultimap().get("set-cookie")) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Set-Cookie (" + counter++ + "): " + cookieHeader);
}
if (counter == 0) {
Log_OC.d(TAG + " #" + mInstanceNumber, "No set-cookie");
}
}
public String getCookiesString() {
StringBuilder cookiesString = new StringBuilder();
List<Cookie> cookieList = getCookiesFromUrl(HttpUrl.parse(mBaseUri.toString()));
@ -384,7 +335,6 @@ public class OwnCloudClient extends HttpClient {
if (invalidated) {
if (getCredentials().authTokenCanBeRefreshed() &&
repeatCounter < MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS) {
try {
mAccount.loadCredentials(getContext());
// if mAccount.getCredentials().length() == 0 --> refresh failed
@ -392,18 +342,16 @@ public class OwnCloudClient extends HttpClient {
credentialsWereRefreshed = true;
} catch (AccountsException | IOException e) {
Log_OC.e(
TAG,
"Error while trying to refresh auth token for " + mAccount.getSavedAccount().name,
e
Timber.e(e, "Error while trying to refresh auth token for %s",
mAccount.getSavedAccount().name
);
}
}
if (!credentialsWereRefreshed && mOwnCloudClientManager != null) {
if (!credentialsWereRefreshed && mSingleSessionManager != null) {
// if credentials are not refreshed, client must be removed
// from the OwnCloudClientManager to prevent it is reused once and again
mOwnCloudClientManager.removeClientFor(mAccount);
mSingleSessionManager.removeClientFor(mAccount);
}
}
// else: onExecute will finish with status 401
@ -421,21 +369,21 @@ public class OwnCloudClient extends HttpClient {
* cannot be invalidated with the given arguments.
*/
private boolean shouldInvalidateAccountCredentials(int httpStatusCode) {
boolean shouldInvalidateAccountCredentials =
(httpStatusCode == HttpConstants.HTTP_UNAUTHORIZED);
boolean should = (httpStatusCode == HttpConstants.HTTP_UNAUTHORIZED); // invalid credentials
should &= (mCredentials != null && // real credentials
shouldInvalidateAccountCredentials &= (mCredentials != null && // real credentials
!(mCredentials instanceof OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials));
// test if have all the needed to effectively invalidate ...
should &= (mAccount != null && mAccount.getSavedAccount() != null && getContext() != null);
shouldInvalidateAccountCredentials &= (mAccount != null && mAccount.getSavedAccount() != null && getContext() != null);
return should;
return shouldInvalidateAccountCredentials;
}
/**
* Invalidates credentials stored for the given account in the system {@link AccountManager} and in
* current {@link OwnCloudClientManagerFactory#getDefaultSingleton()} instance.
* current {@link SingleSessionManager#getDefaultSingleton()} instance.
* <p>
* {@link #shouldInvalidateAccountCredentials(int)} should be called first.
*
@ -451,14 +399,6 @@ public class OwnCloudClient extends HttpClient {
return true;
}
public OwnCloudClientManager getOwnCloudClientManager() {
return mOwnCloudClientManager;
}
void setOwnCloudClientManager(OwnCloudClientManager clientManager) {
mOwnCloudClientManager = clientManager;
}
public boolean followRedirects() {
return mFollowRedirects;
}
@ -466,4 +406,4 @@ public class OwnCloudClient extends HttpClient {
public void setFollowRedirects(boolean followRedirects) {
this.mFollowRedirects = followRedirects;
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -29,8 +29,6 @@ import android.net.Uri;
public class OwnCloudClientFactory {
final private static String TAG = OwnCloudClientFactory.class.getSimpleName();
/**
* Creates a OwnCloudClient to access a URL and sets the desired parameters for ownCloud
* client connections.
@ -39,8 +37,7 @@ public class OwnCloudClientFactory {
* @param context Android context where the OwnCloudClient is being created.
* @return A OwnCloudClient object ready to be used
*/
public static OwnCloudClient createOwnCloudClient(Uri uri, Context context,
boolean followRedirects) {
public static OwnCloudClient createOwnCloudClient(Uri uri, Context context, boolean followRedirects) {
OwnCloudClient client = new OwnCloudClient(uri);
client.setFollowRedirects(followRedirects);
@ -49,4 +46,4 @@ public class OwnCloudClientFactory {
return client;
}
}
}

View File

@ -1,89 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common;
public class OwnCloudClientManagerFactory {
private static Policy sDefaultPolicy = Policy.ALWAYS_NEW_CLIENT;
private static OwnCloudClientManager sDefaultSingleton;
private static String sUserAgent;
public static OwnCloudClientManager newDefaultOwnCloudClientManager() {
return newOwnCloudClientManager(sDefaultPolicy);
}
public static OwnCloudClientManager newOwnCloudClientManager(Policy policy) {
switch (policy) {
case ALWAYS_NEW_CLIENT:
return new SimpleFactoryManager();
case SINGLE_SESSION_PER_ACCOUNT_IF_SERVER_SUPPORTS_SERVER_MONITORING:
return new DynamicSessionManager();
default:
throw new IllegalArgumentException("Unknown policy");
}
}
public static OwnCloudClientManager getDefaultSingleton() {
if (sDefaultSingleton == null) {
sDefaultSingleton = newDefaultOwnCloudClientManager();
}
return sDefaultSingleton;
}
public static Policy getDefaultPolicy() {
return sDefaultPolicy;
}
public static void setDefaultPolicy(Policy policy) {
if (policy == null) {
throw new IllegalArgumentException("Default policy cannot be NULL");
}
if (defaultSingletonMustBeUpdated(policy)) {
sDefaultSingleton = null;
}
sDefaultPolicy = policy;
}
public static String getUserAgent() {
return sUserAgent;
}
public static void setUserAgent(String userAgent) {
sUserAgent = userAgent;
}
private static boolean defaultSingletonMustBeUpdated(Policy policy) {
if (sDefaultSingleton == null) {
return false;
}
return policy == Policy.ALWAYS_NEW_CLIENT && !(sDefaultSingleton instanceof SimpleFactoryManager);
}
public enum Policy {
ALWAYS_NEW_CLIENT,
SINGLE_SESSION_PER_ACCOUNT_IF_SERVER_SUPPORTS_SERVER_MONITORING
}
}

View File

@ -1,79 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.IOException;
public class SimpleFactoryManager implements OwnCloudClientManager {
private static final String TAG = SimpleFactoryManager.class.getSimpleName();
@Override
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws
OperationCanceledException, AuthenticatorException, IOException {
Log_OC.d(TAG, "getClientFor(OwnCloudAccount ... : ");
OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(
account.getBaseUri(),
context.getApplicationContext(),
true);
Log_OC.v(TAG, " new client {" +
(account.getName() != null ?
account.getName() :
AccountUtils.buildAccountName(account.getBaseUri(), "")
) + ", " + client.hashCode() + "}");
if (account.getCredentials() == null) {
account.loadCredentials(context);
}
client.setCredentials(account.getCredentials());
client.setAccount(account);
client.setContext(context);
client.setOwnCloudClientManager(this);
return client;
}
@Override
public OwnCloudClient removeClientFor(OwnCloudAccount account) {
// nothing to do - not taking care of tracking instances!
return null;
}
@Override
public void saveAllClients(Context context, String accountType) {
// nothing to do - not taking care of tracking instances!
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -30,11 +30,10 @@ import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.utils.Log_OC;
import timber.log.Timber;
import java.io.IOException;
import java.util.Iterator;
@ -42,31 +41,39 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Implementation of {@link OwnCloudClientManager}
* <p>
* TODO check multithreading safety
*
* @author David A. Velasco
* @author masensio
* @author Christian Schabesberger
* @author David González Verdugo
*/
public class SingleSessionManager implements OwnCloudClientManager {
public class SingleSessionManager {
private static final String TAG = SingleSessionManager.class.getSimpleName();
private static SingleSessionManager sDefaultSingleton;
private static String sUserAgent;
private ConcurrentMap<String, OwnCloudClient> mClientsWithKnownUsername = new ConcurrentHashMap<>();
private ConcurrentMap<String, OwnCloudClient> mClientsWithUnknownUsername = new ConcurrentHashMap<>();
@Override
public static SingleSessionManager getDefaultSingleton() {
if (sDefaultSingleton == null) {
sDefaultSingleton = new SingleSessionManager();
}
return sDefaultSingleton;
}
public static String getUserAgent() {
return sUserAgent;
}
public static void setUserAgent(String userAgent) {
sUserAgent = userAgent;
}
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws OperationCanceledException,
AuthenticatorException, IOException {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "getClientFor starting ");
}
Timber.d("getClientFor starting ");
if (account == null) {
throw new IllegalArgumentException("Cannot get an OwnCloudClient for a null account");
}
@ -84,21 +91,16 @@ public class SingleSessionManager implements OwnCloudClientManager {
if (accountName != null) {
client = mClientsWithUnknownUsername.remove(sessionName);
if (client != null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "reusing client for session " + sessionName);
}
Timber.v("reusing client for session %s", sessionName);
mClientsWithKnownUsername.put(accountName, client);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "moved client to account " + accountName);
}
Timber.v("moved client to account %s", accountName);
}
} else {
client = mClientsWithUnknownUsername.get(sessionName);
}
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "reusing client for account " + accountName);
}
Timber.v("reusing client for account %s", accountName);
reusingKnown = true;
}
@ -110,47 +112,36 @@ public class SingleSessionManager implements OwnCloudClientManager {
true); // TODO remove dependency on OwnCloudClientFactory
client.setAccount(account);
HttpClient.setContext(context);
client.setOwnCloudClientManager(this);
account.loadCredentials(context);
client.setCredentials(account.getCredentials());
if (accountName != null) {
mClientsWithKnownUsername.put(accountName, client);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "new client for account " + accountName);
}
Timber.v("new client for account %s", accountName);
} else {
mClientsWithUnknownUsername.put(sessionName, client);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "new client for session " + sessionName);
}
Timber.v("new client for session %s", sessionName);
}
} else {
if (!reusingKnown && Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "reusing client for session " + sessionName);
if (!reusingKnown) {
Timber.v("reusing client for session %s", sessionName);
}
keepCredentialsUpdated(client);
keepCookiesUpdated(context, account, client);
keepUriUpdated(account, client);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "getClientFor finishing ");
}
Timber.d("getClientFor finishing ");
return client;
}
@Override
public OwnCloudClient removeClientFor(OwnCloudAccount account) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "removeClientFor starting ");
}
public void removeClientFor(OwnCloudAccount account) {
Timber.d("removeClientFor starting ");
if (account == null) {
return null;
return;
}
OwnCloudClient client;
@ -158,31 +149,20 @@ public class SingleSessionManager implements OwnCloudClientManager {
if (accountName != null) {
client = mClientsWithKnownUsername.remove(accountName);
if (client != null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "Removed client for account " + accountName);
}
return client;
Timber.v("Removed client for account %s", accountName);
return;
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "No client tracked for account " + accountName);
}
Timber.v("No client tracked for account %s", accountName);
}
}
mClientsWithUnknownUsername.clear();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "removeClientFor finishing ");
}
return null;
Timber.d("removeClientFor finishing ");
}
@Override
public void saveAllClients(Context context, String accountType) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "Saving sessions... ");
}
Timber.d("Saving sessions... ");
Iterator<String> accountNames = mClientsWithKnownUsername.keySet().iterator();
String accountName;
@ -193,9 +173,7 @@ public class SingleSessionManager implements OwnCloudClientManager {
AccountUtils.saveClient(mClientsWithKnownUsername.get(accountName), account, context);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "All sessions saved");
}
Timber.d("All sessions saved");
}
private void keepCredentialsUpdated(OwnCloudClient reusedClient) {

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@ -36,19 +36,16 @@ import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import okhttp3.Cookie;
import timber.log.Timber;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class AccountUtils {
private static final String TAG = AccountUtils.class.getSimpleName();
/**
* Constructs full url to host and webdav resource basing on host version
*
@ -66,7 +63,7 @@ public class AccountUtils {
webDavUrlForAccount = getBaseUrlForAccount(context, account) + OwnCloudClient.WEBDAV_FILES_PATH_4_0
+ ownCloudCredentials.getUsername();
} catch (OperationCanceledException | AuthenticatorException | IOException e) {
e.printStackTrace();
Timber.e(e);
}
return webDavUrlForAccount;
@ -104,7 +101,7 @@ public class AccountUtils {
try {
username = account.name.substring(0, account.name.lastIndexOf('@'));
} catch (Exception e) {
Log_OC.e(TAG, "Couldn't get a username for the given account", e);
Timber.e(e, "Couldn't get a username for the given account");
}
return username;
}
@ -124,7 +121,7 @@ public class AccountUtils {
version = new OwnCloudVersion(versionString);
} catch (Exception e) {
Log_OC.e(TAG, "Couldn't get a the server version for an account", e);
Timber.e(e, "Couldn't get a the server version for an account");
}
return version;
}
@ -142,10 +139,9 @@ public class AccountUtils {
AccountManager am = AccountManager.get(context);
String supportsOAuth2 = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2);
boolean isOauth2 = supportsOAuth2 != null && supportsOAuth2.equals("TRUE");
boolean isOauth2 = supportsOAuth2 != null && supportsOAuth2.equals(Constants.OAUTH_SUPPORTED_TRUE);
String username = AccountUtils.getUsernameForAccount(account);
OwnCloudVersion version = new OwnCloudVersion(am.getUserData(account, Constants.KEY_OC_VERSION));
if (isOauth2) {
String accessToken = am.blockingGetAuthToken(
@ -154,7 +150,6 @@ public class AccountUtils {
false);
credentials = OwnCloudCredentialsFactory.newBearerCredentials(username, accessToken);
} else {
String password = am.blockingGetAuthToken(
account,
@ -163,8 +158,7 @@ public class AccountUtils {
credentials = OwnCloudCredentialsFactory.newBasicCredentials(
username,
password,
version.isPreemptiveAuthenticationPreferred()
password
);
}
@ -203,9 +197,8 @@ public class AccountUtils {
if (url.contains("://")) {
url = url.substring(serverBaseUrl.toString().indexOf("://") + 3);
}
String accountName = username + "@" + url;
return accountName;
return username + "@" + url;
}
public static void saveClient(OwnCloudClient client, Account savedAccount, Context context) {
@ -216,7 +209,7 @@ public class AccountUtils {
String cookiesString = client.getCookiesString();
if (!"".equals(cookiesString)) {
ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString);
Log_OC.d(TAG, "Saving Cookies: " + cookiesString);
Timber.d("Saving Cookies: %s", cookiesString);
}
}
}
@ -230,10 +223,10 @@ public class AccountUtils {
*/
public static void restoreCookies(Account account, OwnCloudClient client, Context context) {
if (account == null) {
Log_OC.d(TAG, "Cannot restore cookie for null account");
Timber.d("Cannot restore cookie for null account");
} else {
Log_OC.d(TAG, "Restoring cookies for " + account.name);
Timber.d("Restoring cookies for %s", account.name);
// Account Manager
AccountManager am = AccountManager.get(context.getApplicationContext());
@ -299,8 +292,12 @@ public class AccountUtils {
/**
* Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.
*/
// TODO Please review this constants, move them out of the library, the rest of OAuth variables are in data layer
public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";
public static final String OAUTH_SUPPORTED_TRUE = "TRUE";
/**
* OC account cookies
*/
@ -321,9 +318,6 @@ public class AccountUtils {
*/
public static final String KEY_DISPLAY_NAME = "oc_display_name";
/**
* OAuth2 refresh token
**/
public static final String KEY_OAUTH2_REFRESH_TOKEN = "oc_oauth2_refresh_token";
public static final int ACCOUNT_VERSION = 1;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -31,8 +31,6 @@ import okhttp3.internal.Util;
public class OwnCloudBasicCredentials implements OwnCloudCredentials {
private static final String TAG = OwnCloudCredentials.class.getSimpleName();
private String mUsername;
private String mPassword;

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -38,12 +38,6 @@ public class OwnCloudCredentialsFactory {
return new OwnCloudBasicCredentials(username, password);
}
public static OwnCloudCredentials newBasicCredentials(
String username, String password, boolean preemptiveMode
) {
return new OwnCloudBasicCredentials(username, password, preemptiveMode);
}
public static OwnCloudCredentials newBearerCredentials(String username, String authToken) {
return new OwnCloudBearerCredentials(username, authToken);
}

View File

@ -1,95 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
/**
* @author David A. Velasco
* @author Christian Schabesberger
*/
public class BearerCredentials {
public static final int HASH_SEED = 17;
public static final int HASH_OFFSET = 37;
private String mAccessToken;
/**
* The constructor with the bearer token
*
* @param token The bearer token
*/
public BearerCredentials(String token) {
mAccessToken = (token == null) ? "" : token;
}
/**
* Returns the access token
*
* @return The access token
*/
public String getAccessToken() {
return mAccessToken;
}
/**
* Get this object string.
*
* @return The access token
*/
public String toString() {
return mAccessToken;
}
/**
* Does a hash of the access token.
*
* @return The hash code of the access token
*/
public int hashCode() {
return HASH_SEED * HASH_OFFSET + mAccessToken.hashCode();
}
/**
* These credentials are assumed equal if accessToken is the same.
*
* @param o The other object to compare with.
* @return 'True' if the object is equivalent.
*/
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (this == o) {
return true;
}
if (this.getClass().equals(o.getClass())) {
BearerCredentials that = (BearerCredentials) o;
if (mAccessToken.equals(that.mAccessToken)) {
return true;
}
}
return false;
}
}

View File

@ -1,68 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
/**
* Constant values for OAuth 2 protocol.
* <p>
* Includes required and optional parameter NAMES used in the 'authorization code' grant type.
*/
public class OAuth2Constants {
/// Parameters to send to the Authorization Endpoint
public static final String KEY_RESPONSE_TYPE = "response_type";
public static final String KEY_REDIRECT_URI = "redirect_uri";
public static final String KEY_CLIENT_ID = "client_id";
public static final String KEY_SCOPE = "scope";
public static final String KEY_STATE = "state";
/// Additional parameters to send to the Token Endpoint
public static final String KEY_GRANT_TYPE = "grant_type";
public static final String KEY_CODE = "code";
// Used to get the Access Token using Refresh Token
public static final String OAUTH2_REFRESH_TOKEN_GRANT_TYPE = "refresh_token";
/// Parameters received in an OK response from the Token Endpoint
public static final String KEY_ACCESS_TOKEN = "access_token";
public static final String KEY_TOKEN_TYPE = "token_type";
public static final String KEY_EXPIRES_IN = "expires_in";
public static final String KEY_REFRESH_TOKEN = "refresh_token";
/// Parameters in an ERROR response
public static final String KEY_ERROR = "error";
public static final String KEY_ERROR_DESCRIPTION = "error_description";
public static final String KEY_ERROR_URI = "error_uri";
public static final String VALUE_ERROR_ACCESS_DENIED = "access_denied";
/// Extra not standard
public static final String KEY_USER_ID = "user_id";
/// Depends on oauth2 grant type
public static final String OAUTH2_RESPONSE_TYPE_CODE = "code";
}

View File

@ -1,141 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* @author Christian Schabesberger
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import org.json.JSONObject;
import java.net.URL;
import java.util.Map;
public class OAuth2GetAccessTokenOperation extends RemoteOperation<Map<String, String>> {
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
private String mGrantType;
private String mCode;
private String mClientId;
private String mClientSecret;
private String mRedirectUri;
public OAuth2GetAccessTokenOperation(
String grantType,
String code,
String clientId,
String secretId,
String redirectUri,
String accessTokenEndpointPath
) {
mClientId = clientId;
mClientSecret = secretId;
mRedirectUri = redirectUri;
mGrantType = grantType;
mCode = code;
mAccessTokenEndpointPath =
accessTokenEndpointPath != null ?
accessTokenEndpointPath :
OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH
;
mResponseParser = new OAuth2ResponseParser();
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult<Map<String, String>> result = null;
try {
final RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE, mGrantType)
.addFormDataPart(OAuth2Constants.KEY_CODE, mCode)
.addFormDataPart(OAuth2Constants.KEY_REDIRECT_URI, mRedirectUri)
.addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId)
.build();
Uri.Builder uriBuilder = client.getBaseUri().buildUpon();
uriBuilder.appendEncodedPath(mAccessTokenEndpointPath);
final PostMethod postMethod = new PostMethod(new URL(
client.getBaseUri().buildUpon()
.appendEncodedPath(mAccessTokenEndpointPath)
.build()
.toString()));
postMethod.setRequestBody(requestBody);
OwnCloudCredentials oauthCredentials =
new OwnCloudBasicCredentials(mClientId, mClientSecret);
OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials);
client.executeHttpMethod(postMethod);
switchClientCredentials(oldCredentials);
String response = postMethod.getResponseBodyAsString();
if (response != null && response.length() > 0) {
JSONObject tokenJson = new JSONObject(response);
Map<String, String> accessTokenResult =
mResponseParser.parseAccessTokenResult(tokenJson);
if (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) {
result = new RemoteOperationResult<>(ResultCode.OAUTH2_ERROR);
} else {
result = new RemoteOperationResult<>(ResultCode.OK);
result.setData(accessTokenResult);
}
} else {
result = new RemoteOperationResult<>(ResultCode.OK);
client.exhaustResponse(postMethod.getResponseBodyAsStream());
}
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
}
return result;
}
private OwnCloudCredentials switchClientCredentials(OwnCloudCredentials newCredentials) {
OwnCloudCredentials previousCredentials = getClient().getCredentials();
getClient().setCredentials(newCredentials);
return previousCredentials;
}
}

View File

@ -1,65 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
public interface OAuth2Provider {
/**
* {@link OAuth2RequestBuilder} implementation for this provider.
*
* @return {@link OAuth2RequestBuilder} implementation.
*/
OAuth2RequestBuilder getOperationBuilder();
/**
* Configuration of the client that is using this {@link OAuth2Provider}
* return Configuration of the client that is usinng this {@link OAuth2Provider}
*/
OAuth2ClientConfiguration getClientConfiguration();
/**
* Set configuration of the client that will use this {@link OAuth2Provider}
*
* @param oAuth2ClientConfiguration Configuration of the client that will use this {@link OAuth2Provider}
*/
void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration);
/**
* base URI to authorization server.
*
* @return Base URL to authorization server.
*/
String getAuthorizationServerUri();
/**
* Set base URI to authorization server.
*
* @param authorizationServerUri Set base URL to authorization server.
*/
void setAuthorizationServerUri(String authorizationServerUri);
}

View File

@ -1,121 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import java.util.HashMap;
import java.util.Map;
public class OAuth2ProvidersRegistry {
private Map<String, OAuth2Provider> mProviders = new HashMap<>();
private OAuth2Provider mDefaultProvider = null;
private OAuth2ProvidersRegistry() {
}
/**
* Singleton accesor.
*
* @return Singleton isntance of {@link OAuth2ProvidersRegistry}
*/
public static OAuth2ProvidersRegistry getInstance() {
return LazyHolder.INSTANCE;
}
/**
* Register an {@link OAuth2Provider} with the name passed as parameter.
*
* @param name Name to bind 'oAuthProvider' in the registry.
* @param oAuth2Provider An {@link OAuth2Provider} instance to keep in the registry.
* @throws IllegalArgumentException if 'name' or 'oAuthProvider' are null.
*/
public void registerProvider(String name, OAuth2Provider oAuth2Provider) {
if (name == null) {
throw new IllegalArgumentException("Name must not be NULL");
}
if (oAuth2Provider == null) {
throw new IllegalArgumentException("oAuth2Provider must not be NULL");
}
mProviders.put(name, oAuth2Provider);
if (mProviders.size() == 1) {
mDefaultProvider = oAuth2Provider;
}
}
public OAuth2Provider unregisterProvider(String name) {
OAuth2Provider unregisteredProvider = mProviders.remove(name);
if (mProviders.size() == 0) {
mDefaultProvider = null;
} else if (unregisteredProvider != null && unregisteredProvider == mDefaultProvider) {
mDefaultProvider = mProviders.values().iterator().next();
}
return unregisteredProvider;
}
/**
* Get default {@link OAuth2Provider}.
*
* @return Default provider, or NULL if there is no provider.
*/
public OAuth2Provider getProvider() {
return mDefaultProvider;
}
/**
* Get {@link OAuth2Provider} registered with the name passed as parameter.
*
* @param name Name used to register the desired {@link OAuth2Provider}
* @return {@link OAuth2Provider} registered with the name 'name'
*/
public OAuth2Provider getProvider(String name) {
return mProviders.get(name);
}
/**
* Sets the {@link OAuth2Provider} registered with the name passed as parameter as the default provider
*
* @param name Name used to register the {@link OAuth2Provider} to set as default.
* @return {@link OAuth2Provider} set as default, or NULL if no provider was registered with 'name'.
*/
public OAuth2Provider setDefaultProvider(String name) {
OAuth2Provider toDefault = mProviders.get(name);
if (toDefault != null) {
mDefaultProvider = toDefault;
}
return toDefault;
}
/**
* See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
*/
private static class LazyHolder {
private static final OAuth2ProvidersRegistry INSTANCE = new OAuth2ProvidersRegistry();
}
}

View File

@ -1,74 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.util.HashMap;
import java.util.Map;
public class OAuth2QueryParser {
private static final String TAG = OAuth2QueryParser.class.getName();
private Map<String, String> mOAuth2ParsedAuthorizationResponse;
public OAuth2QueryParser() {
mOAuth2ParsedAuthorizationResponse = new HashMap<>();
}
public Map<String, String> parse(String query) {
mOAuth2ParsedAuthorizationResponse.clear();
if (query != null) {
String[] pairs = query.split("&");
int i = 0;
String key = "";
String value;
while (pairs.length > i) {
int j = 0;
String[] part = pairs[i].split("=");
while (part.length > j) {
String p = part[j];
if (j == 0) {
key = p;
} else if (j == 1) {
value = p;
mOAuth2ParsedAuthorizationResponse.put(key, value);
}
Log_OC.v(TAG, "[" + i + "," + j + "] = " + p);
j++;
}
i++;
}
}
return mOAuth2ParsedAuthorizationResponse;
}
}

View File

@ -1,127 +0,0 @@
/**
* ownCloud Android client application
*
* @author David González Verdugo
* @author Christian Schabesberger
* <p>
* Copyright (C) 2019 ownCloud GmbH.
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
* <p>
* 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.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.common.authentication.oauth;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import org.json.JSONObject;
import java.net.URL;
import java.util.Map;
public class OAuth2RefreshAccessTokenOperation extends RemoteOperation<Map<String, String>> {
private static final String TAG = OAuth2RefreshAccessTokenOperation.class.getSimpleName();
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
private String mClientId;
private String mClientSecret;
private String mRefreshToken;
public OAuth2RefreshAccessTokenOperation(
String clientId,
String secretId,
String refreshToken,
String accessTokenEndpointPath
) {
mClientId = clientId;
mClientSecret = secretId;
mRefreshToken = refreshToken;
mAccessTokenEndpointPath =
accessTokenEndpointPath != null ?
accessTokenEndpointPath :
OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH
;
mResponseParser = new OAuth2ResponseParser();
}
@Override
protected RemoteOperationResult<Map<String, String>> run(OwnCloudClient client) {
try {
final RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE,
OAuth2GrantType.REFRESH_TOKEN.getValue())
.addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId)
.addFormDataPart(OAuth2Constants.KEY_REFRESH_TOKEN, mRefreshToken)
.build();
Uri.Builder uriBuilder = client.getBaseUri().buildUpon();
uriBuilder.appendEncodedPath(mAccessTokenEndpointPath);
final PostMethod postMethod = new PostMethod(new URL(
client.getBaseUri().buildUpon()
.appendEncodedPath(mAccessTokenEndpointPath)
.build()
.toString()));
postMethod.setRequestBody(requestBody);
final OwnCloudCredentials oauthCredentials = new OwnCloudBasicCredentials(mClientId, mClientSecret);
final OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials);
client.executeHttpMethod(postMethod);
switchClientCredentials(oldCredentials);
final String responseData = postMethod.getResponseBodyAsString();
Log_OC.d(TAG, "OAUTH2: raw response from POST TOKEN: " + responseData);
if (responseData != null && responseData.length() > 0) {
final JSONObject tokenJson = new JSONObject(responseData);
final Map<String, String> accessTokenResult =
mResponseParser.parseAccessTokenResult(tokenJson);
final RemoteOperationResult<Map<String, String>> result = new RemoteOperationResult<>(ResultCode.OK);
result.setData(accessTokenResult);
return (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null)
? new RemoteOperationResult<>(ResultCode.OAUTH2_ERROR)
: result;
} else {
return new RemoteOperationResult<>(postMethod);
}
} catch (Exception e) {
return new RemoteOperationResult<>(e);
}
}
private OwnCloudCredentials switchClientCredentials(OwnCloudCredentials newCredentials) {
OwnCloudCredentials previousCredentials = getClient().getCredentials();
getClient().setCredentials(newCredentials);
return previousCredentials;
}
}

View File

@ -1,75 +0,0 @@
/**
* ownCloud Android client application
*
* @author David A. Velasco
* <p>
* Copyright (C) 2017 ownCloud GmbH.
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
* <p>
* 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.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.common.authentication.oauth;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
class OAuth2ResponseParser {
Map<String, String> parseAccessTokenResult(JSONObject tokenJson) throws JSONException {
Map<String, String> resultTokenMap = new HashMap<>();
if (tokenJson.has(OAuth2Constants.KEY_ACCESS_TOKEN)) {
resultTokenMap.put(OAuth2Constants.KEY_ACCESS_TOKEN, tokenJson.
getString(OAuth2Constants.KEY_ACCESS_TOKEN));
}
if (tokenJson.has(OAuth2Constants.KEY_TOKEN_TYPE)) {
resultTokenMap.put(OAuth2Constants.KEY_TOKEN_TYPE, tokenJson.
getString(OAuth2Constants.KEY_TOKEN_TYPE));
}
if (tokenJson.has(OAuth2Constants.KEY_EXPIRES_IN)) {
resultTokenMap.put(OAuth2Constants.KEY_EXPIRES_IN, tokenJson.
getString(OAuth2Constants.KEY_EXPIRES_IN));
}
if (tokenJson.has(OAuth2Constants.KEY_REFRESH_TOKEN)) {
resultTokenMap.put(OAuth2Constants.KEY_REFRESH_TOKEN, tokenJson.
getString(OAuth2Constants.KEY_REFRESH_TOKEN));
}
if (tokenJson.has(OAuth2Constants.KEY_SCOPE)) {
resultTokenMap.put(OAuth2Constants.KEY_SCOPE, tokenJson.
getString(OAuth2Constants.KEY_SCOPE));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR, tokenJson.
getString(OAuth2Constants.KEY_ERROR));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR_DESCRIPTION)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR_DESCRIPTION, tokenJson.
getString(OAuth2Constants.KEY_ERROR_DESCRIPTION));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR_URI)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR_URI, tokenJson.
getString(OAuth2Constants.KEY_ERROR_URI));
}
if (tokenJson.has(OAuth2Constants.KEY_USER_ID)) { // not standard
resultTokenMap.put(OAuth2Constants.KEY_USER_ID, tokenJson.
getString(OAuth2Constants.KEY_USER_ID));
}
return resultTokenMap;
}
}

View File

@ -1,94 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import com.owncloud.android.lib.common.utils.Log_OC;
public class OwnCloudOAuth2Provider implements OAuth2Provider {
public static final String NAME = OAuth2Provider.class.getName();
public static final String ACCESS_TOKEN_ENDPOINT_PATH = "index.php/apps/oauth2/api/v1/token";
private static final String AUTHORIZATION_CODE_ENDPOINT_PATH = "index.php/apps/oauth2/authorize";
private String mAuthorizationServerUrl = "";
private String mAccessTokenEndpointPath = ACCESS_TOKEN_ENDPOINT_PATH;
private String mAuthorizationCodeEndpointPath = AUTHORIZATION_CODE_ENDPOINT_PATH;
private OAuth2ClientConfiguration mClientConfiguration;
@Override
public OAuth2RequestBuilder getOperationBuilder() {
return new OwnCloudOAuth2RequestBuilder(this);
}
@Override
public OAuth2ClientConfiguration getClientConfiguration() {
return mClientConfiguration;
}
@Override
public void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration) {
mClientConfiguration = oAuth2ClientConfiguration;
}
@Override
public String getAuthorizationServerUri() {
return mAuthorizationServerUrl;
}
@Override
public void setAuthorizationServerUri(String authorizationServerUri) {
mAuthorizationServerUrl = authorizationServerUri;
}
public String getAccessTokenEndpointPath() {
return mAccessTokenEndpointPath;
}
public void setAccessTokenEndpointPath(String accessTokenEndpointPath) {
if (accessTokenEndpointPath == null || accessTokenEndpointPath.length() <= 0) {
Log_OC.w(NAME, "Setting invalid access token endpoint path, going on with default");
mAccessTokenEndpointPath = ACCESS_TOKEN_ENDPOINT_PATH;
} else {
mAccessTokenEndpointPath = accessTokenEndpointPath;
}
}
public String getAuthorizationCodeEndpointPath() {
return mAuthorizationCodeEndpointPath;
}
public void setAuthorizationCodeEndpointPath(String authorizationCodeEndpointPath) {
if (authorizationCodeEndpointPath == null || authorizationCodeEndpointPath.length() <= 0) {
Log_OC.w(NAME, "Setting invalid authorization code endpoint path, going on with default");
mAuthorizationCodeEndpointPath = AUTHORIZATION_CODE_ENDPOINT_PATH;
} else {
mAuthorizationCodeEndpointPath = authorizationCodeEndpointPath;
}
}
}

View File

@ -1,155 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import android.net.Uri;
import com.owncloud.android.lib.common.operations.RemoteOperation;
public class OwnCloudOAuth2RequestBuilder implements OAuth2RequestBuilder {
private OwnCloudOAuth2Provider mOAuth2Provider;
private OAuthRequest mRequest;
private OAuth2GrantType mGrantType = OAuth2GrantType.AUTHORIZATION_CODE;
private String mCode;
private String mRefreshToken;
public OwnCloudOAuth2RequestBuilder(OwnCloudOAuth2Provider ownCloudOAuth2Provider) {
mOAuth2Provider = ownCloudOAuth2Provider;
}
@Override
public void setRequest(OAuthRequest request) {
mRequest = request;
}
@Override
public void setGrantType(OAuth2GrantType grantType) {
mGrantType = grantType;
}
@Override
public void setAuthorizationCode(String code) {
mCode = code;
}
@Override
public void setRefreshToken(String refreshToken) {
mRefreshToken = refreshToken;
}
@Override
public RemoteOperation buildOperation() {
if (mGrantType != OAuth2GrantType.AUTHORIZATION_CODE &&
mGrantType != OAuth2GrantType.REFRESH_TOKEN) {
throw new UnsupportedOperationException(
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " and " +
OAuth2GrantType.REFRESH_TOKEN + " are supported"
);
}
OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration();
switch (mRequest) {
case CREATE_ACCESS_TOKEN:
return new OAuth2GetAccessTokenOperation(
mGrantType.getValue(),
mCode,
clientConfiguration.getClientId(),
clientConfiguration.getClientSecret(),
clientConfiguration.getRedirectUri(),
mOAuth2Provider.getAccessTokenEndpointPath()
);
case REFRESH_ACCESS_TOKEN:
return new OAuth2RefreshAccessTokenOperation(
clientConfiguration.getClientId(),
clientConfiguration.getClientSecret(),
mRefreshToken,
mOAuth2Provider.getAccessTokenEndpointPath()
);
default:
throw new UnsupportedOperationException(
"Unsupported request"
);
}
}
@Override
public String buildUri() {
if (OAuth2GrantType.AUTHORIZATION_CODE != mGrantType) {
throw new UnsupportedOperationException(
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " is supported by this provider"
);
}
OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration();
Uri uri;
Uri.Builder uriBuilder;
switch (mRequest) {
case GET_AUTHORIZATION_CODE:
uri = Uri.parse(mOAuth2Provider.getAuthorizationServerUri());
uriBuilder = uri.buildUpon();
uriBuilder.appendEncodedPath(mOAuth2Provider.getAuthorizationCodeEndpointPath());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri()
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId()
);
uri = uriBuilder.build();
return uri.toString();
case CREATE_ACCESS_TOKEN:
uri = Uri.parse(mOAuth2Provider.getAuthorizationServerUri());
uriBuilder = uri.buildUpon();
uriBuilder.appendEncodedPath(mOAuth2Provider.getAccessTokenEndpointPath());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri()
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId()
);
uri = uriBuilder.build();
return uri.toString();
default:
throw new UnsupportedOperationException(
"Unsupported request"
);
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -26,18 +26,17 @@ package com.owncloud.android.lib.common.http;
import android.content.Context;
import android.os.Build;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.SingleSessionManager;
import com.owncloud.android.lib.common.http.interceptors.HttpInterceptor;
import com.owncloud.android.lib.common.http.interceptors.RequestHeaderInterceptor;
import com.owncloud.android.lib.common.network.AdvancedX509TrustManager;
import com.owncloud.android.lib.common.network.NetworkUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import timber.log.Timber;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
@ -58,8 +57,6 @@ import java.util.concurrent.TimeUnit;
* @author David González Verdugo
*/
public class HttpClient {
private static final String TAG = HttpClient.class.toString();
private static OkHttpClient sOkHttpClient;
private static HttpInterceptor sOkHttpInterceptor;
private static Context sContext;
@ -77,10 +74,10 @@ public class HttpClient {
sslContext = SSLContext.getInstance("TLSv1.2");
} catch (NoSuchAlgorithmException tlsv12Exception) {
try {
Log_OC.w(TAG, "TLSv1.2 is not supported in this device; falling through TLSv1.1");
Timber.w("TLSv1.2 is not supported in this device; falling through TLSv1.1");
sslContext = SSLContext.getInstance("TLSv1.1");
} catch (NoSuchAlgorithmException tlsv11Exception) {
Log_OC.w(TAG, "TLSv1.1 is not supported in this device; falling through TLSv1.0");
Timber.w("TLSv1.1 is not supported in this device; falling through TLSv1.0");
sslContext = SSLContext.getInstance("TLSv1");
// should be available in any device; see reference of supported protocols in
// http://developer.android.com/reference/javax/net/ssl/SSLSocket.html
@ -91,22 +88,15 @@ public class HttpClient {
SSLSocketFactory sslSocketFactory;
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
// TLS v1.2 is disabled by default in API 19, use custom SSLSocketFactory to enable it
sslSocketFactory = new TLSSocketFactory(sslContext.getSocketFactory());
} else {
sslSocketFactory = sslContext.getSocketFactory();
}
sslSocketFactory = sslContext.getSocketFactory();
// Automatic cookie handling, NOT PERSISTENT
CookieJar cookieJar = new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
// Avoid duplicated cookies
Set<Cookie> nonDuplicatedCookiesSet = new HashSet<>();
nonDuplicatedCookiesSet.addAll(cookies);
List<Cookie> nonDuplicatedCookiesList = new ArrayList<>();
nonDuplicatedCookiesList.addAll(nonDuplicatedCookiesSet);
Set<Cookie> nonDuplicatedCookiesSet = new HashSet<>(cookies);
List<Cookie> nonDuplicatedCookiesList = new ArrayList<>(nonDuplicatedCookiesSet);
sCookieStore.put(url.host(), nonDuplicatedCookiesList);
}
@ -133,7 +123,7 @@ public class HttpClient {
sOkHttpClient = clientBuilder.build();
} catch (Exception e) {
Log_OC.e(TAG, "Could not setup SSL system.", e);
Timber.e(e, "Could not setup SSL system.");
}
}
return sOkHttpClient;
@ -142,7 +132,7 @@ public class HttpClient {
private static HttpInterceptor getOkHttpInterceptor() {
if (sOkHttpInterceptor == null) {
sOkHttpInterceptor = new HttpInterceptor();
addHeaderForAllRequests(HttpConstants.USER_AGENT_HEADER, OwnCloudClientManagerFactory.getUserAgent());
addHeaderForAllRequests(HttpConstants.USER_AGENT_HEADER, SingleSessionManager.getUserAgent());
addHeaderForAllRequests(HttpConstants.PARAM_SINGLE_COOKIE_HEADER, "true");
addHeaderForAllRequests(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY);
}
@ -158,7 +148,7 @@ public class HttpClient {
public static void addHeaderForAllRequests(String headerName, String headerValue) {
HttpInterceptor httpInterceptor = getOkHttpInterceptor();
if(getOkHttpInterceptor() != null) {
if (getOkHttpInterceptor() != null) {
httpInterceptor.addRequestInterceptor(
new RequestHeaderInterceptor(headerName, headerValue)
);
@ -177,22 +167,6 @@ public class HttpClient {
sContext = context;
}
public void disableAutomaticCookiesHandling() {
OkHttpClient.Builder clientBuilder = getOkHttpClient().newBuilder();
clientBuilder.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
// DO NOTHING
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
return new ArrayList<>();
}
});
sOkHttpClient = clientBuilder.build();
}
public List<Cookie> getCookiesFromUrl(HttpUrl httpUrl) {
return sCookieStore.get(httpUrl.host());
}
@ -200,4 +174,4 @@ public class HttpClient {
public void clearCookies() {
sCookieStore.clear();
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -78,14 +78,18 @@ public abstract class DavMethod extends HttpBaseMethod {
.build();
} else if (mResponse != null) {
ResponseBody responseBody = ResponseBody.create(
mResponse.body().contentType(),
httpException.getResponseBody()
);
// The check below should be included in okhttp library, method ResponseBody.create(
// TODO check most recent versions of okhttp to see if this is already fixed and try to update if so
if (mResponse.body().contentType() != null) {
ResponseBody responseBody = ResponseBody.create(
mResponse.body().contentType(),
httpException.getResponseBody()
);
mResponse = mResponse.newBuilder()
.body(responseBody)
.build();
mResponse = mResponse.newBuilder()
.body(responseBody)
.build();
}
}
return httpException.getCode();

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -24,7 +24,7 @@
package com.owncloud.android.lib.common.network;
import com.owncloud.android.lib.common.utils.Log_OC;
import timber.log.Timber;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
@ -43,11 +43,8 @@ import java.security.cert.X509Certificate;
*/
public class AdvancedX509TrustManager implements X509TrustManager {
private static final String TAG = AdvancedX509TrustManager.class.getSimpleName();
private X509TrustManager mStandardTrustManager;
private KeyStore mKnownServersKeyStore;
/**
* Constructor for AdvancedX509TrustManager
*
@ -136,7 +133,7 @@ public class AdvancedX509TrustManager implements X509TrustManager {
try {
return (mKnownServersKeyStore.getCertificateAlias(cert) != null);
} catch (KeyStoreException e) {
Log_OC.d(TAG, "Fail while checking certificate in the known-servers store");
Timber.e(e, "Fail while checking certificate in the known-servers store");
return false;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,11 +24,9 @@
package com.owncloud.android.lib.common.network;
import android.util.Log;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.MediaType;
import okio.BufferedSink;
import timber.log.Timber;
import java.io.File;
import java.io.IOException;
@ -43,9 +41,6 @@ import java.util.Iterator;
*/
public class ChunkFromFileRequestBody extends FileRequestBody {
private static final String TAG = ChunkFromFileRequestBody.class.getSimpleName();
//private final File mFile;
private final FileChannel mChannel;
private final long mChunkSize;
private long mOffset;
@ -89,17 +84,17 @@ public class ChunkFromFileRequestBody extends FileRequestBody {
long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
while (mChannel.position() < maxCount) {
Log_OC.d(TAG, "Sink buffer size: " + sink.buffer().size());
Timber.v("Sink buffer size: %s", sink.buffer().size());
readCount = mChannel.read(mBuffer);
Log_OC.d(TAG, "Read " + readCount + " bytes from file channel to " + mBuffer.toString());
Timber.v("Read " + readCount + " bytes from file channel to " + mBuffer.toString());
sink.buffer().write(mBuffer.array(), 0, readCount);
sink.flush();
Log_OC.d(TAG, "Write " + readCount + " bytes to sink buffer with size " + sink.buffer().size());
Timber.v("Write " + readCount + " bytes to sink buffer with size " + sink.buffer().size());
mBuffer.clear();
if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
@ -113,19 +108,10 @@ public class ChunkFromFileRequestBody extends FileRequestBody {
}
}
Log.d(TAG, "Chunk with size " + mChunkSize + " written in request body");
Timber.v("Chunk with size " + mChunkSize + " written in request body");
} catch (Exception exception) {
Log.e(TAG, exception.toString());
// // any read problem will be handled as if the file is not there
// if (io instanceof FileNotFoundException) {
// throw io;
// } else {
// FileNotFoundException fnf = new FileNotFoundException("Exception reading source file");
// fnf.initCause(io);
// throw fnf;
// }
Timber.e(exception);
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,13 +24,12 @@
package com.owncloud.android.lib.common.network;
import android.util.Log;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
import timber.log.Timber;
import java.io.File;
import java.util.Collection;
@ -45,11 +44,9 @@ import java.util.Set;
*/
public class FileRequestBody extends RequestBody implements ProgressiveDataTransferer {
private static final String TAG = FileRequestBody.class.getSimpleName();
protected File mFile;
private MediaType mContentType;
Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>();
final Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>();
public FileRequestBody(File file, MediaType contentType) {
mFile = file;
@ -87,11 +84,10 @@ public class FileRequestBody extends RequestBody implements ProgressiveDataTrans
}
}
Log.d(TAG, "File with name " + mFile.getName() + " and size " + mFile.length() +
" written in request body");
Timber.d("File with name " + mFile.getName() + " and size " + mFile.length() + " written in request body");
} catch (Exception e) {
e.printStackTrace();
Timber.e(e);
}
}

View File

@ -26,8 +26,7 @@ package com.owncloud.android.lib.common.network;
import android.content.Context;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import timber.log.Timber;
import java.io.File;
import java.io.FileInputStream;
@ -42,25 +41,6 @@ import java.security.cert.CertificateException;
public class NetworkUtils {
/**
* Default timeout for waiting data from the server
*/
public static final int DEFAULT_DATA_TIMEOUT = 60000;
/**
* Default timeout for establishing a connection
*/
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
/**
* Standard name for protocol TLS version 1.2 in Java Secure Socket Extension (JSSE) API
*/
public static final String PROTOCOL_TLSv1_2 = "TLSv1.2";
/**
* Standard name for protocol TLS version 1.0 in JSSE API
*/
public static final String PROTOCOL_TLSv1_0 = "TLSv1";
final private static String TAG = NetworkUtils.class.getSimpleName();
private static X509HostnameVerifier mHostnameVerifier = null;
private static String LOCAL_TRUSTSTORE_FILENAME = "knownServers.bks";
private static String LOCAL_TRUSTSTORE_PASSWORD = "password";
@ -88,7 +68,7 @@ public class NetworkUtils {
//mKnownServersStore = KeyStore.getInstance("BKS");
mKnownServersStore = KeyStore.getInstance(KeyStore.getDefaultType());
File localTrustStoreFile = new File(context.getFilesDir(), LOCAL_TRUSTSTORE_FILENAME);
Log_OC.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath());
Timber.d("Searching known-servers store at %s", localTrustStoreFile.getAbsolutePath());
if (localTrustStoreFile.exists()) {
InputStream in = new FileInputStream(localTrustStoreFile);
try {
@ -109,22 +89,9 @@ public class NetworkUtils {
KeyStore knownServers = getKnownServersStore(context);
knownServers.setCertificateEntry(Integer.toString(cert.hashCode()), cert);
FileOutputStream fos = null;
try {
fos = context.openFileOutput(LOCAL_TRUSTSTORE_FILENAME, Context.MODE_PRIVATE);
try (FileOutputStream fos = context.openFileOutput(LOCAL_TRUSTSTORE_FILENAME, Context.MODE_PRIVATE)) {
knownServers.store(fos, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
} finally {
fos.close();
}
}
public static boolean isCertInKnownServersStore(Certificate cert, Context context)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore knownServers = getKnownServersStore(context);
Log_OC.d(TAG, "Certificate - HashCode: " + cert.hashCode() + " "
+ Boolean.toString(knownServers.isCertificateEntry(Integer.toString(cert.hashCode()))));
return knownServers.isCertificateEntry(Integer.toString(cert.hashCode()));
}
}

View File

@ -1,145 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import com.owncloud.android.lib.common.utils.Log_OC;
import javax.net.ssl.SSLSocket;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicReference;
/**
* Enables the support of Server Name Indication if existing
* in the underlying network implementation.
* <p>
* Build as a singleton.
*
* @author David A. Velasco
*/
public class ServerNameIndicator {
private static final String TAG = ServerNameIndicator.class.getSimpleName();
private static final AtomicReference<ServerNameIndicator> mSingleInstance = new AtomicReference<ServerNameIndicator>();
private static final String METHOD_NAME = "setHostname";
private final WeakReference<Class<?>> mSSLSocketClassRef;
private final WeakReference<Method> mSetHostnameMethodRef;
/**
* Private constructor, class is a singleton.
*
* @param sslSocketClass Underlying implementation class of {@link SSLSocket} used to connect with the server.
* @param setHostnameMethod Name of the method to call to enable the SNI support.
*/
private ServerNameIndicator(Class<?> sslSocketClass, Method setHostnameMethod) {
mSSLSocketClassRef = new WeakReference<Class<?>>(sslSocketClass);
mSetHostnameMethodRef = (setHostnameMethod == null) ? null : new WeakReference<Method>(setHostnameMethod);
}
/**
* Calls the {@code #setHostname(String)} method of the underlying implementation
* of {@link SSLSocket} if exists.
* <p>
* Creates and initializes the single instance of the class when needed
*
* @param hostname The name of the server host of interest.
* @param sslSocket Client socket to connect with the server.
*/
public static void setServerNameIndication(String hostname, SSLSocket sslSocket) {
final Method setHostnameMethod = getMethod(sslSocket);
if (setHostnameMethod != null) {
try {
setHostnameMethod.invoke(sslSocket, hostname);
Log_OC.i(TAG, "SNI done, hostname: " + hostname);
} catch (IllegalArgumentException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
} catch (IllegalAccessException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
} catch (InvocationTargetException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
}
} else {
Log_OC.i(TAG, "SNI not supported");
}
}
/**
* Gets the method to invoke trying to minimize the effective
* application of reflection.
*
* @param sslSocket Instance of the SSL socket to use in connection with server.
* @return Method to call to indicate the server name of interest to the server.
*/
private static Method getMethod(SSLSocket sslSocket) {
final Class<?> sslSocketClass = sslSocket.getClass();
final ServerNameIndicator instance = mSingleInstance.get();
if (instance == null) {
return initFrom(sslSocketClass);
} else if (instance.mSSLSocketClassRef.get() != sslSocketClass) {
// the underlying class changed
return initFrom(sslSocketClass);
} else if (instance.mSetHostnameMethodRef == null) {
// SNI not supported
return null;
} else {
final Method cachedSetHostnameMethod = instance.mSetHostnameMethodRef.get();
return (cachedSetHostnameMethod == null) ? initFrom(sslSocketClass) : cachedSetHostnameMethod;
}
}
/**
* Singleton initializer.
* <p>
* Uses reflection to extract and 'cache' the method to invoke to indicate the desited host name to the server side.
*
* @param sslSocketClass Underlying class providing the implementation of {@link SSLSocket}.
* @return Method to call to indicate the server name of interest to the server.
*/
private static Method initFrom(Class<?> sslSocketClass) {
Log_OC.i(TAG, "SSLSocket implementation: " + sslSocketClass.getCanonicalName());
Method setHostnameMethod = null;
try {
setHostnameMethod = sslSocketClass.getMethod(METHOD_NAME, String.class);
} catch (SecurityException e) {
Log_OC.e(TAG, "Could not access to SSLSocket#setHostname(String) method ", e);
} catch (NoSuchMethodException e) {
Log_OC.i(TAG, "Could not find SSLSocket#setHostname(String) method - SNI not supported");
}
mSingleInstance.set(new ServerNameIndicator(sslSocketClass, setHostnameMethod));
return setHostnameMethod;
}
}

View File

@ -34,11 +34,12 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class WebdavUtils {
public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat(
"dd.MM.yyyy hh:mm");
import static com.owncloud.android.lib.common.OwnCloudClient.WEBDAV_FILES_PATH_4_0;
import static com.owncloud.android.lib.common.OwnCloudClient.WEBDAV_PATH_4_0_AND_LATER;
private static final SimpleDateFormat DATETIME_FORMATS[] = {
public class WebdavUtils {
private static final SimpleDateFormat[] DATETIME_FORMATS = {
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US),
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US),
@ -50,11 +51,11 @@ public class WebdavUtils {
};
public static Date parseResponseDate(String date) {
Date returnDate = null;
SimpleDateFormat format = null;
for (int i = 0; i < DATETIME_FORMATS.length; ++i) {
Date returnDate;
SimpleDateFormat format;
for (SimpleDateFormat datetimeFormat : DATETIME_FORMATS) {
try {
format = DATETIME_FORMATS[i];
format = datetimeFormat;
synchronized (format) {
returnDate = format.parse(date);
}
@ -82,23 +83,6 @@ public class WebdavUtils {
return encodedPath;
}
/**
* @param rawEtag
* @return
*/
public static String parseEtag(String rawEtag) {
if (rawEtag == null || rawEtag.length() == 0) {
return "";
}
if (rawEtag.endsWith("-gzip")) {
rawEtag = rawEtag.substring(0, rawEtag.length() - 5);
}
if (rawEtag.length() >= 2 && rawEtag.startsWith("\"") && rawEtag.endsWith("\"")) {
rawEtag = rawEtag.substring(1, rawEtag.length() - 1);
}
return rawEtag;
}
/**
* @param httpBaseMethod from which to get the etag
* @return etag from response
@ -120,4 +104,17 @@ public class WebdavUtils {
}
return result;
}
public static String normalizeProtocolPrefix(String url, boolean isSslConn) {
if (!url.toLowerCase().startsWith("http://") &&
!url.toLowerCase().startsWith("https://")) {
if (isSslConn) {
return "https://" + url;
} else {
return "http://" + url;
}
}
return url;
}
}

View File

@ -1,167 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicReference;
/**
* Enforces, if possible, a write timeout for a socket.
* <p>
* Built as a singleton.
* <p>
* Tries to hit something like this:
* https://android.googlesource.com/platform/external/conscrypt/+/lollipop-release/src/main/java/org/conscrypt/OpenSSLSocketImpl.java#1005
* <p>
* Minimizes the chances of getting stalled in PUT/POST request if the network interface is lost while
* writing the entity into the outwards sockect.
* <p>
* It happens. See https://github.com/owncloud/android/issues/1684#issuecomment-295306015
*
* @author David A. Velasco
*/
public class WriteTimeoutEnforcer {
private static final String TAG = WriteTimeoutEnforcer.class.getSimpleName();
private static final AtomicReference<WriteTimeoutEnforcer> mSingleInstance = new AtomicReference<>();
private static final String METHOD_NAME = "setSoWriteTimeout";
private final WeakReference<Class<?>> mSocketClassRef;
private final WeakReference<Method> mSetSoWriteTimeoutMethodRef;
/**
* Private constructor, class is a singleton.
*
* @param socketClass Underlying implementation class of {@link Socket} used to connect
* with the server.
* @param setSoWriteTimeoutMethod Name of the method to call to set a write timeout in the socket.
*/
private WriteTimeoutEnforcer(Class<?> socketClass, Method setSoWriteTimeoutMethod) {
mSocketClassRef = new WeakReference<Class<?>>(socketClass);
mSetSoWriteTimeoutMethodRef =
(setSoWriteTimeoutMethod == null) ?
null :
new WeakReference<>(setSoWriteTimeoutMethod)
;
}
/**
* Calls the {@code #setSoWrite(int)} method of the underlying implementation
* of {@link Socket} if exists.
* <p>
* Creates and initializes the single instance of the class when needed
*
* @param writeTimeoutMilliseconds Write timeout to set, in milliseconds.
* @param socket Client socket to connect with the server.
*/
public static void setSoWriteTimeout(int writeTimeoutMilliseconds, Socket socket) {
final Method setSoWriteTimeoutMethod = getMethod(socket);
if (setSoWriteTimeoutMethod != null) {
try {
setSoWriteTimeoutMethod.invoke(socket, writeTimeoutMilliseconds);
Log_OC.i(
TAG,
"Write timeout set in socket, writeTimeoutMilliseconds: "
+ writeTimeoutMilliseconds
);
} catch (IllegalArgumentException e) {
Log_OC.e(TAG, "Call to (SocketImpl)#setSoWriteTimeout(int) failed ", e);
} catch (IllegalAccessException e) {
Log_OC.e(TAG, "Call to (SocketImpl)#setSoWriteTimeout(int) failed ", e);
} catch (InvocationTargetException e) {
Log_OC.e(TAG, "Call to (SocketImpl)#setSoWriteTimeout(int) failed ", e);
}
} else {
Log_OC.i(TAG, "Write timeout for socket not supported");
}
}
/**
* Gets the method to invoke trying to minimize the cost of reflection reusing objects cached
* in static members.
*
* @param socket Instance of the socket to use in connection with server.
* @return Method to call to set a write timeout in the socket.
*/
private static Method getMethod(Socket socket) {
final Class<?> socketClass = socket.getClass();
final WriteTimeoutEnforcer instance = mSingleInstance.get();
if (instance == null) {
return initFrom(socketClass);
} else if (instance.mSocketClassRef.get() != socketClass) {
// the underlying class changed
return initFrom(socketClass);
} else if (instance.mSetSoWriteTimeoutMethodRef == null) {
// method not supported
return null;
} else {
final Method cachedSetSoWriteTimeoutMethod = instance.mSetSoWriteTimeoutMethodRef.get();
return (cachedSetSoWriteTimeoutMethod == null) ?
initFrom(socketClass) :
cachedSetSoWriteTimeoutMethod
;
}
}
/**
* Singleton initializer.
* <p>
* Uses reflection to extract and 'cache' the method to invoke to set a write timouet in a socket.
*
* @param socketClass Underlying class providing the implementation of {@link Socket}.
* @return Method to call to set a write timeout in the socket.
*/
private static Method initFrom(Class<?> socketClass) {
Log_OC.i(TAG, "Socket implementation: " + socketClass.getCanonicalName());
Method setSoWriteTimeoutMethod = null;
try {
setSoWriteTimeoutMethod = socketClass.getMethod(METHOD_NAME, int.class);
} catch (SecurityException e) {
Log_OC.e(TAG, "Could not access to (SocketImpl)#setSoWriteTimeout(int) method ", e);
} catch (NoSuchMethodException e) {
Log_OC.i(
TAG,
"Could not find (SocketImpl)#setSoWriteTimeout(int) method - write timeout not supported"
);
}
mSingleInstance.set(new WriteTimeoutEnforcer(socketClass, setSoWriteTimeoutMethod));
return setSoWriteTimeoutMethod;
}
}

View File

@ -9,13 +9,14 @@ import android.os.Handler;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.SingleSessionManager;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.OkHttpClient;
import timber.log.Timber;
import java.io.IOException;
@SuppressWarnings("WeakerAccess")
public abstract class RemoteOperation<T> implements Runnable {
/**
@ -26,7 +27,6 @@ public abstract class RemoteOperation<T> implements Runnable {
* OCS API header value
*/
public static final String OCS_API_HEADER_VALUE = "true";
private static final String TAG = RemoteOperation.class.getSimpleName();
/**
* ownCloud account in the remote ownCloud server to operate
*/
@ -40,22 +40,22 @@ public abstract class RemoteOperation<T> implements Runnable {
/**
* Object to interact with the remote server
*/
protected OwnCloudClient mClient = null;
private OwnCloudClient mClient = null;
/**
* Object to interact with the remote server
*/
protected OkHttpClient mHttpClient = null;
private OkHttpClient mHttpClient = null;
/**
* Callback object to notify about the execution of the remote operation
*/
protected OnRemoteOperationListener mListener = null;
private OnRemoteOperationListener mListener = null;
/**
* Handler to the thread where mListener methods will be called
*/
protected Handler mListenerHandler = null;
private Handler mListenerHandler = null;
/**
* Asynchronously executes the remote operation
@ -75,12 +75,10 @@ public abstract class RemoteOperation<T> implements Runnable {
OnRemoteOperationListener listener, Handler listenerHandler) {
if (account == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation with a NULL Account");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
}
if (context == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation with a NULL Context");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
}
// mAccount and mContext in the runnerThread to create below
mAccount = account;
@ -106,11 +104,9 @@ public abstract class RemoteOperation<T> implements Runnable {
* the listener objects must be called.
* @return Thread were the remote operation is executed.
*/
public Thread execute(OwnCloudClient client,
OnRemoteOperationListener listener, Handler listenerHandler) {
public Thread execute(OwnCloudClient client, OnRemoteOperationListener listener, Handler listenerHandler) {
if (client == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation with a NULL OwnCloudClient");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL OwnCloudClient");
}
mClient = client;
if (client.getAccount() != null) {
@ -120,8 +116,7 @@ public abstract class RemoteOperation<T> implements Runnable {
if (listener == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation asynchronously " +
"without a listener to notiy the result");
("Trying to execute a remote operation asynchronously without a listener to notify the result");
}
mListener = listener;
@ -134,12 +129,12 @@ public abstract class RemoteOperation<T> implements Runnable {
return runnerThread;
}
protected void grantOwnCloudClient() throws
private void grantOwnCloudClient() throws
AccountUtils.AccountNotFoundException, OperationCanceledException, AuthenticatorException, IOException {
if (mClient == null) {
if (mAccount != null && mContext != null) {
OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext);
mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
mClient = SingleSessionManager.getDefaultSingleton().
getClientFor(ocAccount, mContext);
} else {
throw new IllegalStateException("Trying to run a remote operation " +
@ -177,12 +172,10 @@ public abstract class RemoteOperation<T> implements Runnable {
*/
public RemoteOperationResult<T> execute(Account account, Context context) {
if (account == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"Account");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
}
if (context == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"Context");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
}
mAccount = account;
mContext = context.getApplicationContext();
@ -192,7 +185,7 @@ public abstract class RemoteOperation<T> implements Runnable {
/**
* Synchronously executes the remote operation
*
* <p>
* Do not call this method from the main thread.
*
* @param client Client object to reach an ownCloud server during the execution of
@ -201,8 +194,7 @@ public abstract class RemoteOperation<T> implements Runnable {
*/
public RemoteOperationResult<T> execute(OwnCloudClient client) {
if (client == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"OwnCloudClient");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL OwnCloudClient");
}
mClient = client;
if (client.getAccount() != null) {
@ -224,8 +216,7 @@ public abstract class RemoteOperation<T> implements Runnable {
*/
public RemoteOperationResult<T> execute(OkHttpClient client, Context context) {
if (client == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"OwnCloudClient");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL OwnCloudClient");
}
mHttpClient = client;
mContext = context;
@ -236,9 +227,7 @@ public abstract class RemoteOperation<T> implements Runnable {
/**
* Run operation for asynchronous or synchronous 'onExecute' method.
* <p>
* Considers and performs silent refresh of account credentials if possible, and if
* {@link RemoteOperation#setSilentRefreshOfAccountCredentials(boolean)} was called with
* parameter 'true' before the execution.
* Considers and performs silent refresh of account credentials if possible
*
* @return Remote operation result
*/
@ -251,7 +240,7 @@ public abstract class RemoteOperation<T> implements Runnable {
result = run(mClient);
} catch (AccountsException | IOException e) {
Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e);
Timber.e(e, "Error while trying to access to %s", mAccount.name);
result = new RemoteOperationResult<>(e);
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -33,9 +33,9 @@ import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.Headers;
import org.json.JSONException;
import timber.log.Timber;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
@ -60,14 +60,13 @@ public class RemoteOperationResult<T>
*/
private static final long serialVersionUID = 4968939884332372230L;
private static final String TAG = RemoteOperationResult.class.getSimpleName();
private boolean mSuccess = false;
private int mHttpCode = -1;
private String mHttpPhrase = null;
private Exception mException = null;
private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
private String mRedirectedLocation;
private ArrayList<String> mAuthenticate = new ArrayList<>();
private List<String> mAuthenticate = new ArrayList<>();
private String mLastPermanentLocation = null;
private T mData = null;
@ -189,10 +188,14 @@ public class RemoteOperationResult<T>
try {
if (xmlParser.parseXMLResponse(is)) {
mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER;
} else {
parseErrorMessageAndSetCode(
httpMethod.getResponseBodyAsString(),
ResultCode.SPECIFIC_BAD_REQUEST
);
}
} catch (Exception e) {
Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage());
Timber.w("Error reading exception from server: %s", e.getMessage());
// mCode stays as set in this(success, httpCode, headers)
}
}
@ -250,7 +253,9 @@ public class RemoteOperationResult<T>
continue;
}
if ("www-authenticate".equals(header.getKey().toLowerCase())) {
mAuthenticate.add(header.getValue().get(0).toLowerCase());
for (String value: header.getValue()) {
mAuthenticate.add(value.toLowerCase());
}
}
}
}
@ -293,11 +298,7 @@ public class RemoteOperationResult<T>
break;
default:
mCode = ResultCode.UNHANDLED_HTTP_CODE; // UNKNOWN ERROR
Log_OC.d(TAG,
"RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
mHttpCode + " " + mHttpPhrase
);
Timber.d("RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + mHttpCode + " " + mHttpPhrase);
}
}
}
@ -308,21 +309,19 @@ public class RemoteOperationResult<T>
*
* @param bodyResponse okHttp response body
* @param resultCode our own custom result code
* @throws IOException
*/
private void parseErrorMessageAndSetCode(String bodyResponse, ResultCode resultCode) {
if (bodyResponse != null && bodyResponse.length() > 0) {
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
ErrorMessageParser xmlParser = new ErrorMessageParser();
try {
String errorMessage = xmlParser.parseXMLResponse(is);
if (errorMessage != "" && errorMessage != null) {
if (!errorMessage.equals("")) {
mCode = resultCode;
mHttpPhrase = errorMessage;
}
} catch (Exception e) {
Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage());
Timber.w("Error reading exception from server: %s", e.getMessage());
// mCode stays as set in this(success, httpCode, headers)
}
}
@ -376,7 +375,7 @@ public class RemoteOperationResult<T>
previousCause = cause;
cause = cause.getCause();
}
if (cause != null && cause instanceof CertificateCombinedException) {
if (cause instanceof CertificateCombinedException) {
result = (CertificateCombinedException) cause;
}
return result;
@ -497,7 +496,7 @@ public class RemoteOperationResult<T>
return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://")));
}
public ArrayList<String> getAuthenticateHeaders() {
public List<String> getAuthenticateHeaders() {
return mAuthenticate;
}
@ -572,6 +571,7 @@ public class RemoteOperationResult<T>
SERVICE_UNAVAILABLE,
SPECIFIC_SERVICE_UNAVAILABLE,
SPECIFIC_UNSUPPORTED_MEDIA_TYPE,
SPECIFIC_METHOD_NOT_ALLOWED
SPECIFIC_METHOD_NOT_ALLOWED,
SPECIFIC_BAD_REQUEST
}
}

View File

@ -1,87 +0,0 @@
package com.owncloud.android.lib.common.utils;
import timber.log.Timber;
import java.io.File;
public class Log_OC {
private static String mOwncloudDataFolderLog;
public static void setLogDataFolder(String logFolder) {
mOwncloudDataFolderLog = logFolder;
}
public static void i(String message) {
Timber.i(message);
}
public static void d(String message) {
Timber.d(message);
}
public static void d(String message, Exception e) {
Timber.d(e, message);
}
public static void e(String message) {
Timber.e(message);
}
public static void e(String message, Throwable e) {
Timber.e(e, message);
}
public static void v(String message) {
Timber.v(message);
}
public static void w(String message) {
Timber.w(message);
}
@Deprecated
public static void i(String tag, String message) {
Timber.i(message);
}
@Deprecated
public static void d(String TAG, String message) {
Timber.d(message);
}
@Deprecated
public static void d(String TAG, String message, Exception e) {
Timber.d(e, message);
}
@Deprecated
public static void e(String TAG, String message) {
Timber.e(message);
}
@Deprecated
public static void e(String TAG, String message, Throwable e) {
Timber.e(e, message);
}
@Deprecated
public static void v(String TAG, String message) {
Timber.v(message);
}
@Deprecated
public static void w(String TAG, String message) {
Timber.w(message);
}
public static void startLogging(String storagePath) {
LoggingHelper.INSTANCE.startLogging(
new File(storagePath+ File.separator + mOwncloudDataFolderLog), mOwncloudDataFolderLog);
}
public static void stopLogging() {
LoggingHelper.INSTANCE.stopLogging();
}
}

View File

@ -13,7 +13,7 @@ object LoggingHelper {
}
if (!directory.exists())
directory.mkdirs()
Timber.plant(FileLoggingTree(directory, filename = storagePath, delegator = Log_OC::class.java))
Timber.plant(FileLoggingTree(directory, filename = storagePath))
}
fun stopLogging() {

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -3,7 +3,7 @@
*
* @author David González Verdugo
*
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,

View File

@ -0,0 +1,115 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod
import com.owncloud.android.lib.common.network.RedirectionPath
import com.owncloud.android.lib.common.network.WebdavUtils
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
import timber.log.Timber
import java.net.URL
import java.util.concurrent.TimeUnit
/**
* Operation to check the existence of a path in a remote server.
*
* @author David A. Velasco
* @author David González Verdugo
* @author Abel García de Prada
*
* @param remotePath Path to append to the URL owned by the client instance.
* @param isUserLogged When `true`, the username won't be added at the end of the PROPFIND url since is not
* needed to check user credentials
*/
class CheckPathExistenceRemoteOperation(
val remotePath: String? = "",
val isUserLogged: Boolean
) : RemoteOperation<Boolean>() {
/**
* Gets the sequence of redirections followed during the execution of the operation.
*
* @return Sequence of redirections followed, if any, or NULL if the operation was not executed.
*/
var redirectionPath: RedirectionPath? = null
private set
override fun run(client: OwnCloudClient): RemoteOperationResult<Boolean> {
val previousFollowRedirects = client.followRedirects()
return try {
val stringUrl =
if (isUserLogged) client.baseFilesWebDavUri.toString()
else client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(remotePath)
val propFindMethod = PropfindMethod(URL(stringUrl), 0, DavUtils.getAllPropset()).apply {
setReadTimeout(TIMEOUT.toLong(), TimeUnit.SECONDS)
setConnectionTimeout(TIMEOUT.toLong(), TimeUnit.SECONDS)
}
client.setFollowRedirects(false)
var status = client.executeHttpMethod(propFindMethod)
if (previousFollowRedirects) {
redirectionPath = client.followRedirection(propFindMethod)
status = redirectionPath?.lastStatus!!
}
/* PROPFIND method
* 404 NOT FOUND: path doesn't exist,
* 207 MULTI_STATUS: path exists.
*/
Timber.d(
"Existence check for $stringUrl finished with HTTP status $status${if (!isSuccess(status)) "(FAIL)" else ""}"
)
if (isSuccess(status)) RemoteOperationResult<Boolean>(ResultCode.OK).apply { data = true }
else RemoteOperationResult<Boolean>(propFindMethod).apply { data = false }
} catch (e: Exception) {
val result = RemoteOperationResult<Boolean>(e)
Timber.e(
e,
"Existence check for ${client.userFilesWebDavUri}${WebdavUtils.encodePath(remotePath)} : ${result.logMessage}"
)
result
} finally {
client.setFollowRedirects(previousFollowRedirects)
}
}
/**
* @return 'True' if the operation was executed and at least one redirection was followed.
*/
fun wasRedirected() = redirectionPath?.redirectionsCount ?: 0 > 0
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_MULTI_STATUS
companion object {
/**
* Maximum time to wait for a response from the server in milliseconds.
*/
private const val TIMEOUT = 10000
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,8 +24,6 @@
package com.owncloud.android.lib.resources.files;
import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.CopyMethod;
@ -33,7 +31,7 @@ import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import timber.log.Timber;
import java.net.URL;
import java.util.concurrent.TimeUnit;
@ -41,16 +39,15 @@ import java.util.concurrent.TimeUnit;
/**
* Remote operation moving a remote file or folder in the ownCloud server to a different folder
* in the same account.
* <p>
*
* Allows renaming the moving file/folder at the same time.
*
* @author David A. Velasco
* @author Christian Schabesberger
* @author David González V.
*/
public class CopyRemoteFileOperation extends RemoteOperation<String> {
private static final String TAG = CopyRemoteFileOperation.class.getSimpleName();
private static final int COPY_READ_TIMEOUT = 600000;
private static final int COPY_CONNECTION_TIMEOUT = 5000;
@ -81,14 +78,6 @@ public class CopyRemoteFileOperation extends RemoteOperation<String> {
*/
@Override
protected RemoteOperationResult<String> run(OwnCloudClient client) {
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
/// check parameters
if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) {
return new RemoteOperationResult<>(ResultCode.INVALID_CHARACTER_IN_NAME);
}
if (mTargetRemotePath.equals(mSrcRemotePath)) {
// nothing to do!
@ -100,7 +89,7 @@ public class CopyRemoteFileOperation extends RemoteOperation<String> {
}
/// perform remote operation
RemoteOperationResult<String> result;
RemoteOperationResult result;
try {
CopyMethod copyMethod =
new CopyMethod(new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mSrcRemotePath)),
@ -128,13 +117,11 @@ public class CopyRemoteFileOperation extends RemoteOperation<String> {
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
}
Log.i(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage());
Timber.i("Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
Log.e(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage(), e);
Timber.e(e, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage());
}
return result;

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -33,8 +33,7 @@ import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import timber.log.Timber;
import java.net.URL;
import java.util.concurrent.TimeUnit;
@ -47,8 +46,6 @@ import java.util.concurrent.TimeUnit;
*/
public class CreateRemoteFolderOperation extends RemoteOperation {
private static final String TAG = CreateRemoteFolderOperation.class.getSimpleName();
private static final int READ_TIMEOUT = 30000;
private static final int CONNECTION_TIMEOUT = 5000;
@ -75,24 +72,14 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result;
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
boolean noInvalidChars = FileUtils.isValidPath(mRemotePath, versionWithForbiddenChars);
if (noInvalidChars) {
result = createFolder(client);
if (!result.isSuccess() && mCreateFullPath &&
RemoteOperationResult.ResultCode.CONFLICT == result.getCode()) {
result = createParentFolder(FileUtils.getParentPath(mRemotePath), client);
if (result.isSuccess()) {
result = createFolder(client); // second (and last) try
}
RemoteOperationResult result = createFolder(client);
if (!result.isSuccess() && mCreateFullPath &&
RemoteOperationResult.ResultCode.CONFLICT == result.getCode()) {
result = createParentFolder(FileUtils.getParentPath(mRemotePath), client);
if (result.isSuccess()) {
result = createFolder(client); // second (and last) try
}
} else {
result = new RemoteOperationResult<>(ResultCode.INVALID_CHARACTER_IN_NAME);
}
return result;
}
@ -108,12 +95,12 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
result = (status == HttpConstants.HTTP_CREATED)
? new RemoteOperationResult<>(ResultCode.OK)
: new RemoteOperationResult<>(mkcol);
Log_OC.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
Timber.d("Create directory " + mRemotePath + ": " + result.getLogMessage());
client.exhaustResponse(mkcol.getResponseBodyAsStream());
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage(), e);
Timber.e(e, "Create directory " + mRemotePath + ": " + result.getLogMessage());
}
return result;
@ -123,4 +110,4 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
RemoteOperation operation = new CreateRemoteFolderOperation(parentPath, mCreateFullPath);
return operation.execute(client);
}
}
}

View File

@ -32,7 +32,7 @@ import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import timber.log.Timber;
import java.io.BufferedInputStream;
import java.io.File;
@ -53,7 +53,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class DownloadRemoteFileOperation extends RemoteOperation {
private static final String TAG = DownloadRemoteFileOperation.class.getSimpleName();
private static final int FORBIDDEN_ERROR = 403;
private static final int SERVICE_UNAVAILABLE_ERROR = 503;
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
@ -81,13 +80,11 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
try {
tmpFile.getParentFile().mkdirs();
result = downloadFile(client, tmpFile);
Log_OC.i(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " +
result.getLogMessage());
Timber.i("Download of " + mRemotePath + " to " + getTmpPath() + ": " + result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " +
result.getLogMessage(), e);
Timber.e(e, "Download of " + mRemotePath + " to " + getTmpPath() + ": " + result.getLogMessage());
}
return result;
@ -149,7 +146,7 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
final Date d = WebdavUtils.parseResponseDate(modificationTime);
mModificationTimestamp = (d != null) ? d.getTime() : 0;
} else {
Log_OC.e(TAG, "Could not read modification time from response downloading " + mRemotePath);
Timber.e("Could not read modification time from response downloading %s", mRemotePath);
}
mEtag = WebdavUtils.getEtagFromResponse(mGet);
@ -158,7 +155,7 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
mEtag = mEtag.replace("\"", "");
if (mEtag.length() == 0) {
Log_OC.e(TAG, "Could not read eTag from response downloading " + mRemotePath);
Timber.e("Could not read eTag from response downloading %s", mRemotePath);
}
} else {

View File

@ -1,153 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils;
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Operation to check the existence or absence of a path in a remote server.
*
* @author David A. Velasco
* @author David González Verdugo
*/
public class ExistenceCheckRemoteOperation extends RemoteOperation {
/**
* Maximum time to wait for a response from the server in MILLISECONDs.
*/
public static final int TIMEOUT = 10000;
private static final String TAG = ExistenceCheckRemoteOperation.class.getSimpleName();
private String mPath;
private boolean mSuccessIfAbsent;
private boolean mIsLogin;
/**
* Sequence of redirections followed. Available only after executing the operation
*/
private RedirectionPath mRedirectionPath = null;
/**
* Full constructor. Success of the operation will depend upon the value of successIfAbsent.
*
* @param remotePath Path to append to the URL owned by the client instance.
* @param successIfAbsent When 'true', the operation finishes in success if the path does
* NOT exist in the remote server (HTTP 404).
* @param isLogin When `true`, the username won't be added at the end of the PROPFIND url since is not
* needed to check user credentials
*/
public ExistenceCheckRemoteOperation(String remotePath, boolean successIfAbsent, boolean isLogin) {
mPath = (remotePath != null) ? remotePath : "";
mSuccessIfAbsent = successIfAbsent;
mIsLogin = isLogin;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
boolean previousFollowRedirects = client.followRedirects();
try {
String stringUrl = mIsLogin ?
client.getBaseFilesWebDavUri().toString() :
client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mPath);
PropfindMethod propfindMethod = new PropfindMethod(
new URL(stringUrl),
0,
DavUtils.getAllPropset()
);
propfindMethod.setReadTimeout(TIMEOUT, TimeUnit.SECONDS);
propfindMethod.setConnectionTimeout(TIMEOUT, TimeUnit.SECONDS);
client.setFollowRedirects(false);
int status = client.executeHttpMethod(propfindMethod);
if (previousFollowRedirects) {
mRedirectionPath = client.followRedirection(propfindMethod);
status = mRedirectionPath.getLastStatus();
}
/**
* PROPFIND method
* 404 NOT FOUND: path doesn't exist,
* 207 MULTI_STATUS: path exists.
*/
Log_OC.d(TAG, "Existence check for " + stringUrl + WebdavUtils.encodePath(mPath) +
" targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") +
"finished with HTTP status " + status + (!isSuccess(status) ? "(FAIL)" : ""));
return isSuccess(status)
? new RemoteOperationResult<>(OK)
: new RemoteOperationResult<>(propfindMethod);
} catch (Exception e) {
final RemoteOperationResult result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Existence check for " + client.getUserFilesWebDavUri() +
WebdavUtils.encodePath(mPath) + " targeting for " +
(mSuccessIfAbsent ? " absence " : " existence ") + ": " +
result.getLogMessage(), result.getException());
return result;
} finally {
client.setFollowRedirects(previousFollowRedirects);
}
}
/**
* Gets the sequence of redirections followed during the execution of the operation.
*
* @return Sequence of redirections followed, if any, or NULL if the operation was not executed.
*/
public RedirectionPath getRedirectionPath() {
return mRedirectionPath;
}
/**
* @return 'True' if the operation was executed and at least one redirection was followed.
*/
public boolean wasRedirected() {
return (mRedirectionPath != null && mRedirectionPath.getRedirectionsCount() > 0);
}
private boolean isSuccess(int status) {
return ((status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_MULTI_STATUS) && !mSuccessIfAbsent)
|| (status == HttpConstants.HTTP_MULTI_STATUS && !mSuccessIfAbsent)
|| (status == HttpConstants.HTTP_NOT_FOUND && mSuccessIfAbsent);
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,17 +24,15 @@
package com.owncloud.android.lib.resources.files;
import com.owncloud.android.lib.common.utils.Log_OC;
import timber.log.Timber;
import java.io.File;
public class FileUtils {
public static final String PATH_SEPARATOR = "/";
public static final String FINAL_CHUNKS_FILE = ".file";
private static final String TAG = FileUtils.class.getSimpleName();
public static String getParentPath(String remotePath) {
static String getParentPath(String remotePath) {
String parentPath = new File(remotePath).getParent();
parentPath = parentPath.endsWith(PATH_SEPARATOR) ? parentPath : parentPath + PATH_SEPARATOR;
return parentPath;
@ -45,40 +43,13 @@ public class FileUtils {
* : , " , | , ? , *
*
* @param fileName
* @param versionSupportsForbiddenChars
* @return
*/
public static boolean isValidName(String fileName, boolean versionSupportsForbiddenChars) {
public static boolean isValidName(String fileName) {
boolean result = true;
Log_OC.d(TAG, "fileName =======" + fileName);
if ((versionSupportsForbiddenChars && fileName.contains(PATH_SEPARATOR)) ||
(!versionSupportsForbiddenChars && (fileName.contains(PATH_SEPARATOR) ||
fileName.contains("\\") || fileName.contains("<") || fileName.contains(">") ||
fileName.contains(":") || fileName.contains("\"") || fileName.contains("|") ||
fileName.contains("?") || fileName.contains("*")))) {
result = false;
}
return result;
}
/**
* Validate the path to detect if contains any forbidden character: \ , < , > , : , " , | ,
* ? , *
*
* @param path
* @return
*/
public static boolean isValidPath(String path, boolean versionSupportsForbidenChars) {
boolean result = true;
Log_OC.d(TAG, "path ....... " + path);
if (!versionSupportsForbidenChars &&
(path.contains("\\") || path.contains("<") || path.contains(">") ||
path.contains(":") || path.contains("\"") || path.contains("|") ||
path.contains("?") || path.contains("*"))) {
Timber.d("fileName =======%s", fileName);
if (fileName.contains(PATH_SEPARATOR)) {
result = false;
}
return result;

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -25,7 +25,6 @@
package com.owncloud.android.lib.resources.files;
import android.net.Uri;
import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
@ -34,7 +33,7 @@ import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import timber.log.Timber;
import java.net.URL;
import java.util.concurrent.TimeUnit;
@ -50,8 +49,6 @@ import java.util.concurrent.TimeUnit;
*/
public class MoveRemoteFileOperation extends RemoteOperation {
private static final String TAG = MoveRemoteFileOperation.class.getSimpleName();
private static final int MOVE_READ_TIMEOUT = 600000;
private static final int MOVE_CONNECTION_TIMEOUT = 5000;
@ -87,16 +84,6 @@ public class MoveRemoteFileOperation extends RemoteOperation {
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
/// check parameters
if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) {
return new RemoteOperationResult<>(ResultCode.INVALID_CHARACTER_IN_NAME);
}
if (mTargetRemotePath.equals(mSrcRemotePath)) {
// nothing to do!
return new RemoteOperationResult<>(ResultCode.OK);
@ -143,13 +130,11 @@ public class MoveRemoteFileOperation extends RemoteOperation {
client.exhaustResponse(move.getResponseBodyAsStream());
}
Log.i(TAG, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage());
Timber.i("Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
Log.e(TAG, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage(), e);
Timber.e(e, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage());
}
return result;
@ -158,4 +143,4 @@ public class MoveRemoteFileOperation extends RemoteOperation {
protected boolean isSuccess(int status) {
return status == HttpConstants.HTTP_CREATED || status == HttpConstants.HTTP_NO_CONTENT;
}
}
}

View File

@ -31,7 +31,7 @@ import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import timber.log.Timber;
import java.net.URL;
import java.util.concurrent.TimeUnit;
@ -49,7 +49,6 @@ import static com.owncloud.android.lib.common.operations.RemoteOperationResult.R
public class ReadRemoteFileOperation extends RemoteOperation<RemoteFile> {
private static final String TAG = ReadRemoteFileOperation.class.getSimpleName();
private static final int SYNC_READ_TIMEOUT = 40000;
private static final int SYNC_CONNECTION_TIMEOUT = 5000;
@ -100,9 +99,7 @@ public class ReadRemoteFileOperation extends RemoteOperation<RemoteFile> {
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
e.printStackTrace();
Log_OC.e(TAG, "Synchronizing file " + mRemotePath + ": " + result.getLogMessage(),
result.getException());
Timber.e(e, "Synchronizing file %s", mRemotePath);
}
return result;

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -34,7 +34,7 @@ import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import timber.log.Timber;
import java.net.URL;
import java.util.ArrayList;
@ -51,8 +51,6 @@ import static com.owncloud.android.lib.common.operations.RemoteOperationResult.R
public class ReadRemoteFolderOperation extends RemoteOperation<ArrayList<RemoteFile>> {
private static final String TAG = ReadRemoteFolderOperation.class.getSimpleName();
private String mRemotePath;
/**
@ -108,14 +106,15 @@ public class ReadRemoteFolderOperation extends RemoteOperation<ArrayList<RemoteF
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
} finally {
if (result.isSuccess()) {
Log_OC.i(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage());
if (result == null) {
Timber.e("Synchronized " + mRemotePath + ": result is null");
} else if (result.isSuccess()) {
Timber.i("Synchronized " + mRemotePath + ": " + result.getLogMessage());
} else {
if (result.isException()) {
Log_OC.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage(),
result.getException());
Timber.e(result.getException(), "Synchronized " + mRemotePath + ": " + result.getLogMessage());
} else {
Log_OC.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage());
Timber.e("Synchronized " + mRemotePath + ": " + result.getLogMessage());
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,7 +24,6 @@
package com.owncloud.android.lib.resources.files;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@ -41,14 +40,11 @@ import at.bitfire.dav4android.property.owncloud.OCId;
import at.bitfire.dav4android.property.owncloud.OCPermissions;
import at.bitfire.dav4android.property.owncloud.OCPrivatelink;
import at.bitfire.dav4android.property.owncloud.OCSize;
import okhttp3.HttpUrl;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import static com.owncloud.android.lib.common.OwnCloudClient.WEBDAV_FILES_PATH_4_0;
/**
* Contains the data of a Remote File from a WebDavEntry
*
@ -115,7 +111,7 @@ public class RemoteFile implements Parcelable, Serializable {
}
public RemoteFile(final Response davResource, String userId) {
this(getRemotePathFromUrl(davResource.getHref(), userId));
this(RemoteFileUtil.Companion.getRemotePathFromUrl(davResource.getHref(), userId));
final List<Property> properties = davResource.getProperties();
for (Property property : properties) {
@ -167,21 +163,6 @@ public class RemoteFile implements Parcelable, Serializable {
readFromParcel(source);
}
/**
* Retrieves a relative path from a remote file url
* <p>
* Example: url:port/remote.php/dav/files/username/Documents/text.txt => /Documents/text.txt
*
* @param url remote file url
* @param userId file owner
* @return remote relative path of the file
*/
private static String getRemotePathFromUrl(HttpUrl url, String userId) {
final String davFilesPath = WEBDAV_FILES_PATH_4_0 + userId;
final String absoluteDavPath = Uri.decode(url.encodedPath());
final String pathToOc = absoluteDavPath.split(davFilesPath)[0];
return absoluteDavPath.replace(pathToOc + davFilesPath, "");
}
/**
* Getters and Setters

View File

@ -1,7 +1,5 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,44 +21,29 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files
package com.owncloud.android.lib.common.authentication.oauth;
import android.net.Uri
import com.owncloud.android.lib.common.OwnCloudClient
import okhttp3.HttpUrl
public class OAuth2ClientConfiguration {
private String mClientId;
private String mClientSecret;
private String mRedirectUri;
public OAuth2ClientConfiguration(String clientId, String clientSecret, String redirectUri) {
mClientId = (clientId == null) ? "" : clientId;
mClientSecret = (clientSecret == null) ? "" : clientSecret;
mRedirectUri = (redirectUri == null) ? "" : redirectUri;
}
public String getClientId() {
return mClientId;
}
public void setClientId(String clientId) {
mClientId = (clientId == null) ? "" : clientId;
}
public String getClientSecret() {
return mClientSecret;
}
public void setClientSecret(String clientSecret) {
mClientSecret = (clientSecret == null) ? "" : clientSecret;
}
public String getRedirectUri() {
return mRedirectUri;
}
public void setRedirectUri(String redirectUri) {
this.mRedirectUri = (redirectUri == null) ? "" : redirectUri;
class RemoteFileUtil {
companion object {
/**
* Retrieves a relative path from a remote file url
*
*
* Example: url:port/remote.php/dav/files/username/Documents/text.txt => /Documents/text.txt
*
* @param url remote file url
* @param userId file owner
* @return remote relative path of the file
*/
fun getRemotePathFromUrl(url: HttpUrl, userId: String): String? {
val davFilesPath = OwnCloudClient.WEBDAV_FILES_PATH_4_0 + userId
val absoluteDavPath = Uri.decode(url.encodedPath())
val pathToOc = absoluteDavPath.split(davFilesPath)[0]
return absoluteDavPath.replace(pathToOc + davFilesPath, "")
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -32,7 +32,7 @@ import com.owncloud.android.lib.common.http.methods.nonwebdav.DeleteMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import timber.log.Timber;
import java.net.URL;
@ -46,7 +46,6 @@ import static com.owncloud.android.lib.common.operations.RemoteOperationResult.R
* @author David González Verdugo
*/
public class RemoveRemoteFileOperation extends RemoteOperation {
private static final String TAG = RemoveRemoteFileOperation.class.getSimpleName();
private String mRemotePath;
protected boolean removeChunksFolder = false;
@ -81,11 +80,11 @@ public class RemoveRemoteFileOperation extends RemoteOperation {
new RemoteOperationResult<>(OK) :
new RemoteOperationResult<>(deleteMethod);
Log_OC.i(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage());
Timber.i("Remove " + mRemotePath + ": " + result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage(), e);
Timber.e(e, "Remove " + mRemotePath + ": " + result.getLogMessage());
}
return result;

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -31,8 +31,7 @@ import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import timber.log.Timber;
import java.io.File;
import java.net.URL;
@ -46,8 +45,6 @@ import java.util.concurrent.TimeUnit;
*/
public class RenameRemoteFileOperation extends RemoteOperation {
private static final String TAG = RenameRemoteFileOperation.class.getSimpleName();
private static final int RENAME_READ_TIMEOUT = 600000;
private static final int RENAME_CONNECTION_TIMEOUT = 5000;
@ -86,15 +83,6 @@ public class RenameRemoteFileOperation extends RemoteOperation {
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
final OwnCloudVersion version = client.getOwnCloudVersion();
final boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
if (!FileUtils.isValidPath(mNewRemotePath, versionWithForbiddenChars)) {
return new RemoteOperationResult<>(ResultCode.INVALID_CHARACTER_IN_NAME);
}
try {
if (mNewName.equals(mOldName)) {
return new RemoteOperationResult<>(ResultCode.OK);
@ -117,16 +105,14 @@ public class RenameRemoteFileOperation extends RemoteOperation {
? new RemoteOperationResult<>(ResultCode.OK)
: new RemoteOperationResult<>(move);
Log_OC.i(TAG, "Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " +
result.getLogMessage()
);
Timber.i("Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " + result.getLogMessage());
client.exhaustResponse(move.getResponseBodyAsStream());
return result;
} catch (Exception e) {
final RemoteOperationResult result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Rename " + mOldRemotePath + " to " +
((mNewRemotePath == null) ? mNewName : mNewRemotePath) + ": " +
result.getLogMessage(), e);
Timber.e(e,
"Rename " + mOldRemotePath + " to " + ((mNewRemotePath == null) ? mNewName : mNewRemotePath) + ":" +
" " + result.getLogMessage());
return result;
}
}
@ -137,9 +123,9 @@ public class RenameRemoteFileOperation extends RemoteOperation {
* @return 'True' if the target path is already used by an existing file.
*/
private boolean targetPathIsUsed(OwnCloudClient client) {
ExistenceCheckRemoteOperation existenceCheckRemoteOperation =
new ExistenceCheckRemoteOperation(mNewRemotePath, false, false);
RemoteOperationResult exists = existenceCheckRemoteOperation.run(client);
CheckPathExistenceRemoteOperation checkPathExistenceRemoteOperation =
new CheckPathExistenceRemoteOperation(mNewRemotePath, false);
RemoteOperationResult exists = checkPathExistenceRemoteOperation.execute(client);
return exists.isSuccess();
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -33,8 +33,8 @@ import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.MediaType;
import timber.log.Timber;
import java.io.File;
import java.net.URL;
@ -54,7 +54,6 @@ import static com.owncloud.android.lib.common.operations.RemoteOperationResult.R
public class UploadRemoteFileOperation extends RemoteOperation {
private static final String TAG = UploadRemoteFileOperation.class.getSimpleName();
protected final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
protected String mLocalPath;
protected String mRemotePath;
@ -62,7 +61,7 @@ public class UploadRemoteFileOperation extends RemoteOperation {
protected String mFileLastModifTimestamp;
protected PutMethod mPutMethod = null;
protected String mRequiredEtag = null;
protected Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
protected Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>();
protected FileRequestBody mFileRequestBody = null;
@ -96,27 +95,25 @@ public class UploadRemoteFileOperation extends RemoteOperation {
} else {
// perform the upload
result = uploadFile(client);
Log_OC.i(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ": " +
result.getLogMessage());
Timber.i("Upload of " + mLocalPath + " to " + mRemotePath + ": " + result.getLogMessage());
}
} catch (Exception e) {
if (mPutMethod != null && mPutMethod.isAborted()) {
result = new RemoteOperationResult<>(new OperationCancelledException());
Log_OC.e(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ": " +
result.getLogMessage(), new OperationCancelledException());
Timber.e(result.getException(),
"Upload of " + mLocalPath + " to " + mRemotePath + ": " + result.getLogMessage());
} else {
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ": " +
result.getLogMessage(), e);
Timber.e(e, "Upload of " + mLocalPath + " to " + mRemotePath + ": " + result.getLogMessage());
}
}
return result;
}
protected RemoteOperationResult<? extends Object> uploadFile(OwnCloudClient client) throws Exception {
protected RemoteOperationResult<?> uploadFile(OwnCloudClient client) throws Exception {
File fileToUpload = new File(mLocalPath);

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -29,10 +29,10 @@ import com.owncloud.android.lib.common.http.methods.webdav.PutMethod;
import com.owncloud.android.lib.common.network.ChunkFromFileRequestBody;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
import okhttp3.MediaType;
import timber.log.Timber;
import java.io.File;
import java.io.RandomAccessFile;
@ -53,7 +53,6 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
public static final long CHUNK_SIZE = 1024000;
private static final int LAST_CHUNK_TIMEOUT = 900000; //15 mins.
private static final String TAG = ChunkedUploadRemoteFileOperation.class.getSimpleName();
private String mTransferId;
@ -113,7 +112,7 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
status = client.executeHttpMethod(mPutMethod);
Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath +
Timber.d("Upload of " + mLocalPath + " to " + mRemotePath +
", chunk index " + chunkIndex + ", count " + chunkCount +
", HTTP result status " + status);

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,6 +1,6 @@
/* ownCloud Android Library is available under MIT license
* @author David González Verdugo
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -0,0 +1,31 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files.services
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.Service
interface FileService: Service {
fun checkPathExistence(path: String, isUserLogged: Boolean): RemoteOperationResult<Boolean>
}

View File

@ -0,0 +1,34 @@
/**
* ownCloud Android client application
*
* @author Abel García de Prada
* Copyright (C) 2020 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.resources.files.services.implementation
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.files.CheckPathExistenceRemoteOperation
import com.owncloud.android.lib.resources.files.services.FileService
class OCFileService(override val client: OwnCloudClient) :
FileService {
override fun checkPathExistence(path: String, isUserLogged: Boolean): RemoteOperationResult<Boolean> =
CheckPathExistenceRemoteOperation(
remotePath = path,
isUserLogged = isUserLogged
).execute(client)
}

View File

@ -0,0 +1,169 @@
/* ownCloud Android Library is available under MIT license
* @author Abel García de Prada
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.response
import com.owncloud.android.lib.resources.status.RemoteCapability
import com.owncloud.android.lib.resources.status.RemoteCapability.CapabilityBooleanType
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class CapabilityResponse(
@Json(name = "version")
val serverVersion: ServerVersion?,
val capabilities: Capabilities?
) {
fun toRemoteCapability(): RemoteCapability = RemoteCapability(
versionMayor = serverVersion?.major ?: 0,
versionMinor = serverVersion?.minor ?: 0,
versionMicro = serverVersion?.micro ?: 0,
versionString = serverVersion?.string ?: "",
versionEdition = serverVersion?.edition ?: "",
corePollinterval = capabilities?.coreCapabilities?.pollinterval ?: 0,
chunkingVersion = capabilities?.davCapabilities?.chunking ?: "",
filesSharingApiEnabled = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingApiEnabled),
filesSharingResharing = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingReSharing),
filesSharingPublicEnabled = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingPublic?.enabled),
filesSharingPublicUpload = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicUpload),
filesSharingPublicSupportsUploadOnly = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicUploadOnly),
filesSharingPublicMultiple = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicMultiple),
filesSharingPublicPasswordEnforced = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicPassword?.enforced),
filesSharingPublicPasswordEnforcedReadOnly = CapabilityBooleanType.fromBooleanValue(
capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicPassword?.enforcedFor?.enforcedReadOnly
),
filesSharingPublicPasswordEnforcedReadWrite = CapabilityBooleanType.fromBooleanValue(
capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicPassword?.enforcedFor?.enforcedReadWrite
),
filesSharingPublicPasswordEnforcedUploadOnly = CapabilityBooleanType.fromBooleanValue(
capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicPassword?.enforcedFor?.enforcedUploadOnly
),
filesSharingPublicExpireDateEnabled = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicExpireDate?.enabled),
filesSharingPublicExpireDateDays = capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicExpireDate?.days
?: 0,
filesSharingPublicExpireDateEnforced = CapabilityBooleanType.fromBooleanValue(
capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicExpireDate?.enforced
),
filesBigFileChunking = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.bigfilechunking),
filesUndelete = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.undelete),
filesVersioning = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.versioning),
filesSharingFederationIncoming = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingFederation?.incoming),
filesSharingFederationOutgoing = CapabilityBooleanType.fromBooleanValue(capabilities?.fileSharingCapabilities?.fileSharingFederation?.outgoing)
)
}
@JsonClass(generateAdapter = true)
data class Capabilities(
@Json(name = "core")
val coreCapabilities: CoreCapabilities?,
@Json(name = "files_sharing")
val fileSharingCapabilities: FileSharingCapabilities?,
@Json(name = "files")
val fileCapabilities: FileCapabilities?,
@Json(name = "dav")
val davCapabilities: DavCapabilities?
)
@JsonClass(generateAdapter = true)
data class CoreCapabilities(
val pollinterval: Int?
)
@JsonClass(generateAdapter = true)
data class FileSharingCapabilities(
@Json(name = "api_enabled")
val fileSharingApiEnabled: Boolean?,
@Json(name = "public")
val fileSharingPublic: FileSharingPublic?,
@Json(name = "resharing")
val fileSharingReSharing: Boolean?,
@Json(name = "federation")
val fileSharingFederation: FileSharingFederation?
)
@JsonClass(generateAdapter = true)
data class FileSharingPublic(
val enabled: Boolean?,
@Json(name = "upload")
val fileSharingPublicUpload: Boolean?,
@Json(name = "supports_upload_only")
val fileSharingPublicUploadOnly: Boolean?,
@Json(name = "multiple")
val fileSharingPublicMultiple: Boolean?,
@Json(name = "password")
val fileSharingPublicPassword: FileSharingPublicPassword?,
@Json(name = "expire_date")
val fileSharingPublicExpireDate: FileSharingPublicExpireDate?
)
@JsonClass(generateAdapter = true)
data class FileSharingPublicPassword(
val enforced: Boolean?,
@Json(name = "enforced_for")
val enforcedFor: FileSharingPublicPasswordEnforced?
)
@JsonClass(generateAdapter = true)
data class FileSharingPublicPasswordEnforced(
@Json(name = "read_only")
val enforcedReadOnly: Boolean?,
@Json(name = "read_write")
val enforcedReadWrite: Boolean?,
@Json(name = "upload_only")
val enforcedUploadOnly: Boolean?
)
@JsonClass(generateAdapter = true)
data class FileSharingPublicExpireDate(
val enabled: Boolean?,
val days: Int?,
val enforced: Boolean?
)
@JsonClass(generateAdapter = true)
data class FileSharingFederation(
val incoming: Boolean?,
val outgoing: Boolean?
)
@JsonClass(generateAdapter = true)
data class FileCapabilities(
val bigfilechunking: Boolean?,
val undelete: Boolean?,
val versioning: Boolean?
)
@JsonClass(generateAdapter = true)
data class DavCapabilities(
val chunking: String?
)
@JsonClass(generateAdapter = true)
data class ServerVersion(
var major: Int?,
var minor: Int?,
var micro: Int?,
var string: String?,
var edition: String?
)

View File

@ -1,5 +1,6 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -19,34 +20,27 @@
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.response
package com.owncloud.android.lib.common;
import com.squareup.moshi.JsonClass
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
// Response retrieved by OCS Rest API, used to obtain capabilities, shares and user info among others.
// More info: https://doc.owncloud.com/server/developer_manual/core/apis/ocs-capabilities.html
@JsonClass(generateAdapter = true)
data class CommonOcsResponse<T>(
val ocs: OCSResponse<T>
)
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
@JsonClass(generateAdapter = true)
data class OCSResponse<T>(
val meta: MetaData,
val data: T
)
import java.io.IOException;
/**
* Manager to create and reuse OwnCloudClient instances to access remote OC servers.
*
* @author David A. Velasco
* @author masensio
* @author Christian Schabesberger
*/
public interface OwnCloudClientManager {
OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws AccountNotFoundException,
OperationCanceledException, AuthenticatorException, IOException;
OwnCloudClient removeClientFor(OwnCloudAccount account);
void saveAllClients(Context context, String accountType) throws AccountNotFoundException, AuthenticatorException, IOException,
OperationCanceledException;
}
@JsonClass(generateAdapter = true)
data class MetaData(
val status: String,
val statuscode: Int,
val message: String?
)

View File

@ -0,0 +1,42 @@
/* ownCloud Android Library is available under MIT license
*
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.owncloud.android.lib.resources.response
import com.owncloud.android.lib.resources.users.RemoteUserInfo
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class UserInfoResponse(
val id: String,
@Json(name = "display-name")
val displayName: String,
val email: String?
) {
fun toRemoteUserInfo() = RemoteUserInfo(
id = id,
displayName = displayName,
email = email
)
}

View File

@ -2,7 +2,7 @@
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
* Copyright (C) 2019 ownCloud GmbH
* Copyright (C) 2020 ownCloud GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -32,9 +32,9 @@ import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.lib.resources.shares.RemoteShare.Companion.INIT_EXPIRATION_DATE_IN_MILLIS
import okhttp3.FormBody
import timber.log.Timber
import java.net.URL
import java.text.SimpleDateFormat
import java.util.Calendar
@ -150,7 +150,7 @@ class CreateRemoteShareOperation(
} catch (e: Exception) {
result = RemoteOperationResult(e)
Log_OC.e(TAG, "Exception while Creating New Share", e)
Timber.e(e, "Exception while Creating New Share")
}
return result
@ -159,8 +159,6 @@ class CreateRemoteShareOperation(
private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK
companion object {
private val TAG = CreateRemoteShareOperation::class.java.simpleName
private const val PARAM_NAME = "name"
private const val PARAM_PASSWORD = "password"
private const val PARAM_EXPIRATION_DATE = "expireDate"

View File

@ -1,7 +1,7 @@
/* ownCloud Android Library is available under MIT license
* @author David A. Velasco
* @author David González Verdugo
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -33,7 +33,7 @@ import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import timber.log.Timber;
import java.net.URL;
@ -46,8 +46,6 @@ import java.net.URL;
public class GetRemoteShareOperation extends RemoteOperation<ShareParserResult> {
private static final String TAG = GetRemoteShareOperation.class.getSimpleName();
private long mRemoteId;
public GetRemoteShareOperation(long remoteId) {
@ -85,7 +83,7 @@ public class GetRemoteShareOperation extends RemoteOperation<ShareParserResult>
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while getting remote shares ", e);
Timber.e(e, "Exception while getting remote shares");
}
return result;
}

View File

@ -3,7 +3,7 @@
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -34,8 +34,8 @@ import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK
import com.owncloud.android.lib.common.utils.Log_OC
import org.json.JSONObject
import timber.log.Timber
import java.net.URL
import java.util.ArrayList
@ -95,13 +95,13 @@ class GetRemoteShareesOperation
val getMethod = GetMethod(URL(uriBuilder.build().toString()))
getMethod.addRequestHeader(RemoteOperation.OCS_API_HEADER, RemoteOperation.OCS_API_HEADER_VALUE)
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
val status = client.executeHttpMethod(getMethod)
val response = getMethod.responseBodyAsString
if (isSuccess(status)) {
Log_OC.d(TAG, "Successful response: " + response!!)
Timber.d("Successful response: $response")
// Parse the response
val respJSON = JSONObject(response)
@ -128,65 +128,61 @@ class GetRemoteShareesOperation
for (j in 0 until jsonResults[i].length()) {
val jsonResult = jsonResults[i].getJSONObject(j)
data.add(jsonResult)
Log_OC.d(TAG, "*** Added item: " + jsonResult.getString(PROPERTY_LABEL))
Timber.d("*** Added item: ${jsonResult.getString(PROPERTY_LABEL)}")
}
}
result = RemoteOperationResult(OK)
result.data = data
Log_OC.d(TAG, "*** Get Users or groups completed ")
Timber.d("*** Get Users or groups completed ")
} else {
result = RemoteOperationResult(getMethod)
Log_OC.e(TAG, "Failed response while getting users/groups from the server ")
Timber.e("Failed response while getting users/groups from the server ")
if (response != null) {
Log_OC.e(TAG, "*** status code: $status; response message: $response")
Timber.e("*** status code: $status; response message: $response")
} else {
Log_OC.e(TAG, "*** status code: $status")
Timber.e("*** status code: $status")
}
}
} catch (e: Exception) {
result = RemoteOperationResult(e)
Log_OC.e(TAG, "Exception while getting users/groups", e)
Timber.e(e, "Exception while getting users/groups")
}
return result
}
private fun isSuccess(status: Int): Boolean {
return status == HttpConstants.HTTP_OK
}
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
companion object {
private val TAG = GetRemoteShareesOperation::class.java.simpleName
// OCS Routes
private val OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/sharees" // from OC 8.2
private const val OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/sharees" // from OC 8.2
// Arguments - names
private val PARAM_FORMAT = "format"
private val PARAM_ITEM_TYPE = "itemType"
private val PARAM_SEARCH = "search"
private val PARAM_PAGE = "page" // default = 1
private val PARAM_PER_PAGE = "perPage" // default = 200
private const val PARAM_FORMAT = "format"
private const val PARAM_ITEM_TYPE = "itemType"
private const val PARAM_SEARCH = "search"
private const val PARAM_PAGE = "page" // default = 1
private const val PARAM_PER_PAGE = "perPage" // default = 200
// Arguments - constant values
private val VALUE_FORMAT = "json"
private val VALUE_ITEM_TYPE = "file" // to get the server search for users / groups
private const val VALUE_FORMAT = "json"
private const val VALUE_ITEM_TYPE = "file" // to get the server search for users / groups
// JSON Node names
private val NODE_OCS = "ocs"
private val NODE_DATA = "data"
private val NODE_EXACT = "exact"
private val NODE_USERS = "users"
private val NODE_GROUPS = "groups"
private val NODE_REMOTES = "remotes"
val NODE_VALUE = "value"
val PROPERTY_LABEL = "label"
val PROPERTY_SHARE_TYPE = "shareType"
val PROPERTY_SHARE_WITH = "shareWith"
val PROPERTY_SHARE_WITH_ADDITIONAL_INFO = "shareWithAdditionalInfo"
private const val NODE_OCS = "ocs"
private const val NODE_DATA = "data"
private const val NODE_EXACT = "exact"
private const val NODE_USERS = "users"
private const val NODE_GROUPS = "groups"
private const val NODE_REMOTES = "remotes"
const val NODE_VALUE = "value"
const val PROPERTY_LABEL = "label"
const val PROPERTY_SHARE_TYPE = "shareType"
const val PROPERTY_SHARE_WITH = "shareWith"
const val PROPERTY_SHARE_WITH_ADDITIONAL_INFO = "shareWithAdditionalInfo"
}
}

View File

@ -2,7 +2,7 @@
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -32,7 +32,7 @@ import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
import timber.log.Timber
import java.net.URL
/**
@ -89,14 +89,14 @@ class GetRemoteSharesForFileOperation(
result = parser.parse(getMethod.responseBodyAsString)
if (result.isSuccess) {
Log_OC.d(TAG, "Got " + result.data.shares.size + " shares")
Timber.d("Got " + result.data.shares.size + " shares")
}
} else {
result = RemoteOperationResult(getMethod)
}
} catch (e: Exception) {
result = RemoteOperationResult(e)
Log_OC.e(TAG, "Exception while getting shares", e)
Timber.e(e, "Exception while getting shares")
}
return result
@ -105,11 +105,8 @@ class GetRemoteSharesForFileOperation(
private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK
companion object {
private val TAG = GetRemoteSharesForFileOperation::class.java.simpleName
private const val PARAM_PATH = "path"
private const val PARAM_RESHARES = "reshares"
private const val PARAM_SUBFILES = "subfiles"
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -42,8 +42,8 @@ data class RemoteShare(
var sharedWithAdditionalInfo: String = "",
var name: String = "",
var shareLink: String = "",
var fileSource: Long = 0,
var itemSource: Long = 0,
var fileSource: String = "0",
var itemSource: String = "0",
var shareType: ShareType? = ShareType.UNKNOWN,
var permissions: Int = DEFAULT_PERMISSION,
var sharedDate: Long = INIT_SHARED_DATE,
@ -66,16 +66,14 @@ data class RemoteShare(
const val MAXIMUM_PERMISSIONS_FOR_FOLDER = MAXIMUM_PERMISSIONS_FOR_FILE +
CREATE_PERMISSION_FLAG +
DELETE_PERMISSION_FLAG
const val FEDERATED_PERMISSIONS_FOR_FILE_UP_TO_OC9 = READ_PERMISSION_FLAG + UPDATE_PERMISSION_FLAG
const val FEDERATED_PERMISSIONS_FOR_FILE_AFTER_OC9 = READ_PERMISSION_FLAG +
const val FEDERATED_PERMISSIONS_FOR_FILE = READ_PERMISSION_FLAG +
UPDATE_PERMISSION_FLAG +
SHARE_PERMISSION_FLAG
const val FEDERATED_PERMISSIONS_FOR_FOLDER_UP_TO_OC9 = READ_PERMISSION_FLAG +
const val FEDERATED_PERMISSIONS_FOR_FOLDER = READ_PERMISSION_FLAG +
UPDATE_PERMISSION_FLAG +
CREATE_PERMISSION_FLAG +
DELETE_PERMISSION_FLAG
const val FEDERATED_PERMISSIONS_FOR_FOLDER_AFTER_OC9 =
FEDERATED_PERMISSIONS_FOR_FOLDER_UP_TO_OC9 + SHARE_PERMISSION_FLAG
DELETE_PERMISSION_FLAG +
SHARE_PERMISSION_FLAG
const val INIT_EXPIRATION_DATE_IN_MILLIS: Long = 0
const val INIT_SHARED_DATE: Long = 0

View File

@ -2,7 +2,7 @@
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -32,7 +32,7 @@ import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.nonwebdav.DeleteMethod
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
import timber.log.Timber
import java.net.URL
/**
@ -75,7 +75,7 @@ class RemoveRemoteShareOperation(private val remoteShareId: Long) : RemoteOperat
)
result = parser.parse(deleteMethod.responseBodyAsString)
Log_OC.d(TAG, "Unshare " + remoteShareId + ": " + result.logMessage)
Timber.d("Unshare " + remoteShareId + ": " + result.logMessage)
} else {
result = RemoteOperationResult(deleteMethod)
@ -83,16 +83,11 @@ class RemoveRemoteShareOperation(private val remoteShareId: Long) : RemoteOperat
} catch (e: Exception) {
result = RemoteOperationResult(e)
Log_OC.e(TAG, "Unshare Link Exception " + result.logMessage, e)
Timber.e(e, "Unshare Link Exception " + result.logMessage)
}
return result
}
private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK
companion object {
private val TAG = RemoveRemoteShareOperation::class.java.simpleName
}
}
}

View File

@ -1,6 +1,6 @@
/* ownCloud Android Library is available under MIT license
* @author Christian Schabesberger
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,6 +1,6 @@
/* ownCloud Android Library is available under MIT license
* @author David A. Velasco
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -2,7 +2,7 @@
* @author David A. Velasco
* @author David González Verdugo
* @author Christian Schabesberger
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -29,9 +29,9 @@ package com.owncloud.android.lib.resources.shares
import android.net.Uri
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.lib.resources.status.OwnCloudVersion
import org.xmlpull.v1.XmlPullParserException
import timber.log.Timber
import java.io.ByteArrayInputStream
import java.io.IOException
import java.util.ArrayList
@ -53,7 +53,7 @@ class ShareToRemoteOperationResultParser(private var shareXmlParser: ShareXMLPar
// Parse xml response and obtain the list of shares
val byteArrayServerResponse = ByteArrayInputStream(serverResponse.toByteArray())
if (shareXmlParser == null) {
Log_OC.w(TAG, "No ShareXmlParser provided, creating new instance ")
Timber.w("No ShareXmlParser provided, creating new instance")
shareXmlParser = ShareXMLParser()
}
val shares = shareXmlParser?.parseXMLResponse(byteArrayServerResponse)
@ -72,10 +72,10 @@ class ShareToRemoteOperationResultParser(private var shareXmlParser: ShareXMLPar
}
if (serverBaseUri != null) {
val sharingLinkPath = ShareUtils.getSharingLinkPath(ownCloudVersion)
val sharingLinkPath = ShareUtils.SHARING_LINK_PATH
share.shareLink = serverBaseUri.toString() + sharingLinkPath + share.token
} else {
Log_OC.e(TAG, "Couldn't build link for public share :(")
Timber.e("Couldn't build link for public share :(")
}
share
@ -87,7 +87,7 @@ class ShareToRemoteOperationResultParser(private var shareXmlParser: ShareXMLPar
} else {
result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE)
Log_OC.e(TAG, "Successful status with no share in the response")
Timber.e("Successful status with no share in the response")
}
}
shareXmlParser?.isWrongParameter!! -> {
@ -107,18 +107,14 @@ class ShareToRemoteOperationResultParser(private var shareXmlParser: ShareXMLPar
}
}
} catch (e: XmlPullParserException) {
Log_OC.e(TAG, "Error parsing response from server ", e)
Timber.e(e, "Error parsing response from server")
result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE)
} catch (e: IOException) {
Log_OC.e(TAG, "Error reading response from server ", e)
Timber.e(e, "Error reading response from server")
result = RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE)
}
return result
}
companion object {
private val TAG = ShareToRemoteOperationResultParser::class.java.simpleName
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,8 +24,6 @@
package com.owncloud.android.lib.resources.shares;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
/**
* Contains Constants for Share Operation
*
@ -39,14 +37,5 @@ public class ShareUtils {
public static final String SHARING_API_PATH = "ocs/v2.php/apps/files_sharing/api/v1/shares";
// String to build the link with the token of a share:
public static final String SHARING_LINK_PATH_BEFORE_VERSION_8 = "/public.php?service=files&t=";
public static final String SHARING_LINK_PATH_AFTER_VERSION_8 = "/index.php/s/";
public static String getSharingLinkPath(OwnCloudVersion version) {
if (version != null && version.isAfter8Version()) {
return SHARING_LINK_PATH_AFTER_VERSION_8;
} else {
return SHARING_LINK_PATH_BEFORE_VERSION_8;
}
}
}
public static final String SHARING_LINK_PATH = "/index.php/s/";
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -110,12 +110,16 @@ class ShareXMLParser {
}
val name = parser.name
// read NODE_META and NODE_DATA
if (name.equals(NODE_META, ignoreCase = true)) {
readMeta(parser)
} else if (name.equals(NODE_DATA, ignoreCase = true)) {
shares = readData(parser)
} else {
skip(parser)
when {
name.equals(NODE_META, ignoreCase = true) -> {
readMeta(parser)
}
name.equals(NODE_DATA, ignoreCase = true) -> {
shares = readData(parser)
}
else -> {
skip(parser)
}
}
}
return shares
@ -130,24 +134,25 @@ class ShareXMLParser {
@Throws(XmlPullParserException::class, IOException::class)
private fun readMeta(parser: XmlPullParser) {
parser.require(XmlPullParser.START_TAG, ns, NODE_META)
//Log_OC.d(TAG, "---- NODE META ---");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.eventType != XmlPullParser.START_TAG) {
continue
}
val name = parser.name
if (name.equals(NODE_STATUS, ignoreCase = true)) {
status = readNode(parser, NODE_STATUS)
} else if (name.equals(NODE_STATUS_CODE, ignoreCase = true)) {
statusCode = Integer.parseInt(readNode(parser, NODE_STATUS_CODE))
} else if (name.equals(NODE_MESSAGE, ignoreCase = true)) {
message = readNode(parser, NODE_MESSAGE)
} else {
skip(parser)
when {
name.equals(NODE_STATUS, ignoreCase = true) -> {
status = readNode(parser, NODE_STATUS)
}
name.equals(NODE_STATUS_CODE, ignoreCase = true) -> {
statusCode = Integer.parseInt(readNode(parser, NODE_STATUS_CODE))
}
name.equals(NODE_MESSAGE, ignoreCase = true) -> {
message = readNode(parser, NODE_MESSAGE)
}
else -> {
skip(parser)
}
}
}
}
@ -165,33 +170,34 @@ class ShareXMLParser {
var share: RemoteShare? = null
parser.require(XmlPullParser.START_TAG, ns, NODE_DATA)
//Log_OC.d(TAG, "---- NODE DATA ---");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.eventType != XmlPullParser.START_TAG) {
continue
}
val name = parser.name
if (name.equals(NODE_ELEMENT, ignoreCase = true)) {
readElement(parser, shares)
} else if (name.equals(NODE_ID, ignoreCase = true)) {// Parse Create XML Response
share = RemoteShare()
val value = readNode(parser, NODE_ID)
share.id = Integer.parseInt(value).toLong()
} else if (name.equals(NODE_URL, ignoreCase = true)) {
// NOTE: this field is received in all the public shares from OC 9.0.0
// in previous versions, it's received in the result of POST requests, but not
// in GET requests
share!!.shareType = ShareType.PUBLIC_LINK
val value = readNode(parser, NODE_URL)
share.shareLink = value
} else if (name.equals(NODE_TOKEN, ignoreCase = true)) {
share!!.token = readNode(parser, NODE_TOKEN)
} else {
skip(parser)
when {
name.equals(NODE_ELEMENT, ignoreCase = true) -> {
readElement(parser, shares)
}
name.equals(NODE_ID, ignoreCase = true) -> {// Parse Create XML Response
share = RemoteShare()
val value = readNode(parser, NODE_ID)
share.id = Integer.parseInt(value).toLong()
}
name.equals(NODE_URL, ignoreCase = true) -> {
// NOTE: this field is received in all the public shares from OC 9.0.0
// in previous versions, it's received in the result of POST requests, but not
// in GET requests
share!!.shareType = ShareType.PUBLIC_LINK
val value = readNode(parser, NODE_URL)
share.shareLink = value
}
name.equals(NODE_TOKEN, ignoreCase = true) -> {
share!!.token = readNode(parser, NODE_TOKEN)
}
else -> {
skip(parser)
}
}
}
@ -217,7 +223,6 @@ class ShareXMLParser {
val remoteShare = RemoteShare()
//Log_OC.d(TAG, "---- NODE ELEMENT ---");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.eventType != XmlPullParser.START_TAG) {
continue
@ -243,7 +248,7 @@ class ShareXMLParser {
}
name.equals(NODE_ITEM_SOURCE, ignoreCase = true) -> {
remoteShare.itemSource = java.lang.Long.parseLong(readNode(parser, NODE_ITEM_SOURCE))
remoteShare.itemSource = readNode(parser, NODE_ITEM_SOURCE)
}
name.equals(NODE_PARENT, ignoreCase = true) -> {
@ -260,7 +265,7 @@ class ShareXMLParser {
}
name.equals(NODE_FILE_SOURCE, ignoreCase = true) -> {
remoteShare.fileSource = java.lang.Long.parseLong(readNode(parser, NODE_FILE_SOURCE))
remoteShare.fileSource = readNode(parser, NODE_FILE_SOURCE)
}
name.equals(NODE_PATH, ignoreCase = true) -> {
@ -343,7 +348,6 @@ class ShareXMLParser {
private fun readNode(parser: XmlPullParser, node: String): String {
parser.require(XmlPullParser.START_TAG, ns, node)
val value = readText(parser)
//Log_OC.d(TAG, "node= " + node + ", value= " + value);
parser.require(XmlPullParser.END_TAG, ns, node)
return value
}
@ -387,8 +391,6 @@ class ShareXMLParser {
companion object {
//private static final String TAG = ShareXMLParser.class.getSimpleName();
// No namespaces
private val ns: String? = null

View File

@ -1,6 +1,6 @@
/* ownCloud Android Library is available under MIT license
*
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -30,9 +30,9 @@ import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.nonwebdav.PutMethod
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.lib.resources.shares.RemoteShare.Companion.DEFAULT_PERMISSION
import okhttp3.FormBody
import timber.log.Timber
import java.net.URL
import java.text.SimpleDateFormat
import java.util.Calendar
@ -61,7 +61,6 @@ class UpdateRemoteShareOperation
/**
* Name to update in Share resource. Ignored by servers previous to version 10.0.0
*
* @param name Name to set to the target share.
* Empty string clears the current name.
* Null results in no update applied to the name.
*/
@ -70,7 +69,6 @@ class UpdateRemoteShareOperation
/**
* Password to update in Share resource.
*
* @param password Password to set to the target share.
* Empty string clears the current password.
* Null results in no update applied to the password.
*/
@ -79,7 +77,6 @@ class UpdateRemoteShareOperation
/**
* Expiration date to update in Share resource.
*
* @param expirationDateInMillis Expiration date to set to the target share.
* A negative value clears the current expiration date.
* Zero value (start-of-epoch) results in no update done on
* the expiration date.
@ -89,7 +86,6 @@ class UpdateRemoteShareOperation
/**
* Permissions to update in Share resource.
*
* @param permissions Permissions to set to the target share.
* Values <= 0 result in no update applied to the permissions.
*/
var permissions: Int = DEFAULT_PERMISSION
@ -97,7 +93,6 @@ class UpdateRemoteShareOperation
/**
* Enable upload permissions to update in Share resource.
*
* @param publicUpload Upload permission to set to the target share.
* Null results in no update applied to the upload permission.
*/
var publicUpload: Boolean? = null
@ -181,7 +176,7 @@ class UpdateRemoteShareOperation
} catch (e: Exception) {
result = RemoteOperationResult(e)
Log_OC.e(TAG, "Exception while Creating New Share", e)
Timber.e(e, "Exception while Creating New Share")
}
return result
@ -190,7 +185,6 @@ class UpdateRemoteShareOperation
private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK
companion object {
private val TAG = GetRemoteShareOperation::class.java.simpleName
private const val PARAM_NAME = "name"
private const val PARAM_PASSWORD = "password"

View File

@ -3,7 +3,7 @@
*
* @author David González Verdugo
*
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
@ -18,10 +18,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.resources.shares
package com.owncloud.android.lib.resources.shares.services
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.Service
import com.owncloud.android.lib.resources.shares.ShareParserResult
import com.owncloud.android.lib.resources.shares.ShareType
interface ShareService : Service {
fun getShares(

View File

@ -3,7 +3,7 @@
*
* @author David González Verdugo
*
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.resources.shares
package com.owncloud.android.lib.resources.shares.services
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.Service

View File

@ -0,0 +1,91 @@
/**
* ownCloud Android client application
*
* @author David González Verdugo
*
* Copyright (C) 2020 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* 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.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.resources.shares.services.implementation
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.shares.CreateRemoteShareOperation
import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation
import com.owncloud.android.lib.resources.shares.RemoveRemoteShareOperation
import com.owncloud.android.lib.resources.shares.ShareParserResult
import com.owncloud.android.lib.resources.shares.ShareType
import com.owncloud.android.lib.resources.shares.UpdateRemoteShareOperation
import com.owncloud.android.lib.resources.shares.services.ShareService
class OCShareService(override val client: OwnCloudClient) :
ShareService {
override fun getShares(
remoteFilePath: String,
reshares: Boolean,
subfiles: Boolean
): RemoteOperationResult<ShareParserResult> = GetRemoteSharesForFileOperation(
remoteFilePath,
reshares,
subfiles
).execute(client)
override fun insertShare(
remoteFilePath: String,
shareType: ShareType,
shareWith: String,
permissions: Int,
name: String,
password: String,
expirationDate: Long,
publicUpload: Boolean
): RemoteOperationResult<ShareParserResult> =
CreateRemoteShareOperation(
remoteFilePath,
shareType,
shareWith,
permissions
).apply {
this.name = name
this.password = password
this.expirationDateInMillis = expirationDate
this.publicUpload = publicUpload
this.retrieveShareDetails = true
}.execute(client)
override fun updateShare(
remoteId: Long,
name: String,
password: String?,
expirationDate: Long,
permissions: Int,
publicUpload: Boolean
): RemoteOperationResult<ShareParserResult> =
UpdateRemoteShareOperation(
remoteId
).apply {
this.name = name
this.password = password
this.expirationDateInMillis = expirationDate
this.permissions = permissions
this.publicUpload = publicUpload
this.retrieveShareDetails = true
}.execute(client)
override fun deleteShare(remoteId: Long): RemoteOperationResult<ShareParserResult> =
RemoveRemoteShareOperation(
remoteId
).execute(client)
}

View File

@ -0,0 +1,42 @@
/**
* ownCloud Android client application
*
* @author David González Verdugo
*
* Copyright (C) 2020 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* 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.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.resources.shares.services.implementation
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.shares.GetRemoteShareesOperation
import com.owncloud.android.lib.resources.shares.services.ShareeService
import org.json.JSONObject
import java.util.ArrayList
class OCShareeService(override val client: OwnCloudClient) :
ShareeService {
override fun getSharees(
searchString: String,
page: Int,
perPage: Int
): RemoteOperationResult<ArrayList<JSONObject>> =
GetRemoteShareesOperation(
searchString,
page,
perPage
).execute(client)
}

View File

@ -2,7 +2,9 @@
* @author masensio
* @author Semih Serhat Karakaya <karakayasemi@itu.edu.tr>
* @author David González Verdugo
* Copyright (C) 2019 ownCloud GmbH.
* @author Abel García de Prada
*
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,7 +26,6 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.status
import com.owncloud.android.lib.common.OwnCloudClient
@ -33,10 +34,14 @@ import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK
import com.owncloud.android.lib.common.utils.Log_OC
import org.json.JSONObject
import com.owncloud.android.lib.resources.response.CapabilityResponse
import com.owncloud.android.lib.resources.response.CommonOcsResponse
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import timber.log.Timber
import java.lang.reflect.Type
import java.net.URL
import com.owncloud.android.lib.resources.status.RemoteCapability.CapabilityBooleanType
/**
* Get the Capabilities from the server
@ -45,228 +50,51 @@ import com.owncloud.android.lib.resources.status.RemoteCapability.CapabilityBool
* @author masensio
* @author David González Verdugo
*/
/**
* Constructor
*/
class GetRemoteCapabilitiesOperation : RemoteOperation<RemoteCapability>() {
override fun run(client: OwnCloudClient): RemoteOperationResult<RemoteCapability> {
var result: RemoteOperationResult<RemoteCapability>
try {
val requestUri = client.baseUri
val uriBuilder = requestUri.buildUpon()
uriBuilder.appendEncodedPath(OCS_ROUTE) // avoid starting "/" in this method
uriBuilder.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
val getMethod = GetMethod(URL(uriBuilder.build().toString()))
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
val uriBuilder = client.baseUri.buildUpon().apply {
appendEncodedPath(OCS_ROUTE) // avoid starting "/" in this method
appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
}
val getMethod = GetMethod(URL(uriBuilder.build().toString())).apply {
addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
}
val status = client.executeHttpMethod(getMethod)
val response = getMethod.responseBodyAsString
if (!isSuccess(status)) {
result = RemoteOperationResult(getMethod)
Log_OC.e(TAG, "Failed response while getting capabilities from the server ")
if (response != null) {
Log_OC.e(TAG, "*** status code: $status; response message: $response")
} else {
Log_OC.e(TAG, "*** status code: $status")
}
if (status == HttpConstants.HTTP_OK) {
Timber.d("Successful response $response")
return result
}
// Parse the response
val moshi: Moshi = Moshi.Builder().build()
val type: Type = Types.newParameterizedType(CommonOcsResponse::class.java, CapabilityResponse::class.java)
val adapter: JsonAdapter<CommonOcsResponse<CapabilityResponse>> = moshi.adapter(type)
val commonResponse: CommonOcsResponse<CapabilityResponse>? = adapter.fromJson(response)
Log_OC.d(TAG, "Successful response: " + response!!)
// Parse the response
val respJSON = JSONObject(response)
val respOCS = respJSON.getJSONObject(NODE_OCS)
val respMeta = respOCS.getJSONObject(NODE_META)
val respData = respOCS.getJSONObject(NODE_DATA)
// Read meta
val statusProp = respMeta.getString(PROPERTY_STATUS).equals(PROPERTY_STATUS_OK, ignoreCase = true)
val statuscode = respMeta.getInt(PROPERTY_STATUSCODE)
val message = respMeta.getString(PROPERTY_MESSAGE)
if (statusProp) {
val capability = RemoteCapability()
// Add Version
if (respData.has(NODE_VERSION)) {
val respVersion = respData.getJSONObject(NODE_VERSION)
capability.versionMayor = respVersion.getInt(PROPERTY_MAJOR)
capability.versionMinor = respVersion.getInt(PROPERTY_MINOR)
capability.versionMicro = respVersion.getInt(PROPERTY_MICRO)
capability.versionString = respVersion.getString(PROPERTY_STRING)
capability.versionEdition = respVersion.getString(PROPERTY_EDITION)
Log_OC.d(TAG, "*** Added $NODE_VERSION")
}
// Capabilities Object
if (respData.has(NODE_CAPABILITIES)) {
val respCapabilities = respData.getJSONObject(NODE_CAPABILITIES)
// Add Core: pollinterval
if (respCapabilities.has(NODE_CORE)) {
val respCore = respCapabilities.getJSONObject(NODE_CORE)
capability.corePollinterval = respCore.getInt(PROPERTY_POLLINTERVAL)
Log_OC.d(TAG, "*** Added $NODE_CORE")
}
// Add files_sharing: public, user, resharing
if (respCapabilities.has(NODE_FILES_SHARING)) {
val respFilesSharing = respCapabilities.getJSONObject(NODE_FILES_SHARING)
if (respFilesSharing.has(PROPERTY_API_ENABLED)) {
capability.filesSharingApiEnabled = CapabilityBooleanType.fromBooleanValue(
respFilesSharing.getBoolean(PROPERTY_API_ENABLED)
)
}
if (respFilesSharing.has(PROPERTY_SEARCH_MIN_LENGTH)){
capability.filesSharingSearchMinLength = respFilesSharing.getInt(
PROPERTY_SEARCH_MIN_LENGTH)
}
if (respFilesSharing.has(NODE_PUBLIC)) {
val respPublic = respFilesSharing.getJSONObject(NODE_PUBLIC)
capability.filesSharingPublicEnabled = CapabilityBooleanType.fromBooleanValue(
respPublic.getBoolean(PROPERTY_ENABLED)
)
if (respPublic.has(NODE_PASSWORD)) {
val respPassword = respPublic.getJSONObject(NODE_PASSWORD)
capability.filesSharingPublicPasswordEnforced =
CapabilityBooleanType.fromBooleanValue(
respPublic.getJSONObject(NODE_PASSWORD).getBoolean(PROPERTY_ENFORCED)
)
if (respPassword.has(NODE_ENFORCED_FOR)) {
capability.filesSharingPublicPasswordEnforcedReadOnly =
CapabilityBooleanType.fromBooleanValue(
respPassword.getJSONObject(NODE_ENFORCED_FOR).getBoolean(
PROPERTY_ENFORCED_READ_ONLY
)
)
capability.filesSharingPublicPasswordEnforcedReadWrite =
CapabilityBooleanType.fromBooleanValue(
respPassword.getJSONObject(NODE_ENFORCED_FOR).getBoolean(
PROPERTY_ENFORCED_READ_WRITE
)
)
capability.filesSharingPublicPasswordEnforcedUploadOnly =
CapabilityBooleanType.fromBooleanValue(
respPassword.getJSONObject(NODE_ENFORCED_FOR).getBoolean(
PROPERTY_ENFORCED_UPLOAD_ONLY
)
)
}
}
if (respPublic.has(NODE_EXPIRE_DATE)) {
val respExpireDate = respPublic.getJSONObject(NODE_EXPIRE_DATE)
capability.filesSharingPublicExpireDateEnabled =
CapabilityBooleanType.fromBooleanValue(
respExpireDate.getBoolean(PROPERTY_ENABLED)
)
if (respExpireDate.has(PROPERTY_DAYS)) {
capability.filesSharingPublicExpireDateDays =
respExpireDate.getInt(PROPERTY_DAYS)
}
if (respExpireDate.has(PROPERTY_ENFORCED)) {
capability.filesSharingPublicExpireDateEnforced =
CapabilityBooleanType.fromBooleanValue(
respExpireDate.getBoolean(PROPERTY_ENFORCED)
)
}
}
if (respPublic.has(PROPERTY_UPLOAD)) {
capability.filesSharingPublicUpload = CapabilityBooleanType.fromBooleanValue(
respPublic.getBoolean(PROPERTY_UPLOAD)
)
}
if (respPublic.has(PROPERTY_UPLOAD_ONLY)) {
capability.filesSharingPublicSupportsUploadOnly =
CapabilityBooleanType.fromBooleanValue(
respPublic.getBoolean(PROPERTY_UPLOAD_ONLY)
)
}
if (respPublic.has(PROPERTY_MULTIPLE)) {
capability.filesSharingPublicMultiple = CapabilityBooleanType.fromBooleanValue(
respPublic.getBoolean(PROPERTY_MULTIPLE)
)
}
}
if (respFilesSharing.has(NODE_USER)) {
val respUser = respFilesSharing.getJSONObject(NODE_USER)
capability.filesSharingUserSendMail = CapabilityBooleanType.fromBooleanValue(
respUser.getBoolean(PROPERTY_SEND_MAIL)
)
}
capability.filesSharingResharing = CapabilityBooleanType.fromBooleanValue(
respFilesSharing.getBoolean(PROPERTY_RESHARING)
)
if (respFilesSharing.has(NODE_FEDERATION)) {
val respFederation = respFilesSharing.getJSONObject(NODE_FEDERATION)
capability.filesSharingFederationOutgoing =
CapabilityBooleanType.fromBooleanValue(respFederation.getBoolean(PROPERTY_OUTGOING))
capability.filesSharingFederationIncoming = CapabilityBooleanType.fromBooleanValue(
respFederation.getBoolean(PROPERTY_INCOMING)
)
}
Log_OC.d(TAG, "*** Added $NODE_FILES_SHARING")
}
if (respCapabilities.has(NODE_FILES)) {
val respFiles = respCapabilities.getJSONObject(NODE_FILES)
// Add files
capability.filesBigFileChunking = CapabilityBooleanType.fromBooleanValue(
respFiles.getBoolean(PROPERTY_BIGFILECHUNKING)
)
if (respFiles.has(PROPERTY_UNDELETE)) {
capability.filesUndelete = CapabilityBooleanType.fromBooleanValue(
respFiles.getBoolean(PROPERTY_UNDELETE)
)
}
if (respFiles.has(PROPERTY_VERSIONING)) {
capability.filesVersioning = CapabilityBooleanType.fromBooleanValue(
respFiles.getBoolean(PROPERTY_VERSIONING)
)
}
Log_OC.d(TAG, "*** Added $NODE_FILES")
}
}
// Result
result = RemoteOperationResult(OK)
result.data = capability
result.data = commonResponse?.ocs?.data?.toRemoteCapability()
Log_OC.d(TAG, "*** Get Capabilities completed ")
Timber.d("Get Capabilities completed and parsed to ${result.data}")
} else {
result = RemoteOperationResult(statuscode, message, null)
Log_OC.e(TAG, "Failed response while getting capabilities from the server ")
Log_OC.e(TAG, "*** status: $statusProp; message: $message")
result = RemoteOperationResult(getMethod)
Timber.e("Failed response while getting capabilities from the server status code: $status; response message: $response")
}
} catch (e: Exception) {
result = RemoteOperationResult(e)
Log_OC.e(TAG, "Exception while getting capabilities", e)
Timber.e(e, "Exception while getting capabilities")
}
return result
}
private fun isSuccess(status: Int): Boolean {
return status == HttpConstants.HTTP_OK
}
companion object {
private val TAG = GetRemoteCapabilitiesOperation::class.java.simpleName
// OCS Routes
private const val OCS_ROUTE = "ocs/v2.php/cloud/capabilities"
@ -275,58 +103,5 @@ class GetRemoteCapabilitiesOperation : RemoteOperation<RemoteCapability>() {
// Arguments - constant values
private const val VALUE_FORMAT = "json"
// JSON Node names
private const val NODE_OCS = "ocs"
private const val NODE_META = "meta"
private const val NODE_DATA = "data"
private const val NODE_VERSION = "version"
private const val NODE_CAPABILITIES = "capabilities"
private const val NODE_CORE = "core"
private const val NODE_FILES_SHARING = "files_sharing"
private const val NODE_PUBLIC = "public"
private const val NODE_PASSWORD = "password"
private const val NODE_ENFORCED_FOR = "enforced_for"
private const val NODE_EXPIRE_DATE = "expire_date"
private const val NODE_USER = "user"
private const val NODE_FEDERATION = "federation"
private const val NODE_FILES = "files"
private const val PROPERTY_STATUS = "status"
private const val PROPERTY_STATUS_OK = "ok"
private const val PROPERTY_STATUSCODE = "statuscode"
private const val PROPERTY_MESSAGE = "message"
private const val PROPERTY_POLLINTERVAL = "pollinterval"
private const val PROPERTY_MAJOR = "major"
private const val PROPERTY_MINOR = "minor"
private const val PROPERTY_MICRO = "micro"
private const val PROPERTY_STRING = "string"
private const val PROPERTY_EDITION = "edition"
private const val PROPERTY_API_ENABLED = "api_enabled"
private const val PROPERTY_ENABLED = "enabled"
private const val PROPERTY_ENFORCED = "enforced"
private const val PROPERTY_ENFORCED_READ_ONLY = "read_only"
private const val PROPERTY_ENFORCED_READ_WRITE = "read_write"
private const val PROPERTY_ENFORCED_UPLOAD_ONLY = "upload_only"
private const val PROPERTY_DAYS = "days"
private const val PROPERTY_SEARCH_MIN_LENGTH = "search_min_length"
private const val PROPERTY_SEND_MAIL = "send_mail"
private const val PROPERTY_UPLOAD = "upload"
private const val PROPERTY_UPLOAD_ONLY = "supports_upload_only"
private const val PROPERTY_MULTIPLE = "multiple"
private const val PROPERTY_RESHARING = "resharing"
private const val PROPERTY_OUTGOING = "outgoing"
private const val PROPERTY_INCOMING = "incoming"
private const val PROPERTY_BIGFILECHUNKING = "bigfilechunking"
private const val PROPERTY_UNDELETE = "undelete"
private const val PROPERTY_VERSIONING = "versioning"
}
}

View File

@ -1,200 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.status;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.json.JSONException;
import org.json.JSONObject;
import javax.net.ssl.SSLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Checks if the server is valid and if the server supports the Share API
*
* @author David A. Velasco
* @author masensio
* @author David González Verdugo
*/
public class GetRemoteStatusOperation extends RemoteOperation<OwnCloudVersion> {
/**
* Maximum time to wait for a response from the server when the connection is being tested,
* in MILLISECONDs.
*/
public static final long TRY_CONNECTION_TIMEOUT = 5000;
private static final String TAG = GetRemoteStatusOperation.class.getSimpleName();
private static final String NODE_INSTALLED = "installed";
private static final String NODE_VERSION = "version";
private static final String HTTPS_PREFIX = "https://";
private static final String HTTP_PREFIX = "http://";
private RemoteOperationResult<OwnCloudVersion> mLatestResult;
private Context mContext;
public GetRemoteStatusOperation(Context context) {
mContext = context;
}
private boolean tryConnection(OwnCloudClient client) {
boolean retval = false;
String baseUrlSt = client.getBaseUri().toString();
try {
GetMethod getMethod = new GetMethod(new URL(baseUrlSt + OwnCloudClient.STATUS_PATH));
getMethod.setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
getMethod.setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
client.setFollowRedirects(false);
boolean isRedirectToNonSecureConnection = false;
int status;
try {
status = client.executeHttpMethod(getMethod);
mLatestResult = isSuccess(status)
? new RemoteOperationResult<>(OK)
: new RemoteOperationResult<>(getMethod);
} catch (SSLException sslE) {
mLatestResult = new RemoteOperationResult(sslE);
return false;
}
String redirectedLocation = mLatestResult.getRedirectedLocation();
while (redirectedLocation != null && redirectedLocation.length() > 0
&& !mLatestResult.isSuccess()) {
isRedirectToNonSecureConnection |= (
baseUrlSt.startsWith(HTTPS_PREFIX) &&
redirectedLocation.startsWith(HTTP_PREFIX)
);
getMethod = new GetMethod(new URL(redirectedLocation));
getMethod.setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
getMethod.setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
status = client.executeHttpMethod(getMethod);
mLatestResult = new RemoteOperationResult<>(getMethod);
redirectedLocation = mLatestResult.getRedirectedLocation();
}
if (isSuccess(status)) {
JSONObject respJSON = new JSONObject(getMethod.getResponseBodyAsString());
if (!respJSON.getBoolean(NODE_INSTALLED)) {
mLatestResult = new RemoteOperationResult(
RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
} else {
String version = respJSON.getString(NODE_VERSION);
OwnCloudVersion ocVersion = new OwnCloudVersion(version);
/// the version object will be returned even if the version is invalid, no error code;
/// every app will decide how to act if (ocVersion.isVersionValid() == false)
if (isRedirectToNonSecureConnection) {
mLatestResult = new RemoteOperationResult<>(
RemoteOperationResult.ResultCode.
OK_REDIRECT_TO_NON_SECURE_CONNECTION);
} else {
mLatestResult = new RemoteOperationResult<>(
baseUrlSt.startsWith(HTTPS_PREFIX) ?
RemoteOperationResult.ResultCode.OK_SSL :
RemoteOperationResult.ResultCode.OK_NO_SSL);
}
mLatestResult.setData(ocVersion);
retval = true;
}
} else {
mLatestResult = new RemoteOperationResult<>(getMethod);
}
} catch (JSONException e) {
mLatestResult = new RemoteOperationResult<>(
RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
} catch (Exception e) {
mLatestResult = new RemoteOperationResult<>(e);
}
if (mLatestResult.isSuccess()) {
Log_OC.i(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage());
} else if (mLatestResult.getException() != null) {
Log_OC.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage(),
mLatestResult.getException());
} else {
Log_OC.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage());
}
return retval;
}
private boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm != null && cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isConnectedOrConnecting();
}
@Override
protected RemoteOperationResult<OwnCloudVersion> run(OwnCloudClient client) {
if (!isOnline()) {
return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
}
String baseUriStr = client.getBaseUri().toString();
if (baseUriStr.startsWith(HTTP_PREFIX) || baseUriStr.startsWith(HTTPS_PREFIX)) {
tryConnection(client);
} else {
client.setBaseUri(Uri.parse(HTTPS_PREFIX + baseUriStr));
boolean httpsSuccess = tryConnection(client);
if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) {
Log_OC.d(TAG, "establishing secure connection failed, trying non secure connection");
client.setBaseUri(Uri.parse(HTTP_PREFIX + baseUriStr));
tryConnection(client);
}
}
return mLatestResult;
}
private boolean isSuccess(int status) {
return (status == HttpConstants.HTTP_OK);
}
}

Some files were not shown because too many files have changed in this diff Show More