Skip to content

Commit 340338a

Browse files
committed
Merge branch 'develop' into feature/thumbnail-playground
2 parents bdc28c2 + 0c4cdb9 commit 340338a

File tree

89 files changed

+683
-315
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+683
-315
lines changed

.github/CONTRIBUTING.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
1-
# Contributing to Cryptomator
1+
# Contributing to Cryptomator for Android
22

33
## Did you find a bug?
44

5-
- Ensure you're running the latest version of Cryptomator.
6-
- Ensure the bug is related to the Android version of Cryptomator. Bugs concerning the Cryptomator desktop application and iOS app can be reported on the [Cryptomator issues list](https://github.com/cryptomator/cryptomator/issues) and [Cryptomator for iOS issues list](https://github.com/cryptomator/cryptomator-ios/issues) respectively.
7-
- Ensure the bug was not [already reported](https://github.com/cryptomator/android/issues). You can also check out our [FAQ](https://community.cryptomator.org/c/kb/faq).
8-
- If you're unable to find an open issue addressing the problem, [submit a new one](https://github.com/cryptomator/android/issues/new).
5+
- Ensure the bug was not [already reported](https://github.com/cryptomator/android/issues?q=).
6+
- If you're unable to find an open issue addressing the problem, [submit a new one](https://github.com/cryptomator/android/issues/new/choose).
7+
8+
## Did you write a patch that fixes a bug?
9+
10+
- Open a new pull request with the patch.
11+
- Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
12+
13+
## Do you intend to add a new feature or change an existing one?
14+
15+
- Suggest your change by [submitting a new issue](https://github.com/cryptomator/android/issues/new/choose) and start writing code.
16+
17+
## Do you intend to add a new translation or change an existing one?
18+
19+
Translations are not managed directly in this repository. Instead, we use [Crowdin](https://translate.cryptomator.org/), which automatically synchronizes translations with this repository. If you want to help us with translations, please visit our translation project on Crowdin.
920

1021
## Code of Conduct
1122

12-
Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/android/blob/develop/.github/CODE_OF_CONDUCT.md).
23+
Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md).
1324

1425
## Above all, thank you for your contributions
1526

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ gem "fastlane"
44
gem "net-sftp"
55
gem "ed25519"
66
gem "bcrypt_pbkdf"
7+
gem 'fastlane-plugin-bundletool'
78

89
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
910
eval_gemfile(plugins_path) if File.exist?(plugins_path)

Gemfile.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ GEM
118118
apktools (~> 0.7)
119119
aws-sdk-s3 (~> 1)
120120
mime-types (~> 3.3)
121+
fastlane-plugin-bundletool (1.1.0)
121122
fastlane-plugin-get_version_name (0.2.2)
122123
fastlane-sirp (1.0.0)
123124
sysrandom (~> 1.0)
@@ -236,6 +237,7 @@ DEPENDENCIES
236237
ed25519
237238
fastlane
238239
fastlane-plugin-aws_s3
240+
fastlane-plugin-bundletool
239241
fastlane-plugin-get_version_name
240242
net-sftp
241243

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
![cryptomator-android](cryptomator-android.png)
22

3-
[![Twitter](https://img.shields.io/badge/[email protected]?style=flat)](http://twitter.com/Cryptomator)
3+
[![Mastodon](https://img.shields.io/mastodon/follow/176112?domain=mastodon.online&style=flat)](https://mastodon.online/@cryptomator)
44
[![Community](https://img.shields.io/badge/help-Community-orange.svg)](https://community.cryptomator.org)
55
[![Documentation](https://img.shields.io/badge/help-Docs-orange.svg)](https://docs.cryptomator.org)
66
[![Crowdin](https://badges.crowdin.net/cryptomator/localized.svg)](https://translate.cryptomator.org/)
@@ -13,7 +13,8 @@ Cryptomator for Android is currently available in the following distribution ch
1313
2. [Using Cryptomator's Website](https://cryptomator.org/android/)
1414
3. [Using Cryptomator's F-Droid Repository](https://cryptomator.org/android/)
1515
4. [Using F-Droid's Main Repository](https://f-droid.org/en/packages/org.cryptomator.lite)
16-
5. Building from source using Gradle (instructions below)
16+
5. [Using Accrescent](https://accrescent.app/app/org.cryptomator)
17+
6. Building from source using Gradle (instructions below)
1718

1819
## Building
1920

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ allprojects {
3737
ext {
3838
androidApplicationId = 'org.cryptomator'
3939
androidVersionCode = getVersionCode() // must be getVersionCode(). only at release tag set the actual value
40-
androidVersionName = '1.11.0-SNAPSHOT'
40+
androidVersionName = '1.12.0-SNAPSHOT'
4141
}
4242
repositories {
4343
mavenCentral()

data/build.gradle

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ android {
5656
lite {
5757
dimension "version"
5858
}
59+
60+
accrescent {
61+
dimension "version"
62+
}
5963
}
6064

6165
sourceSets {
@@ -68,12 +72,16 @@ android {
6872
}
6973

7074
fdroid {
71-
java.srcDirs = ['src/main/java/', 'src/apiKey/java/', 'src/fdroid/java/']
75+
java.srcDirs = ['src/main/java/', 'src/apiKey/java/', 'src/fdroidAccrescent/java/']
7276
}
7377

7478
lite {
7579
java.srcDirs = ['src/main/java/', 'src/lite/java/']
7680
}
81+
82+
accrescent {
83+
java.srcDirs = ['src/main/java/', 'src/apiKey/java/', 'src/fdroidAccrescent/java/']
84+
}
7785
}
7886
packagingOptions {
7987
resources {
@@ -106,6 +114,7 @@ dependencies {
106114
playstoreImplementation dependencies.pcloud
107115
apkstoreImplementation dependencies.pcloud
108116
fdroidImplementation dependencies.pcloud
117+
accrescentImplementation dependencies.pcloud
109118

110119
coreLibraryDesugaring dependencies.coreDesugaring
111120

@@ -127,14 +136,18 @@ dependencies {
127136
apkstoreImplementation dependencies.dropboxAndroid
128137
fdroidImplementation dependencies.dropboxCore
129138
fdroidImplementation dependencies.dropboxAndroid
139+
accrescentImplementation dependencies.dropboxCore
140+
accrescentImplementation dependencies.dropboxAndroid
130141

131142

132143
playstoreImplementation dependencies.msgraphAuth
133144
apkstoreImplementation dependencies.msgraphAuth
134145
fdroidImplementation dependencies.msgraphAuth
146+
accrescentImplementation dependencies.msgraphAuth
135147
playstoreImplementation dependencies.msgraph
136148
apkstoreImplementation dependencies.msgraph
137149
fdroidImplementation dependencies.msgraph
150+
accrescentImplementation dependencies.msgraph
138151

139152
implementation dependencies.stax
140153
api dependencies.minIo

data/src/main/java/org/cryptomator/data/repository/HubRepositoryImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ private Interceptor httpLoggingInterceptor(Context context) {
5858
public String getVaultKeyJwe(UnverifiedHubVaultConfig unverifiedHubVaultConfig, String accessToken) throws BackendException {
5959
var request = new Request.Builder().get() //
6060
.header("Authorization", "Bearer " + accessToken) //
61+
.header("Hub-Device-ID", getHubDeviceCryptor().getDeviceId()) //
6162
.url(unverifiedHubVaultConfig.getApiBaseUrl() + "vaults/" + unverifiedHubVaultConfig.vaultId() + "/access-token") //
6263
.build();
6364
try (var response = getHttpClient().newCall(request).execute()) {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.cryptomator.domain.exception;
2+
3+
public class IllegalFileNameException extends BackendException {
4+
5+
public IllegalFileNameException() {
6+
}
7+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.cryptomator.domain.usecases;
2+
3+
import android.content.Context;
4+
import android.net.Uri;
5+
6+
import org.cryptomator.domain.exception.BackendException;
7+
import org.cryptomator.domain.exception.FatalBackendException;
8+
import org.cryptomator.generator.Parameter;
9+
import org.cryptomator.generator.UseCase;
10+
11+
import java.io.FileNotFoundException;
12+
import java.io.IOException;
13+
import java.io.InputStream;
14+
import java.security.DigestInputStream;
15+
import java.security.MessageDigest;
16+
import java.security.NoSuchAlgorithmException;
17+
18+
@UseCase
19+
public class CalculateFileHash {
20+
21+
private final Context context;
22+
private final Uri uri;
23+
24+
CalculateFileHash(final Context context, @Parameter Uri uri) {
25+
this.context = context;
26+
this.uri = uri;
27+
}
28+
29+
public byte[] execute() throws BackendException, FileNotFoundException {
30+
try {
31+
MessageDigest digest = MessageDigest.getInstance("MD5");
32+
try (InputStream inputStream = context.getContentResolver().openInputStream(uri); //
33+
DigestInputStream dis = new DigestInputStream(inputStream, digest)) {
34+
byte[] buffer = new byte[4096];
35+
while (dis.read(buffer) != -1) {
36+
}
37+
return digest.digest();
38+
} catch (IOException e) {
39+
throw new FatalBackendException(e);
40+
}
41+
} catch (NoSuchAlgorithmException e) {
42+
throw new RuntimeException(e);
43+
}
44+
}
45+
46+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package org.cryptomator.domain.usecases;
2+
3+
import android.content.ContentResolver;
4+
import android.content.Context;
5+
import android.net.Uri;
6+
import android.provider.DocumentsContract;
7+
8+
import org.cryptomator.domain.CloudFile;
9+
import org.cryptomator.domain.exception.BackendException;
10+
import org.cryptomator.domain.exception.FatalBackendException;
11+
import org.cryptomator.domain.exception.IllegalFileNameException;
12+
import org.cryptomator.domain.exception.NoSuchCloudFileException;
13+
import org.cryptomator.generator.Parameter;
14+
import org.cryptomator.generator.UseCase;
15+
import org.cryptomator.util.file.MimeType;
16+
import org.cryptomator.util.file.MimeTypes;
17+
18+
import java.io.FileNotFoundException;
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
@UseCase
23+
public class PrepareDownloadFiles {
24+
25+
private final Context context;
26+
private final MimeTypes mimeTypes;
27+
private final List<CloudFile> filesToExport;
28+
private final Uri parentUri;
29+
private final ContentResolver contentResolver;
30+
private final CloudNodeRecursiveListing cloudNodeRecursiveListing;
31+
32+
private List<DownloadFile> downloadFiles = new ArrayList<>();
33+
34+
PrepareDownloadFiles(Context context, MimeTypes mimeTypes, @Parameter List<CloudFile> filesToExport, @Parameter Uri parentUri, @Parameter CloudNodeRecursiveListing cloudNodeRecursiveListing) {
35+
this.context = context;
36+
this.mimeTypes = mimeTypes;
37+
this.filesToExport = filesToExport;
38+
this.parentUri = parentUri;
39+
this.contentResolver = context.getContentResolver();
40+
this.cloudNodeRecursiveListing = cloudNodeRecursiveListing;
41+
}
42+
43+
List<DownloadFile> execute() throws BackendException, FileNotFoundException {
44+
downloadFiles = prepareFilesForExport(filesToExport, parentUri);
45+
for (CloudFolderRecursiveListing folderRecursiveListing : cloudNodeRecursiveListing.getFoldersContent()) {
46+
prepareFolderContentForExport(folderRecursiveListing, parentUri);
47+
}
48+
return downloadFiles;
49+
}
50+
51+
private List<DownloadFile> prepareFilesForExport(List<CloudFile> filesToExport, Uri parentUri) throws NoSuchCloudFileException, FileNotFoundException, IllegalFileNameException {
52+
List<DownloadFile> downloadFiles = new ArrayList<>();
53+
for (CloudFile cloudFile : filesToExport) {
54+
DownloadFile downloadFile = createDownloadFile(cloudFile, parentUri);
55+
downloadFiles.add(downloadFile);
56+
}
57+
return downloadFiles;
58+
}
59+
60+
private void prepareFolderContentForExport(CloudFolderRecursiveListing folderRecursiveListing, Uri parentUri) throws FileNotFoundException, NoSuchCloudFileException, IllegalFileNameException {
61+
Uri createdFolder = createFolder(parentUri, folderRecursiveListing.getParent().getName());
62+
if (createdFolder != null) {
63+
downloadFiles.addAll(prepareFilesForExport(folderRecursiveListing.getFiles(), createdFolder));
64+
for (CloudFolderRecursiveListing childFolder : folderRecursiveListing.getFolders()) {
65+
prepareFolderContentForExport(childFolder, createdFolder);
66+
}
67+
} else {
68+
throw new FatalBackendException("Failed to create parent folder for export");
69+
}
70+
}
71+
72+
private Uri createFolder(Uri parentUri, String folderName) throws NoSuchCloudFileException {
73+
try {
74+
return DocumentsContract.createDocument(contentResolver, parentUri, DocumentsContract.Document.MIME_TYPE_DIR, folderName);
75+
} catch (FileNotFoundException e) {
76+
throw new NoSuchCloudFileException("Creating folder failed");
77+
}
78+
}
79+
80+
private DownloadFile createDownloadFile(CloudFile file, Uri documentUri) throws NoSuchCloudFileException, IllegalFileNameException {
81+
try {
82+
return new DownloadFile.Builder().setDownloadFile(file).setDataSink(contentResolver.openOutputStream(createNewDocumentUri(documentUri, file.getName()))).build();
83+
} catch (FileNotFoundException e) {
84+
throw new NoSuchCloudFileException(file.getName());
85+
}
86+
}
87+
88+
private Uri createNewDocumentUri(Uri parentUri, String fileName) throws IllegalFileNameException, NoSuchCloudFileException {
89+
MimeType mimeType = mimeTypes.fromFilename(fileName);
90+
if (mimeType == null) {
91+
mimeType = MimeType.APPLICATION_OCTET_STREAM;
92+
}
93+
try {
94+
Uri documentUri = DocumentsContract.createDocument(context.getContentResolver(), parentUri, mimeType.toString(), fileName);
95+
if (documentUri == null) {
96+
throw new IllegalFileNameException();
97+
}
98+
return documentUri;
99+
} catch (FileNotFoundException e) {
100+
throw new NoSuchCloudFileException(fileName);
101+
}
102+
}
103+
104+
}

fastlane/Fastfile

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ platform :android do |options|
3838
deployToServer(alpha:options[:alpha], beta:options[:beta])
3939
deployToFDroid(alpha:options[:alpha], beta:options[:beta])
4040
deployLite(alpha:options[:alpha], beta:options[:beta])
41+
deployToAccrescent(alpha:options[:alpha], beta:options[:beta])
4142
createGitHubDraftRelease(alpha:options[:alpha], beta:options[:beta])
4243

4344
slack(
@@ -292,6 +293,41 @@ platform :android do |options|
292293
FileUtils.cp(lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH], "release/Cryptomator-#{version}_fdroid_signed.apk")
293294
end
294295

296+
desc "Deploy new version to Accrescent"
297+
private_lane :deployToAccrescent do |options|
298+
gradle(task: "clean")
299+
300+
gradle(
301+
task: "bundle",
302+
build_type: "Release",
303+
flavor: "accrescent",
304+
print_command: false,
305+
properties: {
306+
"android.injected.signing.store.file" => ENV["SIGNING_KEYSTORE_PATH"],
307+
"android.injected.signing.store.password" => ENV["SIGNING_KEYSTORE_PASSWORD"],
308+
"android.injected.signing.key.alias" => ENV["SIGNING_KEY_ALIAS"],
309+
"android.injected.signing.key.password" => ENV["SIGNING_KEY_PASSWORD"],
310+
}
311+
)
312+
313+
FileUtils.cp(lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH], "release/Cryptomator-#{version}_signed.aab")
314+
315+
bundletool(
316+
ks_path: ENV["SIGNING_KEYSTORE_PATH"],
317+
ks_password: ENV["SIGNING_KEYSTORE_PASSWORD"],
318+
ks_key_alias: ENV["SIGNING_KEY_ALIAS"],
319+
ks_key_alias_password: ENV["SIGNING_KEY_PASSWORD"],
320+
bundletool_version: '1.10.0',
321+
aab_path: lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH],
322+
apk_output_path: "fastlane/release/Cryptomator-#{version}_signed.apks",
323+
verbose: true,
324+
cache_path: "~/.cache/bundletool",
325+
universal_apk: false
326+
)
327+
328+
puts "Upload fastlane/release/Cryptomator-#{version}_signed.apks to Accrescent"
329+
end
330+
295331
desc "Deploy new lite version"
296332
private_lane :deployLite do |options|
297333
sh("docker build -t cryptomator-android ../buildsystem")

fastlane/release-notes-de.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
- Hub-Unterstützung hinzugefügt
1+
- Cryptomator Hub erhält nun die Geräte-ID während der Tresorschlüsselabfrage
2+
- Potenzieller Absturz beim Öffnen großer Dateien und Exportieren großer Ordner behoben

fastlane/release-notes-en.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
- Add Hub support
1+
- Cryptomator Hub now receives the Device ID during vault key retrieval
2+
- Fixed potential crash when handling large files and exporting large folders

fastlane/release-notes.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
<ul>
2-
<li>Add Hub support</li>
2+
<li>Cryptomator Hub now receives the Device ID during vault key retrieval</li>
3+
<li>Fixed potential crash when handling large files and exporting large folders</li>
34
</ul>

0 commit comments

Comments
 (0)