All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.arquillian.droidium.container.sign.APKSigner Maven / Gradle / Ivy

There is a newer version: 1.0.1.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2013, Red Hat, Inc. and/or its affiliates, and individual
 * contributors by the @authors tag. See the copyright.txt in the
 * distribution for a full listing of individual contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.arquillian.droidium.container.sign;

import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.arquillian.droidium.container.api.AndroidExecutionException;
import org.arquillian.droidium.container.configuration.AndroidContainerConfiguration;
import org.arquillian.droidium.container.configuration.AndroidSDK;
import org.arquillian.droidium.container.configuration.Command;
import org.arquillian.droidium.container.configuration.Validate;
import org.arquillian.droidium.container.execution.ProcessExecutor;
import org.arquillian.droidium.container.utils.DroidiumFileUtils;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;

/**
 * Signs and resigns arbitrary APK files.
 *
 * @author Stefan Miklosovic
 *
 */
public class APKSigner {

    private static final Logger logger = Logger.getLogger(APKSigner.class.getName());

    private final AndroidSDK sdk;

    private final AndroidContainerConfiguration configuration;

    private final ProcessExecutor executor;

    /**
     *
     * @param executor
     * @param sdk
     * @param configuration
     * @throws IllegalArgumentException when some of arguments is a null object
     */
    public APKSigner(ProcessExecutor executor, AndroidSDK sdk, AndroidContainerConfiguration configuration)
        throws IllegalArgumentException {
        Validate.notNull(executor, "Process executor to set can not be a null object!");
        Validate.notNull(sdk, "Android SDK to set can not be a null object!");
        Validate.notNull(configuration, "Droidium configuration to set can not be a null object!");
        this.executor = executor;
        this.sdk = sdk;
        this.configuration = configuration;
    }

    /**
     *
     * @param toSign file to sign
     * @param signed file after the signing
     * @return {@code signed} file
     */
    public File sign(File toSign, File signed) {

        checkKeyStore();

        Command jarSignerCommand = new Command()
            .add(sdk.getPathForJavaTool("jarsigner"))
            .add("-sigalg").add("MD5withRSA")
            .add("-digestalg").add("SHA1")
            .add("-signedjar").add(signed.getAbsolutePath())
            .add("-storepass").add(configuration.getStorepass())
            .add("-keystore").add(new File(configuration.getKeystore()).getAbsolutePath())
            .add(toSign.getAbsolutePath())
            .add(configuration.getAlias());

        logger.log(Level.FINE, jarSignerCommand.toString());

        try {
            executor.execute(jarSignerCommand.getAsArray());
        } catch (AndroidExecutionException e) {
            throw new APKSignerException("Unable to sign package, signing process failed.", e);
        }

        return signed;
    }

    /**
     *
     * @param toResign file to resign
     * @return resigned file
     */
    public File resign(File toResign) {
        Validate.notNull(toResign, "File to resign can not be a null object!");
        Archive apk = ShrinkWrap.createFromZipFile(JavaArchive.class, toResign);
        apk.delete("META-INF");
        File toSign = new File(DroidiumFileUtils.getTmpDir(), DroidiumFileUtils.getRandomAPKFileName());
        DroidiumFileUtils.export(apk, toSign);
        return sign(toSign, new File(DroidiumFileUtils.getTmpDir(), DroidiumFileUtils.getRandomAPKFileName()));
    }

    /**
     * Checks if keystore as specified in {@link DroidiumNativeConfiguration} exists.
     *
     * If it does not exist, checks if default keystore (in $ANDROID_SDK_HOME/.android/debug.keystore) exist. If default
     * keystore does not exist, this method creates it.
     *
     * Sets keystore back to {@link DroidiumNativeConfiguration} to whatever exist first.
     */
    private void checkKeyStore() {
        KeyStoreCreator keyStoreCreator = new KeyStoreCreator(executor, sdk, configuration);
        if (!keyStoreCreator.keyStoreExists(new File(configuration.getKeystore()))) {
            File defaultKeyStore = new File(getDefaultKeyStorePath());
            if (!keyStoreCreator.keyStoreExists(defaultKeyStore)) {
                keyStoreCreator.createKeyStore(defaultKeyStore);
            }
            configuration.setKeystore(defaultKeyStore.getAbsolutePath());
        }
    }

    private String getDefaultKeyStorePath() {
        String separator = System.getProperty("file.separator");
        return configuration.getAndroidSdkHome() + ".android" + separator + "debug.keystore";
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy