123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- "use strict";
- /* Apple Game Center Auth
- https://developer.apple.com/documentation/gamekit/gklocalplayer/1515407-generateidentityverificationsign#discussion
- const authData = {
- publicKeyUrl: 'https://valid.apple.com/public/timeout.cer',
- timestamp: 1460981421303,
- signature: 'PoDwf39DCN464B49jJCU0d9Y0J',
- salt: 'saltST==',
- bundleId: 'com.valid.app'
- id: 'playerId',
- };
- */
- const {
- Parse
- } = require('parse/node');
- const crypto = require('crypto');
- const https = require('https');
- const {
- pki
- } = require('node-forge');
- const ca = {
- cert: null,
- url: null
- };
- const cache = {}; // (publicKey -> cert) cache
- function verifyPublicKeyUrl(publicKeyUrl) {
- try {
- const regex = /^https:\/\/(?:[-_A-Za-z0-9]+\.){0,}apple\.com\/.*\.cer$/;
- return regex.test(publicKeyUrl);
- } catch (error) {
- return false;
- }
- }
- function convertX509CertToPEM(X509Cert) {
- const pemPreFix = '-----BEGIN CERTIFICATE-----\n';
- const pemPostFix = '-----END CERTIFICATE-----';
- const base64 = X509Cert;
- const certBody = base64.match(new RegExp('.{0,64}', 'g')).join('\n');
- return pemPreFix + certBody + pemPostFix;
- }
- async function getAppleCertificate(publicKeyUrl) {
- if (!verifyPublicKeyUrl(publicKeyUrl)) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}`);
- }
- if (cache[publicKeyUrl]) {
- return cache[publicKeyUrl];
- }
- const url = new URL(publicKeyUrl);
- const headOptions = {
- hostname: url.hostname,
- path: url.pathname,
- method: 'HEAD'
- };
- const cert_headers = await new Promise((resolve, reject) => https.get(headOptions, res => resolve(res.headers)).on('error', reject));
- const validContentTypes = ['application/x-x509-ca-cert', 'application/pkix-cert'];
- if (!validContentTypes.includes(cert_headers['content-type']) || cert_headers['content-length'] == null || cert_headers['content-length'] > 10000) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}`);
- }
- const {
- certificate,
- headers
- } = await getCertificate(publicKeyUrl);
- if (headers['cache-control']) {
- const expire = headers['cache-control'].match(/max-age=([0-9]+)/);
- if (expire) {
- cache[publicKeyUrl] = certificate;
- // we'll expire the cache entry later, as per max-age
- setTimeout(() => {
- delete cache[publicKeyUrl];
- }, parseInt(expire[1], 10) * 1000);
- }
- }
- return verifyPublicKeyIssuer(certificate, publicKeyUrl);
- }
- function getCertificate(url, buffer) {
- return new Promise((resolve, reject) => {
- https.get(url, res => {
- const data = [];
- res.on('data', chunk => {
- data.push(chunk);
- });
- res.on('end', () => {
- if (buffer) {
- resolve({
- certificate: Buffer.concat(data),
- headers: res.headers
- });
- return;
- }
- let cert = '';
- for (const chunk of data) {
- cert += chunk.toString('base64');
- }
- const certificate = convertX509CertToPEM(cert);
- resolve({
- certificate,
- headers: res.headers
- });
- });
- }).on('error', reject);
- });
- }
- function convertTimestampToBigEndian(timestamp) {
- const buffer = Buffer.alloc(8);
- const high = ~~(timestamp / 0xffffffff);
- const low = timestamp % (0xffffffff + 0x1);
- buffer.writeUInt32BE(parseInt(high, 10), 0);
- buffer.writeUInt32BE(parseInt(low, 10), 4);
- return buffer;
- }
- function verifySignature(publicKey, authData) {
- const verifier = crypto.createVerify('sha256');
- verifier.update(authData.playerId, 'utf8');
- verifier.update(authData.bundleId, 'utf8');
- verifier.update(convertTimestampToBigEndian(authData.timestamp));
- verifier.update(authData.salt, 'base64');
- if (!verifier.verify(publicKey, authData.signature, 'base64')) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Apple Game Center - invalid signature');
- }
- }
- function verifyPublicKeyIssuer(cert, publicKeyUrl) {
- const publicKeyCert = pki.certificateFromPem(cert);
- if (!ca.cert) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Apple Game Center auth adapter parameter `rootCertificateURL` is invalid.');
- }
- try {
- if (!ca.cert.verify(publicKeyCert)) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}`);
- }
- } catch (e) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}`);
- }
- return cert;
- }
- // Returns a promise that fulfills if this user id is valid.
- async function validateAuthData(authData) {
- if (!authData.id) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Apple Game Center - authData id missing');
- }
- authData.playerId = authData.id;
- const publicKey = await getAppleCertificate(authData.publicKeyUrl);
- return verifySignature(publicKey, authData);
- }
- // Returns a promise that fulfills if this app id is valid.
- async function validateAppId(appIds, authData, options = {}) {
- if (!options.rootCertificateUrl) {
- options.rootCertificateUrl = 'https://cacerts.digicert.com/DigiCertTrustedG4CodeSigningRSA4096SHA3842021CA1.crt.pem';
- }
- if (ca.url === options.rootCertificateUrl) {
- return;
- }
- const {
- certificate,
- headers
- } = await getCertificate(options.rootCertificateUrl, true);
- if (headers['content-type'] !== 'application/x-pem-file' || headers['content-length'] == null || headers['content-length'] > 10000) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Apple Game Center auth adapter parameter `rootCertificateURL` is invalid.');
- }
- ca.cert = pki.certificateFromPem(certificate);
- ca.url = options.rootCertificateUrl;
- }
- module.exports = {
- validateAppId,
- validateAuthData,
- cache
- };
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJQYXJzZSIsInJlcXVpcmUiLCJjcnlwdG8iLCJodHRwcyIsInBraSIsImNhIiwiY2VydCIsInVybCIsImNhY2hlIiwidmVyaWZ5UHVibGljS2V5VXJsIiwicHVibGljS2V5VXJsIiwicmVnZXgiLCJ0ZXN0IiwiZXJyb3IiLCJjb252ZXJ0WDUwOUNlcnRUb1BFTSIsIlg1MDlDZXJ0IiwicGVtUHJlRml4IiwicGVtUG9zdEZpeCIsImJhc2U2NCIsImNlcnRCb2R5IiwibWF0Y2giLCJSZWdFeHAiLCJqb2luIiwiZ2V0QXBwbGVDZXJ0aWZpY2F0ZSIsIkVycm9yIiwiT0JKRUNUX05PVF9GT1VORCIsIlVSTCIsImhlYWRPcHRpb25zIiwiaG9zdG5hbWUiLCJwYXRoIiwicGF0aG5hbWUiLCJtZXRob2QiLCJjZXJ0X2hlYWRlcnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsImdldCIsInJlcyIsImhlYWRlcnMiLCJvbiIsInZhbGlkQ29udGVudFR5cGVzIiwiaW5jbHVkZXMiLCJjZXJ0aWZpY2F0ZSIsImdldENlcnRpZmljYXRlIiwiZXhwaXJlIiwic2V0VGltZW91dCIsInBhcnNlSW50IiwidmVyaWZ5UHVibGljS2V5SXNzdWVyIiwiYnVmZmVyIiwiZGF0YSIsImNodW5rIiwicHVzaCIsIkJ1ZmZlciIsImNvbmNhdCIsInRvU3RyaW5nIiwiY29udmVydFRpbWVzdGFtcFRvQmlnRW5kaWFuIiwidGltZXN0YW1wIiwiYWxsb2MiLCJoaWdoIiwibG93Iiwid3JpdGVVSW50MzJCRSIsInZlcmlmeVNpZ25hdHVyZSIsInB1YmxpY0tleSIsImF1dGhEYXRhIiwidmVyaWZpZXIiLCJjcmVhdGVWZXJpZnkiLCJ1cGRhdGUiLCJwbGF5ZXJJZCIsImJ1bmRsZUlkIiwic2FsdCIsInZlcmlmeSIsInNpZ25hdHVyZSIsInB1YmxpY0tleUNlcnQiLCJjZXJ0aWZpY2F0ZUZyb21QZW0iLCJlIiwidmFsaWRhdGVBdXRoRGF0YSIsImlkIiwidmFsaWRhdGVBcHBJZCIsImFwcElkcyIsIm9wdGlvbnMiLCJyb290Q2VydGlmaWNhdGVVcmwiLCJtb2R1bGUiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL0FkYXB0ZXJzL0F1dGgvZ2NlbnRlci5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBBcHBsZSBHYW1lIENlbnRlciBBdXRoXG5odHRwczovL2RldmVsb3Blci5hcHBsZS5jb20vZG9jdW1lbnRhdGlvbi9nYW1la2l0L2drbG9jYWxwbGF5ZXIvMTUxNTQwNy1nZW5lcmF0ZWlkZW50aXR5dmVyaWZpY2F0aW9uc2lnbiNkaXNjdXNzaW9uXG5cbmNvbnN0IGF1dGhEYXRhID0ge1xuICBwdWJsaWNLZXlVcmw6ICdodHRwczovL3ZhbGlkLmFwcGxlLmNvbS9wdWJsaWMvdGltZW91dC5jZXInLFxuICB0aW1lc3RhbXA6IDE0NjA5ODE0MjEzMDMsXG4gIHNpZ25hdHVyZTogJ1BvRHdmMzlEQ040NjRCNDlqSkNVMGQ5WTBKJyxcbiAgc2FsdDogJ3NhbHRTVD09JyxcbiAgYnVuZGxlSWQ6ICdjb20udmFsaWQuYXBwJ1xuICBpZDogJ3BsYXllcklkJyxcbn07XG4qL1xuXG5jb25zdCB7IFBhcnNlIH0gPSByZXF1aXJlKCdwYXJzZS9ub2RlJyk7XG5jb25zdCBjcnlwdG8gPSByZXF1aXJlKCdjcnlwdG8nKTtcbmNvbnN0IGh0dHBzID0gcmVxdWlyZSgnaHR0cHMnKTtcbmNvbnN0IHsgcGtpIH0gPSByZXF1aXJlKCdub2RlLWZvcmdlJyk7XG5jb25zdCBjYSA9IHsgY2VydDogbnVsbCwgdXJsOiBudWxsIH07XG5jb25zdCBjYWNoZSA9IHt9OyAvLyAocHVibGljS2V5IC0+IGNlcnQpIGNhY2hlXG5cbmZ1bmN0aW9uIHZlcmlmeVB1YmxpY0tleVVybChwdWJsaWNLZXlVcmwpIHtcbiAgdHJ5IHtcbiAgICBjb25zdCByZWdleCA9IC9eaHR0cHM6XFwvXFwvKD86Wy1fQS1aYS16MC05XStcXC4pezAsfWFwcGxlXFwuY29tXFwvLipcXC5jZXIkLztcbiAgICByZXR1cm4gcmVnZXgudGVzdChwdWJsaWNLZXlVcmwpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG5mdW5jdGlvbiBjb252ZXJ0WDUwOUNlcnRUb1BFTShYNTA5Q2VydCkge1xuICBjb25zdCBwZW1QcmVGaXggPSAnLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tXFxuJztcbiAgY29uc3QgcGVtUG9zdEZpeCA9ICctLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tJztcblxuICBjb25zdCBiYXNlNjQgPSBYNTA5Q2VydDtcbiAgY29uc3QgY2VydEJvZHkgPSBiYXNlNjQubWF0Y2gobmV3IFJlZ0V4cCgnLnswLDY0fScsICdnJykpLmpvaW4oJ1xcbicpO1xuXG4gIHJldHVybiBwZW1QcmVGaXggKyBjZXJ0Qm9keSArIHBlbVBvc3RGaXg7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEFwcGxlQ2VydGlmaWNhdGUocHVibGljS2V5VXJsKSB7XG4gIGlmICghdmVyaWZ5UHVibGljS2V5VXJsKHB1YmxpY0tleVVybCkpIHtcbiAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICBQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5ELFxuICAgICAgYEFwcGxlIEdhbWUgQ2VudGVyIC0gaW52YWxpZCBwdWJsaWNLZXlVcmw6ICR7cHVibGljS2V5VXJsfWBcbiAgICApO1xuICB9XG4gIGlmIChjYWNoZVtwdWJsaWNLZXlVcmxdKSB7XG4gICAgcmV0dXJuIGNhY2hlW3B1YmxpY0tleVVybF07XG4gIH1cbiAgY29uc3QgdXJsID0gbmV3IFVSTChwdWJsaWNLZXlVcmwpO1xuICBjb25zdCBoZWFkT3B0aW9ucyA9IHtcbiAgICBob3N0bmFtZTogdXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHVybC5wYXRobmFtZSxcbiAgICBtZXRob2Q6ICdIRUFEJyxcbiAgfTtcbiAgY29uc3QgY2VydF9oZWFkZXJzID0gYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT5cbiAgICBodHRwcy5nZXQoaGVhZE9wdGlvbnMsIHJlcyA9PiByZXNvbHZlKHJlcy5oZWFkZXJzKSkub24oJ2Vycm9yJywgcmVqZWN0KVxuICApO1xuICBjb25zdCB2YWxpZENvbnRlbnRUeXBlcyA9IFsnYXBwbGljYXRpb24veC14NTA5LWNhLWNlcnQnLCAnYXBwbGljYXRpb24vcGtpeC1jZXJ0J107XG4gIGlmIChcbiAgICAhdmFsaWRDb250ZW50VHlwZXMuaW5jbHVkZXMoY2VydF9oZWFkZXJzWydjb250ZW50LXR5cGUnXSkgfHxcbiAgICBjZXJ0X2hlYWRlcnNbJ2NvbnRlbnQtbGVuZ3RoJ10gPT0gbnVsbCB8fFxuICAgIGNlcnRfaGVhZGVyc1snY29udGVudC1sZW5ndGgnXSA+IDEwMDAwXG4gICkge1xuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgIFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsXG4gICAgICBgQXBwbGUgR2FtZSBDZW50ZXIgLSBpbnZhbGlkIHB1YmxpY0tleVVybDogJHtwdWJsaWNLZXlVcmx9YFxuICAgICk7XG4gIH1cbiAgY29uc3QgeyBjZXJ0aWZpY2F0ZSwgaGVhZGVycyB9ID0gYXdhaXQgZ2V0Q2VydGlmaWNhdGUocHVibGljS2V5VXJsKTtcbiAgaWYgKGhlYWRlcnNbJ2NhY2hlLWNvbnRyb2wnXSkge1xuICAgIGNvbnN0IGV4cGlyZSA9IGhlYWRlcnNbJ2NhY2hlLWNvbnRyb2wnXS5tYXRjaCgvbWF4LWFnZT0oWzAtOV0rKS8pO1xuICAgIGlmIChleHBpcmUpIHtcbiAgICAgIGNhY2hlW3B1YmxpY0tleVVybF0gPSBjZXJ0aWZpY2F0ZTtcbiAgICAgIC8vIHdlJ2xsIGV4cGlyZSB0aGUgY2FjaGUgZW50cnkgbGF0ZXIsIGFzIHBlciBtYXgtYWdlXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgZGVsZXRlIGNhY2hlW3B1YmxpY0tleVVybF07XG4gICAgICB9LCBwYXJzZUludChleHBpcmVbMV0sIDEwKSAqIDEwMDApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gdmVyaWZ5UHVibGljS2V5SXNzdWVyKGNlcnRpZmljYXRlLCBwdWJsaWNLZXlVcmwpO1xufVxuXG5mdW5jdGlvbiBnZXRDZXJ0aWZpY2F0ZSh1cmwsIGJ1ZmZlcikge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGh0dHBzXG4gICAgICAuZ2V0KHVybCwgcmVzID0+IHtcbiAgICAgICAgY29uc3QgZGF0YSA9IFtdO1xuICAgICAgICByZXMub24oJ2RhdGEnLCBjaHVuayA9PiB7XG4gICAgICAgICAgZGF0YS5wdXNoKGNodW5rKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xuICAgICAgICAgIGlmIChidWZmZXIpIHtcbiAgICAgICAgICAgIHJlc29sdmUoeyBjZXJ0aWZpY2F0ZTogQnVmZmVyLmNvbmNhdChkYXRhKSwgaGVhZGVyczogcmVzLmhlYWRlcnMgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIGxldCBjZXJ0ID0gJyc7XG4gICAgICAgICAgZm9yIChjb25zdCBjaHVuayBvZiBkYXRhKSB7XG4gICAgICAgICAgICBjZXJ0ICs9IGNodW5rLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgY2VydGlmaWNhdGUgPSBjb252ZXJ0WDUwOUNlcnRUb1BFTShjZXJ0KTtcbiAgICAgICAgICByZXNvbHZlKHsgY2VydGlmaWNhdGUsIGhlYWRlcnM6IHJlcy5oZWFkZXJzIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgICAub24oJ2Vycm9yJywgcmVqZWN0KTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGNvbnZlcnRUaW1lc3RhbXBUb0JpZ0VuZGlhbih0aW1lc3RhbXApIHtcbiAgY29uc3QgYnVmZmVyID0gQnVmZmVyLmFsbG9jKDgpO1xuXG4gIGNvbnN0IGhpZ2ggPSB+fih0aW1lc3RhbXAgLyAweGZmZmZmZmZmKTtcbiAgY29uc3QgbG93ID0gdGltZXN0YW1wICUgKDB4ZmZmZmZmZmYgKyAweDEpO1xuXG4gIGJ1ZmZlci53cml0ZVVJbnQzMkJFKHBhcnNlSW50KGhpZ2gsIDEwKSwgMCk7XG4gIGJ1ZmZlci53cml0ZVVJbnQzMkJFKHBhcnNlSW50KGxvdywgMTApLCA0KTtcblxuICByZXR1cm4gYnVmZmVyO1xufVxuXG5mdW5jdGlvbiB2ZXJpZnlTaWduYXR1cmUocHVibGljS2V5LCBhdXRoRGF0YSkge1xuICBjb25zdCB2ZXJpZmllciA9IGNyeXB0by5jcmVhdGVWZXJpZnkoJ3NoYTI1NicpO1xuICB2ZXJpZmllci51cGRhdGUoYXV0aERhdGEucGxheWVySWQsICd1dGY4Jyk7XG4gIHZlcmlmaWVyLnVwZGF0ZShhdXRoRGF0YS5idW5kbGVJZCwgJ3V0ZjgnKTtcbiAgdmVyaWZpZXIudXBkYXRlKGNvbnZlcnRUaW1lc3RhbXBUb0JpZ0VuZGlhbihhdXRoRGF0YS50aW1lc3RhbXApKTtcbiAgdmVyaWZpZXIudXBkYXRlKGF1dGhEYXRhLnNhbHQsICdiYXNlNjQnKTtcblxuICBpZiAoIXZlcmlmaWVyLnZlcmlmeShwdWJsaWNLZXksIGF1dGhEYXRhLnNpZ25hdHVyZSwgJ2Jhc2U2NCcpKSB7XG4gICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsICdBcHBsZSBHYW1lIENlbnRlciAtIGludmFsaWQgc2lnbmF0dXJlJyk7XG4gIH1cbn1cblxuZnVuY3Rpb24gdmVyaWZ5UHVibGljS2V5SXNzdWVyKGNlcnQsIHB1YmxpY0tleVVybCkge1xuICBjb25zdCBwdWJsaWNLZXlDZXJ0ID0gcGtpLmNlcnRpZmljYXRlRnJvbVBlbShjZXJ0KTtcbiAgaWYgKCFjYS5jZXJ0KSB7XG4gICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFxuICAgICAgUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCxcbiAgICAgICdBcHBsZSBHYW1lIENlbnRlciBhdXRoIGFkYXB0ZXIgcGFyYW1ldGVyIGByb290Q2VydGlmaWNhdGVVUkxgIGlzIGludmFsaWQuJ1xuICAgICk7XG4gIH1cbiAgdHJ5IHtcbiAgICBpZiAoIWNhLmNlcnQudmVyaWZ5KHB1YmxpY0tleUNlcnQpKSB7XG4gICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICAgIFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsXG4gICAgICAgIGBBcHBsZSBHYW1lIENlbnRlciAtIGludmFsaWQgcHVibGljS2V5VXJsOiAke3B1YmxpY0tleVVybH1gXG4gICAgICApO1xuICAgIH1cbiAgfSBjYXRjaCAoZSkge1xuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgIFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsXG4gICAgICBgQXBwbGUgR2FtZSBDZW50ZXIgLSBpbnZhbGlkIHB1YmxpY0tleVVybDogJHtwdWJsaWNLZXlVcmx9YFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIGNlcnQ7XG59XG5cbi8vIFJldHVybnMgYSBwcm9taXNlIHRoYXQgZnVsZmlsbHMgaWYgdGhpcyB1c2VyIGlkIGlzIHZhbGlkLlxuYXN5bmMgZnVuY3Rpb24gdmFsaWRhdGVBdXRoRGF0YShhdXRoRGF0YSkge1xuICBpZiAoIWF1dGhEYXRhLmlkKSB7XG4gICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsICdBcHBsZSBHYW1lIENlbnRlciAtIGF1dGhEYXRhIGlkIG1pc3NpbmcnKTtcbiAgfVxuICBhdXRoRGF0YS5wbGF5ZXJJZCA9IGF1dGhEYXRhLmlkO1xuICBjb25zdCBwdWJsaWNLZXkgPSBhd2FpdCBnZXRBcHBsZUNlcnRpZmljYXRlKGF1dGhEYXRhLnB1YmxpY0tleVVybCk7XG4gIHJldHVybiB2ZXJpZnlTaWduYXR1cmUocHVibGljS2V5LCBhdXRoRGF0YSk7XG59XG5cbi8vIFJldHVybnMgYSBwcm9taXNlIHRoYXQgZnVsZmlsbHMgaWYgdGhpcyBhcHAgaWQgaXMgdmFsaWQuXG5hc3luYyBmdW5jdGlvbiB2YWxpZGF0ZUFwcElkKGFwcElkcywgYXV0aERhdGEsIG9wdGlvbnMgPSB7fSkge1xuICBpZiAoIW9wdGlvbnMucm9vdENlcnRpZmljYXRlVXJsKSB7XG4gICAgb3B0aW9ucy5yb290Q2VydGlmaWNhdGVVcmwgPVxuICAgICAgJ2h0dHBzOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydC5wZW0nO1xuICB9XG4gIGlmIChjYS51cmwgPT09IG9wdGlvbnMucm9vdENlcnRpZmljYXRlVXJsKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IHsgY2VydGlmaWNhdGUsIGhlYWRlcnMgfSA9IGF3YWl0IGdldENlcnRpZmljYXRlKG9wdGlvbnMucm9vdENlcnRpZmljYXRlVXJsLCB0cnVlKTtcbiAgaWYgKFxuICAgIGhlYWRlcnNbJ2NvbnRlbnQtdHlwZSddICE9PSAnYXBwbGljYXRpb24veC1wZW0tZmlsZScgfHxcbiAgICBoZWFkZXJzWydjb250ZW50LWxlbmd0aCddID09IG51bGwgfHxcbiAgICBoZWFkZXJzWydjb250ZW50LWxlbmd0aCddID4gMTAwMDBcbiAgKSB7XG4gICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFxuICAgICAgUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCxcbiAgICAgICdBcHBsZSBHYW1lIENlbnRlciBhdXRoIGFkYXB0ZXIgcGFyYW1ldGVyIGByb290Q2VydGlmaWNhdGVVUkxgIGlzIGludmFsaWQuJ1xuICAgICk7XG4gIH1cbiAgY2EuY2VydCA9IHBraS5jZXJ0aWZpY2F0ZUZyb21QZW0oY2VydGlmaWNhdGUpO1xuICBjYS51cmwgPSBvcHRpb25zLnJvb3RDZXJ0aWZpY2F0ZVVybDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHZhbGlkYXRlQXBwSWQsXG4gIHZhbGlkYXRlQXV0aERhdGEsXG4gIGNhY2hlLFxufTtcbiJdLCJtYXBwaW5ncyI6Ijs7QUFBQTtBQUNBO0FB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Q0FBQ1osUUFBUSxFQUFFO0VBQ3hDLElBQUksQ0FBQ0EsUUFBUSxDQUFDYSxFQUFFLEVBQUU7SUFDaEIsTUFBTSxJQUFJNUUsS0FBSyxDQUFDd0IsS0FBSyxDQUFDeEIsS0FBSyxDQUFDd0IsS0FBSyxDQUFDQyxnQkFBZ0IsRUFBRSx5Q0FBeUMsQ0FBQztFQUNoRztFQUNBc0MsUUFBUSxDQUFDSSxRQUFRLEdBQUdKLFFBQVEsQ0FBQ2EsRUFBRTtFQUMvQixNQUFNZCxTQUFTLEdBQUcsTUFBTXZDLG1CQUFtQixDQUFDd0MsUUFBUSxDQUFDckQsWUFBWSxDQUFDO0VBQ2xFLE9BQU9tRCxlQUFlLENBQUNDLFNBQVMsRUFBRUMsUUFBUSxDQUFDO0FBQzdDOztBQUVBO0FBQ0EsZUFBZWMsYUFBYUEsQ0FBQ0MsTUFBTSxFQUFFZixRQUFRLEVBQUVnQixPQUFPLEdBQUcsQ0FBQyxDQUFDLEVBQUU7RUFDM0QsSUFBSSxDQUFDQSxPQUFPLENBQUNDLGtCQUFrQixFQUFFO0lBQy9CRCxPQUFPLENBQUNDLGtCQUFrQixHQUN4Qix1RkFBdUY7RUFDM0Y7RUFDQSxJQUFJM0UsRUFBRSxDQUFDRSxHQUFHLEtBQUt3RSxPQUFPLENBQUNDLGtCQUFrQixFQUFFO0lBQ3pDO0VBQ0Y7RUFDQSxNQUFNO0lBQUV0QyxXQUFXO0lBQUVKO0VBQVEsQ0FBQyxHQUFHLE1BQU1LLGNBQWMsQ0FBQ29DLE9BQU8sQ0FBQ0Msa0JBQWtCLEVBQUUsSUFBSSxDQUFDO0VBQ3ZGLElBQ0UxQyxPQUFPLENBQUMsY0FBYyxDQUFDLEtBQUssd0JBQXdCLElBQ3BEQSxPQUFPLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxJQUFJLElBQ2pDQSxPQUFPLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxLQUFLLEVBQ2pDO0lBQ0EsTUFBTSxJQUFJdEMsS0FBSyxDQUFDd0IsS0FBSyxDQUNuQnhCLEtBQUssQ0FBQ3dCLEtBQUssQ0FBQ0MsZ0JBQWdCLEVBQzVCLDJFQUNGLENBQUM7RUFDSDtFQUNBcEIsRUFBRSxDQUFDQyxJQUFJLEdBQUdGLEdBQUcsQ0FBQ3FFLGtCQUFrQixDQUFDL0IsV0FBVyxDQUFDO0VBQzdDckMsRUFBRSxDQUFDRSxHQUFHLEdBQUd3RSxPQUFPLENBQUNDLGtCQUFrQjtBQUNyQztBQUVBQyxNQUFNLENBQUNDLE9BQU8sR0FBRztFQUNmTCxhQUFhO0VBQ2JGLGdCQUFnQjtFQUNoQm5FO0FBQ0YsQ0FBQyIsImlnbm9yZUxpc3QiOltdfQ==
|