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

org.robovm.compiler.target.ios.ProvisioningProfile Maven / Gradle / Ivy

There is a newer version: 1.12.0
Show newest version
/*
 * Copyright (C) 2013 Trillian Mobile AB
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.robovm.compiler.target.ios;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.bouncycastle.cms.CMSSignedData;

import com.dd.plist.NSArray;
import com.dd.plist.NSData;
import com.dd.plist.NSDate;
import com.dd.plist.NSDictionary;
import com.dd.plist.NSNumber;
import com.dd.plist.NSObject;
import com.dd.plist.PropertyListParser;

/**
 * Represents a provisioning profile.
 */
public class ProvisioningProfile implements Comparable {
    
    public enum Type {
        Development, AppStore, AdHoc
    }
    
    private static final String HEX_DIGITS = "0123456789ABCDEF";

    private final Type type;
    private final File file;
    private final NSDictionary dict;
    private final String uuid;
    private final String name;
    private final String appIdName;
    private final String appIdPrefix;
    private final String appId;
    private final Date creationDate;
    private final Date expirationDate;
    private final NSDictionary entitlements;
    private final List certFingerprints = new ArrayList();
    
    ProvisioningProfile(File file, NSDictionary dict) {
        this.file = file;
        this.dict = dict;
        this.uuid = dict.objectForKey("UUID").toString();
        this.name = dict.objectForKey("Name").toString();
        this.appIdName = dict.objectForKey("AppIDName") != null 
                ? dict.objectForKey("AppIDName").toString() : null;
        this.appIdPrefix = ((NSArray) dict.objectForKey("ApplicationIdentifierPrefix"))
                .objectAtIndex(0).toString();
        this.creationDate = ((NSDate) dict.objectForKey("CreationDate")).getDate();
        this.expirationDate = ((NSDate) dict.objectForKey("ExpirationDate")).getDate();
        this.entitlements = (NSDictionary) dict.objectForKey("Entitlements");
        this.appId = this.entitlements.objectForKey("application-identifier").toString();
        
        for (NSObject o : ((NSArray) dict.objectForKey("DeveloperCertificates")).getArray()) {
            NSData data = (NSData) o;
            certFingerprints.add(getCertFingerprint(data.bytes()));
        }
        
        boolean getTaskAllow = ((NSNumber) entitlements.objectForKey("get-task-allow")).boolValue();
        NSArray provisionedDevices = (NSArray) dict.objectForKey("ProvisionedDevices");
        if (getTaskAllow) {
            type = Type.Development;
        } else if (provisionedDevices != null) {
            type = Type.AdHoc;
        } else {
            type = Type.AppStore;
        }
    }
    
    @Override
    public int compareTo(ProvisioningProfile o) {
        return this.name.compareToIgnoreCase(o.name);
    }
    
    private static String getCertFingerprint(byte[] certData) {
        try {
            CertificateFactory x509CertFact = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) x509CertFact.generateCertificate(new ByteArrayInputStream(certData));
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            return toHexString(md.digest(cert.getEncoded()));
        } catch (CertificateException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
    
    private static String toHexString(byte bytes[]) {
        StringBuffer buf = new StringBuffer(bytes.length * 2);
        for (int i = 0; i < bytes.length; ++i) {
            buf.append(HEX_DIGITS.charAt((bytes[i] & 0xf0) >> 4));
            buf.append(HEX_DIGITS.charAt(bytes[i] & 0x0f));
        }
        return buf.toString();
    }
    
    public Type getType() {
        return type;
    }
    
    public File getFile() {
        return file;
    }

    public NSDictionary getDict() {
        return dict;
    }

    public String getUuid() {
        return uuid;
    }

    public String getName() {
        return name;
    }

    public String getAppIdName() {
        return appIdName;
    }

    public String getAppIdPrefix() {
        return appIdPrefix;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public Date getExpirationDate() {
        return expirationDate;
    }

    public NSDictionary getEntitlements() {
        return entitlements;
    }

    private static ProvisioningProfile create(File file) {
        InputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(file));
            CMSSignedData data = new CMSSignedData(in);
            byte[] content = (byte[]) data.getSignedContent().getContent();
            NSDictionary dict = (NSDictionary) PropertyListParser.parse(content);
            return new ProvisioningProfile(file, dict);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }
    
    public static List list() {
        File dir = new File(new File(System.getProperty("user.home")), "Library/MobileDevice/Provisioning Profiles");
        if (!dir.exists() || !dir.isDirectory()) {
            return Collections.emptyList();
        }
        List result = new ArrayList();
        for (File f : dir.listFiles()) {
            if (f.getName().endsWith(".mobileprovision")) {
                ProvisioningProfile p = create(f);
                if (p.expirationDate.after(new Date())) {
                    result.add(p);
                }
            }
        }
        Collections.sort(result);
        return result;
    }

    public static ProvisioningProfile find(List profiles, String search) {
        for (ProvisioningProfile p : profiles) {
            if (p.uuid.equals(search) || p.appIdPrefix.equals(search) || p.appIdName != null && p.appIdName.equals(search)
                    || p.name.equals(search)) {
                return p;
            }
        }        
        throw new IllegalArgumentException("No provisioning profile found matching '" + search + "'");
    }
    
    public static ProvisioningProfile find(List profiles, SigningIdentity signingIdentity, String bundleId) {
        return find(profiles, signingIdentity, bundleId, bundleId);
    }
    
    private static ProvisioningProfile find(List profiles, SigningIdentity signingIdentity, String bundleId, String origBundleId) {
        // Try a direct match first
        for (ProvisioningProfile p : profiles) {
            if (p.appId.equals(p.appIdPrefix + "." + bundleId)) {
                for (String fp : p.certFingerprints) {
                    if (fp.equals(signingIdentity.getFingerprint())) {
                        return p;
                    }
                }
            }
        }
        if (!bundleId.equals("*")) {
            // Try with the last component replaced with a wildcard
            if (bundleId.endsWith(".*")) {
                bundleId = bundleId.substring(0, bundleId.length() - 2);
            }
            int lastDot = bundleId.lastIndexOf('.');
            if (lastDot != -1) {
                bundleId = bundleId.substring(0, lastDot) + ".*";
            } else {
                bundleId = "*";
            }
            return find(profiles, signingIdentity, bundleId, origBundleId);
        }
        throw new IllegalArgumentException("No provisioning profile found " 
                + "matching signing identity '" + signingIdentity.getName() 
                + "' and app bundle ID '" + origBundleId + "'");
    }
    
    @Override
    public String toString() {
        return "ProvisioningProfile [type=" + type + ", file=" + file
                + ", uuid=" + uuid + ", name=" + name + ", appIdName="
                + appIdName + ", appIdPrefix=" + appIdPrefix + ", appId="
                + appId + ", creationDate=" + creationDate
                + ", expirationDate=" + expirationDate + ", certFingerprints="
                + certFingerprints + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ProvisioningProfile other = (ProvisioningProfile) obj;
        if (uuid == null) {
            if (other.uuid != null)
                return false;
        } else if (!uuid.equals(other.uuid))
            return false;
        return true;
    }

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println(list());
        } else if (args.length == 1) {
            System.out.println(find(list(), args[0]));
        } else {
            System.out.println(find(list(), SigningIdentity.find(SigningIdentity.list(), args[0]), args[1]));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy