"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = selectDistributionCert;

function _open() {
  const data = _interopRequireDefault(require("open"));

  _open = function () {
    return data;
  };

  return data;
}

function _ora() {
  const data = _interopRequireDefault(require("ora"));

  _ora = function () {
    return data;
  };

  return data;
}

function _xdl() {
  const data = require("@expo/xdl");

  _xdl = function () {
    return data;
  };

  return data;
}

function appleApi() {
  const data = _interopRequireWildcard(require("../build/ios/appleApi"));

  appleApi = function () {
    return data;
  };

  return data;
}

function credentials() {
  const data = _interopRequireWildcard(require("../build/ios/credentials"));

  credentials = function () {
    return data;
  };

  return data;
}

function _promptForCredentials() {
  const data = _interopRequireDefault(require("../build/ios/credentials/prompt/promptForCredentials"));

  _promptForCredentials = function () {
    return data;
  };

  return data;
}

function _log() {
  const data = _interopRequireDefault(require("../../log"));

  _log = function () {
    return data;
  };

  return data;
}

function _prompt() {
  const data = _interopRequireDefault(require("../../prompt"));

  _prompt = function () {
    return data;
  };

  return data;
}

function _tagger() {
  const data = require("./tagger");

  _tagger = function () {
    return data;
  };

  return data;
}

function _selectUtils() {
  const data = require("./selectUtils");

  _selectUtils = function () {
    return data;
  };

  return data;
}

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

async function selectDistributionCert(context, options = {}) {
  const certificates = context.username ? await chooseUnrevokedDistributionCert(context) : [];
  const choices = [...certificates]; // autoselect creds if we find valid ones

  if (certificates.length > 0 && !options.disableAutoSelectExisting) {
    const autoselectedCertificate = (0, _selectUtils().choosePreferredCreds)(context, certificates);
    (0, _log().default)(`Using Distribution Certificate: ${autoselectedCertificate.name}`);
    return autoselectedCertificate.value;
  }

  if (!options.disableCreate) {
    choices.push({
      name: '[Create a new certificate] (Recommended)',
      value: 'GENERATE'
    });
  }

  choices.push({
    name: '[Upload an existing certificate]',
    value: 'UPLOAD'
  });
  choices.push({
    name: '[Show me more info about these choices] ℹ️',
    value: 'INFO'
  });
  const {
    promptValue
  } = await (0, _prompt().default)({
    type: 'list',
    name: 'promptValue',
    message: 'Select an iOS distribution certificate to use for code signing:',
    pageSize: Infinity,
    choices
  });

  if (promptValue === 'GENERATE') {
    return await generateDistributionCert(context);
  } else if (promptValue === 'UPLOAD') {
    const {
      credentials: userProvidedCredentials,
      metadata
    } = await (0, _promptForCredentials().default)(context, ['distributionCert']);
    const distributionCert = userProvidedCredentials.distributionCert;
    distributionCert.distCertSerialNumber = metadata.distCertSerialNumber;
    const isValid = await validateUploadedCertificate(context, distributionCert);

    if (!isValid) {
      return await selectDistributionCert(context, {
        disableAutoSelectExisting: true
      });
    } // tag for updating to Expo servers


    (0, _tagger().tagForUpdate)(distributionCert);
  } else if (promptValue === 'INFO') {
    (0, _open().default)('https://docs.expo.io/versions/latest/guides/adhoc-builds/#distribution-certificate-cli-options');
    return await selectDistributionCert(context);
  } else {
    return promptValue; // this should be an unrevoked cert from the Expo servers
  }
}

