googleapis
Advanced tools
Comparing version 0.8.0 to 1.0.0
@@ -10,19 +10,16 @@ # Contributing | ||
~~~~ sh | ||
``` sh | ||
$ npm install -d | ||
~~~~ | ||
``` | ||
Tests use mocha. To run all tests you can use | ||
Tests are run using mocha. To run all tests just run: | ||
~~~~ sh | ||
``` sh | ||
$ npm test | ||
~~~~ | ||
``` | ||
which looks for tests in the `./tests` directory. | ||
which looks for tests in the `test/` directory. | ||
Your code should honor the | ||
[Google JavaScript Style Guide][js-guide]. | ||
You can use | ||
[Closure Linter][c-linter] | ||
to detect style issues. | ||
Your code should honor the [Google JavaScript Style Guide][js-guide]. | ||
You can use [Closure Linter][c-linter] to detect style issues. | ||
@@ -33,2 +30,21 @@ Submit a pull request. The repo owner will review your request. If it is | ||
## Generating APIs and Documentation | ||
If you're a developer interested in contributing to this library, the following | ||
section will be useful for you. Each of the files in `apis/` is generated from | ||
the discovery docs available online. You can generate these files by running | ||
the following command: | ||
``` sh | ||
npm run generate-apis | ||
``` | ||
You can generate the documentation for the APIs by running: | ||
``` sh | ||
npm run generate-docs | ||
``` | ||
Documentation will be generated in `docs/`. | ||
## Contributor License Agreements | ||
@@ -35,0 +51,0 @@ |
@@ -16,2 +16,5 @@ /** | ||
*/ | ||
'use strict'; | ||
var DefaultTransporter = require('../transporters.js'); | ||
@@ -18,0 +21,0 @@ |
@@ -17,2 +17,4 @@ /** | ||
'use strict'; | ||
var Auth2Client = require('./oauth2client.js'); | ||
@@ -22,4 +24,4 @@ var util = require('util'); | ||
/** | ||
* Google Compute Engine metadata server token endpoint. | ||
* @private | ||
* Google Compute Engine metadata server token endpoint. | ||
*/ | ||
@@ -30,3 +32,2 @@ Compute.GOOGLE_OAUTH2_TOKEN_URL_ = | ||
/** | ||
* @constructor | ||
* Google Compute Engine service account credentials. | ||
@@ -36,3 +37,3 @@ * | ||
* See: https://developers.google.com/compute/docs/authentication | ||
* | ||
* @constructor@constructor | ||
*/ | ||
@@ -64,6 +65,6 @@ function Compute() { | ||
/** | ||
* @private | ||
* Refreshes the access token. | ||
* @param {object=} ignored_ | ||
* @param {function=} opt_callback Optional callback. | ||
* @private | ||
*/ | ||
@@ -70,0 +71,0 @@ Compute.prototype.refreshToken_ = function(ignored_, opt_callback) { |
@@ -17,2 +17,4 @@ /** | ||
'use strict'; | ||
var Auth2Client = require('./oauth2client.js'); | ||
@@ -23,3 +25,2 @@ var util = require('util'); | ||
/** | ||
* @constructor | ||
* JWT service account credentials. | ||
@@ -34,3 +35,3 @@ * | ||
* @param {string=} subject impersonated account's email address. | ||
* | ||
* @constructor | ||
*/ | ||
@@ -80,6 +81,6 @@ function JWT(email, keyFile, key, scopes, subject) { | ||
/** | ||
* @private | ||
* Refreshes the access token. | ||
* @param {object=} ignored_ | ||
* @param {function=} opt_callback Optional callback. | ||
* @private | ||
*/ | ||
@@ -86,0 +87,0 @@ JWT.prototype.refreshToken_ = function(ignored_, opt_callback) { |
@@ -17,6 +17,7 @@ /** | ||
'use strict'; | ||
var USER_ATTR = 'sub'; | ||
/** | ||
* @constructor | ||
* Create a simple class to extract user ID from an ID Token | ||
@@ -26,2 +27,3 @@ * | ||
* @param {string} pay Payload of the jwt | ||
* @constructor | ||
*/ | ||
@@ -28,0 +30,0 @@ function LoginTicket(env, pay) { |
@@ -17,9 +17,13 @@ /** | ||
'use strict'; | ||
var querystring = require('querystring'); | ||
var AuthClient = require('./authclient.js'); | ||
var util = require('util'); | ||
var Cache = require('./../cache.js'); | ||
var PemVerifier = require('./../pemverifier.js'); | ||
var LoginTicket = require('./loginticket.js'); | ||
var certificateCache = null; | ||
var certificateExpiry = null; | ||
function OAuth2Client(clientId, clientSecret, redirectUri, opt_opts) { | ||
@@ -44,3 +48,2 @@ OAuth2Client.super_.call(this); | ||
* @private | ||
* | ||
*/ | ||
@@ -54,3 +57,2 @@ OAuth2Client.GOOGLE_OAUTH2_AUTH_BASE_URL_ = | ||
* @private | ||
* The .. | ||
*/ | ||
@@ -103,8 +105,12 @@ OAuth2Client.GOOGLE_OAUTH2_TOKEN_URL_ = | ||
OAuth2Client.prototype.generateAuthUrl = function(opt_opts) { | ||
var opts = opt_opts || {}; | ||
opts.response_type = opts.response_type || 'code'; | ||
opts.client_id = this.clientId_; | ||
opts.redirect_uri = this.redirectUri_; | ||
opts.client_id = opts.client_id || this.clientId_; | ||
opts.redirect_uri = opts.redirect_uri || this.redirectUri_; | ||
// Allow scopes to be passed either as array or a string | ||
if (opts.scope instanceof Array) { | ||
opts.scope = opts.scope.join(' '); | ||
} | ||
var rootUrl = this.opts.authBaseUrl || | ||
@@ -122,3 +128,2 @@ OAuth2Client.GOOGLE_OAUTH2_AUTH_BASE_URL_; | ||
OAuth2Client.prototype.getToken = function(code, opt_callback) { | ||
var uri = this.opts.tokenUrl || OAuth2Client.GOOGLE_OAUTH2_TOKEN_URL_; | ||
@@ -142,10 +147,8 @@ var values = { | ||
/** | ||
* @private | ||
* Refreshes the access token. | ||
* @param {string} refresh_token Existing refresh token. | ||
* @param {function=} opt_callback Optional callback. | ||
* @private | ||
*/ | ||
OAuth2Client.prototype.refreshToken_ = | ||
function(refresh_token, opt_callback) { | ||
OAuth2Client.prototype.refreshToken_ = function(refresh_token, opt_callback) { | ||
var uri = this.opts.tokenUrl || OAuth2Client.GOOGLE_OAUTH2_TOKEN_URL_; | ||
@@ -172,22 +175,21 @@ var values = { | ||
*/ | ||
OAuth2Client.prototype.refreshAccessToken = | ||
function(callback) { | ||
var that = this; | ||
OAuth2Client.prototype.refreshAccessToken = function(callback) { | ||
var that = this; | ||
if (! this.credentials.refresh_token) { | ||
throw new Error('No refresh token is set'); | ||
if (! this.credentials.refresh_token) { | ||
throw new Error('No refresh token is set'); | ||
} | ||
this.refreshToken_(this.credentials.refresh_token, function(err, result) { | ||
if (err) { | ||
callback(err, null); | ||
} else { | ||
var tokens = result; | ||
tokens.refresh_token = that.credentials.refresh_token; | ||
that.credentials = tokens; | ||
callback(null, that.credentials); | ||
} | ||
}); | ||
}; | ||
this.refreshToken_(this.credentials.refresh_token, function(err, result) { | ||
if (err) { | ||
callback(err, null); | ||
} else { | ||
var tokens = result; | ||
tokens.refresh_token = that.credentials.refresh_token; | ||
that.credentials = tokens; | ||
callback(null, that.credentials); | ||
} | ||
}); | ||
}; | ||
/** | ||
@@ -214,6 +216,6 @@ * Revokes the access given to token. | ||
* @param {boolean=} opt_dontForceRefresh If set, don't ask for a new token | ||
* with refresh_token. | ||
* with refresh_token. | ||
* @return {Request} Request object | ||
*/ | ||
OAuth2Client.prototype.request = | ||
function(opts, opt_callback, opt_dontForceRefresh) { | ||
OAuth2Client.prototype.request = function(opts, opt_callback, opt_dontForceRefresh) { | ||
@@ -229,8 +231,7 @@ var that = this; | ||
opts.headers = opts.headers || {}; | ||
opts.headers['Authorization'] = | ||
credentials.token_type + ' ' + credentials.access_token; | ||
opts.headers['Authorization'] = credentials.token_type + ' ' + credentials.access_token; | ||
this.transporter.request(opts, function(err, body, res) { | ||
return this.transporter.request(opts, function(err, body, res) { | ||
// TODO: Check if it's not userRateLimitExceeded | ||
var hasAuthError = res && (res.statusCode == 401 || res.statusCode == 403); | ||
var hasAuthError = res && (res.statusCode === 401 || res.statusCode === 403); | ||
// if there is an auth error, refresh the token | ||
@@ -240,3 +241,3 @@ // and make the request again | ||
// refresh access token and re-request | ||
that.refreshToken_(credentials.refresh_token, function(err, result) { | ||
that.refreshAccessToken(function(err, result) { | ||
if (err || (result && !result.access_token)) { | ||
@@ -257,3 +258,2 @@ opt_callback && opt_callback(err, result, res); | ||
/** | ||
@@ -265,4 +265,3 @@ * Verify id token is token by checking the certs and audience | ||
*/ | ||
OAuth2Client.prototype.verifyIdToken = | ||
function(idToken, audience, callback) { | ||
OAuth2Client.prototype.verifyIdToken = function(idToken, audience, callback) { | ||
if (!idToken || !callback) { | ||
@@ -293,14 +292,9 @@ throw new Error('The verifyIdToken method requires both ' + | ||
OAuth2Client.prototype.getFederatedSignonCerts = function(callback) { | ||
var api = { | ||
name: 'certs', | ||
version: 'v1' | ||
}; | ||
var cache = new Cache(); | ||
var data = cache.load(api); | ||
if (data) { | ||
callback(null, data); | ||
var nowTime = (new Date()).getTime(); | ||
if (certificateExpiry && (nowTime < certificateExpiry.getTime())) { | ||
callback(null, certificateCache); | ||
return; | ||
} | ||
this.transporter.request({ | ||
var req = this.transporter.request({ | ||
method: 'GET', | ||
@@ -320,13 +314,11 @@ uri: OAuth2Client.GOOGLE_OAUTH2_FEDERATED_SIGNON_CERTS_URL_, | ||
var regexResult = pattern.exec(cacheControl); | ||
if (regexResult.length == 2) { | ||
// Cache results with max-age | ||
cacheAge = regexResult[1] * 1000; | ||
if (regexResult.length === 2) { | ||
// Cache results with max-age (in seconds) | ||
cacheAge = regexResult[1] * 1000; // milliseconds | ||
} | ||
} | ||
// Re-Using the cache, but requires an API value | ||
var cacheOpts = cacheAge === -1 ? null : {expiresIn: cacheAge}; | ||
cache = new Cache(cacheOpts); | ||
cache.write(api, body); | ||
var now = new Date(); | ||
certificateExpiry = cacheAge === -1 ? null : new Date(now.getTime() + cacheAge); | ||
certificateCache = body; | ||
callback(null, body); | ||
@@ -333,0 +325,0 @@ }); |
@@ -17,244 +17,58 @@ /** | ||
var async = require('async'), | ||
Cache = require('./cache.js'), | ||
Client = require('./client.js'), | ||
DefaultTransporter = require('./transporters.js'), | ||
qs = require('querystring'), | ||
requests = require('./requests.js'), | ||
fs = require('fs'); | ||
'use strict'; | ||
/** | ||
* @constructor | ||
* GoogleApisClient constructor. | ||
* @param {OAuth2Client} authClient OAuth2Client for authentication | ||
* A module for interacting with Google APIs | ||
* @module google | ||
*/ | ||
function GoogleApisClient(authClient) { | ||
this.authClient = authClient; | ||
} | ||
/** | ||
* Add a new individual client to the instance. | ||
* @param {String} name | ||
* @param {Client} client | ||
* Load the apis from apis index file | ||
* This file holds all version information | ||
* @private | ||
*/ | ||
GoogleApisClient.prototype.add = function(name, client) { | ||
this[name] = client; | ||
}; | ||
var apis = require('../apis'); | ||
/** | ||
* Creates a new batch request. | ||
* @return {BatchRequest} New batch request. | ||
*/ | ||
GoogleApisClient.prototype.newBatchRequest = function() { | ||
return new requests.BatchRequest() | ||
.withAuthClient(this.authClient); | ||
}; | ||
/** | ||
* GoogleApis constructor. | ||
* @param {object} options Options to be passed in | ||
* @constructor | ||
* @param {transporters.DefaultTransporter=} opt_transporter | ||
* GoogleApis constructor. | ||
*/ | ||
function GoogleApis(opt_transporter) { | ||
this.opts = {}; | ||
this.toBeDiscovered = []; | ||
this.transporter = opt_transporter || new DefaultTransporter(); | ||
this.authClient = null; | ||
function GoogleApis(options) { | ||
this.options(options); | ||
this.addAPIs(apis); | ||
this.auth = { | ||
Compute: require('./auth/computeclient.js'), | ||
JWT: require('./auth/jwtclient.js'), | ||
OAuth2: require('./auth/oauth2client.js') | ||
}; | ||
this.GoogleApis = GoogleApis; | ||
} | ||
/** | ||
* @const | ||
* @private | ||
* Base path for discovery API. | ||
* @type {string} | ||
* Set options | ||
* @param {Object} opts Options to set | ||
*/ | ||
GoogleApis.BASE_DISCOVERY_URL_ = | ||
'https://www.googleapis.com/discovery/v1/apis/'; | ||
GoogleApis.prototype.options = function(opts) { | ||
this._options = opts || {}; | ||
}; | ||
/** | ||
* @const | ||
* Add APIs endpoints to googleapis object | ||
* E.g. googleapis.drive and googleapis.datastore | ||
* | ||
* @param {Array} apis Apis to be added | ||
* @private | ||
* Discovery type. | ||
* @type {string} | ||
*/ | ||
// TODO(burcud): Switch to REST. | ||
GoogleApis.DISCOVERY_TYPE_ = 'rest'; | ||
/** | ||
* @const | ||
* @private | ||
* Additional discovery parameters. | ||
* @type {object} | ||
*/ | ||
GoogleApis.DISCOVERY_PARAMS_ = null; | ||
/** | ||
* Discover the API with the given name, version and opt options. | ||
* @param {String} name The name of the API. | ||
* @param {String} version The version of the API. | ||
* @param {Object} opt_opts Additional options. | ||
* @return {GoogleApis} Returns itself. | ||
*/ | ||
GoogleApis.prototype.discover = function(name, version, opt_opts) { | ||
var alreadyDiscovered = this.toBeDiscovered.some(function(discovery) { | ||
return (discovery.name === name); | ||
}); | ||
if (!alreadyDiscovered) { | ||
this.toBeDiscovered.push({ | ||
name: name, version: version, opts: opt_opts }); | ||
GoogleApis.prototype.addAPIs = function(apis) { | ||
for (var apiName in apis) { | ||
this[apiName] = apis[apiName].bind(this); | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Executes requests to discover APIs. | ||
* @param {Function=} opt_callback | ||
*/ | ||
GoogleApis.prototype.execute = function(opt_callback) { | ||
var that = this, | ||
operations = [], | ||
client = new GoogleApisClient(this.authClient); | ||
var google = new GoogleApis(); | ||
this.toBeDiscovered.forEach(function(obj) { | ||
operations.push(function(callback) { | ||
that.load.call(that, obj, callback); | ||
}); | ||
}); | ||
async.parallel(operations, function(err, results) { | ||
if (err) { | ||
opt_callback && opt_callback(err, null); | ||
} else { | ||
results = results || []; | ||
results.forEach(function(result) { | ||
// extend client object with indivual clients. | ||
client.add(result.getName(), result); | ||
}); | ||
opt_callback && opt_callback(null, client); | ||
} | ||
}); | ||
}; | ||
/** | ||
* Generates a client through discovery API. | ||
* @param {String} api An object to represent the api name, version and opts. | ||
* @param {Function=} opt_callback Optional callback function. | ||
*/ | ||
GoogleApis.prototype.load = function(api, opt_callback) { | ||
var that = this; | ||
var cache = new Cache(this.opts.cache); | ||
if (api.opts && api.opts.localDiscoveryFilePath) { | ||
that.loadFromFile(api.opts.localDiscoveryFilePath, opt_callback); | ||
return; | ||
} | ||
var generateClient = function(err, data) { | ||
var client = null; | ||
if (!err && data) { | ||
cache.write(api, data); | ||
client = new Client(data, that.authClient); | ||
} | ||
opt_callback && opt_callback(err, client); | ||
}; | ||
var data = cache.load(api); | ||
if (data) { | ||
generateClient(null, data); | ||
} else { | ||
that.transporter.request({ | ||
uri: that.generateDiscoveryUrl(api), json: true | ||
}, generateClient); | ||
} | ||
}; | ||
/** | ||
* Generates a client from a local discovery file. | ||
* @param {String} filename Path of the local discovery file. | ||
* @param {Function=} opt_callback Optional callback function. | ||
*/ | ||
GoogleApis.prototype.loadFromFile = function(filename, opt_callback) { | ||
var that = this; | ||
fs.readFile(filename, function(err, data) { | ||
var client = null; | ||
if (!err && data) { | ||
client = new Client(JSON.parse(data), that.authClient); | ||
} | ||
opt_callback && opt_callback(err, client); | ||
}); | ||
}; | ||
/** | ||
* Generates the discovery url. | ||
* @param {String} api An object to represent the api name, version and opts. | ||
* @return {string} discoveryUrl. | ||
*/ | ||
GoogleApis.prototype.generateDiscoveryUrl = function(api) { | ||
api.opts = api.opts || {}; | ||
var baseDiscoveryUrl = api.opts.baseDiscoveryUrl || | ||
GoogleApis.BASE_DISCOVERY_URL_; | ||
var discoveryParams = api.opts.discoveryParams || | ||
GoogleApis.DISCOVERY_PARAMS_; | ||
var discoveryUrl = baseDiscoveryUrl; | ||
discoveryUrl += encodeURIComponent(api.name) + | ||
'/' + encodeURIComponent(api.version) + | ||
'/' + GoogleApis.DISCOVERY_TYPE_; | ||
if (discoveryParams) { | ||
discoveryUrl += '?' + qs.stringify(discoveryParams); | ||
} | ||
return discoveryUrl; | ||
}; | ||
/** | ||
* Adds options. | ||
* | ||
* @param {object} opts Options. | ||
* @return {GoogleApis} Returns itself. | ||
*/ | ||
GoogleApis.prototype.withOpts = function(opts) { | ||
this.opts = opts; | ||
return this; | ||
}; | ||
/** | ||
* Adds global auth client. | ||
* | ||
* @param {auth.AuthClient} client An auth client instance. | ||
* @return {GoogleApis} Returns itself. | ||
*/ | ||
GoogleApis.prototype.withAuthClient = function(client) { | ||
this.authClient = client; | ||
return this; | ||
}; | ||
var googleapis = new GoogleApis(); | ||
/** | ||
* Shortcut to GoogleApis. | ||
*/ | ||
googleapis.GoogleApis = GoogleApis; | ||
/** | ||
* Shortcut to OAuth2Client. | ||
*/ | ||
googleapis.OAuth2Client = require('./auth/oauth2client.js'); | ||
/** | ||
* Shortcut to Auth. | ||
*/ | ||
googleapis.auth = { | ||
Compute: require('./auth/computeclient.js'), | ||
JWT: require('./auth/jwtclient.js'), | ||
OAuth2: googleapis.OAuth2Client | ||
}; | ||
/** | ||
* Exports googleapis. | ||
*/ | ||
module.exports = googleapis; | ||
module.exports = google; |
@@ -17,2 +17,4 @@ /** | ||
'use strict'; | ||
var crypto = require('crypto'); | ||
@@ -19,0 +21,0 @@ |
@@ -17,2 +17,4 @@ /** | ||
'use strict'; | ||
var request = require('request'), | ||
@@ -50,13 +52,14 @@ pkg = require('../package.json'); | ||
* @param {Function=} opt_callback Optional callback. | ||
* @return {Request} Request object | ||
*/ | ||
DefaultTransporter.prototype.request = function(opts, opt_callback) { | ||
opts = this.configure(opts); | ||
request(opts, this.wrapCallback_(opt_callback)); | ||
return request(opts, this.wrapCallback_(opt_callback)); | ||
}; | ||
/** | ||
* @private | ||
* Wraps the response callback. | ||
* @param {Function=} opt_callback Optional callback. | ||
* @return {Function} Wrapped callback function. | ||
* @private | ||
*/ | ||
@@ -63,0 +66,0 @@ DefaultTransporter.prototype.wrapCallback_ = function(opt_callback) { |
@@ -17,15 +17,25 @@ /** | ||
'use strict'; | ||
/** | ||
* Export extend | ||
* @type {Object} | ||
*/ | ||
module.exports = { | ||
/** | ||
* Copy key/values from source object `b` into destination object `a`. | ||
* Copy key/values to obj from all other objects passed in | ||
* | ||
* @param {object} a the destination object. | ||
* @param {object} b the source object. | ||
* | ||
* @return {object} the destination object. | ||
*/ | ||
extend: function(a, b) { | ||
Object.keys(b).forEach(function(k) {a[k] = b[k];}); | ||
return a; | ||
extend: function(obj) { | ||
var source, prop; | ||
for (var i = 1, length = arguments.length; i < length; i++) { | ||
source = arguments[i]; | ||
for (prop in source) { | ||
obj[prop] = source[prop]; | ||
} | ||
} | ||
return obj; | ||
} | ||
}; |
{ | ||
"name": "googleapis", | ||
"version": "0.8.0", | ||
"version": "1.0.0", | ||
"author": "Google Inc.", | ||
@@ -10,3 +10,8 @@ "description": "Google APIs Client Library for Node.js", | ||
"email": "jbd@google.com" | ||
}, { | ||
}, | ||
{ | ||
"name": "Ryan Seys", | ||
"email": "ryanseys@google.com" | ||
}, | ||
{ | ||
"name": "Monsur Hossain", | ||
@@ -28,15 +33,24 @@ "email": "monsur@google.com" | ||
], | ||
"dependencies" : { | ||
"request": "~2.34.0", | ||
"async": "~0.2.10", | ||
"gapitoken": "~0.1.2" | ||
"dependencies": { | ||
"async": "0.2.10", | ||
"gapitoken": "0.1.2", | ||
"multipart-stream": "1.0.0", | ||
"request": "2.37.0" | ||
}, | ||
"devDependencies" : { | ||
"devDependencies": { | ||
"js-beautify": "1.5.1", | ||
"jsdoc": "3.3.0-alpha9", | ||
"mkdirp": "0.5.0", | ||
"mocha": "1.8.1", | ||
"nock": "0.42.1", | ||
"rimraf": "2.2.8", | ||
"swig": "1.3.2", | ||
"url": "0.7.9" | ||
}, | ||
"scripts": { | ||
"test": "mocha --reporter spec --timeout 4000" | ||
"test": "mocha --reporter spec --timeout 4000", | ||
"generate-apis": "node scripts/generate", | ||
"generate-docs": "jsdoc -c jsdoc-conf.json ./README.md" | ||
}, | ||
"license": "Apache 2" | ||
} |
409
README.md
@@ -1,101 +0,84 @@ | ||
# google-api-nodejs-client [alpha] | ||
# Google APIs NodeJS Client [![Build Status][travisimg]][travis] | ||
[![Build Status](https://travis-ci.org/google/google-api-nodejs-client.png)](https://travis-ci.org/google/google-api-nodejs-client) | ||
Google's officially supported [node.js][node] client library for using | ||
Google APIs. It also supports authorization and authentication with OAuth 2.0. | ||
`google-api-nodejs-client` is Google's officially supported | ||
[node.js](http://nodejs.org/) client | ||
library for accessing Google APIs, it also supports authorization and | ||
authentication with OAuth 2.0. | ||
### Migrating to version `1.0.0` of this library | ||
If you've used this library before `1.0.0`, see our [Migration Guide][migrating] | ||
to learn about migrating your code from `0.x.x` to `1.0.0`. It's pretty easy :) | ||
### Questions/problems? | ||
* Ask your development related questions on [![Ask a question on Stackoverflow](https://googledrive.com/host/0ByfSjdPVs9MZbkhjeUhMYzRTeEE/stackoveflow-tag.png)](http://stackoverflow.com/questions/tagged/google-api-nodejs-client) | ||
* If you found a bug, please [file a bug](https://github.com/google/google-api-nodejs-client/issues). | ||
* Ask your development related questions on [![Ask a question on Stackoverflow][overflowimg]][stackoverflow] | ||
* If you've found an bug/issue, please [file it on GitHub][bugs]. | ||
**Note**: This library is currently in *alpha* status, meaning that we can make | ||
changes in the future that *may not be compatible* with the previous versions. | ||
## Installation | ||
The library is distributed on `npm`. In order to add it as a dependency, | ||
This library is distributed on `npm`. In order to add it as a dependency, | ||
run the following command: | ||
~~~~ sh | ||
``` sh | ||
$ npm install googleapis | ||
~~~~ | ||
``` | ||
## Guide | ||
## Usage | ||
### Discover APIs | ||
Example: Creates a URL Shortener client and retrieves the long url of the | ||
given short url: | ||
Dynamically load Google APIs and start making requests: | ||
``` js | ||
var google = require('googleapis'); | ||
var urlshortener = google.urlshortener('v1'); | ||
~~~~ js | ||
var googleapis = require('googleapis'); | ||
var params = { shortUrl: 'http://goo.gl/xKbRu3' }; | ||
googleapis | ||
.discover('urlshortener', 'v1') | ||
.discover('plus', 'v1') | ||
.execute(function(err, client) { | ||
if (err) { | ||
console.log('Problem during the client discovery.', err); | ||
return; | ||
} | ||
var params = { shortUrl: 'http://goo.gl/DdUKX' }; | ||
var getUrlReq = client.urlshortener.url.get(params); | ||
// get the long url of a shortened url | ||
urlshortener.url.get(params, function (err, response) { | ||
console.log('Long url is', response.longUrl); | ||
}); | ||
``` | ||
getUrlReq.execute(function (err, response) { | ||
console.log('Long url is', response.longUrl); | ||
}); | ||
### Create a service client | ||
var getUserReq = client.plus.people.get({ userId: '+burcudogan' }); | ||
To interact with the various Google APIs you need to create a service client | ||
for that particular API. These are immutable objects you use to make API calls. | ||
getUserReq.execute(function(err, user) { | ||
console.log('User id is: ' + user.id); | ||
}); | ||
}); | ||
~~~~ | ||
Example: Creating a `urlshortener` client with version `v1` of the API. | ||
Supported APIs are listed on | ||
[Google APIs Explorer](https://developers.google.com/apis-explorer). | ||
``` js | ||
var google = require('googleapis'); | ||
var urlshortener = google.urlshortener('v1'); | ||
``` | ||
#### Discovery Document Caching | ||
Supported APIs are listed on the [Google APIs Explorer][apiexplorer]. | ||
Discovery documents are being cached for 5 minutes locally. | ||
You can configure the directory used to store cached discovery | ||
files by using the `cache.path` option. | ||
### Authorizing and Authenticating | ||
~~~~ js | ||
googleapis | ||
.discover('plus', 'v3') | ||
.withOpts({ cache: { path: '<path>' })) | ||
.execute(); | ||
~~~~ | ||
This client comes with an [OAuth2][oauth] client that allows you to retrieve an | ||
access token and refreshes the token and retry the request seamlessly if token | ||
is expired. The basics of Google's OAuth2 implementation is explained on | ||
[Google Authorization and Authentication documentation][authdocs]. | ||
### Authorization and Authentication | ||
In the following examples, you may need a `CLIENT_ID`, `CLIENT_SECRET` and | ||
`REDIRECT_URL`. You can find these pieces of information by going to the | ||
[Developer Console][devconsole], clicking your project --> APIs & auth --> credentials. | ||
This client comes with an OAuth2 client that allows you to retrieve an access token and | ||
refreshes the token and re-try the request seamlessly if token is expired. The | ||
basics of Google's OAuth 2.0 implementation is explained on | ||
[Google Authorization and Authentication | ||
documentation](https://developers.google.com/accounts/docs/OAuth2Login). | ||
For more information about OAuth2 and how it works, [see here][oauth]. | ||
A complete sample application that authorizes and authenticates with OAuth2.0 | ||
client is available at `examples/oauth2.js`. | ||
A complete sample application that authorizes and authenticates with the OAuth2 | ||
client is available at [`examples/oauth2.js`][oauthexample]. | ||
#### Consent Page Url | ||
#### Generating an authentication URL | ||
In order to ask for permissions from a user to retrieve an access token, you | ||
should redirect them to a consent page. In order to create a consent page | ||
URL: | ||
To ask for permissions from a user to retrieve an access token, you | ||
redirect them to a consent page. To create a consent page URL: | ||
~~~~ js | ||
var googleapis = require('googleapis'), | ||
OAuth2 = googleapis.auth.OAuth2; | ||
``` js | ||
var google = require('googleapis'); | ||
var OAuth2 = google.auth.OAuth2; | ||
var oauth2Client = | ||
new OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL); | ||
var oauth2Client = new OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL); | ||
// generates a url that allows offline access and asks permissions | ||
// for Google+ scope. | ||
// generate a url that asks permissions for Google+ and Google Calendar scopes | ||
var scopes = [ | ||
@@ -107,140 +90,240 @@ 'https://www.googleapis.com/auth/plus.me', | ||
var url = oauth2Client.generateAuthUrl({ | ||
access_type: 'offline', | ||
scope: scopes.join(" ") // space delimited string of scopes | ||
access_type: 'offline', // 'online' (default) or 'offline' (gets refresh_token) | ||
scope: scopes // If you only need one scope you can pass it as string | ||
}); | ||
~~~~ | ||
``` | ||
#### Retrieving Tokens | ||
#### Retrieve authorization code | ||
Once a user has given permissions on the consent page, Google will redirect | ||
the page to the redirect url you have provided with a code query parameter. | ||
the page to the redirect URL you have provided with a code query parameter. | ||
GET /oauthcallback?code={authorizationCode} | ||
#### Retrieve access token | ||
With the code returned, you can ask for an access token as shown below: | ||
~~~~ js | ||
``` js | ||
oauth2Client.getToken(code, function(err, tokens) { | ||
// contains an access_token and optionally a refresh_token. | ||
// save them permanently. | ||
// Now tokens contains an access_token and an optional refresh_token. Save them. | ||
if(!err) { | ||
oauth2Client.setCredentials(tokens); | ||
} | ||
}); | ||
~~~~ | ||
``` | ||
### API Client | ||
#### Settings global or service-level auth | ||
Client libraries are generated during runtime by metadata provided by Google | ||
APIs Discovery Service. Metadata provided by Discovery Service is cached, | ||
and won't be requested each time you load a client. Below, there is an | ||
example of loading a client for | ||
[URL Shortener API](https://developers.google.com/url-shortener/). | ||
You can set the `auth` as a global or service-level option so you don't need to | ||
specify it every request. | ||
~~~~ js | ||
googleapis | ||
.discover('urlshortener', 'v1') | ||
.execute(function(err, client) { | ||
// handle discovery errors | ||
// make requests | ||
}); | ||
~~~~ | ||
Example: Setting a global `auth` option. | ||
### Requests | ||
``` js | ||
var google = require('googleapis'); | ||
var OAuth2 = google.auth.OAuth2; | ||
var oauth2Client = new OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL); | ||
google.options({ auth: oauth2Client }); // set auth as a global default | ||
``` | ||
The following sample loads a client for URL Shortener and retrieves the long url | ||
of the given short url: | ||
Example: Setting a service-level `auth` option. | ||
~~~~ js | ||
googleapis | ||
.discover('urlshortener', 'v1') | ||
.execute(function(err, client) { | ||
// handle discovery errors | ||
client.urlshortener.url.get({ shortUrl: 'http://goo.gl/DdUKX' }) | ||
.execute(function(err, result) { | ||
// result.longUrl contains the long url. | ||
}); | ||
}); | ||
~~~~ | ||
``` js | ||
var google = require('googleapis'); | ||
var OAuth2 = google.auth.OAuth2; | ||
var oauth2Client = new OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL); | ||
Alternatively, you may need to send an API key with the | ||
request you are going to make. The following creates and executes a request from the Google+ API service to retrieve a person profile given a userId: | ||
var drive = google.drive({ version: 'v2', auth: oauth2Client }); | ||
``` | ||
~~~~ js | ||
googleapis | ||
.discover('plus', 'v1') | ||
.execute(function(err, client) { | ||
// handle discovery errors | ||
var getUserAuthdReq = client.plus.people.get({ userId: '+burcudogan' }) | ||
.withApiKey(API_KEY); | ||
See the [Options section][options] for more information. | ||
getUserAuthdReq.execute(function(err, user) { | ||
console.log("Result: " + (err ? err.message : user.displayName)); | ||
}); | ||
}); | ||
~~~~ | ||
To learn more about API keys, please see the [documentation](https://developers.google.com/console/help/#UsingKeys). | ||
#### Making Authenticated Requests | ||
And you can start using oauth2Client to authorize and authenticate your | ||
You can start using OAuth2 to authorize and authenticate your | ||
requests to Google APIs with the retrieved tokens. If you provide a | ||
refresh_token, the access_token is automatically refreshed and the request is replayed in | ||
case the access_token has expired. | ||
`refresh_token`, the `access_token` is automatically refreshed and the | ||
request is replayed in case the `access_token` has expired. | ||
Following sample retrieves Google+ profile of the authenticated user. | ||
~~~~ js | ||
var oauth2Client = | ||
new OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL); | ||
``` js | ||
var google = require('googleapis'); | ||
var plus = google.plus('v1'); | ||
var oauth2Client = new OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL); | ||
// Retrieve tokens via token exchange explaind above. | ||
// Or you can set them. | ||
oauth2Client.credentials = { | ||
// Retrieve tokens via token exchange explained above or set them: | ||
oauth2Client.setCredentials({ | ||
access_token: 'ACCESS TOKEN HERE', | ||
refresh_token: 'REFRESH TOKEN HERE' | ||
}; | ||
}); | ||
client | ||
.plus.people.get({ userId: 'me' }) | ||
.withAuthClient(oauth2Client) | ||
.execute(callback); | ||
~~~~ | ||
plus.people.get({ userId: 'me', auth: oauth2Client }, function(err, response) { | ||
// handle err and response | ||
}); | ||
``` | ||
### Batch requests (experimental) | ||
#### Using API keys | ||
You can combine multiple requests in a single one by using batch requests. | ||
You may need to send an API key with the request you are going to make. | ||
The following uses an API key to make a request to the Google+ API service to | ||
retrieve a person's profile given a userId: | ||
~~~~ js | ||
var getUserReq = | ||
client.plus.people.get({ userId: '+BurcuDogan' }); | ||
``` js | ||
var google = require('googleapis'); | ||
var plus = google.plus('v1'); | ||
var insertUrlReq = | ||
client.urlshortener.url.insert({ longUrl: 'http://google.com' }); | ||
var API_KEY = 'ABC123'; // specify your API key here | ||
client | ||
.newBatchRequest() | ||
.add(getUserReq) | ||
.add(insertUrlReq) | ||
.execute(function(err, results) { | ||
// handle results | ||
plus.people.get({ auth: API_KEY, userId: '+google' }, function(err, user) { | ||
console.log('Result: ' + (err ? err.message : user.displayName)); | ||
}); | ||
~~~~ | ||
``` | ||
Alternatively, you can specify the `key` parameter and it will get used: | ||
``` js | ||
plus.people.get({ key: API_KEY, userId: '+google' }, function(err, user) { | ||
console.log('Result: ' + (err ? err.message : user.displayName)); | ||
}); | ||
``` | ||
To learn more about API keys, please see the [documentation][usingkeys]. | ||
### Media Uploads | ||
Client supports basic and multipart media uploads. For creation and modification requests | ||
with media attachments, take a look at the `examples/mediaupload.js` sample. | ||
This client supports multipart media uploads. The resource parameters are | ||
specified in the `resource` parameter object, and the media body itself is | ||
specified in the `media` parameter. | ||
~~~~ js | ||
client | ||
.drive.files.insert({ title: 'Test', mimeType: 'text/plain' }) | ||
.withMedia('text/plain', 'Hello World') | ||
.execute(); | ||
~~~~ | ||
Example: Upload a plain text file to Google Drive with the title "Test" and | ||
contents "Hello World". | ||
``` js | ||
var drive = google.drive({ version: 'v2', auth: oauth2Client }); | ||
drive.files.insert({ | ||
resource: { | ||
title: 'Test', | ||
mimeType: 'text/plain' | ||
}, | ||
media: 'Hello World' | ||
}, callback); | ||
``` | ||
You can also upload media by specifying `media` as a [Readable stream][stream]. | ||
This can allow you to upload very large files that cannot fit into memory. | ||
Note: Your readable stream may be [unstable][stability]. Use at your own risk. | ||
Example: Upload an image to Google Drive from a readable stream. | ||
``` js | ||
var fs = require('fs'); | ||
var drive = google.drive({ version: 'v2', auth: oauth2Client }); | ||
drive.files.insert({ | ||
resource: { | ||
title: 'testimage.png', | ||
mimeType: 'image/png' | ||
}, | ||
media: fs.createReadStream('awesome.png') // read streams are awesome! | ||
}, callback); | ||
``` | ||
For more examples of creation and modification requests with media attachments, | ||
take a look at the `examples/mediaupload.js` sample. | ||
## Exposing request object | ||
Every request to the API returns a [`request`][request] object, allowing you to track | ||
the request's progress or general information about the request. | ||
``` js | ||
var req = drive.files.insert(/* ... */); | ||
console.log(req.uri.href); // print out the request's URL. | ||
``` | ||
## Options | ||
For more fine-tuned control over how your API calls are made, | ||
we provide you with the ability to specify additional options that can | ||
be applied directly to the [`mikeal/request`][request] object used in | ||
this library to make network calls to the API. | ||
You may specify additional options either in the global `google` object or on a | ||
service client basis. | ||
### Available options | ||
The options you specify are attached to the `request` object so whatever | ||
`request` supports, this library supports. | ||
A full list of supported options can be [found here][requestopts]. | ||
### Global options | ||
Example: Specifying a default proxy and `auth` to be used for each request | ||
``` js | ||
var google = require('googleapis'); | ||
google.options({ proxy: 'http://proxy.example.com', auth: auth }); | ||
// all requests made with this object will use these settings unless overridden | ||
``` | ||
### Service-client options | ||
You can also specify options when creating a service client. For example, to | ||
specify a default `auth` option (API key or OAuth2 client), simply pass it in | ||
like so: | ||
``` js | ||
var auth = 'API KEY'; // or you could use oauth2Client | ||
var urlshortener = google.urlshortener({ version: 'v1', auth: auth }); | ||
// all requests made with this object will use the specified auth | ||
``` | ||
By doing this, every API call made with this service client will use `'API KEY'` | ||
to authenticate. | ||
**Note:** Created clients are **immutable** so you must create a new one if you | ||
want to specify different options. | ||
### Request-level options | ||
You can specify an `auth` object to be used per request. Each request also | ||
inherits the options specified at the service level and global level. | ||
## License | ||
`google-api-nodejs-client` is licensed with Apache 2.0. Full license text is | ||
available on COPYING file. | ||
This library is licensed under Apache 2.0. Full license text is | ||
available in [COPYING][copying]. | ||
## Contributing | ||
See [CONTRIBUTING](https://github.com/google/google-api-nodejs-client/tree/master/CONTRIBUTING.md). | ||
See [CONTRIBUTING][contributing]. | ||
[travisimg]: https://api.travis-ci.org/google/google-api-nodejs-client.svg | ||
[bugs]: https://github.com/google/google-api-nodejs-client/issues | ||
[node]: http://nodejs.org/ | ||
[travis]: https://travis-ci.org/google/google-api-nodejs-client | ||
[stackoverflow]: http://stackoverflow.com/questions/tagged/google-api-nodejs-client | ||
[apiexplorer]: https://developers.google.com/apis-explorer | ||
[urlshort]: https://developers.google.com/url-shortener/ | ||
[usingkeys]: https://developers.google.com/console/help/#UsingKeys | ||
[contributing]: https://github.com/google/google-api-nodejs-client/tree/master/CONTRIBUTING.md | ||
[copying]: https://github.com/google/google-api-nodejs-client/tree/master/COPYING | ||
[authdocs]: https://developers.google.com/accounts/docs/OAuth2Login | ||
[request]: https://github.com/mikeal/request | ||
[requestopts]: https://github.com/mikeal/request#requestoptions-callback | ||
[stream]: http://nodejs.org/api/stream.html#stream_class_stream_readable | ||
[migrating]: https://github.com/google/google-api-nodejs-client/tree/master/MIGRATING.md | ||
[stability]: http://nodejs.org/api/stream.html#stream_stream | ||
[overflowimg]: https://googledrive.com/host/0ByfSjdPVs9MZbkhjeUhMYzRTeEE/stackoveflow-tag.png | ||
[devconsole]: https://console.developer.google.com | ||
[oauth]: https://developers.google.com/accounts/docs/OAuth2 | ||
[oauthexample]: https://github.com/google/google-api-nodejs-client/tree/master/examples/oauth2.js | ||
[options]: https://github.com/google/google-api-nodejs-client/tree/master#options |
@@ -17,92 +17,46 @@ /** | ||
var url = require('url'), | ||
assert = require('assert'), | ||
qs = require('querystring'), | ||
fs = require('fs'); | ||
'use strict'; | ||
var googleapis = require('../lib/googleapis.js'), | ||
MockTransporter = require('./mocks/transporters.js'); | ||
var assert = require('assert'); | ||
var fs = require('fs'); | ||
var googleapis = require('../lib/googleapis.js'); | ||
describe('Clients', function() { | ||
var mockTransporter = | ||
new MockTransporter(__dirname + '/data/discovery_plus.json'); | ||
it('should create request helpers according ' + | ||
'to the resource on discovery API response', function(done) { | ||
new googleapis.GoogleApis() | ||
.discover('plus', 'v1') | ||
.execute(function(err, client) { | ||
assert.equal(typeof client.plus.people.get, 'function'); | ||
assert.equal(typeof client.plus.activities.search, 'function'); | ||
assert.equal(typeof client.plus.comments.list, 'function'); | ||
done(); | ||
}); | ||
it('should create request helpers according to the resource on discovery API response', function() { | ||
var plus = googleapis.plus('v1'); | ||
assert.equal(typeof plus.people.get, 'function'); | ||
assert.equal(typeof plus.activities.search, 'function'); | ||
assert.equal(typeof plus.comments.list, 'function'); | ||
}); | ||
it('should be able to generate default discovery url', function(done) { | ||
var api = { name: 'plus', version: 'v3', opts: {} }; | ||
var discoveryUrl = | ||
new googleapis.GoogleApis().generateDiscoveryUrl(api); | ||
var parsed = url.parse(discoveryUrl); | ||
assert.equal(parsed.protocol, 'https:'); | ||
assert.equal(parsed.host, 'www.googleapis.com'); | ||
assert.equal(parsed.path, '/discovery/v1/apis/plus/v3/rest'); | ||
assert.equal(parsed.query, null); | ||
done(); | ||
it('should be able to gen methods for top-level methods', function() { | ||
assert.ok(!!googleapis.oauth2('v2').userinfo); | ||
}); | ||
it('should be able to generate default discovery url with custom ' + | ||
'base url and parameters configuration', function(done) { | ||
var api = { name: 'plus', version: 'v3', opts: { | ||
baseDiscoveryUrl: 'http://mydeployment/discovery/', | ||
discoveryParams: { a: 'hello', b: 'hi' } | ||
}}; | ||
var discoveryUrl = new googleapis.GoogleApis().generateDiscoveryUrl(api); | ||
var parsed = url.parse(discoveryUrl); | ||
assert.equal(parsed.protocol, 'http:'); | ||
assert.equal(parsed.host, 'mydeployment'); | ||
assert.equal(parsed.pathname, '/discovery/plus/v3/rest'); | ||
assert.equal(parsed.query, 'a=hello&b=hi'); | ||
done(); | ||
}); | ||
it('should be able to require all api files without error', function() { | ||
function getFiles(dir, files_) { | ||
files_ = files_ || []; | ||
if (typeof files_ === 'undefined') files_ = []; | ||
var files = fs.readdirSync(dir); | ||
for (var i in files) { | ||
if (!files.hasOwnProperty(i)) continue; | ||
var name = dir + '/' + files[i]; | ||
if (fs.statSync(name).isDirectory()) { | ||
getFiles(name, files_); | ||
} else { | ||
files_.push(name); | ||
} | ||
} | ||
return files_; | ||
} | ||
it('should be able to generate methods for top-level methods', | ||
function(done) { | ||
new googleapis.GoogleApis() | ||
.discover('oauth2', 'v2') | ||
.execute(function(err, client) { | ||
assert.ok(!!client.oauth2.tokeninfo); | ||
done(); | ||
}); | ||
}); | ||
var api_files = getFiles(__dirname + '/../apis'); | ||
it('should be able to add defaultParams on new requests', function(done) { | ||
new googleapis.GoogleApis() | ||
.discover('plus', 'v1') | ||
.execute(function(err, client) { | ||
var req = | ||
client.plus.withDefaultParams({a: 1, b: 'foo'}) | ||
.newRequest('doIt', {a: 2}, {}); | ||
assert.equal(2, req.params.a); | ||
assert.equal('foo', req.params.b); | ||
done(); | ||
}); | ||
assert.doesNotThrow(function() { | ||
for (var i in api_files) { | ||
var obj = require(api_files[i]); | ||
} | ||
}); | ||
}); | ||
it('should be able to add defaultParams on new' + | ||
'requests with no params and a body', function(done) { | ||
new googleapis.GoogleApis() | ||
.discover('plus', 'v1') | ||
.execute(function(err, client) { | ||
var req = | ||
client.plus.withDefaultParams({a: 1, b: 'foo'}) | ||
.newRequest('doIt', {has_body: true}); | ||
assert.equal(1, req.params.a); | ||
assert.equal('foo', req.params.b); | ||
assert.equal(undefined, req.params.body); | ||
assert.equal(true, req.body.has_body); | ||
done(); | ||
}); | ||
}); | ||
}); |
@@ -17,7 +17,9 @@ /** | ||
'use strict'; | ||
var assert = require('assert'); | ||
var googleapis = require('../lib/googleapis.js'); | ||
describe('Compute auth client', function() { | ||
it('should get an initial access token', function(done) { | ||
@@ -39,2 +41,3 @@ var compute = new googleapis.auth.Compute(); | ||
}); | ||
it('should refresh token when request fails', function(done) { | ||
@@ -41,0 +44,0 @@ var compute = new googleapis.auth.Compute(); |
@@ -17,7 +17,9 @@ /** | ||
'use strict'; | ||
var assert = require('assert'); | ||
var googleapis = require('../lib/googleapis.js'); | ||
describe('JWT auth client', function() { | ||
it('should get an initial access token', function(done) { | ||
@@ -24,0 +26,0 @@ var jwt = new googleapis.auth.JWT( |
@@ -17,11 +17,14 @@ /** | ||
var url = require('url'), | ||
assert = require('assert'), | ||
qs = require('querystring'), | ||
fs = require('fs'); | ||
'use strict'; | ||
var googleapis = require('../lib/googleapis.js'), | ||
MockTransporter = require('./mocks/transporters.js'), | ||
crypto = require('crypto'); | ||
var url = require('url'); | ||
var assert = require('assert'); | ||
var qs = require('querystring'); | ||
var fs = require('fs'); | ||
var googleapis = require('../lib/googleapis.js'); | ||
var crypto = require('crypto'); | ||
var nock = require('nock'); | ||
nock.disableNetConnect(); | ||
describe('OAuth2 client', function() { | ||
@@ -34,2 +37,3 @@ | ||
var SCOPE = 'scopex'; | ||
var SCOPE_ARRAY = ['scopex', 'scopey']; | ||
@@ -39,5 +43,2 @@ var PUBLIC_KEY = ''; | ||
var urlshortenerDiscoveryTransporter = | ||
new MockTransporter(__dirname + '/data/discovery_urlshortener.json'); | ||
it('should generate a valid consent page url', function(done) { | ||
@@ -64,3 +65,20 @@ var opts = { | ||
it('should set resonse_type param to code if none is given while' + | ||
it('should allow scopes to be specified as array', function(done) { | ||
var opts = { | ||
access_type: ACCESS_TYPE, | ||
scope: SCOPE_ARRAY, | ||
response_type: 'code token' | ||
}; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var generated = oauth2client.generateAuthUrl(opts); | ||
var parsed = url.parse(generated); | ||
var query = qs.parse(parsed.query); | ||
assert.equal(query.scope, SCOPE_ARRAY.join(' ')); | ||
done(); | ||
}); | ||
it('should set response_type param to code if none is given while' + | ||
'generating the consent page url', function(done) { | ||
@@ -80,29 +98,16 @@ var oauth2client = | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
new googleapis.GoogleApis(urlshortenerDiscoveryTransporter) | ||
.discover('urlshortener', 'v1') | ||
.execute(function(err, client) { | ||
assert.throws(function() { | ||
client | ||
.newRequest('dummy', {}) | ||
.withAuthClient(oauth2client) | ||
.execute(); | ||
}, Error, 'No access or refresh token is set.'); | ||
}); | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws(function() { | ||
new googleapis.GoogleApis() | ||
.urlshortener('v1').url.get({ auth: oauth2client }); | ||
}, Error, 'No access or refresh token is set.'); | ||
}); | ||
it('should not throw any exceptions if only refresh token is set', | ||
function() { | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
it('should not throw any exceptions if only refresh token is set', function() { | ||
var oauth2client = new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
oauth2client.credentials = { refresh_token: 'refresh_token' }; | ||
new googleapis.GoogleApis(urlshortenerDiscoveryTransporter) | ||
.discover('urlshortener', 'v1') | ||
.execute(function(err, client) { | ||
assert.doesNotThrow(function() { | ||
client | ||
.urlshortener.url.list() | ||
.withAuthClient(oauth2client) | ||
.execute(); | ||
}); | ||
assert.doesNotThrow(function() { | ||
var google = new googleapis.GoogleApis(); | ||
var options = { auth: oauth2client, shortUrl: '...' }; | ||
google.urlshortener('v1').url.get(options); | ||
}); | ||
@@ -112,668 +117,701 @@ }); | ||
it('should set access token type to Bearer if none is set', function(done) { | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var oauth2client = new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
oauth2client.credentials = { access_token: 'foo', refresh_token: '' }; | ||
new googleapis.GoogleApis(urlshortenerDiscoveryTransporter) | ||
.discover('urlshortener', 'v1') | ||
.execute(function(err, client) { | ||
var req = client.urlshortener.url.list().withAuthClient(oauth2client); | ||
req.execute(function(err, result) { | ||
assert.equal(oauth2client.credentials.token_type, 'Bearer'); | ||
done(); | ||
}); | ||
var scope = nock('https://www.googleapis.com').get('/urlshortener/v1/url/history').reply(200); | ||
var google = new googleapis.GoogleApis(); | ||
var urlshortener = google.urlshortener('v1'); | ||
urlshortener.url.list({ auth: oauth2client }, function(err, result) { | ||
assert.equal(oauth2client.credentials.token_type, 'Bearer'); | ||
scope.done(); | ||
done(err); | ||
}); | ||
}); | ||
it('should replay the request with a refreshed token if auth failed', | ||
function(done) { | ||
it('should replay the request with a refreshed token if auth failed', function(done) { | ||
var i = 0; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var oauth2client = new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
oauth2client.credentials = { access_token: 'foo', refresh_token: 'bar' }; | ||
new googleapis.GoogleApis(urlshortenerDiscoveryTransporter) | ||
.discover('urlshortener', 'v1') | ||
.execute(function(err, client) { | ||
var req = client.urlshortener.url.list().withAuthClient(oauth2client); | ||
oauth2client.transporter = { | ||
request: function(opts, callback) { | ||
if (i == 1) { | ||
assert.equal(opts.uri, | ||
'https://accounts.google.com/o/oauth2/token'); | ||
return done(); | ||
} | ||
i++; | ||
callback(null, null, { statusCode: 401 }); | ||
var google = new googleapis.GoogleApis(); | ||
oauth2client.transporter = { | ||
request: function(opts, callback) { | ||
if (i === 1) { | ||
assert.equal(opts.uri, 'https://accounts.google.com/o/oauth2/token'); | ||
return done(); | ||
} | ||
}; | ||
req.execute(); | ||
}); | ||
i++; | ||
callback(null, null, { statusCode: 401 }); | ||
} | ||
}; | ||
google.urlshortener('v1').url.list({ auth: oauth2client }); | ||
}); | ||
it('should verify a valid certificate against a jwt', | ||
function(done) { | ||
it('should verify a valid certificate against a jwt', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', 'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', 'utf-8'); | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
assert.equal(login.getUserId(), '123456789'); | ||
done(); | ||
}); | ||
assert.equal(login.getUserId(), '123456789'); | ||
done(); | ||
}); | ||
it('should fail due to invalid audience', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should fail due to invalid audience', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"wrongaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"wrongaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Wrong recipient/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Wrong recipient/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should fail due to invalid signature', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should fail due to invalid signature', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":1393241597,' + | ||
'"exp":1393245497' + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":1393241597,' + | ||
'"exp":1393245497' + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
//Originally: data += '.'+signature; | ||
data += signature; | ||
//Originally: data += '.'+signature; | ||
data += signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Wrong number of segments/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Wrong number of segments/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should fail due to invalid envelope', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should fail due to invalid envelope', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid"' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid"' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Can\'t parse token envelope/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Can\'t parse token envelope/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should fail due to invalid payload', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should fail due to invalid payload', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer"' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var idToken = '{' + | ||
'"iss":"testissuer"' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Can\'t parse token payload/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Can\'t parse token payload/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should fail due to invalid signature', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
it('should fail due to invalid signature', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64') + | ||
'.' + 'broken-signature'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64') + | ||
'.' + 'broken-signature'; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Invalid token signature/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Invalid token signature/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should fail due to no expiration date', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should fail due to no expiration date', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/No expiration time/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/No expiration time/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should fail due to no issue time', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should fail due to no issue time', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/No issue time/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/No issue time/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should fail due to certificate with expiration date in future', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should fail due to certificate with expiration date in future', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (2 * maxLifetimeSecs); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (2 * maxLifetimeSecs); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Expiration time too far in future/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Expiration time too far in future/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should pass due to expiration date in future with adjusted max expiry', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should pass due to expiration date in future with adjusted max expiry', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (2 * maxLifetimeSecs); | ||
var maxExpiry = (3 * maxLifetimeSecs); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var maxLifetimeSecs = 86400; | ||
var now = new Date().getTime() / 1000; | ||
var expiry = now + (2 * maxLifetimeSecs); | ||
var maxExpiry = (3 * maxLifetimeSecs); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience', 'testissuer', maxExpiry); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience', 'testissuer', maxExpiry); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should fail due to token being used to early', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should fail due to token being used to early', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var clockSkews = 300; | ||
var now = (new Date().getTime() / 1000); | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var issueTime = now + (clockSkews * 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + issueTime + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var maxLifetimeSecs = 86400; | ||
var clockSkews = 300; | ||
var now = (new Date().getTime() / 1000); | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var issueTime = now + (clockSkews * 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + issueTime + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Token used too early/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience'); | ||
}, | ||
/Token used too early/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should fail due to invalid issuer', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should fail due to invalid issuer', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var clockSkews = 300; | ||
var now = (new Date().getTime() / 1000); | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"invalidissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var maxLifetimeSecs = 86400; | ||
var clockSkews = 300; | ||
var now = (new Date().getTime() / 1000); | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"invalidissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience', 'testissuer'); | ||
}, | ||
/Invalid issuer/ | ||
); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
assert.throws( | ||
function() { | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience', 'testissuer'); | ||
}, | ||
/Invalid issuer/ | ||
); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
it('should pass due to valid issuer', function(done) { | ||
var publicKey = fs.readFileSync('./test/fixtures/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/fixtures/private.pem', | ||
'utf-8'); | ||
it('should pass due to valid issuer', | ||
function(done) { | ||
var publicKey = fs.readFileSync('./test/data/public.pem', | ||
'utf-8'); | ||
var privateKey = fs.readFileSync('./test/data/private.pem', | ||
'utf-8'); | ||
var maxLifetimeSecs = 86400; | ||
var clockSkews = 300; | ||
var now = (new Date().getTime() / 1000); | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var maxLifetimeSecs = 86400; | ||
var clockSkews = 300; | ||
var now = (new Date().getTime() / 1000); | ||
var expiry = now + (maxLifetimeSecs / 2); | ||
var idToken = '{' + | ||
'"iss":"testissuer",' + | ||
'"aud":"testaudience",' + | ||
'"azp":"testauthorisedparty",' + | ||
'"email_verified":"true",' + | ||
'"id":"123456789",' + | ||
'"sub":"123456789",' + | ||
'"email":"test@test.com",' + | ||
'"iat":' + now + ',' + | ||
'"exp":' + expiry + | ||
'}'; | ||
var envelope = '{' + | ||
'"kid":"keyid",' + | ||
'"alg":"RS256"' + | ||
'}'; | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var data = new Buffer(envelope).toString('base64') + | ||
'.' + new Buffer(idToken).toString('base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
var signer = crypto.createSign('sha256'); | ||
signer.update(data); | ||
var signature = signer.sign(privateKey, 'base64'); | ||
data += '.' + signature; | ||
data += '.' + signature; | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience', 'testissuer'); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var login = oauth2client.verifySignedJwtWithCerts(data, | ||
{keyid: publicKey}, 'testaudience', 'testissuer'); | ||
done(); | ||
}); | ||
it('should be able to retrieve a list of Google certificates', function(done) { | ||
var scope = nock('https://www.googleapis.com').get('/oauth2/v1/certs').replyWithFile(200, __dirname + '/fixtures/oauthcerts.json'); | ||
var oauth2client = new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
oauth2client.getFederatedSignonCerts(function(err, certs) { | ||
assert.equal(err, null); | ||
assert.equal(Object.keys(certs).length, 2); | ||
assert.notEqual(certs['a15eea964ab9cce480e5ef4f47cb17b9fa7d0b21'], null); | ||
assert.notEqual(certs['39596dc3a3f12aa74b481579e4ec944f86d24b95'], null); | ||
scope.done(); | ||
done(); | ||
}); | ||
}); | ||
it('should be able to retrieve a list of Google certificates from cache the second time', function(done) { | ||
var scope = nock('https://www.googleapis.com') | ||
.defaultReplyHeaders({ | ||
'Cache-Control': 'public, max-age=23641, must-revalidate, no-transform', | ||
'Content-Type': 'application/json' | ||
}) | ||
.get('/oauth2/v1/certs') | ||
.once() | ||
.replyWithFile(200, __dirname + '/fixtures/oauthcerts.json'); | ||
var oauth2client = new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
oauth2client.getFederatedSignonCerts(function(err, certs) { | ||
assert.equal(err, null); | ||
assert.equal(Object.keys(certs).length, 2); | ||
scope.done(); // has retrieved from nock... nock no longer will reply | ||
oauth2client.getFederatedSignonCerts(function(err, certs) { | ||
assert.equal(err, null); | ||
assert.equal(Object.keys(certs).length, 2); | ||
scope.done(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('should be able to retrieve a list of Google certificates', | ||
function(done) { | ||
it('should set redirect_uri if not provided in options', function() { | ||
var oauth2client = new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var generated = oauth2client.generateAuthUrl({}); | ||
var parsed = url.parse(generated); | ||
var query = qs.parse(parsed.query); | ||
assert.equal(query.redirect_uri, REDIRECT_URI); | ||
}); | ||
var oauth2client = | ||
new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
oauth2client.getFederatedSignonCerts(function(err, certs) { | ||
assert(Object.keys(certs).length > 0); | ||
done(); | ||
}); | ||
it('should set client_id if not provided in options', function() { | ||
var oauth2client = new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var generated = oauth2client.generateAuthUrl({}); | ||
var parsed = url.parse(generated); | ||
var query = qs.parse(parsed.query); | ||
assert.equal(query.client_id, CLIENT_ID); | ||
}); | ||
}); | ||
it('should override redirect_uri if provided in options', function() { | ||
var oauth2client = new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var generated = oauth2client.generateAuthUrl({ redirect_uri: 'overridden' }); | ||
var parsed = url.parse(generated); | ||
var query = qs.parse(parsed.query); | ||
assert.equal(query.redirect_uri, 'overridden'); | ||
}); | ||
it('should override client_id if provided in options', function() { | ||
var oauth2client = new googleapis.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); | ||
var generated = oauth2client.generateAuthUrl({ client_id: 'client_override' }); | ||
var parsed = url.parse(generated); | ||
var query = qs.parse(parsed.query); | ||
assert.equal(query.client_id, 'client_override'); | ||
}); | ||
}); |
@@ -17,27 +17,22 @@ /** | ||
var url = require('url'), | ||
assert = require('assert'), | ||
qs = require('querystring'), | ||
fs = require('fs'); | ||
'use strict'; | ||
var googleapis = require('../lib/googleapis.js'), | ||
MockTransporter = require('./mocks/transporters.js'); | ||
var assert = require('assert'); | ||
var googleapis = require('../lib/googleapis.js'); | ||
var DefaultTransporter = require('../lib/transporters'); | ||
describe('Transporters', function() { | ||
var urlshortenerDiscoveryTransporter = | ||
new MockTransporter(__dirname + '/data/discovery_urlshortener.json'); | ||
var defaultUserAgentRE = 'google-api-nodejs-client/\\d+\.\\d+\.\\d+'; | ||
var transporter = new DefaultTransporter(); | ||
it('should set default client user agent if none is set', function(done) { | ||
var opts = urlshortenerDiscoveryTransporter.configure({}); | ||
it('should set default client user agent if none is set', function() { | ||
var opts = transporter.configure({}); | ||
var re = new RegExp(defaultUserAgentRE); | ||
assert(re.test(opts.headers['User-Agent'])); | ||
done(); | ||
}); | ||
it('should append default client user agent to the existing user agent', | ||
function(done) { | ||
it('should append default client user agent to the existing user agent', function() { | ||
var applicationName = 'MyTestApplication-1.0'; | ||
var opts = urlshortenerDiscoveryTransporter.configure({ | ||
var opts = transporter.configure({ | ||
headers: { 'User-Agent': applicationName } | ||
@@ -47,5 +42,10 @@ }); | ||
assert(re.test(opts.headers['User-Agent'])); | ||
done(); | ||
}); | ||
it('should automatically add content-type', function() { | ||
var google = require('../lib/googleapis'); | ||
var drive = google.drive('v2'); | ||
var req = drive.files.list(); | ||
assert.equal(req.headers['content-type'], 'application/json'); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
2012016
136
45074
1
329
7
4
8
1
+ Addedmultipart-stream@1.0.0
+ Addedabbrev@1.1.1(transitive)
+ Addedarray-buffer-byte-length@1.0.1(transitive)
+ Addedarraybuffer.prototype.slice@1.0.3(transitive)
+ Addedavailable-typed-arrays@1.0.7(transitive)
+ Addedbase64url@0.0.3(transitive)
+ Addedbuffer-equal@0.0.2(transitive)
+ Addedbunker@0.1.2(transitive)
+ Addedburrito@0.2.12(transitive)
+ Addedcall-bind@1.0.7(transitive)
+ Addedcharm@0.1.2(transitive)
+ Addeddata-view-buffer@1.0.1(transitive)
+ Addeddata-view-byte-length@1.0.1(transitive)
+ Addeddata-view-byte-offset@1.0.0(transitive)
+ Addeddeep-equal@0.0.0(transitive)
+ Addeddeep-is@0.1.4(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddefine-properties@1.2.1(transitive)
+ Addeddifflet@0.2.6(transitive)
+ Addedes-abstract@1.23.3(transitive)
+ Addedes-define-property@1.0.0(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.0.0(transitive)
+ Addedes-set-tostringtag@2.0.3(transitive)
+ Addedes-to-primitive@1.2.1(transitive)
+ Addedfor-each@0.3.3(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedfunction.prototype.name@1.1.6(transitive)
+ Addedfunctions-have-names@1.2.3(transitive)
+ Addedgapitoken@0.1.2(transitive)
+ Addedget-intrinsic@1.2.4(transitive)
+ Addedget-symbol-description@1.0.2(transitive)
+ Addedglobalthis@1.0.4(transitive)
+ Addedgopd@1.0.1(transitive)
+ Addedhas-bigints@1.0.2(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-proto@1.0.3(transitive)
+ Addedhas-symbols@1.0.3(transitive)
+ Addedhas-tostringtag@1.0.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedhawk@1.1.1(transitive)
+ Addedinternal-slot@1.0.7(transitive)
+ Addedis-array-buffer@3.0.4(transitive)
+ Addedis-bigint@1.0.4(transitive)
+ Addedis-boolean-object@1.1.2(transitive)
+ Addedis-callable@1.2.7(transitive)
+ Addedis-data-view@1.0.1(transitive)
+ Addedis-date-object@1.0.5(transitive)
+ Addedis-negative-zero@2.0.3(transitive)
+ Addedis-number-object@1.0.7(transitive)
+ Addedis-regex@1.1.4(transitive)
+ Addedis-shared-array-buffer@1.0.3(transitive)
+ Addedis-string@1.0.7(transitive)
+ Addedis-symbol@1.0.4(transitive)
+ Addedis-typed-array@1.1.13(transitive)
+ Addedis-weakref@1.0.2(transitive)
+ Addedisarray@2.0.5(transitive)
+ Addedjws@0.0.2(transitive)
+ Addedmime-types@1.0.2(transitive)
+ Addedmkdirp@0.3.5(transitive)
+ Addedmultipart-stream@1.0.0(transitive)
+ Addednopt@2.2.1(transitive)
+ Addedobject-inspect@1.13.2(transitive)
+ Addedobject-keys@1.1.1(transitive)
+ Addedobject.assign@4.1.5(transitive)
+ Addedpossible-typed-array-names@1.0.0(transitive)
+ Addedregexp.prototype.flags@1.5.2(transitive)
+ Addedrequest@2.37.0(transitive)
+ Addedrunforcover@0.0.2(transitive)
+ Addedsafe-array-concat@1.1.2(transitive)
+ Addedsafe-regex-test@1.0.3(transitive)
+ Addedsandwich-stream@0.0.4(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedset-function-name@2.0.2(transitive)
+ Addedside-channel@1.0.6(transitive)
+ Addedslide@1.1.6(transitive)
+ Addedstring.prototype.trim@1.2.9(transitive)
+ Addedstring.prototype.trimend@1.0.8(transitive)
+ Addedstring.prototype.trimstart@1.0.8(transitive)
+ Addedtap@0.3.3(transitive)
+ Addedtldts@6.1.48(transitive)
+ Addedtldts-core@6.1.48(transitive)
+ Addedtough-cookie@5.0.0(transitive)
+ Addedtraverse@0.5.20.6.10(transitive)
+ Addedtunnel-agent@0.4.3(transitive)
+ Addedtyped-array-buffer@1.0.2(transitive)
+ Addedtyped-array-byte-length@1.0.1(transitive)
+ Addedtyped-array-byte-offset@1.0.2(transitive)
+ Addedtyped-array-length@1.0.6(transitive)
+ Addedtypedarray.prototype.slice@1.0.3(transitive)
+ Addeduglify-js@1.1.1(transitive)
+ Addedunbox-primitive@1.0.2(transitive)
+ Addedwhich-boxed-primitive@1.0.2(transitive)
+ Addedwhich-typed-array@1.1.15(transitive)
- Removedajv@6.12.6(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbase64url@0.0.61.0.6(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedbuffer-equal-constant-time@1.0.1(transitive)
- Removedcamelcase@1.2.1(transitive)
- Removedcamelcase-keys@1.0.0(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removedconcat-stream@1.4.11(transitive)
- Removedcore-util-is@1.0.21.0.3(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedecdsa-sig-formatter@1.0.11(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.3(transitive)
- Removedgapitoken@0.1.5(transitive)
- Removedget-stdin@4.0.1(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhawk@1.0.0(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedindent-string@1.2.2(transitive)
- Removedis-finite@1.1.0(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisarray@0.0.1(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedjwa@1.0.2(transitive)
- Removedjws@3.0.0(transitive)
- Removedmap-obj@1.0.1(transitive)
- Removedmeow@2.0.0(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedminimist@1.2.8(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedobject-assign@1.0.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpsl@1.9.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedreadable-stream@1.1.14(transitive)
- Removedrepeating@1.1.3(transitive)
- Removedrequest@2.34.02.88.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedstring_decoder@0.10.31(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtunnel-agent@0.3.00.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removedtypedarray@0.0.7(transitive)
- Removeduri-js@4.4.1(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)
Updatedasync@0.2.10
Updatedgapitoken@0.1.2
Updatedrequest@2.37.0