"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var fs_1 = require("fs");
var path_1 = require("path");
var plist = require("plist");
var child_process_1 = require("child_process");
var sec_find_id = require("./parsers/security-find-identity");
var sec_find_cert = require("./parsers/security-find-certificate");
var provision;
(function (provision_1) {
    var nodefs = { readdirSync: fs_1.readdirSync, readFileSync: fs_1.readFileSync };
    var defaultPath = process && process.env && process.env.HOME ? path_1.join(process.env.HOME, "Library/MobileDevice/Provisioning Profiles/") : ".";
    var plistStartToken = new Buffer("<plist", "ascii");
    var plistEndToken = new Buffer("</plist>", "ascii");
    function parseAppIdSelector(id) {
        var teamIdDot = id.indexOf(".");
        var isWildcard = id.substring(id.length - 2) === ".*";
        var team = id.substring(0, teamIdDot);
        var prefixStart = teamIdDot + 1;
        var prefixEnd = isWildcard ? id.length - 2 : id.length;
        var identifier = prefixStart < prefixEnd ? id.substring(prefixStart, prefixEnd) : "";
        var test = isWildcard ? function (testId) { return testId.substring(0, identifier.length) == identifier; } : function (testId) { return testId === identifier; };
        return { team: team, identifier: identifier, isWildcard: isWildcard, test: test };
    }
    /**
     * Read all provisioning profiles.
     */
    function read(_a) {
        var _b = _a === void 0 ? nodefs : _a, readdirSync = _b.readdirSync, readFileSync = _b.readFileSync;
        return readdirSync(defaultPath)
            .filter(function (file) { return path_1.extname(file) === ".mobileprovision"; })
            .map(function (file) {
            try {
                var filePath = path_1.join(defaultPath, file);
                return readFromFile(filePath, { readdirSync: readdirSync, readFileSync: readFileSync });
            }
            catch (e) {
                return null;
            }
        })
            .filter(function (p) { return !!p; });
    }
    provision_1.read = read;
    /**
     * Reads a provisioning profile.
     */
    function readFromFile(filePath, _a) {
        var _b = _a === void 0 ? nodefs : _a, readdirSync = _b.readdirSync, readFileSync = _b.readFileSync;
        try {
            var fileContent = readFileSync(filePath);
            var plistStart = fileContent.indexOf(plistStartToken);
            var plistEnd = fileContent.indexOf(plistEndToken) + plistEndToken.length;
            if (plistStart >= 0 && plistStart < plistEnd) {
                var plistContent = fileContent.toString('utf-8', plistStart, plistEnd);
                var plistJson = plist.parse(plistContent);
                if (plistJson.DeveloperCertificates) {
                    plistJson.DeveloperCertificates = plistJson.DeveloperCertificates.map(function (c) { return c.toString('base64'); });
                }
                if (plistJson.ProvisionsAllDevices) {
                    plistJson.Type = "Enterprise";
                }
                else if (plistJson.ProvisionedDevices && plistJson.ProvisionedDevices.length) {
                    var entitlements = plistJson.Entitlements;
                    if (entitlements["get-task-allow"]) {
                        plistJson.Type = "Development";
                    }
                    else {
                        plistJson.Type = "AdHoc";
                    }
                }
                else {
                    plistJson.Type = "Distribution";
                }
                return plistJson;
            }
            else {
                return null;
            }
        }
        catch (e) {
            return null;
        }
    }
    provision_1.readFromFile = readFromFile;
    function select(mobileprovisions, _a) {
        var _b = _a.ExpirationDate, ExpirationDate = _b === void 0 ? new Date() : _b, TeamName = _a.TeamName, AppId = _a.AppId, ProvisionedDevices = _a.ProvisionedDevices, Type = _a.Type, Certificates = _a.Certificates, _c = _a.Unique, Unique = _c === void 0 ? true : _c;
        var filter = function () { return true; };
        var both = function (a, b) { return function (provision) { return a(provision) && b(provision); }; };
        var chain = function (next) { return filter = both(filter, next); };
        chain(function (provision) { return provision.ExpirationDate >= ExpirationDate; });
        TeamName && chain(function (provision) { return provision.TeamName === TeamName; });
        AppId && chain(function (provision) { return parseAppIdSelector(provision.Entitlements["application-identifier"]).test(AppId); });
        ProvisionedDevices && chain(function (provision) { return provision.ProvisionsAllDevices || ProvisionedDevices.every(function (required) { return provision.ProvisionedDevices && provision.ProvisionedDevices.some(function (provisioned) { return required === provisioned; }); }); });
        Type && chain(function (provision) { return provision.Type === Type; });
        if (Certificates) {
            var validPemHeads_1 = {};
            Certificates.forEach(function (c) { return validPemHeads_1[c.pem.substr(0, 60)] = true; });
            chain(function (provision) { return provision.DeveloperCertificates.some(function (dc) { return validPemHeads_1[dc.substr(0, 60)]; }); });
        }
        filter = (function (test) { return function (provision) {
            try {
                return test(provision);
            }
            catch (e) {
                return false;
            }
        }; })(filter);
        var eligable = [];
        var nonEligable = [];
        mobileprovisions.forEach(function (prov) {
            if (filter(prov)) {
                eligable.push(prov);
            }
            else {
                nonEligable.push(prov);
            }
        });
        if (Unique) {
            var eligableMap_1 = {};
            var nonEligableMap_1 = {};
            eligable.forEach(function (next) {
                var prev = eligableMap_1[next.Name];
                if (!prev || prev.CreationDate < next.CreationDate) {
                    eligableMap_1[next.Name] = next;
                }
            });
            nonEligable.forEach(function (next) {
                var prev = nonEligableMap_1[next.Name];
                if (!eligableMap_1[next.Name] && (!prev || prev.CreationDate < next.CreationDate)) {
                    nonEligableMap_1[next.Name] = next;
                }
            });
            return {
                eligable: Object.keys(eligableMap_1).map(function (name) { return eligableMap_1[name]; }),
                nonEligable: Object.keys(nonEligableMap_1).map(function (name) { return nonEligableMap_1[name]; })
            };
        }
        else {
            return { eligable: eligable, nonEligable: nonEligable };
        }
    }
    provision_1.select = select;
})(provision = exports.provision || (exports.provision = {}));
var cert;
(function (cert_1) {
    /**
     * Read all codesigning sertificates using the 'security' tool from the default keychain search list.
     */
    function read() {
        var findIdentity = child_process_1.execSync("security find-identity -p codesigning").toString();
        var certIdentities = sec_find_id.parse(findIdentity);
        var findCertificate = child_process_1.execSync("security find-certificate -apZ").toString();
        var certHashes = sec_find_cert.parse(findCertificate);
        var hashToPem = {};
        certHashes.forEach(function (certHash) { return hashToPem[certHash.hash] = certHash.pem; });
        var hashToIsValid = {};
        certIdentities.valid.forEach(function (id) { return hashToIsValid[id.hash] = true; });
        var certs = certIdentities.matching.map(function (cert) { return ({
            hash: cert.hash,
            name: cert.name,
            issue: cert.issue,
            isValid: hashToIsValid[cert.hash] && !cert.issue,
            pem: hashToPem[cert.hash]
        }); }).reduce(function (acc, cert) { return (cert.isValid ? acc.valid : acc.invalid).push(cert) && acc; }, { valid: [], invalid: [] });
        return certs;
    }
    cert_1.read = read;
})(cert = exports.cert || (exports.cert = {}));
