"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _fsExtra() {
const data = _interopRequireDefault(require("fs-extra"));
_fsExtra = function () {
return data;
};
return data;
}
function _get() {
const data = _interopRequireDefault(require("lodash/get"));
_get = function () {
return data;
};
return data;
}
function _xdl() {
const data = require("@expo/xdl");
_xdl = function () {
return data;
};
return data;
}
function _credentials() {
const data = require("../../credentials");
_credentials = function () {
return data;
};
return data;
}
function _AndroidCredentials() {
const data = require("../../credentials/views/AndroidCredentials");
_AndroidCredentials = 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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
class AppSigningOptInProcess {
// Keystore used to sign production app
// Keystore used to sign app before uploading to Google Play store
// private signing key and public cert extracted from signKeystore and encrypted using Google Play encryption key.
// public cert extracted from upload keystore
constructor(projectDir) {
_defineProperty(this, "projectDir", '');
_defineProperty(this, "signKeystore", '');
_defineProperty(this, "uploadKeystore", '');
_defineProperty(this, "privateSigningKey", '');
_defineProperty(this, "publicUploadCert", '');
_defineProperty(this, "uploadKeystoreCredentials", {});
_defineProperty(this, "signKeystoreCredentials", {});
this.projectDir = projectDir;
}
async run() {
const ctx = new (_credentials().Context)();
await ctx.init(this.projectDir);
await this.init(ctx.manifest.slug);
const view = new (_AndroidCredentials().DownloadKeystore)(ctx.manifest.slug);
await view.fetch(ctx);
await view.save(ctx, this.signKeystore, true);
this.signKeystoreCredentials = {
keystorePassword: (0, _get().default)(view, 'credentials.keystorePassword'),
keyAlias: (0, _get().default)(view, 'credentials.keyAlias'),
keyPassword: (0, _get().default)(view, 'credentials.keyPassword')
};
try {
await this.exportPrivateKey();
await this.prepareKeystores(ctx.user.username, ctx.manifest);
} catch (error) {
_log().default.error(error);
await this.cleanup(true);
return;
}
await this.afterStoreSubmit(ctx.user.username, ctx.manifest);
}
async init(slug) {
_log().default.warn('Make sure you are not using Google Play App Signing already as this process will remove your current keystore from Expo servers.');
(0, _log().default)(`You can check whether you are using Google Play App Signing here: ${_chalk().default.underline('https://play.google.com/apps/publish')}. Select your app and go to "Release management" → "App signing" tab. If you are already using Google Play App Signing, there will be a message that says, "App Signing by Google Play is enabled for this app", at the top of the page.`);
const confirmQuestion = [{
type: 'confirm',
name: 'confirm',
message: 'Is Google Play App Signing enabled for this app?'
}];
const {
confirm: confirmEnabled
} = await (0, _prompt().default)(confirmQuestion);
if (confirmEnabled) {
(0, _log().default)('Google Play App Signing is already enabled; there is nothing to do here.');
process.exit(0);
}
this.signKeystore = _path().default.join(this.projectDir, `${slug}_sign.jks.bak`);
this.uploadKeystore = _path().default.join(this.projectDir, `${slug}_upload.jks.tmp`);
this.privateSigningKey = _path().default.join(this.projectDir, `${slug}_private_sign_key`);
this.publicUploadCert = _path().default.join(this.projectDir, `${slug}_upload_cert.pem`);
await this.cleanup(true);
}
async exportPrivateKey() {
(0, _log().default)(`Go to the "App signing" tab in the Google Play console, select "${_chalk().default.bold('Export and upload a key (not using a Java keystore)')}" and copy the encryption key that is listed in step 1.`);
const encryptKeyQuestion = [{
type: 'input',
name: 'encryptionKey',
message: 'Google Play encryption key',
validate: value => value.length === 136 && /^[A-Fa-f0-9]+$/.test(value) || 'Encryption key needs to be a hex-encoded 68-byte string (a 4-byte identity followed by a 64-byte P-256 point).'
}];
const {
encryptionKey
} = await (0, _prompt().default)(encryptKeyQuestion);
await _xdl().AndroidCredentials.exportPrivateKey({
keystorePath: this.signKeystore,
...this.signKeystoreCredentials
}, encryptionKey, this.privateSigningKey);
}
async prepareKeystores(username, exp) {
(0, _log().default)(`Saving upload keystore to ${this.uploadKeystore}...`);
this.uploadKeystoreCredentials = await _xdl().AndroidCredentials.generateUploadKeystore(this.uploadKeystore, (0, _get().default)(exp, 'android.package'), `@${username}/${exp.slug}`);
(0, _log().default)(`Saving upload certificate to ${this.publicUploadCert}`);
await _xdl().AndroidCredentials.exportCertBase64({
keystorePath: this.uploadKeystore,
keystorePassword: this.uploadKeystoreCredentials.keystorePassword,
keyAlias: this.uploadKeystoreCredentials.keyAlias
}, this.publicUploadCert);
await _xdl().AndroidCredentials.logKeystoreCredentials(this.uploadKeystoreCredentials, 'Credentials for upload keystore');
(0, _log().default)('App signing certificate');
await _xdl().AndroidCredentials.logKeystoreHashes({
keystorePath: this.signKeystore,
...this.signKeystoreCredentials
});
(0, _log().default)('Upload certificate');
await _xdl().AndroidCredentials.logKeystoreHashes({
keystorePath: this.uploadKeystore,
...this.uploadKeystoreCredentials
});
}
async afterStoreSubmit(username, exp) {
_log().default.warn(`On the previously opened Google Play console page, upload ${_chalk().default.underline(this.privateSigningKey)} as "${_chalk().default.bold('APP SIGNING PRIVATE KEY')}" and ${_chalk().default.underline(this.publicUploadCert)} as "${_chalk().default.bold('UPLOAD KEY PUBLIC CERTIFICATE')}"`);
_log().default.warn(`The next step will ${_chalk().default.red('remove your current keystore from Expo servers')}. Make sure that private key is uploaded successfully and compare the hashes displayed above with the ones printed in the console.`);
const {
confirm: confirmUpload
} = await (0, _prompt().default)([{
type: 'confirm',
name: 'confirm',
message: 'Is App Signing by Google Play enabled succesfully?',
default: false
}]);
if (!confirmUpload) {
await this.cleanup(true);
_log().default.error('Aborting, no changes were applied');
process.exit(1);
}
await _xdl().Credentials.updateCredentialsForPlatform('android', {
keystorePassword: this.uploadKeystoreCredentials.keystorePassword,
keystoreAlias: this.uploadKeystoreCredentials.keyAlias,
keyPassword: this.uploadKeystoreCredentials.keyPassword,
keystore: (await _fsExtra().default.readFile(this.uploadKeystore)).toString('base64')
}, [], {
platform: 'android',
username,
experienceName: `@${username}/${exp.slug}`
});
(0, _log().default)(`The original keystore is stored in ${this.signKeystore}; remove it only if you are sure that Google Play App Signing is enabled for your app.`);
_xdl().AndroidCredentials.logKeystoreCredentials(this.signKeystoreCredentials, 'Credentials for original keystore');
await this.cleanup();
}
async cleanup(all = false) {
tryUnlink(this.uploadKeystore);
tryUnlink(this.publicUploadCert);
tryUnlink(this.privateSigningKey);
if (all) {
tryUnlink(this.signKeystore);
}
}
}
exports.default = AppSigningOptInProcess;
async function tryUnlink(file) {
try {
await _fsExtra().default.unlink(file);
} catch (err) {}
}
//# sourceMappingURL=../../__sourcemaps__/commands/google-play/AppSigningOptIn.js.map