diff --git a/.idea/runConfigurations/Cryptomator_macOS.xml b/.idea/runConfigurations/Cryptomator_macOS.xml
index bdd57a54a..b1fd85746 100644
--- a/.idea/runConfigurations/Cryptomator_macOS.xml
+++ b/.idea/runConfigurations/Cryptomator_macOS.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/dist/mac/dmg/build.sh b/dist/mac/dmg/build.sh
index 391ee7bb5..fbe81931c 100755
--- a/dist/mac/dmg/build.sh
+++ b/dist/mac/dmg/build.sh
@@ -123,7 +123,7 @@ ${JAVA_HOME}/bin/jpackage \
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"${APP_NAME}\"" \
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Library/Application Support${APP_NAME}/mnt\"" \
--java-options "-Dcryptomator.showTrayIcon=true" \
- --java-options "-Dcryptomator.updateMechanism=org.cryptomator.updater.MacOsDmgUpdateMechanism" \
+ --java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism" \
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
--mac-package-identifier ${PACKAGE_IDENTIFIER} \
--resource-dir ../resources
diff --git a/pom.xml b/pom.xml
index 6b461a5f8..94415ed3d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,9 +34,9 @@
2.9.0
- 1.7.0-SNAPSHOT
+ 1.8.0-SNAPSHOT
1.5.1
- 1.4.1
+ 1.5.0-SNAPSHOT
1.7.0-SNAPSHOT
5.1.0
3.0.0
@@ -75,6 +75,20 @@
+
+
+ Central Portal Snapshots
+ central-portal-snapshots
+ https://central.sonatype.com/repository/maven-snapshots/
+
+ false
+
+
+ true
+
+
+
+
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 8db372c7a..c4a1bfe58 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -21,7 +21,6 @@ import org.cryptomator.networking.SSLContextWithWindowsCertStore;
import org.cryptomator.integrations.tray.TrayMenuController;
import org.cryptomator.logging.LogbackConfiguratorFactory;
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
-import org.cryptomator.updater.MacOsDmgUpdateMechanism;
open module org.cryptomator.desktop {
requires static org.jetbrains.annotations;
@@ -64,9 +63,6 @@ open module org.cryptomator.desktop {
uses SSLContextProvider;
uses org.cryptomator.event.NotificationHandler;
- // opens org.cryptomator.updater to org.cryptomator.integrations.api;
- provides UpdateMechanism with MacOsDmgUpdateMechanism;
-
provides TrayMenuController with AwtTrayMenuController;
provides Configurator with LogbackConfiguratorFactory;
provides SSLContextProvider with SSLContextWithWindowsCertStore, SSLContextWithMacKeychain, SSLContextWithPKCS12TrustStore;
diff --git a/src/main/java/org/cryptomator/updater/DownloadUpdateMechanism.java b/src/main/java/org/cryptomator/updater/DownloadUpdateMechanism.java
deleted file mode 100644
index dc9679d36..000000000
--- a/src/main/java/org/cryptomator/updater/DownloadUpdateMechanism.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.cryptomator.updater;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.cryptomator.integrations.update.UpdateInfo;
-import org.cryptomator.integrations.update.UpdateMechanism;
-import org.jetbrains.annotations.Blocking;
-import org.jetbrains.annotations.Nullable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.util.List;
-
-public abstract class DownloadUpdateMechanism implements UpdateMechanism {
-
- private static final Logger LOG = LoggerFactory .getLogger(DownloadUpdateMechanism.class);
- private static final String LATEST_VERSION_API_URL = "https://api.cryptomator.org/connect/apps/desktop/latest-version?format=1";
- private static final ObjectMapper MAPPER = new ObjectMapper();
-
- public record DownloadUpdateInfo(
- DownloadUpdateMechanism updateMechanism,
- String version,
- Asset asset
- ) implements UpdateInfo {}
-
- @Override
- public DownloadUpdateInfo checkForUpdate(String currentVersion, HttpClient httpClient) {
- try {
- HttpRequest request = HttpRequest.newBuilder().uri(URI.create(LATEST_VERSION_API_URL)).build();
- HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
- if (response.statusCode() != 200) {
- throw new RuntimeException("Failed to fetch release: " + response.statusCode());
- }
- var release = MAPPER.readValue(response.body(), LatestVersionResponse.class);
- return checkForUpdate(currentVersion, release);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- LOG.debug("Update check interrupted.");
- return null;
- } catch (IOException e) {
- LOG.warn("Update check failed", e);
- return null;
- }
- }
-
- @Nullable
- @Blocking
- abstract DownloadUpdateInfo checkForUpdate(String currentVersion, LatestVersionResponse response);
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- public record LatestVersionResponse(
- @JsonProperty("latestVersion") LatestVersion latestVersion,
- @JsonProperty("assets") List assets
- ) {}
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- public record LatestVersion(
- @JsonProperty("mac") String macVersion,
- @JsonProperty("win") String winVersion,
- @JsonProperty("linux") String linuxVersion
- ) {}
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- public record Asset(
- @JsonProperty("name") String name,
- @JsonProperty("digest") String digest,
- @JsonProperty("size") long size,
- @JsonProperty("downloadUrl") String downloadUrl
- ) {}
-
-}
diff --git a/src/main/java/org/cryptomator/updater/MacOsDmgUpdateMechanism.java b/src/main/java/org/cryptomator/updater/MacOsDmgUpdateMechanism.java
deleted file mode 100644
index 91205b610..000000000
--- a/src/main/java/org/cryptomator/updater/MacOsDmgUpdateMechanism.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package org.cryptomator.updater;
-
-import org.cryptomator.integrations.common.DisplayName;
-import org.cryptomator.integrations.common.OperatingSystem;
-import org.cryptomator.integrations.common.Priority;
-import org.cryptomator.integrations.update.DownloadUpdateStep;
-import org.cryptomator.integrations.update.UpdateFailedException;
-import org.cryptomator.integrations.update.UpdateMechanism;
-import org.cryptomator.integrations.update.UpdateStep;
-import org.jetbrains.annotations.Nullable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.HexFormat;
-import java.util.List;
-import java.util.UUID;
-
-
-@Priority(1000)
-@OperatingSystem(OperatingSystem.Value.MAC)
-@DisplayName("download .dmg file") // TODO: localize
-public class MacOsDmgUpdateMechanism extends DownloadUpdateMechanism {
-
- private static final Logger LOG = LoggerFactory.getLogger(MacOsDmgUpdateMechanism.class);
-
- @Override
- DownloadUpdateInfo checkForUpdate(String currentVersion, LatestVersionResponse response) {
- String suffix = switch (System.getProperty("os.arch")) {
- case "aarch64", "arm64" -> "arm64.dmg";
- default -> "x64.dmg";
- };
- var updateVersion = response.latestVersion().macVersion();
- var asset = response.assets().stream().filter(a -> a.name().endsWith(suffix)).findAny().orElse(null);
- if (UpdateMechanism.isUpdateAvailable(updateVersion, currentVersion) && asset != null) {
- return new DownloadUpdateMechanism.DownloadUpdateInfo(this, updateVersion, asset);
- } else {
- return null;
- }
- }
-
- @Override
- public UpdateStep firstStep(DownloadUpdateInfo updateInfo) throws UpdateFailedException {
- try {
- Path workDir = Files.createTempDirectory("cryptomator-update");
- return new UpdateProcessImpl(workDir, updateInfo);
- } catch (IOException e) {
- throw new UpdateFailedException("Failed to create temporary directory for update", e);
- }
- }
-
- private static class UpdateProcessImpl extends DownloadUpdateStep {
-
- private final Path workDir;
-
- public UpdateProcessImpl(Path workDir, DownloadUpdateInfo updateInfo) {
- var destination = workDir.resolve("update.dmg");
- var downloadUri = URI.create(updateInfo.asset().downloadUrl());
- var checksum = HexFormat.of().withLowerCase().parseHex(updateInfo.asset().digest().substring(7)); // remove "sha256:" prefix
- super(downloadUri, destination, checksum, 60_000_000L); // initially assume 60 MB for the update size
- this.workDir = workDir;
- }
-
- @Override
- public @Nullable UpdateStep nextStep() throws IllegalStateException, IOException {
- if (!isDone()) {
- throw new IllegalStateException("Update not yet downloaded");
- } else if (downloadException != null) {
- throw new UpdateFailedException("Download failed", downloadException);
- }
- return UpdateStep.of("Mounting...", this::mount);
- }
-
- private UpdateStep mount() throws IOException {
- // Extract Cryptomator.app from the .dmg file
- String script = """
- hdiutil attach 'update.dmg' -mountpoint "/Volumes/Cryptomator_${MOUNT_ID}" -nobrowse -quiet &&
- cp -R "/Volumes/Cryptomator_${MOUNT_ID}/Cryptomator.app" 'Cryptomator.app' &&
- hdiutil detach "/Volumes/Cryptomator_${MOUNT_ID}" -quiet
- """;
- var command = List.of("bash", "-c", script);
- var processBuilder = new ProcessBuilder(command);
- processBuilder.directory(workDir.toFile());
- processBuilder.environment().put("MOUNT_ID", UUID.randomUUID().toString());
- Process p = processBuilder.start();
- try {
- if (p.waitFor() != 0) {
- LOG.error("Failed to extract DMG, exit code: {}, output: {}", p.exitValue(), new String(p.getErrorStream().readAllBytes()));
- throw new IOException("Failed to extract DMG, exit code: " + p.exitValue());
- }
- LOG.debug("Update ready: {}", workDir.resolve("Cryptomator.app"));
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new InterruptedIOException("Failed to extract DMG, interrupted");
- }
- return UpdateStep.of("Restarting...", this::restart);
- }
-
- public UpdateStep restart() throws IllegalStateException, IOException {
- String selfPath = ProcessHandle.current().info().command().orElse("");
- String installPath;
- if (selfPath.startsWith("/Applications/Cryptomator.app")) {
- installPath = "/Applications/Cryptomator.app";
- } else if (selfPath.contains("/Cryptomator.app/")) {
- installPath = selfPath.substring(0, selfPath.indexOf("/Cryptomator.app/")) + "/Cryptomator.app";
- } else {
- throw new UpdateFailedException("Cannot determine destination path for Cryptomator.app, current path: " + selfPath);
- }
- LOG.info("Restarting to apply Update in {} now...", workDir);
- String script = """
- while kill -0 ${CRYPTOMATOR_PID} 2> /dev/null; do sleep 0.5; done;
- if [ -d "${CRYPTOMATOR_INSTALL_PATH}" ]; then
- echo "Removing old installation at ${CRYPTOMATOR_INSTALL_PATH}";
- rm -rf "${CRYPTOMATOR_INSTALL_PATH}"
- fi
- mv 'Cryptomator.app' "${CRYPTOMATOR_INSTALL_PATH}";
- open -a "${CRYPTOMATOR_INSTALL_PATH}";
- """;
- Files.writeString(workDir.resolve("install.sh"), script, StandardCharsets.US_ASCII, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);
- var command = List.of("bash", "-c", "nohup bash install.sh >install.log 2>&1 &");
- var processBuilder = new ProcessBuilder(command);
- processBuilder.directory(workDir.toFile());
- processBuilder.environment().put("CRYPTOMATOR_PID", String.valueOf(ProcessHandle.current().pid()));
- processBuilder.environment().put("CRYPTOMATOR_INSTALL_PATH", installPath);
- processBuilder.start();
-
- return UpdateStep.EXIT;
- }
- }
-
-}