UNPKG

aladinnetwork-blockstack

Version:

The Aladin Javascript library for authentication, identity, and storage.

326 lines 15.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const query_string_1 = __importDefault(require("query-string")); // @ts-ignore: Could not find a declaration file for module const jsontokens_1 = require("jsontokens"); const authVerification_1 = require("./authVerification"); const utils_1 = require("../utils"); const fetchUtil_1 = require("../fetchUtil"); const dids_1 = require("../dids"); const errors_1 = require("../errors"); const authMessages_1 = require("./authMessages"); const authConstants_1 = require("./authConstants"); const profileTokens_1 = require("../profiles/profileTokens"); const userSession_1 = require("./userSession"); const config_1 = require("../config"); const logger_1 = require("../logger"); const protocolEchoDetection_1 = require("./protocolEchoDetection"); const protocolLaunch_1 = require("./protocolLaunch"); const DEFAULT_PROFILE = { '@type': 'Person', '@context': 'http://schema.org' }; /** * @deprecated * #### v19 Use [[UserSession.isUserSignedIn]] instead. * * Check if a user is currently signed in. * @return {Boolean} `true` if the user is signed in, `false` if not. */ function isUserSignedIn() { console.warn('DEPRECATION WARNING: The static isUserSignedIn() function will be deprecated in ' + 'the next major release of aladin.js. Create an instance of UserSession and call the ' + 'instance method isUserSignedIn().'); const userSession = new userSession_1.UserSession(); return userSession.isUserSignedIn(); } exports.isUserSignedIn = isUserSignedIn; /** * * * @deprecated * #### v19 Use [[UserSession.isUserSignedIn]] instead. * * Generates an authentication request and redirects the user to the Aladin * browser to approve the sign in request. * * Please note that this requires that the web browser properly handles the * `aladin:` 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 `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(redirectURI, manifestURI, scopes) { console.warn('DEPRECATION WARNING: The static redirectToSignIn() function will be deprecated in the ' + 'next major release of aladin.js. Create an instance of UserSession and call the ' + 'instance method redirectToSignIn().'); const authRequest = authMessages_1.makeAuthRequest(null, redirectURI, manifestURI, scopes); redirectToSignInWithAuthRequest(authRequest); } exports.redirectToSignIn = redirectToSignIn; /** * @deprecated * #### v19 Use [[UserSession.isSignInPending]] instead. * * Check if there is a authentication request that hasn't been handled. * * Also checks for a protocol echo reply (which if detected then the page * will be automatically redirected after this call). * * @return {Boolean} `true` if there is a pending sign in, otherwise `false` */ function isSignInPending() { try { const isProtocolEcho = protocolEchoDetection_1.protocolEchoReplyDetection(); if (isProtocolEcho) { logger_1.Logger.info('protocolEchoReply detected from isSignInPending call, the page is about to redirect.'); return true; } } catch (error) { logger_1.Logger.error(`Error checking for protocol echo reply isSignInPending: ${error}`); } return !!getAuthResponseToken(); } exports.isSignInPending = isSignInPending; /** * @deprecated * #### v19 Use [[UserSession.getAuthResponseToken]] instead. * * Retrieve the authentication token from the URL query * @return {String} the authentication token if it exists otherwise `null` */ function getAuthResponseToken() { const search = utils_1.getGlobalObject('location', { throwIfUnavailable: true, usageDesc: 'getAuthResponseToken' }).search; const queryDict = query_string_1.default.parse(search); return queryDict.authResponse ? queryDict.authResponse : ''; } exports.getAuthResponseToken = getAuthResponseToken; /** * @deprecated * #### v19 Use [[UserSession.loadUserData]] instead. * * Retrieves the user data object. The user's profile is stored in the key `profile`. * @return {Object} User data object. */ function loadUserData() { console.warn('DEPRECATION WARNING: The static loadUserData() function will be deprecated in the ' + 'next major release of aladin.js. Create an instance of UserSession and call the ' + 'instance method loadUserData().'); const userSession = new userSession_1.UserSession(); return userSession.loadUserData(); } exports.loadUserData = loadUserData; /** * @deprecated * #### v19 Use [[UserSession.signUserOut]] instead. * * Sign the user out and optionally redirect to given location. * @param redirectURL * Location to redirect user to after sign out. * Only used in environments with `window` available */ function signUserOut(redirectURL, caller) { const userSession = caller || new userSession_1.UserSession(); userSession.store.deleteSessionData(); if (redirectURL) { utils_1.getGlobalObject('location', { throwIfUnavailable: true, usageDesc: 'signUserOut' }).href = redirectURL; } } exports.signUserOut = signUserOut; /** * @deprecated * #### v19 Use [[UserSession.redirectToSignInWithAuthRequest]] instead. * * Redirects the user to the Aladin browser to approve the sign in request * given. * * The user is redirected to the `aladinIDHost` if the `aladin:` * 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} aladinIDHost - the URL to redirect the user to if the aladin * protocol handler is not detected * @return {void} */ function redirectToSignInWithAuthRequest(authRequest, aladinIDHost = authConstants_1.DEFAULT_ALADIN_HOST) { authRequest = authRequest || authMessages_1.makeAuthRequest(); const httpsURI = `${aladinIDHost}?authRequest=${authRequest}`; const { navigator, location } = utils_1.getGlobalObjects(['navigator', 'location'], { throwIfUnavailable: true, usageDesc: 'redirectToSignInWithAuthRequest' }); // If they're on a mobile OS, always redirect them to HTTPS site if (/Android|webOS|iPhone|iPad|iPod|Opera Mini/i.test(navigator.userAgent)) { logger_1.Logger.info('detected mobile OS, sending to https'); location.href = httpsURI; return; } function successCallback() { logger_1.Logger.info('protocol handler detected'); // The detection function should open the link for us } function failCallback() { logger_1.Logger.warn('protocol handler not detected'); location.href = httpsURI; } protocolLaunch_1.launchCustomProtocol(authRequest, successCallback, failCallback); } exports.redirectToSignInWithAuthRequest = redirectToSignInWithAuthRequest; /** * @deprecated * #### v19 Use [[UserSession.handlePendingSignIn]] instead. * * 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 * @param {String} authResponseToken - the signed authentication response token * @param {String} transitKey - the transit private key that corresponds to the transit public key * that was provided in the authentication request * @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(nameLookupURL = '', authResponseToken = getAuthResponseToken(), transitKey, caller) { return __awaiter(this, void 0, void 0, function* () { try { const isProtocolEcho = protocolEchoDetection_1.protocolEchoReplyDetection(); if (isProtocolEcho) { const msg = 'handlePendingSignIn called while protocolEchoReply was detected, and ' + 'the page is about to redirect. This function will resolve with an error after ' + 'several seconds, if the page was not redirected for some reason.'; logger_1.Logger.info(msg); return new Promise((_resolve, reject) => { setTimeout(() => { logger_1.Logger.error('Page should have redirected by now. handlePendingSignIn will now throw.'); reject(msg); }, 3000); }); } } catch (error) { logger_1.Logger.error(`Error checking for protocol echo reply handlePendingSignIn: ${error}`); } if (!caller) { caller = new userSession_1.UserSession(); } if (!transitKey) { transitKey = caller.store.getSessionData().transitKey; } if (!nameLookupURL) { const tokenPayload = jsontokens_1.decodeToken(authResponseToken).payload; if (utils_1.isLaterVersion(tokenPayload.version, '1.3.0') && tokenPayload.aladinAPIUrl !== null && tokenPayload.aladinAPIUrl !== undefined) { // override globally logger_1.Logger.info(`Overriding ${config_1.config.network.aladinAPIUrl} ` + `with ${tokenPayload.aladinAPIUrl}`); config_1.config.network.aladinAPIUrl = tokenPayload.aladinAPIUrl; } nameLookupURL = `${config_1.config.network.aladinAPIUrl}${authConstants_1.NAME_LOOKUP_PATH}`; } const isValid = yield authVerification_1.verifyAuthResponse(authResponseToken, nameLookupURL); if (!isValid) { throw new errors_1.LoginFailedError('Invalid authentication response.'); } const tokenPayload = jsontokens_1.decodeToken(authResponseToken).payload; // TODO: real version handling let appPrivateKey = tokenPayload.private_key; let coreSessionToken = tokenPayload.core_token; if (utils_1.isLaterVersion(tokenPayload.version, '1.1.0')) { if (transitKey !== undefined && transitKey != null) { if (tokenPayload.private_key !== undefined && tokenPayload.private_key !== null) { try { appPrivateKey = authMessages_1.decryptPrivateKey(transitKey, tokenPayload.private_key); } catch (e) { logger_1.Logger.warn('Failed decryption of appPrivateKey, will try to use as given'); try { utils_1.hexStringToECPair(tokenPayload.private_key); } catch (ecPairError) { throw new errors_1.LoginFailedError('Failed decrypting appPrivateKey. Usually means' + ' that the transit key has changed during login.'); } } } if (coreSessionToken !== undefined && coreSessionToken !== null) { try { coreSessionToken = authMessages_1.decryptPrivateKey(transitKey, coreSessionToken); } catch (e) { logger_1.Logger.info('Failed decryption of coreSessionToken, will try to use as given'); } } } else { throw new errors_1.LoginFailedError('Authenticating with protocol > 1.1.0 requires transit' + ' key, and none found.'); } } let hubUrl = authConstants_1.ALADIN_DEFAULT_GAIA_HUB_URL; let gaiaAssociationToken; if (utils_1.isLaterVersion(tokenPayload.version, '1.2.0') && tokenPayload.hubUrl !== null && tokenPayload.hubUrl !== undefined) { hubUrl = tokenPayload.hubUrl; } if (utils_1.isLaterVersion(tokenPayload.version, '1.3.0') && tokenPayload.associationToken !== null && tokenPayload.associationToken !== undefined) { gaiaAssociationToken = tokenPayload.associationToken; } const userData = { username: tokenPayload.username, profile: tokenPayload.profile, email: tokenPayload.email, decentralizedID: tokenPayload.iss, identityAddress: dids_1.getAddressFromDID(tokenPayload.iss), appPrivateKey, coreSessionToken, authResponseToken, hubUrl, gaiaAssociationToken }; const profileURL = tokenPayload.profile_url; if (!userData.profile && profileURL) { const response = yield fetchUtil_1.fetchPrivate(profileURL); if (!response.ok) { // return blank profile if we fail to fetch userData.profile = Object.assign({}, DEFAULT_PROFILE); } else { const responseText = yield response.text(); const wrappedProfile = JSON.parse(responseText); const profile = profileTokens_1.extractProfile(wrappedProfile[0].token); userData.profile = profile; } } else { userData.profile = tokenPayload.profile; } const sessionData = caller.store.getSessionData(); sessionData.userData = userData; caller.store.setSessionData(sessionData); return userData; }); } exports.handlePendingSignIn = handlePendingSignIn; //# sourceMappingURL=authApp.js.map