762 args.add("security"); 763 args.add("list-keychains"); 764 args.add("-s"); 765 766 args.addAll(keyChains); 767 768 ProcessBuilder pb = new ProcessBuilder(args); 769 IOUtils.exec(pb); 770 } 771 772 public static void signAppBundle( 773 Map<String, ? super Object> params, Path appLocation, 774 String signingIdentity, String identifierPrefix, 775 String entitlementsFile, String inheritedEntitlements) 776 throws IOException { 777 AtomicReference<IOException> toThrow = new AtomicReference<>(); 778 String appExecutable = "/Contents/MacOS/" + APP_NAME.fetchFrom(params); 779 String keyChain = SIGNING_KEYCHAIN.fetchFrom(params); 780 781 // sign all dylibs and jars 782 Files.walk(appLocation) 783 // fix permissions 784 .peek(path -> { 785 try { 786 Set<PosixFilePermission> pfp = 787 Files.getPosixFilePermissions(path); 788 if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) { 789 pfp = EnumSet.copyOf(pfp); 790 pfp.add(PosixFilePermission.OWNER_WRITE); 791 Files.setPosixFilePermissions(path, pfp); 792 } 793 } catch (IOException e) { 794 Log.verbose(e); 795 } 796 }) 797 .filter(p -> Files.isRegularFile(p) && 798 !(p.toString().contains("/Contents/MacOS/libjli.dylib") 799 || p.toString().endsWith(appExecutable)) 800 ).forEach(p -> { 801 //noinspection ThrowableResultOfMethodCallIgnored 802 if (toThrow.get() != null) return; 803 804 // If p is a symlink then skip the signing process. 805 if (Files.isSymbolicLink(p)) { 806 if (VERBOSE.fetchFrom(params)) { 807 Log.verbose(MessageFormat.format(I18N.getString( 808 "message.ignoring.symlink"), p.toString())); 809 } 810 } 811 else { 812 List<String> args = new ArrayList<>(); 813 args.addAll(Arrays.asList("codesign", 814 "-s", signingIdentity, // sign with this key 815 "--prefix", identifierPrefix, 816 // use the identifier as a prefix 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); 915 // sign the app itself 916 List<String> args = new ArrayList<>(); 917 args.addAll(Arrays.asList("codesign", 918 "-s", signingIdentity, // sign with this key 919 "-vvvv")); // super verbose output 920 if (entitlementsFile != null) { 921 args.add("--entitlements"); 922 args.add(entitlementsFile); // entitlements 923 } 924 if (keyChain != null && !keyChain.isEmpty()) { 925 args.add("--keychain"); 926 args.add(keyChain); 927 } 928 args.add(appLocation.toString()); 929 930 ProcessBuilder pb = 931 new ProcessBuilder(args.toArray(new String[args.size()])); 932 IOUtils.exec(pb); 933 } 934 935 } | 762 args.add("security"); 763 args.add("list-keychains"); 764 args.add("-s"); 765 766 args.addAll(keyChains); 767 768 ProcessBuilder pb = new ProcessBuilder(args); 769 IOUtils.exec(pb); 770 } 771 772 public static void signAppBundle( 773 Map<String, ? super Object> params, Path appLocation, 774 String signingIdentity, String identifierPrefix, 775 String entitlementsFile, String inheritedEntitlements) 776 throws IOException { 777 AtomicReference<IOException> toThrow = new AtomicReference<>(); 778 String appExecutable = "/Contents/MacOS/" + APP_NAME.fetchFrom(params); 779 String keyChain = SIGNING_KEYCHAIN.fetchFrom(params); 780 781 // sign all dylibs and jars 782 Files.walk(appLocation).peek(path -> { // fix permissions 783 try { 784 Set<PosixFilePermission> pfp = 785 Files.getPosixFilePermissions(path); 786 if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) { 787 pfp = EnumSet.copyOf(pfp); 788 pfp.add(PosixFilePermission.OWNER_WRITE); 789 Files.setPosixFilePermissions(path, pfp); 790 } 791 } catch (IOException e) { 792 Log.verbose(e); 793 } 794 }).filter(p -> Files.isRegularFile(p) 795 && !(p.toString().contains("/Contents/MacOS/libjli.dylib") 796 || p.toString().endsWith(appExecutable) 797 || p.toString().contains("/Contents/runtime") 798 || p.toString().contains("/Contents/Frameworks"))).forEach(p -> { 799 //noinspection ThrowableResultOfMethodCallIgnored 800 if (toThrow.get() != null) return; 801 802 // If p is a symlink then skip the signing process. 803 if (Files.isSymbolicLink(p)) { 804 if (VERBOSE.fetchFrom(params)) { 805 Log.verbose(MessageFormat.format(I18N.getString( 806 "message.ignoring.symlink"), p.toString())); 807 } 808 } else { 809 if (p.toString().endsWith(LIBRARY_NAME)) { 810 if (isFileSigned(p)) { 811 return; 812 } 813 } 814 815 List<String> args = new ArrayList<>(); 816 args.addAll(Arrays.asList("codesign", 817 "-s", signingIdentity, // sign with this key 818 "--prefix", identifierPrefix, 819 // use the identifier as a prefix 820 "-vvvv")); 821 if (entitlementsFile != null && 822 (p.toString().endsWith(".jar") 823 || p.toString().endsWith(".dylib"))) { 824 args.add("--entitlements"); 825 args.add(entitlementsFile); // entitlements 826 } else if (inheritedEntitlements != null && 827 Files.isExecutable(p)) { 828 args.add("--entitlements"); 829 args.add(inheritedEntitlements); 830 // inherited entitlements for executable processes 831 } 832 if (keyChain != null && !keyChain.isEmpty()) { 833 args.add("--keychain"); 834 args.add(keyChain); 918 // sign the app itself 919 List<String> args = new ArrayList<>(); 920 args.addAll(Arrays.asList("codesign", 921 "-s", signingIdentity, // sign with this key 922 "-vvvv")); // super verbose output 923 if (entitlementsFile != null) { 924 args.add("--entitlements"); 925 args.add(entitlementsFile); // entitlements 926 } 927 if (keyChain != null && !keyChain.isEmpty()) { 928 args.add("--keychain"); 929 args.add(keyChain); 930 } 931 args.add(appLocation.toString()); 932 933 ProcessBuilder pb = 934 new ProcessBuilder(args.toArray(new String[args.size()])); 935 IOUtils.exec(pb); 936 } 937 938 private static boolean isFileSigned(Path file) { 939 List<String> args = new ArrayList<>(); 940 args.addAll(Arrays.asList("codesign", 941 "--verify", 942 file.toString())); 943 944 ProcessBuilder pb 945 = new ProcessBuilder(args.toArray(new String[args.size()])); 946 947 try { 948 IOUtils.exec(pb); 949 } catch (IOException ex) { 950 return false; 951 } 952 953 return true; 954 } 955 956 } |