@ -30,22 +30,65 @@ const container = document.getElementById('app-content');
const ONE _SECOND _IN _MILLISECONDS = 1_000 ;
const ONE _SECOND _IN _MILLISECONDS = 1_000 ;
const WORKER _KEEP _ALIVE _INTERVAL = ONE _SECOND _IN _MILLISECONDS ;
const WORKER _KEEP _ALIVE _INTERVAL = ONE _SECOND _IN _MILLISECONDS ;
// Service Worker Keep Alive Message Constants
const WORKER _KEEP _ALIVE _MESSAGE = 'WORKER_KEEP_ALIVE_MESSAGE' ;
const WORKER _KEEP _ALIVE _MESSAGE = 'WORKER_KEEP_ALIVE_MESSAGE' ;
const ACK _KEEP _ALIVE _WAIT _TIME = 60_000 ; // 1 minute
const ACK _KEEP _ALIVE _MESSAGE = 'ACK_KEEP_ALIVE_MESSAGE' ;
// Timeout for initializing phishing warning page.
// Timeout for initializing phishing warning page.
const PHISHING _WARNING _PAGE _TIMEOUT = ONE _SECOND _IN _MILLISECONDS ;
const PHISHING _WARNING _PAGE _TIMEOUT = ONE _SECOND _IN _MILLISECONDS ;
const PHISHING _WARNING _SW _STORAGE _KEY = 'phishing-warning-sw-registered' ;
const PHISHING _WARNING _SW _STORAGE _KEY = 'phishing-warning-sw-registered' ;
let lastMessageRecievedTimestamp = Date . now ( ) ;
/ *
/ *
* As long as UI is open it will keep sending messages to service worker
* As long as UI is open it will keep sending messages to service worker
* In service worker as this message is received
* In service worker as this message is received
* if service worker is inactive it is reactivated and script re - loaded
* if service worker is inactive it is reactivated and script re - loaded
* Time has been kept to 1000 ms but can be reduced for even faster re - activation of service worker
* Time has been kept to 1000 ms but can be reduced for even faster re - activation of service worker
* /
* /
let extensionPort ;
let timeoutHandle ;
if ( isManifestV3 ) {
if ( isManifestV3 ) {
setInterval ( ( ) => {
// Checking for SW aliveness (or stuckness) flow
// 1. Check if we have an extensionPort, if yes
// 2a. Send a keep alive message to the background via extensionPort
// 2b. Add a listener to it (if not already added)
// 3a. Set a timeout to check if we have received an ACK from background
// 3b. If we have not received an ACK within Xs, we know the background is stuck or dead
// 4. If we recieve an ACK_KEEP_ALIVE_MESSAGE from the service worker, we know it is alive
const ackKeepAliveListener = ( message ) => {
if ( message . name === ACK _KEEP _ALIVE _MESSAGE ) {
lastMessageRecievedTimestamp = Date . now ( ) ;
clearTimeout ( timeoutHandle ) ;
}
} ;
const handle = setInterval ( ( ) => {
browser . runtime . sendMessage ( { name : WORKER _KEEP _ALIVE _MESSAGE } ) ;
browser . runtime . sendMessage ( { name : WORKER _KEEP _ALIVE _MESSAGE } ) ;
if ( extensionPort !== null && extensionPort !== undefined ) {
extensionPort . postMessage ( { name : WORKER _KEEP _ALIVE _MESSAGE } ) ;
if ( extensionPort . onMessage . hasListener ( ackKeepAliveListener ) === false ) {
extensionPort . onMessage . addListener ( ackKeepAliveListener ) ;
}
}
timeoutHandle = setTimeout ( ( ) => {
if (
Date . now ( ) - lastMessageRecievedTimestamp >
ACK _KEEP _ALIVE _WAIT _TIME
) {
clearInterval ( handle ) ;
displayCriticalError (
'somethingIsWrong' ,
new Error ( "Something's gone wrong. Try reloading the page." ) ,
) ;
}
} , ACK _KEEP _ALIVE _WAIT _TIME ) ;
} , WORKER _KEEP _ALIVE _INTERVAL ) ;
} , WORKER _KEEP _ALIVE _INTERVAL ) ;
}
}
@ -61,7 +104,7 @@ async function start() {
let isUIInitialised = false ;
let isUIInitialised = false ;
// setup stream to background
// setup stream to background
let extensionPort = browser . runtime . connect ( { name : windowType } ) ;
extensionPort = browser . runtime . connect ( { name : windowType } ) ;
let connectionStream = new PortStream ( extensionPort ) ;
let connectionStream = new PortStream ( extensionPort ) ;
const activeTab = await queryCurrentActiveTab ( windowType ) ;
const activeTab = await queryCurrentActiveTab ( windowType ) ;
@ -208,7 +251,7 @@ async function start() {
initializeUi ( tab , connectionStream , ( err , store ) => {
initializeUi ( tab , connectionStream , ( err , store ) => {
if ( err ) {
if ( err ) {
// if there's an error, store will be = metamaskState
// if there's an error, store will be = metamaskState
displayCriticalError ( err , store ) ;
displayCriticalError ( 'troubleStarting' , err , store ) ;
return ;
return ;
}
}
isUIInitialised = true ;
isUIInitialised = true ;
@ -226,7 +269,7 @@ async function start() {
function updateUiStreams ( ) {
function updateUiStreams ( ) {
connectToAccountManager ( connectionStream , ( err , backgroundConnection ) => {
connectToAccountManager ( connectionStream , ( err , backgroundConnection ) => {
if ( err ) {
if ( err ) {
displayCriticalError ( err ) ;
displayCriticalError ( 'troubleStarting' , err ) ;
return ;
return ;
}
}
@ -277,8 +320,8 @@ function initializeUi(activeTab, connectionStream, cb) {
} ) ;
} ) ;
}
}
async function displayCriticalError ( err , metamaskState ) {
async function displayCriticalError ( errorKey , err , metamaskState ) {
const html = await getErrorHtml ( SUPPORT _LINK , metamaskState ) ;
const html = await getErrorHtml ( errorKey , SUPPORT _LINK , metamaskState ) ;
container . innerHTML = html ;
container . innerHTML = html ;