'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.generateAndStoreTransitKey = generateAndStoreTransitKey;
exports.getTransitKey = getTransitKey;
exports.isUserSignedIn = isUserSignedIn;
exports.redirectToSignInWithAuthRequest = redirectToSignInWithAuthRequest;
exports.redirectToSignIn = redirectToSignIn;
exports.getAuthResponseToken = getAuthResponseToken;
exports.isSignInPending = isSignInPending;
exports.handlePendingSignIn = handlePendingSignIn;
exports.loadUserData = loadUserData;
exports.signUserOut = signUserOut;

var _queryString = require('query-string');

var _queryString2 = _interopRequireDefault(_queryString);

var _jsontokens = require('jsontokens');

var _index = require('./index');

var _customProtocolDetectionBlockstack = require('custom-protocol-detection-blockstack');

var _customProtocolDetectionBlockstack2 = _interopRequireDefault(_customProtocolDetectionBlockstack);

var _utils = require('../utils');

var _index2 = require('../index');

var _authMessages = require('./authMessages');

var _authConstants = require('./authConstants');

var _profiles = require('../profiles');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * Generates a ECDSA keypair and stores the hex value of the private key in
 * local storage.
 * @return {String} the hex encoded private key
 * @private
 */
function generateAndStoreTransitKey() {
  var transitKey = (0, _index2.makeECPrivateKey)();
  localStorage.setItem(_authConstants.BLOCKSTACK_APP_PRIVATE_KEY_LABEL, transitKey);
  return transitKey;
}

/**
 * Fetches the hex value of the transit private key from local storage.
 * @return {String} the hex encoded private key
 * @private
 */

function getTransitKey() {
  return localStorage.getItem(_authConstants.BLOCKSTACK_APP_PRIVATE_KEY_LABEL);
}

/**
 * Check if a user is currently signed in.
 * @return {Boolean} `true` if the user is signed in, `false` if not.
 */
function isUserSignedIn() {
  return !!window.localStorage.getItem(_authConstants.BLOCKSTACK_STORAGE_LABEL);
}

/**
 * Redirects the user to the Blockstack browser to approve the sign in request
 * given.
 *
 * The user is redirected to the `blockstackIDHost` if the `blockstack:`
 * protocol handler is not detected. Please note that the protocol handler detection
 * does not work on all browsers.
 * @param  {String} authRequest - the authentication request generated by `makeAuthRequest`
 * @param  {String} blockstackIDHost - the URL to redirect the user to if the blockstack
 *                                     protocol handler is not detected
 * @return {void}
 */
function redirectToSignInWithAuthRequest() {
  var authRequest = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : (0, _index.makeAuthRequest)();
  var blockstackIDHost = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _authConstants.DEFAULT_BLOCKSTACK_HOST;

  var protocolURI = _utils.BLOCKSTACK_HANDLER + ':' + authRequest;
  var httpsURI = blockstackIDHost + '?authRequest=' + authRequest;
  function successCallback() {
    console.log('protocol handler detected');
    // protocolCheck should open the link for us
  }

  function failCallback() {
    console.log('protocol handler not detected');
    window.location = httpsURI;
  }

  function unsupportedBrowserCallback() {
    // Safari is unsupported by protocolCheck
    console.log('can not detect custom protocols on this browser');
    window.location = protocolURI;
  }

  (0, _customProtocolDetectionBlockstack2.default)(protocolURI, failCallback, successCallback, unsupportedBrowserCallback);
}

/**
 * Generates an authentication request and redirects the user to the Blockstack
 * browser to approve the sign in request.
 *
 * Please note that this requires that the web browser properly handles the
 * `blockstack:` URL protocol handler.
 *
 * Most applications should use this
 * method for sign in unless they require more fine grained control over how the
 * authentication request is generated. If your app falls into this category,
 * use `generateAndStoreTransitKey`, `makeAuthRequest`,
 * and `redirectToSignInWithAuthRequest` to build your own sign in process.
 *
 * @param {String} [redirectURI=`${window.location.origin}/`]
 * The location to which the identity provider will redirect the user after
 * the user approves sign in.
 * @param  {String} [manifestURI=`${window.location.origin}/manifest.json`]
 * Location of the manifest file.
 * @param  {Array} [scopes=DEFAULT_SCOPE] Defaults to requesting write access to
 * this app's data store.
 * An array of strings indicating which permissions this app is requesting.
 * @return {void}
 */
