Source: strategy.js

/* eslint-disable max-statements */

const InternalOAuthError = require("passport-oauth2").InternalOAuthError,
    OAuth2Strategy = require("passport-oauth2"),
    Profile = require("./profile"),
    TypetalkAPIError = require("./errors/typetalkapierror"),
    uri = require("url"),
    util = require("util");

/**
 * Creates an instance of `Strategy`.
 *
 * The Typetalk authentication strategy authenticates requests by delegating to
 * Typetalk using the OAuth 2.0 protocol.
 *
 * Options:
 *    - `clientID`     your Typetalk application's client ID
 *    - `clientSecret` your Typetalk application's client secret
 *    - `callbackURL`  URL to which Typetalk will redirect
 *                     the user after granting authorization
 *    - `scope`        Permission scopes
 *
 * Examples:
 *
 *    passport.use(new TypetalkStrategy({
 *        clientID: '123-456-789'
 *        clientSecret: 'shhh-its-a-secret'
 *        callbackURL: 'https://www.example.net/auth/typetalk/callback',
 *        scope: ['my', 'topic.read']
 *      },
 *      function(accessToken, refreshToken, profile, cb) {
 *        User.findOrCreate(..., function (err, user) {
 *          cb(err, user);
 *      }
 *    ));
 *
 * @constructor
 * @param {object} maybeOptions
 * @param {function} maybeVerify
 * @access public
 */
function Strategy (maybeOptions, maybeVerify) {
    const options = maybeOptions || {},
        verify = maybeVerify || function verify () {
            // Do nothing.
        };

    options.authorizationURL =
        options.authorizationURL || "https://typetalk.com/oauth2/authorize";
    options.tokenURL =
        options.tokenURL || "https://typetalk.com/oauth2/access_token";
    options.scope = options.scope || ["my"];
    options.scopeSeparator = options.scopeSeparator || " ";


    OAuth2Strategy.call(this, options, verify);
    this.name = "typetalk";
    this._profileURL =
        options.profileURL || "https://typetalk.com/api/v1/profile";
    this._clientSecret = options.clientSecret;
}

/**
 * Inherit from `OAuth2Strategy`.
 */
util.inherits(Strategy, OAuth2Strategy);

/**
 * Authenticate request by delegating to Typetalk using OAuth 2.0.
 *
 * @param {object} req The request to authenticate.
 * @param {object} options
 * @access protected
 */
Strategy.prototype.authenticate = function authenticate (req, options) {
    OAuth2Strategy.prototype.authenticate.call(this, req, options);
};

/**
 * Retrieve user profile from Typetalk.
 *
 * This function constructs a normalized profile, with the following properties:
 *
 *   - `provider` always set to `typetalk`
 *   - `id`       the user's Typetalk ID
 *
 * @param {string} accessToken
 * @param {function} done
 * @access protected
 */
Strategy.prototype.userProfile = function userProfile (accessToken, done) {
    const url = uri.format(uri.parse(this._profileURL));

    this._oauth2.get(url, accessToken, (err, body) => {
        let json = {};

        if (err) {
            if (err.data) {
                try {
                    json = JSON.parse(err.data);
                } catch (e) {
                    // Do nothing.
                }
            }

            if (json && json.error && typeof json.error === "string") {
                /* eslint-disable-next-line max-len */
                return done(new TypetalkAPIError(json.error, json.error_description));
            }
            /* eslint-disable-next-line max-len */
            return done(new InternalOAuthError("Failed to fetch user profile", err));
        }

        try {
            json = JSON.parse(body);
        } catch (ex) {
            return done(new Error("Failed to parse user profile"));
        }

        const profile = Profile.parse(json);
        profile.provider = "typetalk";

        done(null, profile);
    });
};

/**
 * Expose `Strategy`.
 */
module.exports = Strategy;