123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- 'use strict';
- // Helper functions for accessing the google API.
- var Parse = require('parse/node').Parse;
- const https = require('https');
- const jwt = require('jsonwebtoken');
- const authUtils = require('./utils');
- const TOKEN_ISSUER = 'accounts.google.com';
- const HTTPS_TOKEN_ISSUER = 'https://accounts.google.com';
- let cache = {};
- // Retrieve Google Signin Keys (with cache control)
- function getGoogleKeyByKeyId(keyId) {
- if (cache[keyId] && cache.expiresAt > new Date()) {
- return cache[keyId];
- }
- return new Promise((resolve, reject) => {
- https.get(`https://www.googleapis.com/oauth2/v3/certs`, res => {
- let data = '';
- res.on('data', chunk => {
- data += chunk.toString('utf8');
- });
- res.on('end', () => {
- const {
- keys
- } = JSON.parse(data);
- const pems = keys.reduce((pems, {
- n: modulus,
- e: exposant,
- kid
- }) => Object.assign(pems, {
- [kid]: rsaPublicKeyToPEM(modulus, exposant)
- }), {});
- if (res.headers['cache-control']) {
- var expire = res.headers['cache-control'].match(/max-age=([0-9]+)/);
- if (expire) {
- cache = Object.assign({}, pems, {
- expiresAt: new Date(new Date().getTime() + Number(expire[1]) * 1000)
- });
- }
- }
- resolve(pems[keyId]);
- });
- }).on('error', reject);
- });
- }
- async function verifyIdToken({
- id_token: token,
- id
- }, {
- clientId
- }) {
- if (!token) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `id token is invalid for this user.`);
- }
- const {
- kid: keyId,
- alg: algorithm
- } = authUtils.getHeaderFromToken(token);
- let jwtClaims;
- const googleKey = await getGoogleKeyByKeyId(keyId);
- try {
- jwtClaims = jwt.verify(token, googleKey, {
- algorithms: algorithm,
- audience: clientId
- });
- } catch (exception) {
- const message = exception.message;
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `${message}`);
- }
- if (jwtClaims.iss !== TOKEN_ISSUER && jwtClaims.iss !== HTTPS_TOKEN_ISSUER) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `id token not issued by correct provider - expected: ${TOKEN_ISSUER} or ${HTTPS_TOKEN_ISSUER} | from: ${jwtClaims.iss}`);
- }
- if (jwtClaims.sub !== id) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `auth data is invalid for this user.`);
- }
- if (clientId && jwtClaims.aud !== clientId) {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `id token not authorized for this clientId.`);
- }
- return jwtClaims;
- }
- // Returns a promise that fulfills if this user id is valid.
- function validateAuthData(authData, options = {}) {
- return verifyIdToken(authData, options);
- }
- // Returns a promise that fulfills if this app id is valid.
- function validateAppId() {
- return Promise.resolve();
- }
- module.exports = {
- validateAppId: validateAppId,
- validateAuthData: validateAuthData
- };
- // Helpers functions to convert the RSA certs to PEM (from jwks-rsa)
- function rsaPublicKeyToPEM(modulusB64, exponentB64) {
- const modulus = new Buffer(modulusB64, 'base64');
- const exponent = new Buffer(exponentB64, 'base64');
- const modulusHex = prepadSigned(modulus.toString('hex'));
- const exponentHex = prepadSigned(exponent.toString('hex'));
- const modlen = modulusHex.length / 2;
- const explen = exponentHex.length / 2;
- const encodedModlen = encodeLengthHex(modlen);
- const encodedExplen = encodeLengthHex(explen);
- const encodedPubkey = '30' + encodeLengthHex(modlen + explen + encodedModlen.length / 2 + encodedExplen.length / 2 + 2) + '02' + encodedModlen + modulusHex + '02' + encodedExplen + exponentHex;
- const der = new Buffer(encodedPubkey, 'hex').toString('base64');
- let pem = '-----BEGIN RSA PUBLIC KEY-----\n';
- pem += `${der.match(/.{1,64}/g).join('\n')}`;
- pem += '\n-----END RSA PUBLIC KEY-----\n';
- return pem;
- }
- function prepadSigned(hexStr) {
- const msb = hexStr[0];
- if (msb < '0' || msb > '7') {
- return `00${hexStr}`;
- }
- return hexStr;
- }
- function toHex(number) {
- const nstr = number.toString(16);
- if (nstr.length % 2) {
- return `0${nstr}`;
- }
- return nstr;
- }
- function encodeLengthHex(n) {
- if (n <= 127) {
- return toHex(n);
- }
- const nHex = toHex(n);
- const lengthOfLengthByte = 128 + nHex.length / 2;
- return toHex(lengthOfLengthByte) + nHex;
- }
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJQYXJzZSIsInJlcXVpcmUiLCJodHRwcyIsImp3dCIsImF1dGhVdGlscyIsIlRPS0VOX0lTU1VFUiIsIkhUVFBTX1RPS0VOX0lTU1VFUiIsImNhY2hlIiwiZ2V0R29vZ2xlS2V5QnlLZXlJZCIsImtleUlkIiwiZXhwaXJlc0F0IiwiRGF0ZSIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwiZ2V0IiwicmVzIiwiZGF0YSIsIm9uIiwiY2h1bmsiLCJ0b1N0cmluZyIsImtleXMiLCJKU09OIiwicGFyc2UiLCJwZW1zIiwicmVkdWNlIiwibiIsIm1vZHVsdXMiLCJlIiwiZXhwb3NhbnQiLCJraWQiLCJPYmplY3QiLCJhc3NpZ24iLCJyc2FQdWJsaWNLZXlUb1BFTSIsImhlYWRlcnMiLCJleHBpcmUiLCJtYXRjaCIsImdldFRpbWUiLCJOdW1iZXIiLCJ2ZXJpZnlJZFRva2VuIiwiaWRfdG9rZW4iLCJ0b2tlbiIsImlkIiwiY2xpZW50SWQiLCJFcnJvciIsIk9CSkVDVF9OT1RfRk9VTkQiLCJhbGciLCJhbGdvcml0aG0iLCJnZXRIZWFkZXJGcm9tVG9rZW4iLCJqd3RDbGFpbXMiLCJnb29nbGVLZXkiLCJ2ZXJpZnkiLCJhbGdvcml0aG1zIiwiYXVkaWVuY2UiLCJleGNlcHRpb24iLCJtZXNzYWdlIiwiaXNzIiwic3ViIiwiYXVkIiwidmFsaWRhdGVBdXRoRGF0YSIsImF1dGhEYXRhIiwib3B0aW9ucyIsInZhbGlkYXRlQXBwSWQiLCJtb2R1bGUiLCJleHBvcnRzIiwibW9kdWx1c0I2NCIsImV4cG9uZW50QjY0IiwiQnVmZmVyIiwiZXhwb25lbnQiLCJtb2R1bHVzSGV4IiwicHJlcGFkU2lnbmVkIiwiZXhwb25lbnRIZXgiLCJtb2RsZW4iLCJsZW5ndGgiLCJleHBsZW4iLCJlbmNvZGVkTW9kbGVuIiwiZW5jb2RlTGVuZ3RoSGV4IiwiZW5jb2RlZEV4cGxlbiIsImVuY29kZWRQdWJrZXkiLCJkZXIiLCJwZW0iLCJqb2luIiwiaGV4U3RyIiwibXNiIiwidG9IZXgiLCJudW1iZXIiLCJuc3RyIiwibkhleCIsImxlbmd0aE9mTGVuZ3RoQnl0ZSJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9BZGFwdGVycy9BdXRoL2dvb2dsZS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbi8vIEhlbHBlciBmdW5jdGlvbnMgZm9yIGFjY2Vzc2luZyB0aGUgZ29vZ2xlIEFQSS5cbnZhciBQYXJzZSA9IHJlcXVpcmUoJ3BhcnNlL25vZGUnKS5QYXJzZTtcblxuY29uc3QgaHR0cHMgPSByZXF1aXJlKCdodHRwcycpO1xuY29uc3Qgand0ID0gcmVxdWlyZSgnanNvbndlYnRva2VuJyk7XG5jb25zdCBhdXRoVXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzJyk7XG5cbmNvbnN0IFRPS0VOX0lTU1VFUiA9ICdhY2NvdW50cy5nb29nbGUuY29tJztcbmNvbnN0IEhUVFBTX1RPS0VOX0lTU1VFUiA9ICdodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20nO1xuXG5sZXQgY2FjaGUgPSB7fTtcblxuLy8gUmV0cmlldmUgR29vZ2xlIFNpZ25pbiBLZXlzICh3aXRoIGNhY2hlIGNvbnRyb2wpXG5mdW5jdGlvbiBnZXRHb29nbGVLZXlCeUtleUlkKGtleUlkKSB7XG4gIGlmIChjYWNoZVtrZXlJZF0gJiYgY2FjaGUuZXhwaXJlc0F0ID4gbmV3IERhdGUoKSkge1xuICAgIHJldHVybiBjYWNoZVtrZXlJZF07XG4gIH1cblxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGh0dHBzXG4gICAgICAuZ2V0KGBodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9vYXV0aDIvdjMvY2VydHNgLCByZXMgPT4ge1xuICAgICAgICBsZXQgZGF0YSA9ICcnO1xuICAgICAgICByZXMub24oJ2RhdGEnLCBjaHVuayA9PiB7XG4gICAgICAgICAgZGF0YSArPSBjaHVuay50b1N0cmluZygndXRmOCcpO1xuICAgICAgICB9KTtcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgeyBrZXlzIH0gPSBKU09OLnBhcnNlKGRhdGEpO1xuICAgICAgICAgIGNvbnN0IHBlbXMgPSBrZXlzLnJlZHVjZShcbiAgICAgICAgICAgIChwZW1zLCB7IG46IG1vZHVsdXMsIGU6IGV4cG9zYW50LCBraWQgfSkgPT5cbiAgICAgICAgICAgICAgT2JqZWN0LmFzc2lnbihwZW1zLCB7XG4gICAgICAgICAgICAgICAgW2tpZF06IHJzYVB1YmxpY0tleVRvUEVNKG1vZHVsdXMsIGV4cG9zYW50KSxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB7fVxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBpZiAocmVzLmhlYWRlcnNbJ2NhY2hlLWNvbnRyb2wnXSkge1xuICAgICAgICAgICAgdmFyIGV4cGlyZSA9IHJlcy5oZWFkZXJzWydjYWNoZS1jb250cm9sJ10ubWF0Y2goL21heC1hZ2U9KFswLTldKykvKTtcblxuICAgICAgICAgICAgaWYgKGV4cGlyZSkge1xuICAgICAgICAgICAgICBjYWNoZSA9IE9iamVjdC5hc3NpZ24oe30sIHBlbXMsIHtcbiAgICAgICAgICAgICAgICBleHBpcmVzQXQ6IG5ldyBEYXRlKG5ldyBEYXRlKCkuZ2V0VGltZSgpICsgTnVtYmVyKGV4cGlyZVsxXSkgKiAxMDAwKSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmVzb2x2ZShwZW1zW2tleUlkXSk7XG4gICAgICAgIH0pO1xuICAgICAgfSlcbiAgICAgIC5vbignZXJyb3InLCByZWplY3QpO1xuICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdmVyaWZ5SWRUb2tlbih7IGlkX3Rva2VuOiB0b2tlbiwgaWQgfSwgeyBjbGllbnRJZCB9KSB7XG4gIGlmICghdG9rZW4pIHtcbiAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCwgYGlkIHRva2VuIGlzIGludmFsaWQgZm9yIHRoaXMgdXNlci5gKTtcbiAgfVxuXG4gIGNvbnN0IHsga2lkOiBrZXlJZCwgYWxnOiBhbGdvcml0aG0gfSA9IGF1dGhVdGlscy5nZXRIZWFkZXJGcm9tVG9rZW4odG9rZW4pO1xuICBsZXQgand0Q2xhaW1zO1xuICBjb25zdCBnb29nbGVLZXkgPSBhd2FpdCBnZXRHb29nbGVLZXlCeUtleUlkKGtleUlkKTtcblxuICB0cnkge1xuICAgIGp3dENsYWltcyA9IGp3dC52ZXJpZnkodG9rZW4sIGdvb2dsZUtleSwge1xuICAgICAgYWxnb3JpdGhtczogYWxnb3JpdGhtLFxuICAgICAgYXVkaWVuY2U6IGNsaWVudElkLFxuICAgIH0pO1xuICB9IGNhdGNoIChleGNlcHRpb24pIHtcbiAgICBjb25zdCBtZXNzYWdlID0gZXhjZXB0aW9uLm1lc3NhZ2U7XG4gICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsIGAke21lc3NhZ2V9YCk7XG4gIH1cblxuICBpZiAoand0Q2xhaW1zLmlzcyAhPT0gVE9LRU5fSVNTVUVSICYmIGp3dENsYWltcy5pc3MgIT09IEhUVFBTX1RPS0VOX0lTU1VFUikge1xuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgIFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsXG4gICAgICBgaWQgdG9rZW4gbm90IGlzc3VlZCBieSBjb3JyZWN0IHByb3ZpZGVyIC0gZXhwZWN0ZWQ6ICR7VE9LRU5fSVNTVUVSfSBvciAke0hUVFBTX1RPS0VOX0lTU1VFUn0gfCBmcm9tOiAke2p3dENsYWltcy5pc3N9YFxuICAgICk7XG4gIH1cblxuICBpZiAoand0Q2xhaW1zLnN1YiAhPT0gaWQpIHtcbiAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCwgYGF1dGggZGF0YSBpcyBpbnZhbGlkIGZvciB0aGlzIHVzZXIuYCk7XG4gIH1cblxuICBpZiAoY2xpZW50SWQgJiYgand0Q2xhaW1zLmF1ZCAhPT0gY2xpZW50SWQpIHtcbiAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICBQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5ELFxuICAgICAgYGlkIHRva2VuIG5vdCBhdXRob3JpemVkIGZvciB0aGlzIGNsaWVudElkLmBcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIGp3dENsYWltcztcbn1cblxuLy8gUmV0dXJucyBhIHByb21pc2UgdGhhdCBmdWxmaWxscyBpZiB0aGlzIHVzZXIgaWQgaXMgdmFsaWQuXG5mdW5jdGlvbiB2YWxpZGF0ZUF1dGhEYXRhKGF1dGhEYXRhLCBvcHRpb25zID0ge30pIHtcbiAgcmV0dXJuIHZlcmlmeUlkVG9rZW4oYXV0aERhdGEsIG9wdGlvbnMpO1xufVxuXG4vLyBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IGZ1bGZpbGxzIGlmIHRoaXMgYXBwIGlkIGlzIHZhbGlkLlxuZnVuY3Rpb24gdmFsaWRhdGVBcHBJZCgpIHtcbiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgdmFsaWRhdGVBcHBJZDogdmFsaWRhdGVBcHBJZCxcbiAgdmFsaWRhdGVBdXRoRGF0YTogdmFsaWRhdGVBdXRoRGF0YSxcbn07XG5cbi8vIEhlbHBlcnMgZnVuY3Rpb25zIHRvIGNvbnZlcnQgdGhlIFJTQSBjZXJ0cyB0byBQRU0gKGZyb20gandrcy1yc2EpXG5mdW5jdGlvbiByc2FQdWJsaWNLZXlUb1BFTShtb2R1bHVzQjY0LCBleHBvbmVudEI2NCkge1xuICBjb25zdCBtb2R1bHVzID0gbmV3IEJ1ZmZlcihtb2R1bHVzQjY0LCAnYmFzZTY0Jyk7XG4gIGNvbnN0IGV4cG9uZW50ID0gbmV3IEJ1ZmZlcihleHBvbmVudEI2NCwgJ2Jhc2U2NCcpO1xuICBjb25zdCBtb2R1bHVzSGV4ID0gcHJlcGFkU2lnbmVkKG1vZHVsdXMudG9TdHJpbmcoJ2hleCcpKTtcbiAgY29uc3QgZXhwb25lbnRIZXggPSBwcmVwYWRTaWduZWQoZXhwb25lbnQudG9TdHJpbmcoJ2hleCcpKTtcbiAgY29uc3QgbW9kbGVuID0gbW9kdWx1c0hleC5sZW5ndGggLyAyO1xuICBjb25zdCBleHBsZW4gPSBleHBvbmVudEhleC5sZW5ndGggLyAyO1xuXG4gIGNvbnN0IGVuY29kZWRNb2RsZW4gPSBlbmNvZGVMZW5ndGhIZXgobW9kbGVuKTtcbiAgY29uc3QgZW5jb2RlZEV4cGxlbiA9IGVuY29kZUxlbmd0aEhleChleHBsZW4pO1xuICBjb25zdCBlbmNvZGVkUHVia2V5ID1cbiAgICAnMzAnICtcbiAgICBlbmNvZGVMZW5ndGhIZXgobW9kbGVuICsgZXhwbGVuICsgZW5jb2RlZE1vZGxlbi5sZW5ndGggLyAyICsgZW5jb2RlZEV4cGxlbi5sZW5ndGggLyAyICsgMikgK1xuICAgICcwMicgK1xuICAgIGVuY29kZWRNb2RsZW4gK1xuICAgIG1vZHVsdXNIZXggK1xuICAgICcwMicgK1xuICAgIGVuY29kZWRFeHBsZW4gK1xuICAgIGV4cG9uZW50SGV4O1xuXG4gIGNvbnN0IGRlciA9IG5ldyBCdWZmZXIoZW5jb2RlZFB1YmtleSwgJ2hleCcpLnRvU3RyaW5nKCdiYXNlNjQnKTtcblxuICBsZXQgcGVtID0gJy0tLS0tQkVHSU4gUlNBIFBVQkxJQyBLRVktLS0tLVxcbic7XG4gIHBlbSArPSBgJHtkZXIubWF0Y2goLy57MSw2NH0vZykuam9pbignXFxuJyl9YDtcbiAgcGVtICs9ICdcXG4tLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tXFxuJztcbiAgcmV0dXJuIHBlbTtcbn1cblxuZnVuY3Rpb24gcHJlcGFkU2lnbmVkKGhleFN0cikge1xuICBjb25zdCBtc2IgPSBoZXhTdHJbMF07XG4gIGlmIChtc2IgPCAnMCcgfHwgbXNiID4gJzcnKSB7XG4gICAgcmV0dXJuIGAwMCR7aGV4U3RyfWA7XG4gIH1cbiAgcmV0dXJuIGhleFN0cjtcbn1cblxuZnVuY3Rpb24gdG9IZXgobnVtYmVyKSB7XG4gIGNvbnN0IG5zdHIgPSBudW1iZXIudG9TdHJpbmcoMTYpO1xuICBpZiAobnN0ci5sZW5ndGggJSAyKSB7XG4gICAgcmV0dXJuIGAwJHtuc3RyfWA7XG4gIH1cbiAgcmV0dXJuIG5zdHI7XG59XG5cbmZ1bmN0aW9uIGVuY29kZUxlbmd0aEhleChuKSB7XG4gIGlmIChuIDw9IDEyNykge1xuICAgIHJldHVybiB0b0hleChuKTtcbiAgfVxuICBjb25zdCBuSGV4ID0gdG9IZXgobik7XG4gIGNvbnN0IGxlbmd0aE9mTGVuZ3RoQnl0ZSA9IDEyOCArIG5IZXgubGVuZ3RoIC8gMjtcbiAgcmV0dXJuIHRvSGV4KGxlbmd0aE9mTGVuZ3RoQnl0ZSkgKyBuSGV4O1xufVxuIl0sIm1hcHBpbmdzIjoiQUFBQSxZQUFZOztBQUVaO0FBQ0EsSUFBSUEsS0FBSyxHQUFHQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUNELEtBQUs7QUFFdkMsTUFBTUUsS0FBSyxHQUFHRCxPQUFPLENBQUMsT0FBTyxDQUFDO0FBQzlCLE1BQU1FLEdBQUcsR0FBR0YsT0FBTyxDQUFDLGNBQWMsQ0FBQztBQUNuQyxNQUFNRyxTQUFTLEdBQUdILE9BQU8sQ0FBQyxTQUFTLENBQUM7QUFFcEMsTUFBTUksWUFBWSxHQUFHLHFCQUFxQjtBQUMxQyxNQUFNQyxrQkFBa0IsR0FBRyw2QkFBNkI7QUFFeEQsSUFBSUMsS0FBSyxHQUFHLENBQUMsQ0FBQzs7QUFFZDtBQUNBLFNBQVNDLG1CQUFtQkEsQ0FBQ0MsS0FBSyxFQUFFO0VBQ2xDLElBQUlGLEtBQUssQ0FBQ0UsS0FBSyxDQUFDLElBQUlGLEtBQUssQ0FBQ0csU0FBUyxHQUFHLElBQUlDLElBQUksQ0FBQyxDQUFDLEVBQUU7SUFDaEQsT0FBT0osS0FBSyxDQUFDRSxLQUFLLENBQUM7RUFDckI7RUFFQSxPQUFPLElBQUlHLE9BQU8sQ0FBQyxDQUFDQyxPQUFPLEVBQUVDLE1BQU0sS0FBSztJQUN0Q1osS0FBSyxDQUNGYSxHQUFHLENBQUMsNENBQTRDLEVBQUVDLEdBQUcsSUFBSTtNQUN4RCxJQUFJQyxJQUFJLEdBQUcsRUFBRTtNQUNiRCxHQUFHLENBQUNFLEVB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
|