async function validateUploadedCertificate(context, distributionCert) {
  const spinner = (0, _ora().default)(`Checking validity of distribution certificate on Apple Developer Portal...`).start();

  const formattedDistCertArray = _xdl().Credentials.Ios.formatDistCerts([distributionCert], {
    provideFullCertificate: true
  });

  const filteredFormattedDistCertArray = await filterRevokedDistributionCerts(context, formattedDistCertArray);
  const isValidCert = filteredFormattedDistCertArray.length > 0;

  if (isValidCert) {
    const successMsg = `Successfully validated Distribution Certificate you uploaded against Apple Servers`;
    spinner.succeed(successMsg);
  } else {
    const failureMsg = `The Distribution Certificate you uploaded is not valid. Please check that you uploaded your certificate to the Apple Servers. See docs.expo.io/versions/latest/guides/adhoc-builds for more details on uploading your credentials.`;
    spinner.fail(failureMsg);
  }

  return isValidCert;
}

async function chooseUnrevokedDistributionCert(context) {
  const certsOnExpoServer = await _xdl().Credentials.Ios.getExistingDistCerts(context.username, context.team.id, {
    provideFullCertificate: true
  });

  if (certsOnExpoServer.length === 0) {
    return []; // no certs stored on server
  }

  const spinner = (0, _ora().default)(`Checking validity of distribution certificates on Apple Developer Portal...`).start();
  const validCertsOnExpoServer = await filterRevokedDistributionCerts(context, certsOnExpoServer);
  const numValidCerts = validCertsOnExpoServer.length;
  const numRevokedCerts = certsOnExpoServer.length - validCertsOnExpoServer.length;
  const statusToDisplay = `Distribution Certificate: You have ${numValidCerts} valid and ${numRevokedCerts} revoked certificates on the Expo servers.`;

  if (numValidCerts > 0) {
    spinner.succeed(statusToDisplay);
  } else {
    spinner.warn(statusToDisplay);
  }

  return validCertsOnExpoServer;
}

async function filterRevokedDistributionCerts(context, distributionCerts) {
  // if the credentials are valid, check it against apple to make sure it hasnt been revoked
  const distCertManager = appleApi().createManagers(context).distributionCert;
  const certsOnAppleServer = await distCertManager.list();
  const validCertSerialsOnAppleServer = certsOnAppleServer.filter( // remove expired certs
  cert => cert.expires > Math.floor(Date.now() / 1000)).map(cert => cert.serialNumber);
  const validCertsOnExpoServer = distributionCerts.filter(cert => {
    const serialNumber = cert.value && cert.value.distCertSerialNumber;
    return validCertSerialsOnAppleServer.includes(serialNumber);
  });
  return validCertsOnExpoServer;
}

async function generateDistributionCert(context) {
  const manager = appleApi().createManagers(context).distributionCert;

  try {
    const distributionCert = await manager.create({}); // tag for updating to Expo servers

    (0, _tagger().tagForUpdate)(distributionCert);
    return distributionCert;
  } catch (e) {
    if (e.code === 'APPLE_DIST_CERTS_TOO_MANY_GENERATED_ERROR') {
      const certificates = await manager.list();

      _log().default.warn(`Maximum number (${certificates.length}) of certificates generated.`);

      const {
        answer
      } = await (0, _prompt().default)({
        type: 'list',
        name: 'answer',
        message: 'Please revoke or reuse an existing certificate:',
        choices: [{
          key: 'r',
          name: 'Choose certificates to revoke and try again',
          value: 'REVOKE'
        }, {
          key: 'e',
          name: 'Use an existing certificate',
          value: 'USE_EXISTING'
        }, {
          name: '[Show me more info about these choices] ℹ️',
          value: 'INFO'
        }]
      });

      if (answer === 'REVOKE') {
        await credentials().revoke(context, ['distributionCert']);
        return await generateDistributionCert(context);
      } else if (answer === 'USE_EXISTING') {
        return await selectDistributionCert(context, {
          disableCreate: true,
          disableAutoSelectExisting: true
        });
      } else if (answer === 'INFO') {
        (0, _open().default)('https://docs.expo.io/versions/latest/guides/adhoc-builds/#distribution-certificate-cli-options');
        return await generateDistributionCert(context);
      }
    }

    throw new Error(e);
  }
}
//# sourceMappingURL=../../__sourcemaps__/commands/client/selectDistributionCert.js.map