All files / src/auth protocolEchoDetection.ts

28% Statements 7/25
15.38% Branches 2/13
50% Functions 1/2
28% Lines 7/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69              1x 1x 1x                         1x     8x   8x       8x                                                                          
/**
 * This logic is in a separate file with no dependencies so that it can be 
 * loaded and executed as soon as possible to fulfill the purpose of the protocol 
 * detection technique. The effectiveness of this is obviously subject to how web 
 * apps bundle/consume the blockstack.js lib. 
 */ 
 
const GLOBAL_DETECTION_CACHE_KEY = '_blockstackDidCheckEchoReply'
const ECHO_REPLY_PARAM = 'echoReply'
const AUTH_CONTINUATION_PARAM = 'authContinuation'
 
/**
 * Checks if the current window location URL contains an 'echoReply' parameter 
 * which indicates that this page was only opened to signal back to the originating 
 * tab that the protocol handler is installed. 
 * If found, then localStorage events are used to notify the other tab,
 * and this page is redirected back to the Blockstack authenticator URL. 
 * This function caches its result and will not trigger multiple redirects when
 * invoked multiple times. 
 * @returns True if detected and the page will be automatically redirected. 
 * @hidden
 */
export function protocolEchoReplyDetection(): boolean {
  // Check that the `window` APIs exist
  let globalScope: Window
  Iif (typeof self !== 'undefined') {
    globalScope = self
  } else Iif (typeof window !== 'undefined') {
    globalScope = window
  } else {
    // Exit detection function - we are not running in a browser environment.
    return false
  }
 
  if (!globalScope.location || !globalScope.localStorage || !globalScope.URLSearchParams) {
    // Exit detection function - we are not running in a browser environment.
    return false
  }
 
  // Avoid performing the check twice and triggered multiple redirect timers.
  const existingDetection = (globalScope as any)[GLOBAL_DETECTION_CACHE_KEY]
  if (typeof existingDetection === 'boolean') {
    return existingDetection
  }
 
  const searchParams = new globalScope.URLSearchParams(globalScope.location.search)
  const echoReplyParam = searchParams.get(ECHO_REPLY_PARAM)
  if (echoReplyParam) {
    (globalScope as any)[GLOBAL_DETECTION_CACHE_KEY] = true
 
    // Use localStorage to notify originated tab that protocol handler is available and working.
    const echoReplyKey = `echo-reply-${echoReplyParam}`
 
    // Set the echo-reply result in localStorage for the other window to see.
    globalScope.localStorage.setItem(echoReplyKey, 'success')
 
    // Redirect back to the localhost auth url, as opposed to another protocol launch.
    // This will re-use the same tab rather than creating another useless one.
    globalScope.setTimeout(() => {
      const authContinuationParam = searchParams.get(AUTH_CONTINUATION_PARAM)
      globalScope.location.href = authContinuationParam
    }, 10)
 
    return true
  }
 
  return false
}