198 } else {
199 APP_BUNDLER.fetchFrom(params).doValidate(params);
200 }
201 }
202
203 protected File prepareAppBundle(Map<String, ? super Object> p) {
204 File predefinedImage = getPredefinedImage(p);
205 if (predefinedImage != null) {
206 return predefinedImage;
207 }
208
209 File appImageRoot = APP_IMAGE_BUILD_ROOT.fetchFrom(p);
210 return APP_BUNDLER.fetchFrom(p).doBundle(p, appImageRoot, true);
211 }
212
213 protected File prepareDaemonBundle(Map<String, ? super Object> p) {
214 File daemonImageRoot = DAEMON_IMAGE_BUILD_ROOT.fetchFrom(p);
215 return DAEMON_BUNDLER.fetchFrom(p).doBundle(p, daemonImageRoot, true);
216 }
217
218 public static void signAppBundle(Map<String, ? super Object> params, File appLocation, String signingIdentity, String identifierPrefix) throws IOException {
219 signAppBundle(params, appLocation, signingIdentity, identifierPrefix, null, null);
220 }
221
222 public static void signAppBundle(Map<String, ? super Object> params, File appLocation, String signingIdentity, String identifierPrefix, String entitlementsFile, String inheritedEntitlements) throws IOException {
223 AtomicReference<IOException> toThrow = new AtomicReference<>();
224 String appExecutable = "/Contents/MacOS/" + APP_NAME.fetchFrom(params);
225 String keyChain = SIGNING_KEYCHAIN.fetchFrom(params);
226
227 // sign all dylibs and jars
228 Files.walk(appLocation.toPath())
229 // while we are searching let's fix permissions
230 .peek(path -> {
231 try {
232 Set<PosixFilePermission> pfp = Files.getPosixFilePermissions(path);
233 if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) {
234 pfp = EnumSet.copyOf(pfp);
235 pfp.add(PosixFilePermission.OWNER_WRITE);
236 Files.setPosixFilePermissions(path, pfp);
237 }
238 } catch (IOException e) {
239 Log.debug(e);
240 }
241 })
242 .filter(p -> Files.isRegularFile(p) &&
243 !(p.toString().contains("/Contents/MacOS/libjli.dylib")
244 || p.toString().contains("/Contents/MacOS/JavaAppletPlugin")
245 || p.toString().endsWith(appExecutable))
246 ).forEach(p -> {
247 //noinspection ThrowableResultOfMethodCallIgnored
248 if (toThrow.get() != null) return;
249
250 List<String> args = new ArrayList<>();
251 args.addAll(Arrays.asList("codesign",
252 "-s", signingIdentity, // sign with this key
253 "--prefix", identifierPrefix, // use the identifier as a prefix
254 "-vvvv"));
255 if (entitlementsFile != null &&
256 (p.toString().endsWith(".jar")
257 || p.toString().endsWith(".dylib")))
258 {
259 args.add("--entitlements");
260 args.add(entitlementsFile); // entitlements
261 } else if (inheritedEntitlements != null && Files.isExecutable(p)) {
262 args.add("--entitlements");
263 args.add(inheritedEntitlements); // inherited entitlements for executable processes
264 }
265 if (keyChain != null && !keyChain.isEmpty()) {
266 args.add("--keychain");
267 args.add(keyChain);
268 }
269 args.add(p.toString());
270
271 try {
272 Set<PosixFilePermission> oldPermissions = Files.getPosixFilePermissions(p);
273 File f = p.toFile();
274 f.setWritable(true, true);
275
276 ProcessBuilder pb = new ProcessBuilder(args);
277 IOUtils.exec(pb, VERBOSE.fetchFrom(params));
278
279 Files.setPosixFilePermissions(p, oldPermissions);
280 } catch (IOException ioe) {
281 toThrow.set(ioe);
282 }
283 });
284
285 IOException ioe = toThrow.get();
286 if (ioe != null) {
287 throw ioe;
288 }
289
290 // sign all plugins and frameworks
291 Consumer<? super Path> signIdentifiedByPList = path -> {
292 //noinspection ThrowableResultOfMethodCallIgnored
293 if (toThrow.get() != null) return;
294
295 try {
296 List<String> args = new ArrayList<>();
297 args.addAll(Arrays.asList("codesign",
298 "-s", signingIdentity, // sign with this key
299 "--prefix", identifierPrefix, // use the identifier as a prefix
300 "-vvvv"));
301 if (keyChain != null && !keyChain.isEmpty()) {
302 args.add("--keychain");
303 args.add(keyChain);
304 }
305 args.add(path.toString());
306 ProcessBuilder pb = new ProcessBuilder(args);
307 IOUtils.exec(pb, VERBOSE.fetchFrom(params));
308
309 args = new ArrayList<>();
310 args.addAll(Arrays.asList("codesign",
311 "-s", signingIdentity, // sign with this key
312 "--prefix", identifierPrefix, // use the identifier as a prefix
313 "-vvvv"));
314 if (keyChain != null && !keyChain.isEmpty()) {
315 args.add("--keychain");
316 args.add(keyChain);
317 }
318 args.add(path.toString() + "/Contents/_CodeSignature/CodeResources");
319 pb = new ProcessBuilder(args);
320 IOUtils.exec(pb, VERBOSE.fetchFrom(params));
321 } catch (IOException e) {
322 toThrow.set(e);
323 }
324 };
325
326 Path pluginsPath = appLocation.toPath().resolve("Contents/PlugIns");
327 if (Files.isDirectory(pluginsPath)) {
328 Files.list(pluginsPath)
329 .forEach(signIdentifiedByPList);
330
331 ioe = toThrow.get();
332 if (ioe != null) {
333 throw ioe;
334 }
335 }
336 Path frameworkPath = appLocation.toPath().resolve("Contents/Frameworks");
337 if (Files.isDirectory(frameworkPath)) {
338 Files.list(frameworkPath)
339 .forEach(signIdentifiedByPList);
340
341 ioe = toThrow.get();
342 if (ioe != null) {
343 throw ioe;
344 }
345 }
346
347 // sign the app itself
348 List<String> args = new ArrayList<>();
349 args.addAll(Arrays.asList("codesign",
350 "-s", signingIdentity, // sign with this key
351 "-vvvv")); // super verbose output
352 if (entitlementsFile != null) {
353 args.add("--entitlements");
354 args.add(entitlementsFile); // entitlements
355 }
356 if (keyChain != null && !keyChain.isEmpty()) {
357 args.add("--keychain");
358 args.add(keyChain);
359 }
360 args.add(appLocation.toString());
361
362 ProcessBuilder pb = new ProcessBuilder(args.toArray(new String[args.size()]));
363 IOUtils.exec(pb, VERBOSE.fetchFrom(params));
364 }
365
366 @Override
367 public Collection<BundlerParamInfo<?>> getBundleParameters() {
368 Collection<BundlerParamInfo<?>> results = new LinkedHashSet<>();
369
370 results.addAll(MacAppBundler.getAppBundleParameters());
371 results.addAll(Arrays.asList(
372 APP_BUNDLER,
373 CONFIG_ROOT,
374 APP_IMAGE_BUILD_ROOT,
375 MAC_APP_IMAGE
376 ));
377
378 return results;
379 }
380
381 @Override
382 public String getBundleType() {
383 return "INSTALLER";
384 }
|
198 } else {
199 APP_BUNDLER.fetchFrom(params).doValidate(params);
200 }
201 }
202
203 protected File prepareAppBundle(Map<String, ? super Object> p) {
204 File predefinedImage = getPredefinedImage(p);
205 if (predefinedImage != null) {
206 return predefinedImage;
207 }
208
209 File appImageRoot = APP_IMAGE_BUILD_ROOT.fetchFrom(p);
210 return APP_BUNDLER.fetchFrom(p).doBundle(p, appImageRoot, true);
211 }
212
213 protected File prepareDaemonBundle(Map<String, ? super Object> p) {
214 File daemonImageRoot = DAEMON_IMAGE_BUILD_ROOT.fetchFrom(p);
215 return DAEMON_BUNDLER.fetchFrom(p).doBundle(p, daemonImageRoot, true);
216 }
217
218 // public static void signAppBundle(Map<String, ? super Object> params, File appLocation, String signingIdentity, String identifierPrefix) throws IOException {
219 // signAppBundle(params, appLocation, signingIdentity, identifierPrefix, null, null);
220 // }
221 //
222
223
224 @Override
225 public Collection<BundlerParamInfo<?>> getBundleParameters() {
226 Collection<BundlerParamInfo<?>> results = new LinkedHashSet<>();
227
228 results.addAll(MacAppBundler.getAppBundleParameters());
229 results.addAll(Arrays.asList(
230 APP_BUNDLER,
231 CONFIG_ROOT,
232 APP_IMAGE_BUILD_ROOT,
233 MAC_APP_IMAGE
234 ));
235
236 return results;
237 }
238
239 @Override
240 public String getBundleType() {
241 return "INSTALLER";
242 }
|