function redirectToSignIn() {
  var redirectURI = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.location.origin + '/';
  var manifestURI = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : window.location.origin + '/manifest.json';
  var scopes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _authConstants.DEFAULT_SCOPE;

  var authRequest = (0, _index.makeAuthRequest)(generateAndStoreTransitKey(), redirectURI, manifestURI, scopes);
  redirectToSignInWithAuthRequest(authRequest);
}

/**
 * Retrieve the authentication token from the URL query
 * @return {String} the authentication token if it exists otherwise `null`
 */
function getAuthResponseToken() {
  var queryDict = _queryString2.default.parse(location.search);
  return queryDict.authResponse ? queryDict.authResponse : null;
}

/**
 * Check if there is a authentication request that hasn't been handled.
 * @return {Boolean} `true` if there is a pending sign in, otherwise `false`
 */
function isSignInPending() {
  return !!getAuthResponseToken();
}

/**
 * Try to process any pending sign in request by returning a `Promise` that resolves
 * to the user data object if the sign in succeeds.
 *
 * @param {String} nameLookupURL - the endpoint against which to verify public
 * keys match claimed username
 *
 * @return {Promise} that resolves to the user data object if successful and rejects
 * if handling the sign in request fails or there was no pending sign in request.
 */
function handlePendingSignIn() {
  var nameLookupURL = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'https://core.blockstack.org/v1/names/';

  var authResponseToken = getAuthResponseToken();

  return new Promise(function (resolve, reject) {
    (0, _index.verifyAuthResponse)(authResponseToken, nameLookupURL).then(function (isValid) {
      if (isValid) {
        var tokenPayload = (0, _jsontokens.decodeToken)(authResponseToken).payload;
        // TODO: real version handling
        var appPrivateKey = tokenPayload.private_key;
        var coreSessionToken = tokenPayload.core_token;
        if (tokenPayload.version === '1.1.0') {
          var transitKey = getTransitKey();
          if (transitKey !== undefined && transitKey != null) {
            if (appPrivateKey !== undefined && appPrivateKey !== null) {
              appPrivateKey = (0, _authMessages.decryptPrivateKey)(transitKey, appPrivateKey);
            }
            if (coreSessionToken !== undefined && coreSessionToken !== null) {
              coreSessionToken = (0, _authMessages.decryptPrivateKey)(transitKey, coreSessionToken);
            }
          }
        }

        var userData = {
          username: tokenPayload.username,
          profile: tokenPayload.profile,
          appPrivateKey: appPrivateKey,
          coreSessionToken: coreSessionToken,
          authResponseToken: authResponseToken
        };
        var profileURL = tokenPayload.profile_url;
        if ((userData.profile === null || userData.profile === undefined) && profileURL !== undefined && profileURL !== null) {
          fetch(profileURL).then(function (response) {
            return response.text();
          }).then(function (response) {
            return JSON.parse(response);
          }).then(function (wrappedProfile) {
            return (0, _profiles.extractProfile)(wrappedProfile[0].token);
          }).then(function (profile) {
            userData.profile = profile;
            window.localStorage.setItem(_authConstants.BLOCKSTACK_STORAGE_LABEL, JSON.stringify(userData));
            resolve(userData);
          });
        } else {
          userData.profile = tokenPayload.profile;
          window.localStorage.setItem(_authConstants.BLOCKSTACK_STORAGE_LABEL, JSON.stringify(userData));
          resolve(userData);
        }
      } else {
        reject();
      }
    });
  });
}

/**
 * Retrieves the user data object. The user's profile is stored in the key `profile`.
 * @return {Object} User data object.
 */
function loadUserData() {
  return JSON.parse(window.localStorage.getItem(_authConstants.BLOCKSTACK_STORAGE_LABEL));
}

/**
 * Sign the user out and optionally redirect to given location.
 * @param  {String} [redirectURL=null] Location to redirect user to after sign out.
 * @return {void}
 */
function signUserOut() {
  var redirectURL = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;

  window.localStorage.removeItem(_authConstants.BLOCKSTACK_STORAGE_LABEL);

  if (redirectURL !== null) {
    window.location = redirectURL;
  }
}