@aoberoi/passport-slack
Advanced tools
Comparing version 2.0.0-beta.7 to 2.0.0-beta.8
@@ -54,3 +54,3 @@ "use strict"; | ||
const overrideOptions = { passReqToCallback: true }; | ||
super(Object.assign({}, resolvedOptions, overrideOptions), wrapVerify(verify, resolvedOptions.passReqToCallback, resolvedOptions.skipUserProfile)); | ||
super(Object.assign({}, resolvedOptions, overrideOptions), wrapVerify(verify, resolvedOptions.passReqToCallback, resolvedOptions.skipUserProfile, resolvedOptions.profileURL)); | ||
this.name = 'slack'; | ||
@@ -66,37 +66,12 @@ this.slack = { | ||
userProfile(accessToken, done) { | ||
let handled = false; | ||
const handle = (error, profile) => { | ||
if (!handled) { | ||
handled = true; | ||
done(error, profile); | ||
slackGet(this.slack.profileURL, { token: accessToken }) | ||
.then(data => done(null, data)) | ||
.catch((error) => { | ||
// Check for an error related to the X-Slack-User header missing | ||
if (error.message === 'user_not_specified') { | ||
done(null, undefined); | ||
return; | ||
} | ||
}; | ||
const req = https_1.get(`${this.slack.profileURL}?${querystring_1.stringify({ token: accessToken })}`, (res) => { | ||
let body = ''; | ||
if (res.statusCode !== 200) { | ||
handle(new Error(res.statusMessage)); | ||
} | ||
res.setEncoding('utf8'); | ||
res.on('data', chunk => body += chunk); | ||
res.on('end', () => { | ||
try { | ||
body = JSON.parse(body); | ||
} | ||
catch (error) { | ||
handle(error); | ||
} | ||
if (!body.ok) { | ||
// Check for an error related to the X-Slack-User header missing | ||
if (body.error === 'user_not_specified') { | ||
handle(null, undefined); | ||
} | ||
else { | ||
handle(new Error(body.error)); | ||
} | ||
} | ||
handle(null, body); | ||
}); | ||
res.on('error', handle); | ||
done(error); | ||
}); | ||
req.on('error', handle); | ||
} | ||
@@ -121,68 +96,113 @@ /** | ||
*/ | ||
function wrapVerify(verify, passReqToCallback, _skipUserProfile) { | ||
function wrapVerify(verify, passReqToCallback, skipUserProfile, profileURL) { | ||
return function _verify(req, accessToken, refreshToken, results, // TODO: define some types for the oauth.access response shapes | ||
profile, verified) { | ||
// TODO: If the profile is undefined, but the skipUserProfile option says there should be a profile, it may have | ||
// been skipped because there was no user ID available to use for the X-Slack-User header. We can attempt to | ||
// retrieve it now. | ||
const info = { | ||
access_token: accessToken, | ||
refresh_token: refreshToken, | ||
user: { | ||
// will be undefined for user-token apps that don't fetch the profile | ||
id: results.installer_user ? results.installer_user.user_id : (profile && profile.user && profile.user.id), | ||
name: profile !== undefined && profile.user !== undefined ? profile.user.id : undefined, | ||
}, | ||
team: { | ||
id: results.team_id || (results.team && results.team.id), | ||
name: results.team_name || (results.team && results.team.name), | ||
}, | ||
scopes: [], | ||
}; | ||
// Copy all user profile properties into the user | ||
if (profile !== undefined && profile.user !== undefined) { | ||
for (const [key, val] of object_entries_1.default(profile.user)) { | ||
if (info.user[key] === undefined) { | ||
info.user[key] = val; | ||
const skipProfilePromise = new Promise((resolve, reject) => { | ||
if (typeof skipUserProfile !== 'function') { | ||
resolve(skipUserProfile); | ||
return; | ||
} | ||
skipUserProfile(accessToken, (error, skip) => { | ||
if (error) { | ||
reject(error); | ||
return; | ||
} | ||
resolve(skip); | ||
}); | ||
}); | ||
skipProfilePromise.then((skip) => { | ||
if (!skip && profile !== undefined) { | ||
return slackGet(profileURL, { token: accessToken }, { | ||
'X-Slack-User': results.installer_user && results.installer_user.user_id, | ||
}); | ||
} | ||
} | ||
// Build scopes info | ||
if (results.current_grant) { | ||
// in workspace apps, a structured object is returned for scopes | ||
info.scopes = results.current_grant.permissions.reduce((scopes, permission) => (scopes.concat(permission.scopes)), info.scopes); | ||
} | ||
else if (results.scope && typeof results.scope === 'string') { | ||
// in all other apps an array is returned, by splitting a string on the comma separator | ||
info.scopes = results.scope.split(','); | ||
} | ||
else { | ||
// TODO: log a warning | ||
} | ||
// TODO: in workspace apps, there's a whole bunch of very important properties that are not | ||
// being passed to the verification callback | ||
// installer_user, authorizing_user, app_id, app_user_id | ||
// Attach info related to bot user | ||
if (results.bot) { | ||
info.bot = { | ||
user_id: results.bot.bot_user_id, | ||
access_token: results.bot.bot_access_token, | ||
return profile; | ||
}).then((profile) => { | ||
const info = { | ||
access_token: accessToken, | ||
refresh_token: refreshToken, | ||
user: { | ||
// will be undefined for user-token apps that don't fetch the profile | ||
id: results.installer_user ? results.installer_user.user_id : (profile && profile.user && profile.user.id), | ||
name: profile !== undefined && profile.user !== undefined ? profile.user.id : undefined, | ||
}, | ||
team: { | ||
id: results.team_id || (results.team && results.team.id), | ||
name: results.team_name || (results.team && results.team.name), | ||
}, | ||
scopes: [], | ||
}; | ||
} | ||
// Attach info related to incoming webhook | ||
if (results.incoming_webhook) { | ||
info.incoming_webhook = results.incoming_webhook; | ||
} | ||
// Invoke the verify callback using the preference for having the req passed or not | ||
if (!passReqToCallback) { | ||
const verifyWithoutReq = verify; | ||
verifyWithoutReq(info, verified); | ||
} | ||
else { | ||
const verifyWithReq = verify; | ||
verifyWithReq(req, info, verified); | ||
} | ||
// Copy all user profile properties into the user | ||
if (profile !== undefined && profile.user !== undefined) { | ||
for (const [key, val] of object_entries_1.default(profile.user)) { | ||
if (info.user[key] === undefined) { | ||
info.user[key] = val; | ||
} | ||
} | ||
} | ||
// Build scopes info | ||
if (results.current_grant) { | ||
// in workspace apps, a structured object is returned for scopes | ||
info.scopes = results.current_grant.permissions.reduce((scopes, permission) => (scopes.concat(permission.scopes)), info.scopes); | ||
} | ||
else if (results.scope && typeof results.scope === 'string') { | ||
// in all other apps an array is returned, by splitting a string on the comma separator | ||
info.scopes = results.scope.split(','); | ||
} | ||
else { | ||
// TODO: log a warning | ||
} | ||
// TODO: in workspace apps, there's a whole bunch of very important properties that are not | ||
// being passed to the verification callback | ||
// installer_user, authorizing_user, app_id, app_user_id | ||
// Attach info related to bot user | ||
if (results.bot) { | ||
info.bot = { | ||
user_id: results.bot.bot_user_id, | ||
access_token: results.bot.bot_access_token, | ||
}; | ||
} | ||
// Attach info related to incoming webhook | ||
if (results.incoming_webhook) { | ||
info.incoming_webhook = results.incoming_webhook; | ||
} | ||
// Invoke the verify callback using the preference for having the req passed or not | ||
if (!passReqToCallback) { | ||
const verifyWithoutReq = verify; | ||
verifyWithoutReq(info, verified); | ||
} | ||
else { | ||
const verifyWithReq = verify; | ||
verifyWithReq(req, info, verified); | ||
} | ||
}); | ||
}; | ||
} | ||
function slackGet(url, data, headers = {}) { | ||
return new Promise((resolve, reject) => { | ||
const req = https_1.get(`${url}?${querystring_1.stringify(data)}`, { headers }, (res) => { | ||
let body = ''; | ||
if (res.statusCode !== 200) { | ||
reject(new Error(res.statusMessage)); | ||
} | ||
res.setEncoding('utf8'); | ||
res.on('data', chunk => body += chunk); | ||
res.on('end', () => { | ||
try { | ||
body = JSON.parse(body); | ||
} | ||
catch (error) { | ||
reject(error); | ||
} | ||
if (!body.ok) { | ||
reject(new Error(body.error)); | ||
} | ||
resolve(body); | ||
}); | ||
res.on('error', reject); | ||
}); | ||
req.on('error', reject); | ||
}); | ||
} | ||
exports.Strategy = SlackStrategy; // tslint:disable-line:variable-name | ||
//# sourceMappingURL=strategy.js.map |
{ | ||
"name": "@aoberoi/passport-slack", | ||
"version": "2.0.0-beta.7", | ||
"version": "2.0.0-beta.8", | ||
"description": "Slack authentication strategy for Passport", | ||
@@ -5,0 +5,0 @@ "main": "dist/strategy.js", |
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
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
32264
413