package com.inet.gradle.appbundler;
import java.io.File;
import java.util.ArrayList;
import org.gradle.api.internal.file.FileResolver;
import com.inet.gradle.setup.abstracts.AbstractBuilder;
import com.inet.gradle.setup.abstracts.AbstractSetupBuilder;
import com.inet.gradle.setup.abstracts.AbstractTask;
/**
* Create code signature for packages. Deep Signing.
* @author gamma
* @param <T> concrete Task
* @param <S> concrete SetupBuilder
*
*/
public class OSXCodeSign<T extends AbstractTask, S extends AbstractSetupBuilder> extends AbstractBuilder<T,S> {
private String identity, identifier, keychain, keychainPassword;
private boolean ignoreError, deepsign = true;
/**
* Setup up the Sign Tool
* @param task task
* @param fileResolver resolver
*/
public OSXCodeSign(T task, FileResolver fileResolver) {
super(task, fileResolver);
}
/**
* Return the Identity to sign with
* This is the "Common Name" part from the certificate
* @return identity
*/
public String getIdentity() {
if ( identity == null ) {
throw new IllegalArgumentException( "You have to define the signing identity" );
}
return identity;
}
/**
* Set the Identity to sign with.
* This is the "Common Name" part from the certificate
* @param identity to sign with
*/
public void setIdentity(String identity) {
this.identity = identity;
}
/**
* Specific Identifier to embed in code (option -i)
* @return identifier
*/
public String getIdentifier() {
return identifier;
}
/**
* Specific Identifier to embed in code (option -i)
* @param identifier to set
*/
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
/**
* Key chain to use for signing. It has to be unlocked.
* @return key chain
*/
public String getKeychain() {
return keychain;
}
/**
* Set Key chain to use for signing. It has to be unlocked.
* @param keychain key chain
*/
public void setKeychain(String keychain) {
this.keychain = keychain;
}
/**
* The password to unlock the keychain
* @return the keychainPassword
*/
public String getKeychainPassword() {
return keychainPassword;
}
/**
* Set the keychain password to unlock the keychain
* @param keychainPassword the keychainPassword to set
*/
public void setKeychainPassword(String keychainPassword) {
this.keychainPassword = keychainPassword;
}
/**
* True if errors during signing should be ignored
* @return ignore errors
*/
public boolean isIgnoreError() {
return ignoreError;
}
/**
* Should errors be ignored during signing
* @param ignoreError ignore
*/
public void setIgnoreError(boolean ignoreError) {
this.ignoreError = ignoreError;
}
/**
* Unlocks the keychain if the password is not null.
* Will unlock the default login.keychain if no other is set.
*/
private void unlockKeychain() {
if ( getKeychainPassword() == null ) {
return;
}
String keychain = getKeychain() != null ? getKeychain() : System.getenv("HOME") + "/Library/Keychains/login.keychain";
// unlock keychain
ArrayList<String> command = new ArrayList<>();
command.add( "security" );
command.add( "-v" );
command.add( "unlock-keychain" );
command.add( "-p" );
command.add( getKeychainPassword() );
command.add( keychain );
exec( command, null, null, isIgnoreError() );
}
/**
* Signed an application package
* @param path of the application
*/
public void signApplication( File path ) {
unlockKeychain();
// Codesign
ArrayList<String> command = new ArrayList<>();
command.add( "codesign" );
command.add( "-f" );
if ( isDeepsign() ) {
command.add( "--deep" );
}
command.add( "-s" );
command.add( getIdentity() );
if ( getIdentifier() != null ) {
command.add( "-i" );
command.add( getIdentifier() );
}
if ( getKeychain() != null ) {
command.add( "--keychain" );
command.add( getKeychain() );
}
command.add( path.getAbsolutePath() );
exec( command, null, null, isIgnoreError() );
}
/**
* Signed a product package
* @param path of the application
*/
public void signProduct( File path ) {
unlockKeychain();
// Productsign
ArrayList<String> command = new ArrayList<>();
command.add( "productsign" );
command.add( "--sign" );
command.add( getIdentity() );
if ( getKeychain() != null ) {
command.add( "--keychain" );
command.add( getKeychain() );
}
command.add( path.getAbsolutePath() );
File output = new File( path.getParentFile(), "signed." + path.getName() );
command.add( output.getAbsolutePath() );
exec( command, null, null, isIgnoreError() );
// Move to old directory
if ( output.exists() && path.delete() ) {
output.renameTo( path );
}
}
/**
* Should be deep signed?
* @return
*/
public boolean isDeepsign() {
return deepsign;
}
/**
* Set deep signing
* @param deepsign deep sign?
*/
public void setDeepsign(boolean deepsign) {
this.deepsign = deepsign;
}
}