"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.exportCertBinary = exportCertBinary;
exports.exportCertBase64 = exportCertBase64;
exports.exportPrivateKey = exportPrivateKey;
exports.logKeystoreHashes = logKeystoreHashes;
exports.logKeystoreCredentials = logKeystoreCredentials;
exports.createKeystore = createKeystore;
exports.generateUploadKeystore = generateUploadKeystore;
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
function _fsExtra() {
const data = _interopRequireDefault(require("fs-extra"));
_fsExtra = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _crypto() {
const data = _interopRequireDefault(require("crypto"));
_crypto = function () {
return data;
};
return data;
}
function _v() {
const data = _interopRequireDefault(require("uuid/v4"));
_v = function () {
return data;
};
return data;
}
function _spawnAsync() {
const data = _interopRequireDefault(require("@expo/spawn-async"));
_spawnAsync = function () {
return data;
};
return data;
}
function _axios() {
const data = _interopRequireDefault(require("axios"));
_axios = function () {
return data;
};
return data;
}
function _progress() {
const data = _interopRequireDefault(require("progress"));
_progress = function () {
return data;
};
return data;
}
function _Logger() {
const data = _interopRequireDefault(require("../Logger"));
_Logger = function () {
return data;
};
return data;
}
function _UserSettings() {
const data = _interopRequireDefault(require("../UserSettings"));
_UserSettings = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const log = _Logger().default.global;
const NEWLINE = process.platform === 'win32' ? '\r\n' : '\n';
const javaExecutable = process.platform === 'win32' ? 'java.exe' : 'java';
async function exportCertBinary({
keystorePath,
keystorePassword,
keyAlias
}, certFile) {
try {
return (0, _spawnAsync().default)('keytool', ['-exportcert', '-keystore', keystorePath, '-storepass', keystorePassword, '-alias', keyAlias, '-file', certFile, '-noprompt', '-storetype', 'JKS']);
} catch (err) {
if (err.code === 'ENOENT') {
log.warn('Are you sure you have keytool installed?');
log.info('keytool is a part of OpenJDK: https://openjdk.java.net/');
log.info('Also make sure that keytool is in your PATH after installation.');
}
throw err;
}
}
async function exportCertBase64({
keystorePath,
keystorePassword,
keyAlias
}, certFile) {
try {
return (0, _spawnAsync().default)('keytool', ['-export', '-rfc', '-keystore', keystorePath, '-storepass', keystorePassword, '-alias', keyAlias, '-file', certFile, '-noprompt', '-storetype', 'JKS']);
} catch (err) {
if (err.code === 'ENOENT') {
log.warn('Are you sure you have keytool installed?');
log.info('keytool is a part of OpenJDK: https://openjdk.java.net/');
log.info('Also make sure that keytool is in your PATH after installation.');
}
throw err;
}
}
async function exportPrivateKey({
keystorePath,
keystorePassword,
keyAlias,
keyPassword
}, encryptionKey, outputPath) {
let nodePty;
const ptyTmpDir = '/tmp/pty-tmp-install';
try {
// it's not very pretty solution, but we decided to use it because it's affecting only people using
// this command and if node-pty is supported on that system instalation process will be invisble for user.
nodePty = require('node-pty-prebuilt');
} catch (err) {
try {
log.info('Installing node-pty-prebuilt in a temporary directory');
await _fsExtra().default.mkdirp(ptyTmpDir);
await (0, _spawnAsync().default)('npm', ['init', '--yes'], {
cwd: ptyTmpDir
});
await (0, _spawnAsync().default)('npm', ['install', 'node-pty-prebuilt'], {
cwd: ptyTmpDir,
stdio: ['pipe', 1, 2]
});
nodePty = require(`${ptyTmpDir}/node_modules/node-pty-prebuilt`);
} catch (err) {
log.info(`Run ${_chalk().default.cyan('npm -g install node-pty-prebuilt')} to install node pty`);
throw new Error('Package node-pty-prebuilt is required to use PEPK tool');
}
}
const ptySpawn = nodePty.spawn;
const encryptToolPath = _path().default.join(_UserSettings().default.dotExpoHomeDirectory(), 'android_tools_pepk.jar');
if (!_fsExtra().default.existsSync(encryptToolPath)) {
log.info(`Downloading PEPK tool from Google Play to ${encryptToolPath}`);
const downloadUrl = 'https://www.gstatic.com/play-apps-publisher-rapid/signing-tool/prod/pepk.jar';
const file = _fsExtra().default.createWriteStream(encryptToolPath);
const response = await (0, _axios().default)({
url: downloadUrl,
method: 'GET',
responseType: 'stream'
});
const bar = new (_progress().default)(' downloading pepk tool [:bar] :rate/bps :percent :etas', {
complete: '=',
incomplete: ' ',
width: 40,
total: parseInt(response.headers['content-length'], 10)
});
response.data.pipe(file);
response.data.on('data', chunk => bar.tick(chunk.length));
await new Promise((resolve, reject) => {
file.on('finish', resolve);
file.on('error', reject);
});
}
try {
await new Promise((res, rej) => {
const child = ptySpawn(javaExecutable, ['-jar', encryptToolPath, '--keystore', keystorePath, '--alias', keyAlias, '--output', outputPath, '--encryptionkey', encryptionKey], {
name: 'pepk tool',
cols: 80,
rows: 30,
cwd: process.cwd(),
env: process.env
});
child.on('error', err => {
log.error('error', err);
rej(err);
});
child.on('exit', exitCode => {
if (exitCode !== 0) {
rej(exitCode);
} else {
res();
}
});
child.write(keystorePassword + NEWLINE);
child.write(keyPassword + NEWLINE);
});
log.info(`Exported and encrypted private App Signing Key to file ${outputPath}`);
} catch (error) {
throw new Error(`PEPK tool failed with return code ${error}`);
} finally {
_fsExtra().default.remove(ptyTmpDir);
}
}
async function logKeystoreHashes(keystoreInfo, linePrefix = '') {
const {
keystorePath,
keystorePassword,
keyAlias
} = keystoreInfo;
const certFile = `${keystorePath}.cer`;
try {
await exportCertBinary(keystoreInfo, certFile);
const data = await _fsExtra().default.readFile(certFile);
const googleHash = _crypto().default.createHash('sha1').update(data).digest('hex').toUpperCase();
const googleHash256 = _crypto().default.createHash('sha256').update(data).digest('hex').toUpperCase();
const fbHash = _crypto().default.createHash('sha1').update(data).digest('base64');
log.info(`${linePrefix}Google Certificate Fingerprint: ${googleHash.replace(/(.{2}(?!$))/g, '$1:')}`);
log.info(`${linePrefix}Google Certificate Hash (SHA-1): ${googleHash}`);
log.info(`${linePrefix}Google Certificate Hash (SHA-256): ${googleHash256}`);
log.info(`${linePrefix}Facebook Key Hash: ${fbHash}`);
} catch (err) {
if (err.code === 'ENOENT') {
log.warn('Are you sure you have keytool installed?');
log.info('keytool is a part of OpenJDK: https://openjdk.java.net/');
log.info('Also make sure that keytool is in your PATH after installation.');
}
if (err.stdout) {
log.info(err.stdout);
}
if (err.stderr) {
log.error(err.stderr);
}
throw err;
} finally {
try {
await _fsExtra().default.unlink(certFile);
} catch (err) {
if (err.code !== 'ENOENT') {
log.error(err);
}
}
}
}
function logKeystoreCredentials({
keystorePassword,
keyAlias,
keyPassword
}, title = 'Keystore credentials', linePrefix = '') {
log.info(`${linePrefix}${title}
${linePrefix} Keystore password: ${_chalk().default.bold(keystorePassword)}
${linePrefix} Key alias: ${_chalk().default.bold(keyAlias)}
${linePrefix} Key password: ${_chalk().default.bold(keyPassword)}
`);
}
async function createKeystore({
keystorePath,
keystorePassword,
keyAlias,
keyPassword
}, androidPackage) {
try {
return await (0, _spawnAsync().default)('keytool', ['-genkey', '-v', '-storetype', 'JKS', '-storepass', keystorePassword, '-keypass', keyPassword, '-keystore', keystorePath, '-alias', keyAlias, '-keyalg', 'RSA', '-keysize', '2048', '-validity', '10000', '-dname', `CN=${androidPackage},OU=,O=,L=,S=,C=US`]);
} catch (error) {
if (error.code === 'ENOENT') {
log.warn('Are you sure you have keytool installed?');
log.info('keytool is a part of OpenJDK: https://openjdk.java.net/');
log.info('Also make sure that keytool is in your PATH after installation.');
}
throw error;
}
}
async function generateUploadKeystore(uploadKeystorePath, androidPackage, experienceName) {
const keystoreData = {
keystorePassword: (0, _v().default)().replace(/-/g, ''),
keyPassword: (0, _v().default)().replace(/-/g, ''),
keyAlias: Buffer.from(experienceName).toString('base64'),
keystorePath: uploadKeystorePath
};
await createKeystore(keystoreData, androidPackage);
return keystoreData;
}
//# sourceMappingURL=../__sourcemaps__/credentials/AndroidCredentials.js.map