import { InternalOAuthError, Strategy as OAuth2Strategy } from 'passport-oauth2' import { config } from '../../../config' import { PassportProfile, ProviderEnum } from '../utils' import { logger } from '../../../logger' function extractProfileAttribute (data, path: string): string { // can handle stuff like `attrs[0].name` const pathArray = path.split('.') for (const segment of pathArray) { const regex = /([\d\w]+)\[(.*)\]/ const m = regex.exec(segment) data = m ? data[m[1]][m[2]] : data[segment] } return data } function parseProfile (data): Partial { const username = extractProfileAttribute(data, config.oauth2.userProfileUsernameAttr) let displayName: string | undefined try { // This may fail if the config.oauth2.userProfileDisplayNameAttr is undefined, // or it is foo.bar and data["foo"] is undefined. displayName = extractProfileAttribute(data, config.oauth2.userProfileDisplayNameAttr) } catch (e) { displayName = undefined logger.debug('\'id_token[%s]\' is undefined. Setting \'displayName\' to \'undefined\'.\n%s', config.oauth2.userProfileDisplayNameAttr, e.message) } const emails: string[] = [] try { const email = extractProfileAttribute(data, config.oauth2.userProfileEmailAttr) if (email !== undefined) { emails.push(email) } else { logger.debug('\'id_token[%s]\' is undefined. Setting \'emails\' to [].', config.oauth2.userProfileEmailAttr) } } catch (e) { logger.debug('\'id_token[%s]\' is undefined. Setting \'emails\' to [].\n%s', config.oauth2.userProfileEmailAttr, e.message) } return { id: username, username: username, displayName: displayName, emails: emails } } class OAuth2CustomStrategy extends OAuth2Strategy { private readonly _userProfileURL: string; constructor (options, verify) { options.customHeaders = options.customHeaders || {} super(options, verify) this.name = 'oauth2' this._userProfileURL = options.userProfileURL this._oauth2.useAuthorizationHeaderforGET(true) } userProfile (accessToken, done): void { this._oauth2.get(this._userProfileURL, accessToken, function (err, body, _) { let json if (err) { return done(new InternalOAuthError('Failed to fetch user profile', err)) } try { if (body !== undefined) { json = JSON.parse(body.toString()) } } catch (ex) { return done(new Error('Failed to parse user profile')) } const profile = parseProfile(json) profile.provider = ProviderEnum.oauth2 done(null, profile) }) } } export { OAuth2CustomStrategy }