Source: managers/auth.js

import Manager from "./manager"
import {Identity, Storage} from "../storage";
import * as utils from "../utils"

/**
 * @memberOf Auth
 * @typedef {Object} User
 * @property {string} user.id - User ID
 * @property {string} user.display_name - Username
 * @property {string} user.avatar_url - URL to user's picture
 * @property {Object} user.auth_identities - Custom identity key/value pairs, e.g "email":"hello@example.com"
 * @property {Object.<string, string>} user.public_properties -  User's Public Properties key/value pairs, e.g "level":"1"
 * @property {Object.<string, string>} user.private_properties - User's Private Properties key/value pairs, e.g "paying_user":"true"
 */

/**
 * @memberOf Auth
 * @typedef {Object} AuthResponse
 * @property {User} user - Authenticated user
 * @property {Object} referral - Referral information, if any
 * @property {Object} referral.data - Referral data, see [reference]{@link https://docs.getsocial.im/knowledge-base/referral-data-reference/}.
 * @property {Object} referral.original_data - Contains original values of keys in <code>data</code> if they were [overriden]{@link https://docs.getsocial.im/guides/smart-links/create-smart-links/url-overrides/}.
 * @property {User} referral.referrer - The user who referred the current user, if any.
 */

/**
 * @class Auth
 * @hideconstructor
 */
export default class Auth extends Manager {
    constructor(client) {
        super(client);
    }

    /**
     * Authenticate with GetSocial.
     *
     * @memberOf Auth
     * @param {Object} params - Authentication parameters.
     * @param {string} params.identity_type - Custom identity type, e.g <code>email</code> or <code>myapp</code>.
     * @param {string} params.value - Value of the identity, e.g <code>example@example.com</code>. Must be an empty string if identity_type is <code>facebook</code>.
     * @param {string} params.token - A unique token for this user. You will need to provide the same token to be able to reauthenticate as this user. We recommend using a hash of the identity value and a secret as the token. If <code>identity_type</code> is <code>facebook</code>, use a valid Facebook access token instead.
     * @param {boolean} params.new_user - Whether this user is new to your app or not.
     *
     * @returns {Promise<AuthResponse>} A Promise for the authenticated user and referral information.
     */
    authenticate(params) {
        // Whenever authenticate is called, we need to store the given identity in-memory,
        // so if the access token unexpectedly expires, we can automatically authenticate
        // again, without bugging the user.
        Storage.setIdentity(new Identity(params.identity_type, params.value, params.token));

        let that = this;
        return new Promise((resolve, reject) => {
            const newUser = params.new_user || false;
            delete params.new_user;

            // If we have a cached user, return that.
            const identityHash = utils.hash(params.identity_type + "|" + params.value + "|" + params.token);
            const auth = Storage.getAuth(identityHash);
            if (typeof auth !== 'undefined') {
                console.log("Using cached auth...");
                that.client.setAccessToken(auth.access_token);
                that.getRef(resolve, reject, params, newUser, auth.user);
                return;
            }

            that.client.rawRequest("/authenticate/user", {
                useAppId: true,
                method: "POST",
                queryParams: params,
            }).then(function (resp) {
                Storage.storeAuth(identityHash, resp);
                that.client.setAccessToken(resp.access_token);
                that.getRef(resolve, reject, params, newUser, resp.user);
            }).catch(function (e) {
                reject(e);
            });
        });
    }

    /**
     * Logs out the current user.
     *
     * @memberOf Auth
     */
    logout() {
        const i = Storage.getIdentity();
        if (typeof i === 'object' && i instanceof Identity) {
            Storage.clearAuth(i.getHash());
        }
    }

    /**
     * Gets referral data if we have a click ID.
     *
     * @ignore
     */
    getRef(resolve, reject, params, newUser, user) {
        const cid = Storage.getClickID();
        if (typeof cid === 'undefined') {
            // Without click ID, there is no referrer information.
            resolve({
                user: user,
                referral: {},
            });
            return;
        }

        let pp = {
            "new_user": newUser,
            "url": cid,
        };

        this.client.authenticatedRequest("/referral/process", {
            method: "GET",
            queryParams: pp,
        }).then(function (resp) {
            Storage.clearClickID();
            resolve({
                user: user,
                referral: resp,
            });
        }).catch(function (e) {
            if (e.hasOwnProperty("error") && e.error === "NotFound") {
                // NotFound here means there is no match, which is not really an error.
                Storage.clearClickID();
                resolve({
                    user: user,
                    referral: {},
                });
                return;
            }

            reject(e);
        });
    }
}