Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into feature/dao-migration
Browse files Browse the repository at this point in the history
  • Loading branch information
JaniruTEC committed May 25, 2024
2 parents 40a4ed5 + 45f7d0e commit 7eb386f
Show file tree
Hide file tree
Showing 61 changed files with 1,957 additions and 211 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ Cryptomator for Android is currently available in the following distribution ch
### Run Git and Gradle

```
git submodule init && git submodule update // (not necessary if cloned using --recurse-submodules)
./gradlew assembleApkstoreDebug
```

Expand All @@ -42,7 +41,7 @@ Before connecting to Google Drive you have to create a new project in [Google Cl

Use the Docker image to verify the build of the 'lite' flavor:

1. Clone this repository (don't forget `--recurse-submodules`)
1. Clone this repository
2. Checkout the tag you want to build, e.g. 1.8.0
3. Build the image using `docker build -t cryptomator-android .` in the `buildsystem/` directory
4. Build Cryptomator using `docker run --rm -u $(id -u):$(id -g) -v $(pwd):/project -w /project cryptomator-android ./gradlew clean assembleLiteRelease` in the root of this folder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.dropbox.core.v2.files.Metadata
internal object DropboxCloudNodeFactory {

fun from(parent: DropboxFolder, metadata: FileMetadata): DropboxFile {
return DropboxFile(parent, metadata.name, metadata.pathDisplay, metadata.size, metadata.serverModified)
return DropboxFile(parent, metadata.name, metadata.pathDisplay, metadata.size, metadata.clientModified)
}

@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import org.cryptomator.util.file.LruFileCacheUtil.Companion.retrieveFromLruCache
import java.io.File
import java.io.IOException
import java.io.OutputStream
import java.util.Date
import timber.log.Timber

internal class DropboxImpl(cloud: DropboxCloud, context: Context) {
Expand Down Expand Up @@ -167,6 +168,7 @@ internal class DropboxImpl(cloud: DropboxCloud, context: Context) {
client() //
.files() //
.uploadBuilder(file.path) //
.withClientModified(data.modifiedDate(context).orElse(Date())) //
.withMode(writeMode) //
.uploadAndFinish(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ internal object OnedriveCloudNodeFactory {
}

private fun lastModified(item: DriveItem): Date? {
return item.lastModifiedDateTime?.let {
return Date.from(it.toInstant())
}
return item.fileSystemInfo?.lastModifiedDateTime?.let { clientDate -> Date.from(clientDate.toInstant()) }
?: item.lastModifiedDateTime?.let { serverDate -> Date.from(serverDate.toInstant()) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.microsoft.graph.http.GraphServiceException
import com.microsoft.graph.models.DriveItem
import com.microsoft.graph.models.DriveItemCreateUploadSessionParameterSet
import com.microsoft.graph.models.DriveItemUploadableProperties
import com.microsoft.graph.models.FileSystemInfo
import com.microsoft.graph.models.Folder
import com.microsoft.graph.models.ItemReference
import com.microsoft.graph.options.Option
Expand Down Expand Up @@ -39,6 +40,8 @@ import org.cryptomator.util.file.LruFileCacheUtil.Companion.retrieveFromLruCache
import java.io.File
import java.io.IOException
import java.io.OutputStream
import java.time.OffsetDateTime
import java.time.ZoneId
import java.util.Date
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutionException
Expand Down Expand Up @@ -202,14 +205,21 @@ internal class OnedriveImpl(private val cloud: OnedriveCloud, private val client
}
progressAware.onProgress(Progress.completed(UploadState.upload(file)))
return try {
OnedriveCloudNodeFactory.file(file.parent, result.get(), Date())
val driveItem: DriveItem = result.get()
val lastModifiedDate = getLastModifiedDateTime(driveItem) ?: Date()
OnedriveCloudNodeFactory.file(file.parent, driveItem, lastModifiedDate)
} catch (e: ExecutionException) {
throw FatalBackendException(e)
} catch (e: InterruptedException) {
throw FatalBackendException(e)
}
}

private fun getLastModifiedDateTime(driveItem: DriveItem): Date? {
return driveItem.fileSystemInfo?.lastModifiedDateTime?.let { clientDate -> Date.from(clientDate.toInstant()) }
?: driveItem.lastModifiedDateTime?.let { serverDate -> Date.from(serverDate.toInstant()) }
}

@Throws(NoSuchCloudFileException::class)
private fun uploadFile(file: OnedriveFile, data: DataSource, progressAware: ProgressAware<UploadState>, result: CompletableFuture<DriveItem>, conflictBehaviorOption: Option, size: Long) {
data.open(context)?.use { inputStream ->
Expand All @@ -228,12 +238,26 @@ internal class OnedriveImpl(private val cloud: OnedriveCloud, private val client
.putAsync(CopyStream.toByteArray(it)) //
.whenComplete { driveItem, error ->
run {
if (error == null) {
val modifiedDate = data.modifiedDate(context)
if (error != null) {
result.completeExceptionally(error)
return@whenComplete
}
if (modifiedDate.isPresent) {
patchAsyncLastModifiedDate(parentNodeInfo, driveItem, modifiedDate.get())
.whenComplete { driveItem, error ->
if (error == null) {
progressAware.onProgress(Progress.completed(UploadState.upload(file)))
result.complete(driveItem)
cacheNodeInfo(file, driveItem)
} else {
result.completeExceptionally(error)
}
}
} else { // current date is the default, no need to patch()
progressAware.onProgress(Progress.completed(UploadState.upload(file)))
result.complete(driveItem)
cacheNodeInfo(file, driveItem)
} else {
result.completeExceptionally(error)
}
}
}
Expand All @@ -244,13 +268,32 @@ internal class OnedriveImpl(private val cloud: OnedriveCloud, private val client
} ?: throw FatalBackendException("InputStream shouldn't bee null")
}

private fun patchAsyncLastModifiedDate(parentNodeInfo: OnedriveIdCache.NodeInfo, driveItem: DriveItem, modifiedDate: Date): CompletableFuture<DriveItem> {
val diffItem = DriveItem()
diffItem.fileSystemInfo = FileSystemInfo()
diffItem.fileSystemInfo!!.lastModifiedDateTime = OffsetDateTime.ofInstant(modifiedDate.toInstant(), ZoneId.systemDefault())
return drive(parentNodeInfo.driveId) //
.items(driveItem.id!!) //
.buildRequest() //
.patchAsync(diffItem) //
}

@Throws(IOException::class, NoSuchCloudFileException::class)
private fun chunkedUploadFile(file: OnedriveFile, data: DataSource, progressAware: ProgressAware<UploadState>, result: CompletableFuture<DriveItem>, conflictBehaviorOption: Option, size: Long) {
val parentNodeInfo = requireNodeInfo(file.parent)

val props = DriveItemUploadableProperties()
val modifiedDate = data.modifiedDate(context)

if (modifiedDate.isPresent) {
props.fileSystemInfo = FileSystemInfo()
props.fileSystemInfo!!.lastModifiedDateTime = OffsetDateTime.ofInstant(modifiedDate.get().toInstant(), ZoneId.systemDefault())
}

drive(parentNodeInfo.driveId) //
.items(parentNodeInfo.id) //
.itemWithPath(file.name) //
.createUploadSession(DriveItemCreateUploadSessionParameterSet.newBuilder().withItem(DriveItemUploadableProperties()).build()) //
.createUploadSession(DriveItemCreateUploadSessionParameterSet.newBuilder().withItem(props).build()) //
.buildRequest() //
.post()?.let { uploadSession ->
data.open(context)?.use { inputStream ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ internal class PCloudImpl(private val cloud: PCloud, private val client: ApiClie
}
return try {
client //
.createFile(file.parent.path, file.name, pCloudDataSource, Date(), listener, uploadOptions) //
.createFile(file.parent.path, file.name, pCloudDataSource, data.modifiedDate(context).orElse(Date()), listener, uploadOptions) //
.execute()
} catch (ex: ApiError) {
handleApiError(ex, file.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.cryptomator.data.cloud.googledrive
import android.content.Context
import com.google.api.client.googleapis.json.GoogleJsonResponseException
import com.google.api.client.http.HttpResponseException
import com.google.api.client.util.DateTime
import com.google.api.services.drive.Drive
import com.google.api.services.drive.model.File
import com.google.api.services.drive.model.Revision
Expand All @@ -25,6 +26,7 @@ import org.cryptomator.util.file.LruFileCacheUtil
import org.cryptomator.util.file.LruFileCacheUtil.Companion.retrieveFromLruCache
import java.io.IOException
import java.io.OutputStream
import java.util.Date
import timber.log.Timber

internal class GoogleDriveImpl(context: Context, googleDriveCloud: GoogleDriveCloud, idCache: GoogleDriveIdCache) {
Expand Down Expand Up @@ -203,6 +205,7 @@ internal class GoogleDriveImpl(context: Context, googleDriveCloud: GoogleDriveCl
val metadata = File()
metadata.name = file.name
progressAware.onProgress(Progress.started(UploadState.upload(file)))
metadata.setModifiedTime(DateTime(data.modifiedDate(context).orElse(Date())))
val uploadedFile = if (file.driveId != null && replace) {
updateFile(file, data, progressAware, size, metadata)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ abstract class CryptoImplDecorator(
progressAware.onProgress(Progress.progress(UploadState.encryption(cryptoFile)).between(0).and(ciphertextSize).withValue(encrypted))
}
encryptingWritableByteChannel.close()
data.modifiedDate(context).ifPresent { encryptedTmpFile.setLastModified(it.time) }
progressAware.onProgress(Progress.completed(UploadState.encryption(cryptoFile)))
return writeFromTmpFile(data, cryptoFile, encryptedTmpFile, progressAware, replace)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator {
progressAware.onProgress(Progress.progress(UploadState.encryption(cloudFile)).between(0).and(ciphertextSize).withValue(encrypted))
}
encryptingWritableByteChannel.close()
data.modifiedDate(context).ifPresent { encryptedTmpFile.setLastModified(it.time) }
progressAware.onProgress(Progress.completed(UploadState.encryption(cloudFile)))
val targetFile = targetFile(cryptoFile, cloudFile, replace)
return file(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.cryptomator.domain.usecases.cloud.Progress
import org.cryptomator.domain.usecases.cloud.UploadState
import java.io.IOException
import java.io.OutputStream
import java.util.Date
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull

internal class WebDavImpl(private val cloud: WebDavCloud, private val connectionHandler: ConnectionHandlerHandlerImpl, private val context: Context) {
Expand Down Expand Up @@ -133,7 +134,7 @@ internal class WebDavImpl(private val cloud: WebDavCloud, private val connection
)
}
}.use {
connectionHandler.writeFile(absoluteUriFrom(uploadFile.path), it)
connectionHandler.writeFile(absoluteUriFrom(uploadFile.path), it, data.modifiedDate(context).orElse(Date()))
}
} ?: throw FatalBackendException("InputStream shouldn't bee null")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.cryptomator.data.cloud.webdav.WebDavNode
import org.cryptomator.domain.CloudFolder
import org.cryptomator.domain.exception.BackendException
import java.io.InputStream
import java.util.Date
import javax.inject.Inject

class ConnectionHandlerHandlerImpl @Inject internal constructor(httpClient: WebDavCompatibleHttpClient) {
Expand All @@ -27,8 +28,8 @@ class ConnectionHandlerHandlerImpl @Inject internal constructor(httpClient: WebD
}

@Throws(BackendException::class)
fun writeFile(url: String, inputStream: InputStream) {
webDavClient.writeFile(url, inputStream)
fun writeFile(url: String, inputStream: InputStream, modifiedDate: Date) {
webDavClient.writeFile(url, inputStream, modifiedDate)
}

@Throws(BackendException::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ internal class InputStreamSourceBasedRequestBody private constructor(private val

@Throws(IOException::class)
override fun contentLength(): Long {
return inputStream.available().toLong()
val availableBytes = inputStream.available()
/**
* inputStream.available() is an int and if the file to upload is > int.max it will overflow to 0.
* In this case we set contentLength to -1, which is fine, it just means the length is unknown.
* If inputStream.available() is actually 0, it does no harm either because we are not uploading a byte.
*/
return if (availableBytes != 0) {
availableBytes.toLong()
} else {
-1
}
}

override fun contentType(): MediaType? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import java.io.IOException
import java.io.InputStream
import java.net.HttpURLConnection
import java.util.Collections
import java.util.Date
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
Expand Down Expand Up @@ -150,8 +151,9 @@ internal class WebDavClient(private val httpClient: WebDavCompatibleHttpClient)
}

@Throws(BackendException::class)
fun writeFile(url: String, inputStream: InputStream) {
fun writeFile(url: String, inputStream: InputStream, modifiedDate: Date) {
val builder = Request.Builder() //
.addHeader("X-OC-Mtime", modifiedDate.toInstant().toEpochMilli().div(1000).toString()) //
.put(InputStreamSourceBasedRequestBody.from(inputStream)) //
.url(url)
try {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.cryptomator.domain.usecases.cloud

import android.content.Context
import org.cryptomator.util.Optional
import java.io.ByteArrayInputStream
import java.io.IOException
import java.io.InputStream
import java.util.Date

class ByteArrayDataSource private constructor(private val bytes: ByteArray) : DataSource {

Expand All @@ -25,6 +27,10 @@ class ByteArrayDataSource private constructor(private val bytes: ByteArray) : Da
// do nothing because ByteArrayInputStream need no close
}

override fun modifiedDate(context: Context): Optional<Date> {
return Optional.empty()
}

companion object {

@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package org.cryptomator.domain.usecases.cloud

import android.content.Context
import org.cryptomator.domain.exception.CancellationException
import org.cryptomator.util.Optional
import java.io.IOException
import java.io.InputStream
import java.util.Date

class CancelAwareDataSource private constructor(private val delegate: DataSource, private val cancelled: Flag) : DataSource {

Expand Down Expand Up @@ -31,6 +33,13 @@ class CancelAwareDataSource private constructor(private val delegate: DataSource
delegate.close()
}

override fun modifiedDate(context: Context): Optional<Date> {
if (cancelled.get()) {
throw CancellationException()
}
return delegate.modifiedDate(context)
}

companion object {

@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.cryptomator.domain.usecases.cloud

import android.content.Context
import org.cryptomator.util.Optional
import java.io.Closeable
import java.io.IOException
import java.io.InputStream
import java.io.Serializable
import java.util.Date

interface DataSource : Serializable, Closeable {

Expand All @@ -15,4 +17,6 @@ interface DataSource : Serializable, Closeable {

fun decorate(delegate: DataSource): DataSource

fun modifiedDate(context: Context): Optional<Date>

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.cryptomator.domain.usecases.cloud

import android.content.Context
import org.cryptomator.util.Optional
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.util.Date

class FileBasedDataSource private constructor(private val file: File) : DataSource {

Expand All @@ -26,6 +28,10 @@ class FileBasedDataSource private constructor(private val file: File) : DataSour
// Do nothing
}

override fun modifiedDate(context: Context): Optional<Date> {
return Optional.of(Date(file.lastModified()))
}

companion object {

@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ private File copyDataToFile(DataSource dataSource) {
InputStream in = CancelAwareDataSource.wrap(dataSource, cancelledFlag).open(context);
OutputStream out = new FileOutputStream(target);
copy(in, out);
dataSource.modifiedDate(context).ifPresent(value -> target.setLastModified(value.getTime()));
return target;
} catch (IOException e) {
throw new FatalBackendException(e);
Expand Down

0 comments on commit 7eb386f

Please sign in to comment.