Skip to content

Commit 56ce389

Browse files
committed
Merge branch 'release/1.2.0'
2 parents 98ffe4a + e2c7ff0 commit 56ce389

File tree

10 files changed

+199
-32
lines changed

10 files changed

+199
-32
lines changed

.github/workflows/build.yml

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ jobs:
77
runs-on: ubuntu-latest
88
if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')"
99
steps:
10-
- uses: actions/checkout@v2
11-
- uses: actions/setup-java@v2
10+
- uses: actions/checkout@v3
11+
- uses: actions/setup-java@v3
1212
with:
1313
distribution: 'temurin'
14-
java-version: 17
14+
java-version: 19
1515
cache: 'maven'
1616
- name: Ensure to use tagged version
1717
if: startsWith(github.ref, 'refs/tags/')
@@ -21,16 +21,14 @@ jobs:
2121
- name: Build and Test
2222
id: buildAndTest
2323
run: mvn -B clean install -Pdependency-check
24-
- uses: actions/upload-artifact@v2
24+
- uses: actions/upload-artifact@v3
2525
with:
2626
name: artifacts
2727
path: target/*.jar
2828
- name: Create Release
29-
uses: actions/create-release@v1
29+
uses: softprops/action-gh-release@v1
3030
if: startsWith(github.ref, 'refs/tags/')
31-
env:
32-
GITHUB_TOKEN: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} # release as "cryptobot"
3331
with:
34-
tag_name: ${{ github.ref }}
35-
release_name: Release ${{ github.ref }}
36-
prerelease: true
32+
prerelease: true
33+
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
34+
generate_release_notes: true

.github/workflows/codeql-analysis.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ jobs:
1515
runs-on: ubuntu-latest
1616
if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')"
1717
steps:
18-
- uses: actions/checkout@v2
18+
- uses: actions/checkout@v3
1919
with:
2020
fetch-depth: 2
21-
- uses: actions/setup-java@v2
21+
- uses: actions/setup-java@v3
2222
with:
2323
distribution: 'temurin'
24-
java-version: 17
24+
java-version: 19
2525
cache: 'maven'
2626
- name: Initialize CodeQL
27-
uses: github/codeql-action/init@v1
27+
uses: github/codeql-action/init@v2
2828
with:
2929
languages: java
3030
- name: Build
3131
run: mvn -B compile
3232
- name: Perform CodeQL Analysis
33-
uses: github/codeql-action/analyze@v1
33+
uses: github/codeql-action/analyze@v2

.github/workflows/publish-central.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ jobs:
1010
publish:
1111
runs-on: ubuntu-latest
1212
steps:
13-
- uses: actions/checkout@v2
13+
- uses: actions/checkout@v3
1414
with:
1515
ref: "refs/tags/${{ github.event.inputs.tag }}"
16-
- uses: actions/setup-java@v2
16+
- uses: actions/setup-java@v3
1717
with:
1818
distribution: 'temurin'
19-
java-version: 17
19+
java-version: 19
2020
cache: 'maven'
2121
server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml
2222
server-username: MAVEN_USERNAME # env variable for username in deploy

.github/workflows/publish-github.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ jobs:
77
runs-on: ubuntu-latest
88
if: startsWith(github.ref, 'refs/tags/') # only allow publishing tagged versions
99
steps:
10-
- uses: actions/checkout@v2
11-
- uses: actions/setup-java@v2
10+
- uses: actions/checkout@v3
11+
- uses: actions/setup-java@v3
1212
with:
1313
distribution: 'temurin'
14-
java-version: 17
14+
java-version: 19
1515
cache: 'maven'
1616
gpg-private-key: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
1717
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase

pom.xml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<modelVersion>4.0.0</modelVersion>
66
<groupId>org.cryptomator</groupId>
77
<artifactId>integrations-linux</artifactId>
8-
<version>1.1.0</version>
8+
<version>1.2.0</version>
99

1010
<name>integrations-linux</name>
1111
<description>Provides optional Linux services used by Cryptomator</description>
@@ -36,12 +36,13 @@
3636

3737
<properties>
3838
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
39-
<project.jdk.version>17</project.jdk.version>
39+
<project.jdk.version>19</project.jdk.version>
4040

4141
<!-- runtime dependencies -->
42-
<api.version>1.1.0</api.version>
43-
<secret-service.version>1.7.0</secret-service.version>
44-
<kdewallet.version>1.2.6</kdewallet.version>
42+
43+
<api.version>1.2.0-beta4</api.version>
44+
<secret-service.version>1.8.1-jdk17</secret-service.version>
45+
<kdewallet.version>1.2.8</kdewallet.version>
4546
<guava.version>31.1-jre</guava.version>
4647
<slf4j.version>1.7.36</slf4j.version>
4748

@@ -94,7 +95,7 @@
9495
<artifactId>maven-compiler-plugin</artifactId>
9596
<version>3.9.0</version>
9697
<configuration>
97-
<release>17</release>
98+
<release>${project.jdk.version}</release>
9899
</configuration>
99100
</plugin>
100101
<plugin>

src/main/java/org/cryptomator/linux/keychain/KDEWalletKeychainAccess.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
import org.cryptomator.integrations.keychain.KeychainAccessException;
77
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
88
import org.freedesktop.dbus.connections.impl.DBusConnection;
9+
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder;
910
import org.freedesktop.dbus.exceptions.DBusConnectionException;
1011
import org.freedesktop.dbus.exceptions.DBusException;
12+
import org.freedesktop.dbus.exceptions.DBusExecutionException;
1113
import org.kde.KWallet;
1214
import org.kde.Static;
1315
import org.purejava.KDEWallet;
@@ -89,11 +91,12 @@ static Optional<ConnectedWallet> connect() {
8991

9092
private static DBusConnection getNewConnection() throws DBusException {
9193
try {
92-
return DBusConnection.newConnection(DBusConnection.DBusBusType.SESSION);
93-
} catch (DBusConnectionException ce) {
94-
LOG.warn("SESSION DBus not found, falling back to SYSTEM DBus");
94+
return DBusConnectionBuilder.forSessionBus().withShared(false).build();
95+
} catch (DBusConnectionException | DBusExecutionException de) {
96+
LOG.warn("Connecting to SESSION bus failed.", de);
97+
LOG.warn("Falling back to SYSTEM DBus");
9598
try {
96-
return DBusConnection.newConnection(DBusConnection.DBusBusType.SYSTEM);
99+
return DBusConnectionBuilder.forSystemBus().build();
97100
} catch (DBusException e) {
98101
throw e;
99102
}

src/main/java/org/cryptomator/linux/keychain/SecretServiceKeychainAccess.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import org.cryptomator.integrations.common.Priority;
55
import org.cryptomator.integrations.keychain.KeychainAccessException;
66
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
7+
import org.freedesktop.dbus.exceptions.DBusConnectionException;
8+
import org.freedesktop.dbus.exceptions.DBusExecutionException;
79
import org.freedesktop.secret.simple.SimpleCollection;
810

911
import java.io.IOException;
@@ -23,7 +25,16 @@ public String displayName() {
2325

2426
@Override
2527
public boolean isSupported() {
26-
return SimpleCollection.isAvailable();
28+
try {
29+
return SimpleCollection.isAvailable();
30+
} catch (ExceptionInInitializerError e) {
31+
//TODO: remove try-catch once secret-service lib is fixed
32+
if(e.getException() instanceof DBusExecutionException) {
33+
return false;
34+
} else {
35+
throw e;
36+
}
37+
}
2738
}
2839

2940
@Override
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package org.cryptomator.linux.revealpath;
2+
3+
import com.google.common.base.Preconditions;
4+
import org.cryptomator.integrations.revealpath.RevealFailedException;
5+
import org.cryptomator.integrations.revealpath.RevealPathService;
6+
7+
import java.io.IOException;
8+
import java.net.URLEncoder;
9+
import java.nio.charset.StandardCharsets;
10+
import java.nio.file.Files;
11+
import java.nio.file.LinkOption;
12+
import java.nio.file.Path;
13+
import java.nio.file.attribute.BasicFileAttributes;
14+
import java.util.Arrays;
15+
import java.util.concurrent.CountDownLatch;
16+
import java.util.concurrent.TimeUnit;
17+
import java.util.stream.Collectors;
18+
19+
/**
20+
* RevealPathService provider using the <a href="https://freedesktop.org/wiki/Specifications/file-manager-interface/">DBus freedesktop FileManager1 interface</a> and dbus-send command.
21+
*/
22+
public class DBusSendRevealPathService implements RevealPathService {
23+
24+
private static final String FILEMANAGER1_XML_ELEMENT = "<interface name=\"org.freedesktop.FileManager1\">";
25+
private static final String FOR_FOLDERS = "org.freedesktop.FileManager1.ShowFolders";
26+
private static final String FOR_FILES = "org.freedesktop.FileManager1.ShowItems";
27+
private static final int TIMEOUT_THRESHOLD = 5000;
28+
29+
@Override
30+
public void reveal(Path path) throws RevealFailedException {
31+
try {
32+
var attrs = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
33+
var uriPath = Arrays.stream(path.toUri().getPath().split("/")).map(s -> URLEncoder.encode(s, StandardCharsets.UTF_8).replace("+", "%20")).collect(Collectors.joining("/"));
34+
ProcessBuilder pb = new ProcessBuilder().command("dbus-send",
35+
"--print-reply",
36+
"--reply-timeout=" + TIMEOUT_THRESHOLD,
37+
"--dest=org.freedesktop.FileManager1",
38+
"--type=method_call",
39+
"/org/freedesktop/FileManager1",
40+
attrs.isDirectory() ? FOR_FOLDERS : FOR_FILES,
41+
String.format("array:string:file://%s", uriPath),
42+
"string:\"\""
43+
);
44+
var process = pb.start();
45+
try (var reader = process.errorReader()) {
46+
if (process.waitFor(TIMEOUT_THRESHOLD, TimeUnit.MILLISECONDS)) {
47+
int exitValue = process.exitValue();
48+
if (process.exitValue() != 0) {
49+
String error = reader.lines().collect(Collectors.joining());
50+
throw new RevealFailedException("dbus-send exited with code " + exitValue + " and error message: " + error);
51+
}
52+
}
53+
}
54+
} catch (IOException e) {
55+
throw new RevealFailedException(e);
56+
} catch (InterruptedException e) {
57+
Thread.currentThread().interrupt();
58+
throw new RevealFailedException(e);
59+
}
60+
}
61+
62+
@Override
63+
public boolean isSupported() {
64+
CountDownLatch waitBarrier = new CountDownLatch(2);
65+
ProcessBuilder dbusSendExistsBuilder = new ProcessBuilder().command("test", " `command -v dbus-send`");
66+
ProcessBuilder fileManager1ExistsBuilder = createFileManager1Check();
67+
68+
try {
69+
var dbusSendExists = dbusSendExistsBuilder.start();
70+
dbusSendExists.onExit().thenRun(waitBarrier::countDown);
71+
var fileManager1Exists = fileManager1ExistsBuilder.start();
72+
fileManager1Exists.onExit().thenRun(waitBarrier::countDown);
73+
74+
if (waitBarrier.await(TIMEOUT_THRESHOLD, TimeUnit.MILLISECONDS)) {
75+
if (dbusSendExists.exitValue() == 0 && fileManager1Exists.exitValue() == 0) {
76+
return parseOutputForFileManagerInterface(fileManager1Exists);
77+
}
78+
}
79+
} catch (IOException | InterruptedException e) {
80+
//NO-OP
81+
}
82+
return false;
83+
}
84+
85+
/**
86+
* Parses process stdout to see if the answer contains "{@value FILEMANAGER1_XML_ELEMENT}".
87+
* DBus introspection output is defined in the <a href="https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format">dbus spec</a>.
88+
*
89+
* @param fileManager1Process The already exited process for checking the FileManager1 interface
90+
* @return {@code true} if the interface is found in the introspection output, otherwise false
91+
* @throws IOException if the Inputer reader on the process output cannot be created
92+
*/
93+
private boolean parseOutputForFileManagerInterface(Process fileManager1Process) throws IOException {
94+
Preconditions.checkState(!fileManager1Process.isAlive());
95+
try (var reader = fileManager1Process.inputReader(StandardCharsets.UTF_8)) {
96+
return reader.lines().map(String::trim).anyMatch(FILEMANAGER1_XML_ELEMENT::equals);
97+
}
98+
}
99+
100+
private static ProcessBuilder createFileManager1Check() {
101+
return new ProcessBuilder().command(
102+
"dbus-send",
103+
"--session",
104+
"--print-reply",
105+
"--reply-timeout=" + TIMEOUT_THRESHOLD,
106+
"--dest=org.freedesktop.FileManager1",
107+
"--type=method_call",
108+
"/org/freedesktop/FileManager1",
109+
"org.freedesktop.DBus.Introspectable.Introspect"
110+
);
111+
}
112+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.cryptomator.linux.revealpath.DBusSendRevealPathService
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.cryptomator.linux.revealpath;
2+
3+
import org.cryptomator.integrations.revealpath.RevealFailedException;
4+
import org.junit.jupiter.api.Assertions;
5+
import org.junit.jupiter.api.Assumptions;
6+
import org.junit.jupiter.api.Disabled;
7+
import org.junit.jupiter.api.Test;
8+
import org.junit.jupiter.api.condition.EnabledOnOs;
9+
import org.junit.jupiter.api.condition.OS;
10+
import org.junit.jupiter.api.io.TempDir;
11+
12+
import java.nio.file.Path;
13+
14+
@EnabledOnOs(OS.LINUX)
15+
@Disabled
16+
public class DBusSendRevealPathServiceTest {
17+
18+
@TempDir Path tmpDir;
19+
DBusSendRevealPathService inTest = new DBusSendRevealPathService();
20+
21+
@Test
22+
public void testIsSupported() {
23+
Assertions.assertDoesNotThrow(() -> inTest.isSupported());
24+
}
25+
26+
@Test
27+
public void testRevealSuccess() {
28+
DBusSendRevealPathService revealPathService = new DBusSendRevealPathService();
29+
Assumptions.assumeTrue(revealPathService.isSupported());
30+
31+
Assertions.assertDoesNotThrow(() -> revealPathService.reveal(tmpDir));
32+
}
33+
34+
@Test
35+
public void testRevealFail() {
36+
DBusSendRevealPathService revealPathService = new DBusSendRevealPathService();
37+
Assumptions.assumeTrue(revealPathService.isSupported());
38+
39+
Assertions.assertThrows(RevealFailedException.class, () -> revealPathService.reveal(tmpDir.resolve("foobar")));
40+
}
41+
}

0 commit comments

Comments
 (0)