..
This commit is contained in:
247
backend/node_modules/gtoken/lib/index.js
generated
vendored
Normal file
247
backend/node_modules/gtoken/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
var gp12pem = require('google-p12-pem');
|
||||
var request = require('request');
|
||||
var mime = require('mime');
|
||||
var jws = require('jws');
|
||||
var fs = require('fs');
|
||||
|
||||
var GOOGLE_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token';
|
||||
var GOOGLE_REVOKE_TOKEN_URL = 'https://accounts.google.com/o/oauth2/revoke?token=';
|
||||
|
||||
/**
|
||||
* Create a GoogleToken.
|
||||
*
|
||||
* @param {object} options Configuration object.
|
||||
*/
|
||||
function GoogleToken(options) {
|
||||
if (!(this instanceof GoogleToken)) {
|
||||
return new GoogleToken(options);
|
||||
}
|
||||
this._configure(options);
|
||||
}
|
||||
|
||||
GoogleToken.prototype._mime = mime;
|
||||
|
||||
/**
|
||||
* Returns whether the token has expired.
|
||||
*
|
||||
* @return {Boolean} true if the token has expired, false otherwise.
|
||||
*/
|
||||
GoogleToken.prototype.hasExpired = function() {
|
||||
var now = (new Date()).getTime();
|
||||
if (this.token && this.expires_at) {
|
||||
return now >= this.expires_at;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
GoogleToken.prototype._gp12pem = gp12pem;
|
||||
|
||||
/**
|
||||
* Returns a cached token or retrieves a new one from Google.
|
||||
*
|
||||
* @param {Function} callback The callback function.
|
||||
*/
|
||||
GoogleToken.prototype.getToken = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (!this.hasExpired()) {
|
||||
return callback(null, this.token);
|
||||
} else {
|
||||
if (!this.key && !this.keyFile) {
|
||||
callback(new Error('No key or keyFile set.'));
|
||||
return;
|
||||
} else if (!this.key && this.keyFile) {
|
||||
var mimeType = this._mime.lookup(this.keyFile);
|
||||
if (mimeType === 'application/json') {
|
||||
// json file
|
||||
fs.readFile(this.keyFile, handleJSONKey);
|
||||
} else {
|
||||
// Must be a .p12 file or .pem key
|
||||
if (!self.iss) {
|
||||
var error = new Error('email is required.');
|
||||
error.code = 'MISSING_CREDENTIALS';
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mimeType === 'application/x-pkcs12') {
|
||||
// convert to .pem on the fly
|
||||
self._gp12pem(this.keyFile, handleKey);
|
||||
} else {
|
||||
// assume .pem key otherwise
|
||||
fs.readFile(this.keyFile, handleKey);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return this._requestToken(callback);
|
||||
}
|
||||
}
|
||||
|
||||
function handleJSONKey(err, key) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var body = JSON.parse(key);
|
||||
self.key = body.private_key;
|
||||
self.iss = body.client_email;
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.key || !self.iss) {
|
||||
var error = new Error('private_key and client_email are required.');
|
||||
error.code = 'MISSING_CREDENTIALS';
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
self._requestToken(callback);
|
||||
}
|
||||
|
||||
function handleKey(err, key) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
self.key = key;
|
||||
self._requestToken(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Revoke the token if one is set.
|
||||
*
|
||||
* @param {Function} callback The callback function.
|
||||
*/
|
||||
GoogleToken.prototype.revokeToken = function(callback) {
|
||||
var self = this;
|
||||
if (this.token) {
|
||||
this._request(GOOGLE_REVOKE_TOKEN_URL + this.token, function(err, res) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
self._configure({
|
||||
email: self.iss,
|
||||
sub: self.sub,
|
||||
key: self.key,
|
||||
keyFile: self.keyFile,
|
||||
scope: self.scope
|
||||
});
|
||||
callback();
|
||||
});
|
||||
} else {
|
||||
callback(new Error('No token to revoke.'));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure the GoogleToken for re-use.
|
||||
* @param {object} options Configuration object.
|
||||
*/
|
||||
GoogleToken.prototype._configure = function(options) {
|
||||
var self = this;
|
||||
options = options || {};
|
||||
this.keyFile = options.keyFile;
|
||||
this.key = options.key;
|
||||
this._request = request;
|
||||
this.token = this.expires_at = this.raw_token = null;
|
||||
this.iss = options.email || options.iss;
|
||||
|
||||
if (options.sub) {
|
||||
this.sub = options.sub;
|
||||
}
|
||||
|
||||
if (typeof options.scope === 'object') {
|
||||
this.scope = options.scope.join(' ');
|
||||
} else {
|
||||
this.scope = options.scope;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Request the token from Google.
|
||||
*
|
||||
* @param {Function} callback The callback function.
|
||||
*/
|
||||
GoogleToken.prototype._requestToken = function(callback) {
|
||||
var self = this;
|
||||
var iat = Math.floor(new Date().getTime() / 1000);
|
||||
var payload = {
|
||||
iss: this.iss,
|
||||
scope: this.scope,
|
||||
aud: GOOGLE_TOKEN_URL,
|
||||
exp: iat + 3600, // 3600 seconds = 1 hour
|
||||
iat: iat
|
||||
};
|
||||
|
||||
if (this.sub) {
|
||||
payload.sub = this.sub;
|
||||
}
|
||||
|
||||
var toSign = {
|
||||
header: {
|
||||
alg: 'RS256',
|
||||
typ: 'JWT'
|
||||
},
|
||||
payload: payload,
|
||||
secret: this.key
|
||||
};
|
||||
|
||||
return this._signJWT(toSign, function(err, signedJWT) {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
|
||||
return self._request({
|
||||
method: 'post',
|
||||
url: GOOGLE_TOKEN_URL,
|
||||
form: {
|
||||
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
||||
assertion: signedJWT
|
||||
}
|
||||
}, function(err, res, body) {
|
||||
try {
|
||||
body = JSON.parse(body);
|
||||
} catch (e) {
|
||||
body = {};
|
||||
}
|
||||
|
||||
err = err || body.error && new Error(body.error);
|
||||
|
||||
if (err) {
|
||||
self.token = null;
|
||||
self.token_expires = null;
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
|
||||
self.raw_token = body;
|
||||
self.token = body.access_token;
|
||||
self.expires_at = (iat + body.expires_in) * 1000;
|
||||
return callback(null, self.token);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sign the JWT object, returning any errors in the callback.
|
||||
*
|
||||
* @param {object} opts The configuration object.
|
||||
* @param {Function} callback The callback function.
|
||||
*/
|
||||
GoogleToken.prototype._signJWT = function(opts, callback) {
|
||||
try {
|
||||
var signedJWT = jws.sign(opts);
|
||||
return callback(null, signedJWT);
|
||||
} catch (err) {
|
||||
callback(err, null);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = GoogleToken;
|
||||
Reference in New Issue
Block a user