Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

asana

Package Overview
Dependencies
Maintainers
3
Versions
91
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

asana - npm Package Compare versions

Comparing version 0.6.4 to 0.7.0

2

bower.json
{
"name": "asana",
"main": "dist/asana.js",
"version": "0.6.4",
"version": "0.7.0",
"homepage": "https://github.com/Asana/node-asana",

@@ -6,0 +6,0 @@ "authors": [

@@ -20,12 +20,23 @@ /**

/**
* Establishes credentials. If credentials could be out of date and it is
* possible to refresh them, does so.
* Establishes credentials.
*
* @return {Promise} Resolves when credentials have been successfully
* established and `authenticateRequest` calls can expect to succeed.
* @return {Promise} Resolves when initial credentials have been
* completed and `authenticateRequest` calls can expect to succeed.
*/
Authenticator.prototype.ensureCredentials = function() {
Authenticator.prototype.establishCredentials = function() {
throw new Error('not implemented');
};
/**
* Attempts to refresh credentials, if possible, given the current credentials.
*
* @return {Promise} Resolves to `true` if credentials have been successfully
* established and `authenticateRequests` can expect to succeed, else
* resolves to `false`.
*/
Authenticator.prototype.refreshCredentials = function() {
throw new Error('not implemented');
};
module.exports = Authenticator;

@@ -23,6 +23,12 @@ var util = require('util');

BasicAuthenticator.prototype.ensureCredentials = function() {
BasicAuthenticator.prototype.establishCredentials = function() {
// Credentials are already built-in.
return Bluebird.resolve();
};
BasicAuthenticator.prototype.refreshCredentials = function() {
// We have no way of refreshing credentials.
return Bluebird.resolve(false);
};
module.exports = BasicAuthenticator;

@@ -10,2 +10,3 @@ var util = require('util');

* of `flow` or `credentials`.
* @option {App} app The app being authenticated for.
* @option {OauthFlow} [flow] The flow to use to get credentials

@@ -29,2 +30,3 @@ * when needed.

this.flow = options.flow || null;
this.app = options.app;
}

@@ -57,3 +59,4 @@

*/
OauthAuthenticator.prototype.ensureCredentials = function() {
OauthAuthenticator.prototype.establishCredentials = function() {
/* jshint camelcase: false */
var me = this;

@@ -67,8 +70,51 @@ if (me.flow) {

} else {
// We were given a fixed set of credentials and don't know how to get
// new ones, so assume what we have is ok.
return Bluebird.resolve();
if (me.credentials.access_token) {
// Assume what we have is ok.
return Bluebird.resolve();
} else if (me.credentials.refresh_token) {
// We were given a refresh token but NOT an access token. Get access.
return me.refreshCredentials();
} else {
// What kind of credentials did we get anyway?
return Bluebird.reject(new Error('Invalid credentials'));
}
}
};
/**
* Attempts to refresh credentials, if possible, given the current credentials.
* @return {Promise} Resolves to `true` if credentials have been successfully
* established and `authenticateRequests` can expect to succeed, else
* resolves to `false`.
*/
OauthAuthenticator.prototype.refreshCredentials = function() {
/* jshint camelcase: false */
var me = this;
if (me.credentials && me.credentials.refresh_token) {
// We have a refresh token. Use it to get a new access token.
// Only have one outstanding request, any simultaneous requests waiting on
// refresh should gate on this promise.
if (!me.refreshPromise) {
var refreshToken = me.credentials.refresh_token;
me.refreshPromise = me.app.accessTokenFromRefreshToken(refreshToken).then(
function(credentials) {
// Update credentials, but hang on to refresh token.
if (!credentials.refresh_token) {
credentials.refresh_token = refreshToken;
}
me.credentials = credentials;
me.refreshPromise = null;
return true;
});
}
return me.refreshPromise;
} else if (me.flow) {
// Try running the flow again to get credentials.
return this.ensureCredentials();
} else {
// We are unable to refresh credentials automatically.
return Bluebird.resolve(false);
}
};
module.exports = OauthAuthenticator;

@@ -23,4 +23,17 @@ /* jshint browser:true */

var me = this;
var popup, popupTimer, listener;
function cleanup() {
if (popup && popupTimer) {
clearInterval(popupTimer);
popupTimer = null;
}
if (listener) {
window.removeEventListener('message', listener, false);
listener = null;
}
}
me._authorizationPromise = new Bluebird(function(resolve, reject) {
var listener = function(event) {
listener = function(event) {
var receivedUrl;

@@ -37,3 +50,3 @@ try {

state = null; // don't ever respond to again
window.removeEventListener('message', listener, false);
cleanup();
if (params.error) {

@@ -48,5 +61,34 @@ reject(new OauthError(params));

window.addEventListener('message', listener, false);
window.open(authUrl, 'asana_oauth', me._popupParams(800, 600));
// TODO: listen for when window is closed so we don't hang forever if
// user closes popup or it is blocked?
popup = window.open(authUrl, 'asana_oauth', me._popupParams(800, 600));
// Detect popup blocking and fail.
if (!popup) {
cleanup();
reject(new OauthError({
'error': 'access_denied',
'error_description': 'The popup window containing the ' +
'authorization UI was blocked by the browser.'
}));
return;
}
// Detect popup closure (which may not be handled by the content, because
// it may never load) and fail. If the popup posts a message to us, we
// SHOULD get that message before it closes and this interval fires,
// but just in case we wait for two successive intervals.
var seenClosed = false;
popupTimer = setInterval(function() {
if (popup.closed) {
if (seenClosed) {
cleanup();
reject(new OauthError({
'error': 'access_denied',
'error_description': 'The popup window containing the ' +
'authorization UI was closed by the user.'
}));
} else {
seenClosed = true;
}
}
}, 500);
});

@@ -53,0 +95,0 @@ return Promise.resolve();

@@ -126,4 +126,6 @@ var Dispatcher = require('./dispatcher');

if (options.credentials) {
authenticator =
new OauthAuthenticator({ credentials: options.credentials });
authenticator = new OauthAuthenticator({
app: this.app,
credentials: options.credentials
});
} else {

@@ -135,3 +137,6 @@ var FlowType = options.flowType || autoDetect();

var flow = new FlowType(options);
authenticator = new OauthAuthenticator({ flow: flow });
authenticator = new OauthAuthenticator({
app: this.app,
flow: flow
});
}

@@ -138,0 +143,0 @@ this.dispatcher.setAuthenticator(authenticator);

@@ -26,2 +26,5 @@ var errors = require('./errors');

* errors by sleeping and retrying after the waiting period.
* @option {Function} [handleUnauthorized] Automatically handle
* `NoAuthorization` with the callback. If the callback returns `true`
* (or a promise resolving to `true), will retry the request.
* @option {String} [asanaBaseUrl] Base URL for Asana, for debugging

@@ -46,2 +49,10 @@ */

this.retryOnRateLimit = options.retryOnRateLimit || false;
/**
* Handler for unauthorized requests which may seek reauthorization.
* Default behavior is available if configured with an Oauth authenticator
* that has a refresh token, and will refresh the current access token.
* @type {Function}
*/
this.handleUnauthorized = (options.handleUnauthorized !== undefined) ?
options.handleUnauthorized : Dispatcher.maybeReauthorize;
}

@@ -56,2 +67,15 @@

/**
* Default handler for requests that are considered unauthorized.
* Requests that the authenticator try to refresh its credentials if
* possible.
* @return {Promise<boolean>} True iff refresh was successful, false if not.
*/
Dispatcher.maybeReauthorize = function() {
if (!this.authenticator) {
return false;
}
return this.authenticator.refreshCredentials();
};
/**
* Creates an Asana API Url by concatenating the ROOT_URL with path provided.

@@ -85,3 +109,3 @@ * @param {String} path The path

}
return this.authenticator.ensureCredentials();
return this.authenticator.establishCredentials();
};

@@ -98,10 +122,10 @@

var me = this;
// TODO: actually honor these options as overriding defaults
dispatchOptions = dispatchOptions || {};
if (me.authenticator !== null) {
me.authenticator.authenticateRequest(params);
}
return new Bluebird(function (resolve, reject) {
function doRequest() {
if (me.authenticator !== null) {
me.authenticator.authenticateRequest(params);
}
request(params, function(err, res, payload) {

@@ -113,8 +137,24 @@ if (err) {

var error = new STATUS_MAP[res.statusCode](payload);
if (me.retryOnRateLimit &&
error instanceof (errors.RateLimitEnforced)) {
// Maybe attempt retry for rate limiting.
// Delay a half-second more in case of rounding error.
// TODO: verify Asana is always being conservative with duration
setTimeout(doRequest, error.retryAfterSeconds * 1000 + 500);
} else if (me.handleUnauthorized &&
error instanceof (errors.NoAuthorization)) {
// Maybe attempt to retry unauthorized requests after getting
// a new access token.
Bluebird.resolve(me.handleUnauthorized()).then(function(reauth) {
if (reauth) {
doRequest();
} else {
reject(error);
}
});
} else {
// Not an error we can handle.
return reject(error);

@@ -121,0 +161,0 @@ }

{
"name": "asana",
"version": "0.6.4",
"version": "0.7.0",
"description": "A node.js client for the Asana API",

@@ -5,0 +5,0 @@ "main": "index.js",

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc