351 // JDK 9, 10, and 11 have extra '/jli/' subdir
352 Path jli = runtimeRoot.resolve("lib/libjli.dylib");
353 if (!Files.exists(jli)) {
354 jli = runtimeRoot.resolve("lib/jli/libjli.dylib");
355 }
356
357 Files.copy(jli, runtimeMacOSDir.resolve("libjli.dylib"));
358 }
359
360 private void sign(Map<String, ? super Object> params) throws IOException {
361 if (Optional.ofNullable(
362 SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) {
363 try {
364 addNewKeychain(params);
365 } catch (InterruptedException e) {
366 Log.error(e.getMessage());
367 }
368 String signingIdentity =
369 DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params);
370 if (signingIdentity != null) {
371 signAppBundle(params, root, signingIdentity,
372 BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params), null, null);
373 }
374 restoreKeychainList(params);
375 }
376 }
377
378 private String getLauncherName(Map<String, ? super Object> params) {
379 if (APP_NAME.fetchFrom(params) != null) {
380 return APP_NAME.fetchFrom(params);
381 } else {
382 return MAIN_CLASS.fetchFrom(params);
383 }
384 }
385
386 public static String getLauncherCfgName(
387 Map<String, ? super Object> params) {
388 return "Contents/app/" + APP_NAME.fetchFrom(params) + ".cfg";
389 }
390
391 private void copyClassPathEntries(Path javaDirectory,
392 Map<String, ? super Object> params) throws IOException {
393 List<RelativeFileSet> resourcesList =
394 APP_RESOURCES_LIST.fetchFrom(params);
395 if (resourcesList == null) {
396 throw new RuntimeException(
397 I18N.getString("message.null-classpath"));
745 String keyChain = SIGNING_KEYCHAIN.fetchFrom(params);
746
747 // sign all dylibs and jars
748 try (Stream<Path> stream = Files.walk(appLocation)) {
749 stream.peek(path -> { // fix permissions
750 try {
751 Set<PosixFilePermission> pfp =
752 Files.getPosixFilePermissions(path);
753 if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) {
754 pfp = EnumSet.copyOf(pfp);
755 pfp.add(PosixFilePermission.OWNER_WRITE);
756 Files.setPosixFilePermissions(path, pfp);
757 }
758 } catch (IOException e) {
759 Log.verbose(e);
760 }
761 }).filter(p -> Files.isRegularFile(p)
762 && !(p.toString().contains("/Contents/MacOS/libjli.dylib")
763 || p.toString().endsWith(appExecutable)
764 || p.toString().contains("/Contents/runtime")
765 || p.toString().contains("/Contents/Frameworks"))).forEach(p -> {
766 //noinspection ThrowableResultOfMethodCallIgnored
767 if (toThrow.get() != null) return;
768
769 // If p is a symlink then skip the signing process.
770 if (Files.isSymbolicLink(p)) {
771 if (VERBOSE.fetchFrom(params)) {
772 Log.verbose(MessageFormat.format(I18N.getString(
773 "message.ignoring.symlink"), p.toString()));
774 }
775 } else {
776 if (p.toString().endsWith(LIBRARY_NAME)) {
777 if (isFileSigned(p)) {
778 return;
779 }
780 }
781
782 List<String> args = new ArrayList<>();
783 args.addAll(Arrays.asList("codesign",
784 "-s", signingIdentity, // sign with this key
785 "--prefix", identifierPrefix,
786 // use the identifier as a prefix
787 "-vvvv"));
788 if (entitlementsFile != null &&
789 (p.toString().endsWith(".jar")
790 || p.toString().endsWith(".dylib"))) {
791 args.add("--entitlements");
792 args.add(entitlementsFile); // entitlements
793 } else if (inheritedEntitlements != null &&
794 Files.isExecutable(p)) {
795 args.add("--entitlements");
796 args.add(inheritedEntitlements);
797 // inherited entitlements for executable processes
798 }
799 if (keyChain != null && !keyChain.isEmpty()) {
800 args.add("--keychain");
801 args.add(keyChain);
802 }
803 args.add(p.toString());
804
805 try {
806 Set<PosixFilePermission> oldPermissions =
819 });
820 }
821 IOException ioe = toThrow.get();
822 if (ioe != null) {
823 throw ioe;
824 }
825
826 // sign all runtime and frameworks
827 Consumer<? super Path> signIdentifiedByPList = path -> {
828 //noinspection ThrowableResultOfMethodCallIgnored
829 if (toThrow.get() != null) return;
830
831 try {
832 List<String> args = new ArrayList<>();
833 args.addAll(Arrays.asList("codesign",
834 "-f",
835 "-s", signingIdentity, // sign with this key
836 "--prefix", identifierPrefix,
837 // use the identifier as a prefix
838 "-vvvv"));
839 if (keyChain != null && !keyChain.isEmpty()) {
840 args.add("--keychain");
841 args.add(keyChain);
842 }
843 args.add(path.toString());
844 ProcessBuilder pb = new ProcessBuilder(args);
845 IOUtils.exec(pb);
846
847 args = new ArrayList<>();
848 args.addAll(Arrays.asList("codesign",
849 "-s", signingIdentity, // sign with this key
850 "--prefix", identifierPrefix,
851 // use the identifier as a prefix
852 "-vvvv"));
853 if (keyChain != null && !keyChain.isEmpty()) {
854 args.add("--keychain");
855 args.add(keyChain);
856 }
857 args.add(path.toString()
858 + "/Contents/_CodeSignature/CodeResources");
859 pb = new ProcessBuilder(args);
860 IOUtils.exec(pb);
861 } catch (IOException e) {
862 toThrow.set(e);
863 }
864 };
865
866 Path javaPath = appLocation.resolve("Contents/runtime");
867 if (Files.isDirectory(javaPath)) {
868 signIdentifiedByPList.accept(javaPath);
869
870 ioe = toThrow.get();
871 if (ioe != null) {
872 throw ioe;
873 }
874 }
875 Path frameworkPath = appLocation.resolve("Contents/Frameworks");
876 if (Files.isDirectory(frameworkPath)) {
877 Files.list(frameworkPath)
878 .forEach(signIdentifiedByPList);
879
880 ioe = toThrow.get();
881 if (ioe != null) {
882 throw ioe;
883 }
884 }
885
886 // sign the app itself
887 List<String> args = new ArrayList<>();
888 args.addAll(Arrays.asList("codesign",
889 "-s", signingIdentity, // sign with this key
890 "-vvvv")); // super verbose output
891 if (entitlementsFile != null) {
892 args.add("--entitlements");
893 args.add(entitlementsFile); // entitlements
894 }
895 if (keyChain != null && !keyChain.isEmpty()) {
896 args.add("--keychain");
897 args.add(keyChain);
898 }
899 args.add(appLocation.toString());
900
901 ProcessBuilder pb =
902 new ProcessBuilder(args.toArray(new String[args.size()]));
903 IOUtils.exec(pb);
904 }
905
906 private static boolean isFileSigned(Path file) {
907 ProcessBuilder pb =
908 new ProcessBuilder("codesign", "--verify", file.toString());
909
910 try {
|
351 // JDK 9, 10, and 11 have extra '/jli/' subdir
352 Path jli = runtimeRoot.resolve("lib/libjli.dylib");
353 if (!Files.exists(jli)) {
354 jli = runtimeRoot.resolve("lib/jli/libjli.dylib");
355 }
356
357 Files.copy(jli, runtimeMacOSDir.resolve("libjli.dylib"));
358 }
359
360 private void sign(Map<String, ? super Object> params) throws IOException {
361 if (Optional.ofNullable(
362 SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) {
363 try {
364 addNewKeychain(params);
365 } catch (InterruptedException e) {
366 Log.error(e.getMessage());
367 }
368 String signingIdentity =
369 DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params);
370 if (signingIdentity != null) {
371 prepareEntitlements(params);
372 signAppBundle(params, root, signingIdentity,
373 BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params),
374 getConfig_Entitlements(params).toString(),
375 getConfig_Inherit_Entitlements(params).toString());
376 }
377 restoreKeychainList(params);
378 }
379 }
380
381 private File getConfig_Entitlements(Map<String, ? super Object> params) {
382 return new File(CONFIG_ROOT.fetchFrom(params),
383 getLauncherName(params) + ".entitlements");
384 }
385
386 private File getConfig_Inherit_Entitlements(
387 Map<String, ? super Object> params) {
388 return new File(CONFIG_ROOT.fetchFrom(params),
389 getLauncherName(params) + "_Inherit.entitlements");
390 }
391
392 private void prepareEntitlements(Map<String, ? super Object> params)
393 throws IOException {
394 createResource("Mac.entitlements", params)
395 .setCategory(I18N.getString("resource.mac-entitlements"))
396 .saveToFile(getConfig_Entitlements(params));
397
398 createResource("Mac_Inherit.entitlements", params)
399 .setCategory(I18N.getString(
400 "resource.mac-inherit-entitlements"))
401 .saveToFile(getConfig_Inherit_Entitlements(params));
402 }
403
404
405 private String getLauncherName(Map<String, ? super Object> params) {
406 if (APP_NAME.fetchFrom(params) != null) {
407 return APP_NAME.fetchFrom(params);
408 } else {
409 return MAIN_CLASS.fetchFrom(params);
410 }
411 }
412
413 public static String getLauncherCfgName(
414 Map<String, ? super Object> params) {
415 return "Contents/app/" + APP_NAME.fetchFrom(params) + ".cfg";
416 }
417
418 private void copyClassPathEntries(Path javaDirectory,
419 Map<String, ? super Object> params) throws IOException {
420 List<RelativeFileSet> resourcesList =
421 APP_RESOURCES_LIST.fetchFrom(params);
422 if (resourcesList == null) {
423 throw new RuntimeException(
424 I18N.getString("message.null-classpath"));
772 String keyChain = SIGNING_KEYCHAIN.fetchFrom(params);
773
774 // sign all dylibs and jars
775 try (Stream<Path> stream = Files.walk(appLocation)) {
776 stream.peek(path -> { // fix permissions
777 try {
778 Set<PosixFilePermission> pfp =
779 Files.getPosixFilePermissions(path);
780 if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) {
781 pfp = EnumSet.copyOf(pfp);
782 pfp.add(PosixFilePermission.OWNER_WRITE);
783 Files.setPosixFilePermissions(path, pfp);
784 }
785 } catch (IOException e) {
786 Log.verbose(e);
787 }
788 }).filter(p -> Files.isRegularFile(p)
789 && !(p.toString().contains("/Contents/MacOS/libjli.dylib")
790 || p.toString().endsWith(appExecutable)
791 || p.toString().contains("/Contents/runtime")
792 || p.toString().contains("/Contents/Frameworks"))
793 ).forEach(p -> {
794 //noinspection ThrowableResultOfMethodCallIgnored
795 if (toThrow.get() != null) return;
796
797 // If p is a symlink then skip the signing process.
798 if (Files.isSymbolicLink(p)) {
799 if (VERBOSE.fetchFrom(params)) {
800 Log.verbose(MessageFormat.format(I18N.getString(
801 "message.ignoring.symlink"), p.toString()));
802 }
803 } else {
804 if (p.toString().endsWith(LIBRARY_NAME)) {
805 if (isFileSigned(p)) {
806 return;
807 }
808 }
809 List<String> args = new ArrayList<>();
810 args.addAll(Arrays.asList("codesign",
811 "--timestamp",
812 "--options", "runtime",
813 "--deep",
814 "--force",
815 "-s", signingIdentity,
816 "--prefix", identifierPrefix,
817 "-vvvv"));
818 if (entitlementsFile != null &&
819 (p.toString().endsWith(".jar")
820 || p.toString().endsWith(".dylib"))) {
821 args.add("--entitlements");
822 args.add(entitlementsFile); // entitlements
823 } else if (inheritedEntitlements != null &&
824 Files.isExecutable(p)) {
825 args.add("--entitlements");
826 args.add(inheritedEntitlements);
827 // inherited entitlements for executable processes
828 }
829 if (keyChain != null && !keyChain.isEmpty()) {
830 args.add("--keychain");
831 args.add(keyChain);
832 }
833 args.add(p.toString());
834
835 try {
836 Set<PosixFilePermission> oldPermissions =
849 });
850 }
851 IOException ioe = toThrow.get();
852 if (ioe != null) {
853 throw ioe;
854 }
855
856 // sign all runtime and frameworks
857 Consumer<? super Path> signIdentifiedByPList = path -> {
858 //noinspection ThrowableResultOfMethodCallIgnored
859 if (toThrow.get() != null) return;
860
861 try {
862 List<String> args = new ArrayList<>();
863 args.addAll(Arrays.asList("codesign",
864 "-f",
865 "-s", signingIdentity, // sign with this key
866 "--prefix", identifierPrefix,
867 // use the identifier as a prefix
868 "-vvvv"));
869
870 if (entitlementsFile != null &&
871 (path.toString().endsWith(".jar")
872 || path.toString().endsWith(".dylib"))) {
873 args.add("--entitlements");
874 args.add(entitlementsFile); // entitlements
875 } else if (inheritedEntitlements != null &&
876 Files.isExecutable(path)) {
877 args.add("--entitlements");
878 args.add(inheritedEntitlements);
879 // inherited entitlements for executable processes
880 }
881
882 if (keyChain != null && !keyChain.isEmpty()) {
883 args.add("--keychain");
884 args.add(keyChain);
885 }
886 args.add(path.toString());
887 ProcessBuilder pb = new ProcessBuilder(args);
888 IOUtils.exec(pb);
889
890
891 args = new ArrayList<>();
892 args.addAll(Arrays.asList("codesign",
893 "--timestamp",
894 "--options", "runtime",
895 "--deep",
896 "--force",
897 "-s", signingIdentity,
898 "--prefix", identifierPrefix,
899 "-vvvv"));
900 if (keyChain != null && !keyChain.isEmpty()) {
901 args.add("--keychain");
902 args.add(keyChain);
903 }
904 args.add(path.toString()
905 + "/Contents/_CodeSignature/CodeResources");
906 pb = new ProcessBuilder(args);
907 IOUtils.exec(pb);
908 } catch (IOException e) {
909 toThrow.set(e);
910 }
911 };
912
913 Path javaPath = appLocation.resolve("Contents/runtime");
914 if (Files.isDirectory(javaPath)) {
915 signIdentifiedByPList.accept(javaPath);
916
917 ioe = toThrow.get();
918 if (ioe != null) {
919 throw ioe;
920 }
921 }
922 Path frameworkPath = appLocation.resolve("Contents/Frameworks");
923 if (Files.isDirectory(frameworkPath)) {
924 Files.list(frameworkPath)
925 .forEach(signIdentifiedByPList);
926
927 ioe = toThrow.get();
928 if (ioe != null) {
929 throw ioe;
930 }
931 }
932
933 // sign the app itself
934 List<String> args = new ArrayList<>();
935 args.addAll(Arrays.asList("codesign",
936 "--timestamp",
937 "--options", "runtime",
938 "--deep",
939 "--force",
940 "-s", signingIdentity,
941 "-vvvv"));
942 if (entitlementsFile != null) {
943 args.add("--entitlements");
944 args.add(entitlementsFile); // entitlements
945 }
946 if (keyChain != null && !keyChain.isEmpty()) {
947 args.add("--keychain");
948 args.add(keyChain);
949 }
950 args.add(appLocation.toString());
951
952 ProcessBuilder pb =
953 new ProcessBuilder(args.toArray(new String[args.size()]));
954 IOUtils.exec(pb);
955 }
956
957 private static boolean isFileSigned(Path file) {
958 ProcessBuilder pb =
959 new ProcessBuilder("codesign", "--verify", file.toString());
960
961 try {
|