Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved C2P Script Injection #528

Merged
merged 11 commits into from Apr 28, 2020
Next

better handling of C2P script injection by tab

  • Loading branch information
christophertino committed Apr 21, 2020
commit a55c4d1ce75066f6ec372ce2e067ef5a48453f80
@@ -878,7 +878,7 @@ class EventHandlers {
*
*/
_resetNotifications() {
globals.C2P_LOADED = globals.NOTIFICATIONS_LOADED = false; // eslint-disable-line no-multi-assign
globals.NOTIFICATIONS_LOADED = false;
}
}

@@ -41,7 +41,6 @@ class Globals {
this.REQUIRE_LEGACY_OPT_IN = false;
this.HOTFIX = false;
this.LET_REDIRECTS_THROUGH = false;
this.C2P_LOADED = false;
this.NOTIFICATIONS_LOADED = false;
this.upgrade_alert_shown = false;

@@ -2,6 +2,8 @@
* TabInfo Class
*
* this._tabInfo[tab_id]: {
* c2pStatus {string} current status of the click_to_play.js script injection on the tab (none|loading|done)
* c2pQueue {array} queue of c2p messages collected when c2pStatus is none or loading
* domain: {string} the general domain name plus suffix (no sub-domains)
* hash: {string} hash values appended to the url
* host: {string} the domain name plus suffix and sub-domains
@@ -46,7 +48,7 @@ class TabInfo {

/**
* Create a new _tabInfo object
* @param {number} tab_id tab id
* @param {number} tab_id tab id
* @param {string} tab_url tab url
*/
create(tab_id, tab_url) {
@@ -68,6 +70,8 @@ class TabInfo {
unblocked: {},
},
insecureRedirects: [],
c2pStatus: 'none',
c2pQueue: [],
};

this._tabInfo[tab_id] = info;
@@ -76,12 +80,12 @@ class TabInfo {

/**
* Getter method
* @param {number} tab_id tab id
* @param {number} tab_id tab id
* @param {string} property property name
* @return {Object} _tabInfo data
*/
// TODO consider improving handling of what if we mistype the property name.
// always returning object where property might sometimes have returned false could result in subtle bugs.
// TODO consider improving handling of what happens if we mistype the property name. Always
// returning an object where property would otherwise have returned false could result in subtle bugs.
getTabInfo(tab_id, property) {
if (this._tabInfo.hasOwnProperty(tab_id)) {
if (property) {
@@ -94,8 +98,8 @@ class TabInfo {

/**
* Getter method for tab parameters which we want to persist during the session.
* @param {number} tab_id tab id
* @param {string} property persitant property name
* @param {number} tab_id tab id
* @param {string} property persistent property name
* @return {Object} persistent data for this tab
*/
getTabInfoPersist(tab_id, property) {
@@ -167,7 +171,7 @@ class TabInfo {
*
* @private
*
* @param {number} tab_id tab id
* @param {number} tab_id tab id
* @param {string} tab_url tab url
*/
_updateUrl(tab_id, tab_url) {
@@ -40,8 +40,14 @@ const policy = new Policy();
*/
export function buildC2P(details, app_id) {
const { tab_id } = details;
let c2pApp = c2pDb.db.apps && c2pDb.db.apps[app_id];
const tab = tabInfo.getTabInfo(tab_id);

// If the tab is prefetched, a chrome newtab or Firefox about:page, we can't add C2P to it
if (!tab || tab.prefetched || tab.path.includes('_/chrome/newtab') || tab.protocol === 'about' || globals.EXCLUDES.includes(tab.host)) {
return;
}

let c2pApp = c2pDb.db.apps && c2pDb.db.apps[app_id];
if (!c2pApp) {
return;
}
@@ -56,8 +62,7 @@ export function buildC2P(details, app_id) {
}
const app_name = bugDb.db.apps[app_id].name;
const c2pHtml = [];
const tab_host = tabInfo.getTabInfo(tab_id, 'host');
const blacklisted = !!policy.blacklisted(tab_host);
const blacklisted = !!policy.blacklisted(tab.host);

// Generate the templates for each c2p definition (could be multiple for an app ID)
c2pApp.forEach((c2pAppDef) => {
@@ -88,20 +93,50 @@ export function buildC2P(details, app_id) {
c2pHtml.push(c2p_tpl({ data: tplData }));
});

if (app_id === 2575) { // Hubspot forms. Adjust selector.
// Hubspot forms. Adjust selector
if (app_id === 2575) {
c2pApp.ele = _getHubspotFormSelector(details.url);
}
// TODO top-level documents only for now
_injectClickToPlay(tab_id).then((result) => {
if (result) {

// Make sure that the click_to_play.js content script has loaded on the
// top-level document before sending c2p data to the page
switch (tab.c2pStatus) {
case 'none':
tab.c2pStatus = 'loading';
injectScript(tab_id, 'dist/click_to_play.js', '', 'document_end').then(() => {
// Dequeue C2P data stored while the script injection was taking place
let msg = tab.c2pQueue.shift();
while (msg !== undefined) {
sendMessage(tab_id, 'c2p', {
app_id: msg.app_id,
data: msg.c2pApp,
html: msg.c2pHtml
});
msg = tab.c2pQueue.shift();
}
tab.c2pStatus = 'done';
}).catch((err) => {
log('buildC2P error', err);
});
break;
case 'loading':
// Push C2P data to a holding queue until click_to_play.js has finished loading on the page
tab.c2pQueue.push({
app_id,
c2pApp,
c2pHtml
});
break;
case 'done':
sendMessage(tab_id, 'c2p', {
app_id,
data: c2pApp,
html: c2pHtml
// tabWindowId: message.tabWindowId
});
}
});
break;
default:
log(`buildC2P error: c2pStatus type ${tab.c2pStatus} not matched`);
}
}

/**
@@ -193,30 +228,3 @@ function _getHubspotFormSelector(url) {
const tokens = url.substr(8).split(/\/|\&|\?|\#|\=/ig); // eslint-disable-line no-useless-escape
return `form[id="hsForm_${tokens[5]}"]`;
}

/**
* Inject dist/click_to_play.js content script
* @private
*
* @param {number} tab_id tab id
* @return {Promise} true/false
*/
function _injectClickToPlay(tab_id) {
if (globals.C2P_LOADED) {
return Promise.resolve(true);
}

const tab = tabInfo.getTabInfo(tab_id);
if (!tab || tab.prefetched || tab.path.includes('_/chrome/newtab') || tab.protocol === 'about' || globals.EXCLUDES.includes(tab.host)) {
// If the tab is prefetched, a chrome newtab or Firefox about:page, we can't add C2P to it.
return Promise.resolve(true);
}

return injectScript(tab_id, 'dist/click_to_play.js', '', 'document_end').then(() => {
globals.C2P_LOADED = true;
return true;
}).catch((err) => {
log('_injectClickToPlay error', err);
return false; // prevent sendMessage calls
});
}
ProTip! Use n and p to navigate between commits in a pull request.