Skip to content
This repository has been archived by the owner on Sep 19, 2023. It is now read-only.

Commit

Permalink
8289030: [macos] app image signature invalid when creating DMG or PKG
Browse files Browse the repository at this point in the history
Reviewed-by: asemenyuk
  • Loading branch information
Alexander Matveev committed Jul 8, 2022
1 parent 1304390 commit 6428607
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 27 deletions.
Expand Up @@ -38,7 +38,9 @@

public class MacAppBundler extends AppImageBundler {
public MacAppBundler() {
setAppImageSupplier(MacAppImageBuilder::new);
setAppImageSupplier(imageOutDir -> {
return new MacAppImageBuilder(imageOutDir, isDependentTask());
});
setParamsValidator(MacAppBundler::doValidate);
}

Expand Down
Expand Up @@ -90,6 +90,8 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
private final Path runtimeDir;
private final Path runtimeRoot;

private final boolean withPackageFile;

private static List<String> keyChains;

public static final BundlerParamInfo<Boolean>
Expand Down Expand Up @@ -243,10 +245,11 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
(s, p) -> Arrays.asList(s.split("(,|\\s)+"))
);

public MacAppImageBuilder(Path imageOutDir) {
public MacAppImageBuilder(Path imageOutDir, boolean withPackageFile) {
super(imageOutDir);

this.root = imageOutDir;
this.withPackageFile = withPackageFile;
this.contentsDir = root.resolve("Contents");
this.resourcesDir = appLayout.destktopIntegrationDirectory();
this.macOSDir = appLayout.launchersDirectory();
Expand Down Expand Up @@ -309,6 +312,11 @@ public void prepareApplicationFiles(Map<String, ? super Object> params)
// Copy class path entries to Java folder
copyApplication(params);

if (withPackageFile) {
new PackageFile(APP_NAME.fetchFrom(params)).save(
ApplicationLayout.macAppImage().resolveAt(root));
}

/*********** Take care of "config" files *******/

createResource(TEMPLATE_BUNDLE_ICON, params)
Expand Down
Expand Up @@ -29,6 +29,7 @@
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.ArrayList;
Expand Down Expand Up @@ -113,7 +114,8 @@ static String getInstallDir(
}

public MacBaseInstallerBundler() {
appImageBundler = new MacAppBundler().setDependentTask(true);
appImageBundler = new MacAppBundler()
.setDependentTask(true);
}

protected void validateAppImageAndBundeler(
Expand All @@ -136,11 +138,18 @@ protected void validateAppImageAndBundeler(
I18N.getString(
"message.app-image-requires-app-name.advice"));
}
if (Optional.ofNullable(
SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) {
// if signing bundle with app-image, warn user if app-image
// is not already signed.
if (!(AppImageFile.load(applicationImage).isSigned())) {
if (AppImageFile.load(applicationImage).isSigned()) {
if (!Files.exists(
PackageFile.getPathInAppImage(applicationImage))) {
Log.info(MessageFormat.format(I18N.getString(
"warning.per.user.app.image.signed"),
PackageFile.getPathInAppImage(applicationImage)));
}
} else {
if (Optional.ofNullable(
SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) {
// if signing bundle with app-image, warn user if app-image
// is not already signed.
Log.info(MessageFormat.format(I18N.getString(
"warning.unsigned.app.image"), getID()));
}
Expand All @@ -158,17 +167,19 @@ protected Path prepareAppBundle(Map<String, ? super Object> params)
StandardBundlerParam.getPredefinedAppImage(params);
if (predefinedImage != null) {
appDir = appImageRoot.resolve(APP_NAME.fetchFrom(params) + ".app");
IOUtils.copyRecursive(predefinedImage, appDir);
IOUtils.copyRecursive(predefinedImage, appDir,
LinkOption.NOFOLLOW_LINKS);

// Create PackageFile if predefined app image is not signed
if (!StandardBundlerParam.isRuntimeInstaller(params) &&
!AppImageFile.load(predefinedImage).isSigned()) {
new PackageFile(APP_NAME.fetchFrom(params)).save(
ApplicationLayout.macAppImage().resolveAt(appDir));
}
} else {
appDir = appImageBundler.execute(params, appImageRoot);
}

if (!StandardBundlerParam.isRuntimeInstaller(params)) {
new PackageFile(APP_NAME.fetchFrom(params)).save(
ApplicationLayout.macAppImage().resolveAt(appDir));
Files.deleteIfExists(AppImageFile.getPathInAppImage(appDir));
}

return appDir;
}

Expand Down
Expand Up @@ -94,3 +94,4 @@ message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trus
message.setfile.dmg=Setting custom icon on DMG file skipped because 'SetFile' utility was not found. Installing Xcode with Command Line Tools should resolve this issue.
message.install-dir-ignored=Warning: "--install-dir" is not supported by DMG and will be default to /Applications.
warning.unsigned.app.image=Warning: Using unsigned app-image to build signed {0}.
warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image.
Expand Up @@ -90,3 +90,4 @@ message.signing.pkg=Warnung: Zum Signieren von PKG m\u00FCssen Sie m\u00F6gliche
message.setfile.dmg=Das Festlegen des benutzerdefinierten Symbols f\u00FCr die DMG-Datei wurde \u00FCbersprungen, weil das Utility "SetFile" nicht gefunden wurde. Durch Installieren von Xcode mit Befehlszeilentools sollte dieses Problem behoben werden.
message.install-dir-ignored=Warnung: "--install-dir" wird von DMG nicht unterst\u00FCtzt. Stattdessen wird standardm\u00E4\u00DFig /Applications verwendet.
warning.unsigned.app.image=Warnung: Nicht signiertes app-image wird zum Erstellen von signiertem {0} verwendet.
warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image.
Expand Up @@ -94,3 +94,4 @@ message.signing.pkg=\u8B66\u544A: PKG\u3078\u306E\u7F72\u540D\u306E\u5834\u5408\
message.setfile.dmg='SetFile'\u30E6\u30FC\u30C6\u30A3\u30EA\u30C6\u30A3\u304C\u898B\u3064\u304B\u3089\u306A\u3044\u305F\u3081\u3001DMG\u30D5\u30A1\u30A4\u30EB\u3067\u306E\u30AB\u30B9\u30BF\u30E0\u30FB\u30A2\u30A4\u30B3\u30F3\u306E\u8A2D\u5B9A\u304C\u30B9\u30AD\u30C3\u30D7\u3055\u308C\u307E\u3057\u305F\u3002Xcode\u3068\u30B3\u30DE\u30F3\u30C9\u30FB\u30E9\u30A4\u30F3\u30FB\u30C4\u30FC\u30EB\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3059\u308B\u3068\u3001\u3053\u306E\u554F\u984C\u306F\u89E3\u6C7A\u3055\u308C\u307E\u3059\u3002
message.install-dir-ignored=\u8B66\u544A: "--install-dir"\u306FDMG\u3067\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002/Applications\u306B\u30C7\u30D5\u30A9\u30EB\u30C8\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
warning.unsigned.app.image=\u8B66\u544A: \u7F72\u540D\u3055\u308C\u3066\u3044\u306A\u3044app-image\u3092\u4F7F\u7528\u3057\u3066\u7F72\u540D\u3055\u308C\u305F{0}\u3092\u4F5C\u6210\u3057\u307E\u3059\u3002
warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image.
Expand Up @@ -94,3 +94,4 @@ message.signing.pkg=\u8B66\u544A\uFF1A\u8981\u5BF9 PKG \u8FDB\u884C\u7B7E\u540D\
message.setfile.dmg=\u7531\u4E8E\u672A\u627E\u5230 'SetFile' \u5B9E\u7528\u7A0B\u5E8F\uFF0C\u8DF3\u8FC7\u4E86\u9488\u5BF9 DMG \u6587\u4EF6\u8BBE\u7F6E\u5B9A\u5236\u56FE\u6807\u7684\u64CD\u4F5C\u3002\u5B89\u88C5\u5E26\u547D\u4EE4\u884C\u5DE5\u5177\u7684 Xcode \u5E94\u80FD\u89E3\u51B3\u6B64\u95EE\u9898\u3002
message.install-dir-ignored=\u8B66\u544A\uFF1A"--install-dir" \u4E0D\u53D7 DMG \u652F\u6301\uFF0C\u5C06\u9ED8\u8BA4\u4E3A /Applications\u3002
warning.unsigned.app.image=\u8B66\u544A\uFF1A\u4F7F\u7528\u672A\u7B7E\u540D\u7684 app-image \u751F\u6210\u5DF2\u7B7E\u540D\u7684 {0}\u3002
warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image.
Expand Up @@ -76,7 +76,9 @@ protected void copyApplication(Map<String, ? super Object> params)
IOUtils.copyRecursive(SOURCE_DIR.fetchFrom(params),
appLayout.appDirectory());
}

AppImageFile.save(root, params);

List<String> items = APP_CONTENT.fetchFrom(params);
for (String item : items) {
IOUtils.copyRecursive(Path.of(item),
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -112,6 +112,10 @@ final AppImageBundler setDependentTask(boolean v) {
return this;
}

final boolean isDependentTask() {
return dependentTask;
}

final AppImageBundler setAppImageSupplier(
Function<Path, AbstractAppImageBuilder> v) {
appImageSupplier = v;
Expand Down
Expand Up @@ -146,7 +146,7 @@ String getMainClass() {
return mainClass;
}

boolean isSigned() {
public boolean isSigned() {
return signed;
}

Expand Down Expand Up @@ -218,7 +218,7 @@ static void save(Path appImageDir, Map<String, Object> params)
* @return valid info about application image or null
* @throws IOException
*/
static AppImageFile load(Path appImageDir) {
public static AppImageFile load(Path appImageDir) {
try {
Document doc = readXml(appImageDir);

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -35,6 +35,7 @@
import java.lang.reflect.Proxy;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.CopyOption;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
Expand Down Expand Up @@ -112,12 +113,14 @@ public FileVisitResult postVisitDirectory(Path dir, IOException e)
}
}

public static void copyRecursive(Path src, Path dest) throws IOException {
copyRecursive(src, dest, List.of());
public static void copyRecursive(Path src, Path dest, CopyOption... options)
throws IOException {
copyRecursive(src, dest, List.of(), options);
}

public static void copyRecursive(Path src, Path dest,
final List<String> excludes) throws IOException {
final List<String> excludes, CopyOption... options)
throws IOException {
Files.walkFileTree(src, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(final Path dir,
Expand All @@ -134,7 +137,7 @@ public FileVisitResult preVisitDirectory(final Path dir,
public FileVisitResult visitFile(final Path file,
final BasicFileAttributes attrs) throws IOException {
if (!excludes.contains(file.toFile().getName())) {
Files.copy(file, dest.resolve(src.relativize(file)));
Files.copy(file, dest.resolve(src.relativize(file)), options);
}
return FileVisitResult.CONTINUE;
}
Expand Down
Expand Up @@ -820,7 +820,7 @@ JPackageCommand assertAppLayout() {
private void assertAppImageFile() {
final Path lookupPath = AppImageFile.getPathInAppImage(Path.of(""));

if (isRuntime() || !isImagePackageType()) {
if (isRuntime() || (!isImagePackageType() && !TKit.isOSX())) {
assertFileInAppImage(lookupPath, null);
} else {
assertFileInAppImage(lookupPath, lookupPath);
Expand All @@ -833,7 +833,17 @@ private void assertPackageFile() {
if (isRuntime() || isImagePackageType() || TKit.isLinux()) {
assertFileInAppImage(lookupPath, null);
} else {
assertFileInAppImage(lookupPath, lookupPath);
if (TKit.isOSX() && hasArgument("--app-image")) {
String appImage = getArgumentValue("--app-image",
() -> null);
if (AppImageFile.load(Path.of(appImage)).isSigned()) {
assertFileInAppImage(lookupPath, null);
} else {
assertFileInAppImage(lookupPath, lookupPath);
}
} else {
assertFileInAppImage(lookupPath, lookupPath);
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions test/jdk/tools/jpackage/macosx/SigningPackageTest.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -22,6 +22,7 @@
*/

import java.nio.file.Path;
import jdk.jpackage.internal.ApplicationLayout;
import jdk.jpackage.test.JPackageCommand;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
Expand Down Expand Up @@ -75,7 +76,8 @@ private static void verifyDMG(JPackageCommand cmd) {

private static void verifyAppImageInDMG(JPackageCommand cmd) {
MacHelper.withExplodedDmg(cmd, dmgImage -> {
Path launcherPath = dmgImage.resolve(Path.of("Contents", "MacOS", cmd.name()));
Path launcherPath = ApplicationLayout.platformAppImage()
.resolveAt(dmgImage).launchersDirectory().resolve(cmd.name());
// We will be called with all folders in DMG since JDK-8263155, but
// we only need to verify app.
if (dmgImage.endsWith(cmd.name() + ".app")) {
Expand Down

1 comment on commit 6428607

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.