@integromat/proto-oauth
Version:
Integromat OAuth Proto-Classes
227 lines (177 loc) • 5.97 kB
JavaScript
'use strict';
const debug = require('@integromat/debug')('imt:proto:oauth1');
const { IMTOAuthAccount } = require('@integromat/proto');
global.IMTOAuth1Account = class IMTOAuth1Account extends IMTOAuthAccount {
/**
*
*/
constructor(options) {
super();
this.options = options || {};
this.options.version = this.options.version || '1.0A';
}
/**
* Composes the Redirects object based on the environment and other conditions
* @return {{redirectUri: string, localRedirectUri: string, makeRedirectUri: string}}
*/
get redirects() {
const wrapWithRedirectBase = (uri) => {
if (!this.environment.oauthRedirectBase) return uri;
return this.environment.oauthRedirectBase.replace('{{accountName}}', this.name);
};
// If using the new format of specifying redirects, use this one
if (this.environment.redirects) {
const localRedirectUri = wrapWithRedirectBase(`https://${this.environment.host}/oauth/cb/${this.name}`); // Local Address is always based on host
const redirectUri = wrapWithRedirectBase(`https://${this.environment.redirects.integromat}/oauth/cb/${this.name}`); // Redirect URI has to always point at Integromat
const makeRedirectUri = wrapWithRedirectBase(`https://${this.environment.redirects.make}/oauth/cb/${this.name}`); // Make Redirect URI has to always point at Make
return {
redirectUri,
localRedirectUri,
makeRedirectUri
};
}
// Otherwise, keep the legacy standard
const redirectUri = wrapWithRedirectBase(`https://${this.environment.host}/oauth/cb/${this.name}`);
// We're polyfilling the object to make it backward compatible with instances that use new versions of apps but old configuration
return {
redirectUri,
localRedirectUri: redirectUri,
makeRedirectUri: redirectUri
};
}
/**
*
*/
initialize(done) {
this.options.clientId = this.data.consumerKey || this.data.clientId || this.common.consumerKey || this.common.clientId;
this.options.clientSecret = this.data.consumerSecret || this.data.clientSecret || this.common.consumerSecret || this.common.clientSecret;
this.options.redirectUri = this.options.redirectUri || this.redirects.redirectUri;
this.options.customHeaders = this.options.customHeaders || {};
if (!Object.keys(this.options.customHeaders).find(k => /User-Agent/i.test(k)))
this.options.customHeaders['User-Agent'] = `Integromat/${process.env.IMT_ENV}`;
let oauth = require('oauth');
this.client = new oauth.OAuth(this.options.requestUri, this.options.tokenUri, this.options.clientId, this.options.clientSecret, this.options.version, this.options.redirectUri, 'HMAC-SHA1', null, this.options.customHeaders);
done();
}
/**
*
*/
authorize(scope, done) {
this.client.getOAuthRequestToken((err, oauthToken, oauthTokenSecret) => {
let error = this.getResponseError(err);
if (error) return done(error);
this.data.requestToken = oauthToken;
this.data.requestTokenSecret = oauthTokenSecret;
IMTOAuthAccount.createToken(oauthToken, {
account: this.id,
expires: this.environment.currentDate.getTime() + (900 * 1000) // 15 minutes
}, (err) => {
if (err) return done(err);
done(null, this.getAuthorizeUrl(oauthToken));
});
});
}
/**
*
*/
callback(request, done) {
if (this.isAccessDenied(request)) return done(new Error('Access Denied.'));
this.client.getOAuthAccessToken(this.data.requestToken, this.data.requestTokenSecret, request.query.oauth_verifier, (err, accessToken, accessTokenSecret, data) => {
let error = this.getResponseError(err);
if (error) return done(error);
delete this.data.requestToken;
delete this.data.requestTokenSecret;
this.saveTokens(accessToken, accessTokenSecret, data);
this.saveExpire(data);
done(null);
});
}
/**
*
*/
test(done) {
this.getUserInfo((err, response, body) => {
if (err) return done(err, false);
this.saveMetadata(response, body);
done(null, true);
});
}
/**
*
*/
get(url, done) {
if (!this.data.accessToken) return done(new Error('No access token specified.'));
this.client.get(url, this.data.accessToken, this.data.accessTokenSecret, (err, data, response) => {
let error = this.getResponseError(err);
if (error) return done(error);
if (/^application\/json/.test(response.headers['content-type'])) {
try {
var body = JSON.parse(data);
} catch (e) {
return done(new Error('Invalid response JSON.'));
}
} else {
return done(new Error('Invalid response type.'));
}
done(null, response, body);
});
}
/**
*
*/
post(url, body, contentType, done) {
if (typeof contentType == 'function') {
var done = contentType;
contentType = null;
}
if (!this.data.accessToken) return done(new Error('No access token specified.'));
this.client.post(url, this.data.accessToken, this.data.accessTokenSecret, body, 'application/json', (err, data, response) => {
let error = this.getResponseError(err);
if (error) return done(error);
if (/^application\/json/.test(response.headers['content-type'])) {
try {
var body = JSON.parse(data);
} catch (e) {
return done(new Error('Invalid response JSON.'));
}
} else {
return done(new Error('Invalid response type.'));
}
done(null, response, body);
});
}
/**
*
*/
getAuthorizeUrl(token) {
return `${this.options.authorizeUri}?oauth_token=${token}`;
}
/**
*
*/
getTokenFromRequest(request) {
return request.query.oauth_token || request.query.denied;
}
/**
*
*/
isAccessDenied(request) {
return request.query.denied;
}
/**
*
*/
saveTokens(accessToken, accessTokenSecret, data) {
this.data.accessToken = accessToken;
this.data.accessTokenSecret = accessTokenSecret;
}
/**
*
*/
getResponseError(err) {
if (!err) return false;
if (err instanceof Error) return err;
if (err.statusCode && err.statusCode < 300) return false;
return new Error(err.data);
}
};