Skip to content

Commit

Permalink
fix: rework new tab setup and platform detection
Browse files Browse the repository at this point in the history
  • Loading branch information
dessant committed Nov 2, 2023
1 parent e26eb03 commit 90a9066
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 152 deletions.
192 changes: 104 additions & 88 deletions src/background/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -653,85 +653,36 @@ async function searchEngine(session, search, image, imageId, tabActive) {
}

const token = uuidv4();

const tab = await createTab({
token,
index: session.sourceTabIndex,
active: tabActive,
getTab: true
});
const tabId = tab.id;

if (search.sendsReceipt) {
await registry.addTaskRegistryItem({taskId, tabId});
}
const beaconToken = targetEnv === 'samsung' ? uuidv4() : '';

const tabUrl = await getTabUrl(session, search, image, taskId);

await setupNewEngineTab(tabId, tabUrl, token, search.engine);
}
const setupSteps = [];

async function setupNewEngineTab(tabId, tabUrl, token, engine) {
let beaconToken;
const userAgent = await getRequiredUserAgent(engine);
const userAgent = await getRequiredUserAgent(search.engine);
if (userAgent) {
if (targetEnv === 'samsung') {
// Samsung Internet 13: webRequest listener filtering by tab ID
// provided by tabs.createTab returns requests from different tab.
beaconToken = uuidv4();

function requestCallback(details) {
removeCallback();
setUserAgentHeader(details.tabId, userAgent);
}
setupSteps.push({id: 'setUserAgent', tabUrl, userAgent, beaconToken});
}

const removeCallback = function () {
window.clearTimeout(timeoutId);
browser.webRequest.onBeforeRequest.removeListener(requestCallback);
};
const timeoutId = window.setTimeout(removeCallback, 10000); // 10 seconds

browser.webRequest.onBeforeRequest.addListener(
requestCallback,
{
urls: [getNewTabUrl(beaconToken)],
types: ['main_frame']
},
['blocking']
);
} else if (targetEnv === 'safari') {
// Safari 16.4 or later
if (browser.declarativeNetRequest?.updateSessionRules) {
await browser.declarativeNetRequest.updateSessionRules({
addRules: [
{
id: tabId,
action: {
type: 'modifyHeaders',
requestHeaders: [
{header: 'User-Agent', operation: 'set', value: userAgent}
]
},
condition: {
// Safari: tabIds is not supported
urlFilter: `${tabUrl}*`,
resourceTypes: ['main_frame', 'sub_frame']
}
}
]
});
if (search.sendsReceipt) {
setupSteps.push({id: 'addTask', taskId});
}

browser.alarms.create(`delete-net-request-session-rule_${tabId}`, {
delayInMinutes: 1
});
} else {
await showNotification({messageId: 'error_engineSafariOutdated'});
}
} else {
setUserAgentHeader(tabId, userAgent);
}
const storageItem = {
tabUrl: beaconToken ? getNewTabUrl(beaconToken) : tabUrl,
keepHistory: false
};

if (setupSteps.length) {
storageItem.setupSteps = setupSteps;
}

await registry.addStorageItem(storageItem, {
receipts: {expected: 1, received: 0},
expiryTime: 1.0,
token
});

if (beaconToken) {
await registry.addStorageItem(
{tabUrl, keepHistory: false},
Expand All @@ -743,26 +694,89 @@ async function setupNewEngineTab(tabId, tabUrl, token, engine) {
);
}

await registry.addStorageItem(
{
tabUrl: beaconToken ? getNewTabUrl(beaconToken) : tabUrl,
keepHistory: false
},
{
receipts: {expected: 1, received: 0},
expiryTime: 1.0,
token
await createTab({token, index: session.sourceTabIndex, active: tabActive});
}

async function setupTab(sender, steps) {
const results = {};

for (const step of steps) {
if (step.id === 'setUserAgent') {
await setTabUserAgent({
tabId: sender.tab.id,
tabUrl: step.tabUrl,
userAgent: step.userAgent,
beaconToken: step.beaconToken
});

results[step.id] = '';
} else if (step.id === 'addTask') {
await registry.addTaskRegistryItem({
taskId: step.taskId,
tabId: sender.tab.id
});

results[step.id] = '';
}
}

return results;
}

async function setTabUserAgent({tabId, tabUrl, userAgent, beaconToken} = {}) {
if (targetEnv === 'samsung') {
// Samsung Internet 13: webRequest listener filtering by tab ID
// provided by tabs.createTab returns requests from different tab.

function requestCallback(details) {
removeCallback();
setUserAgentHeader(details.tabId, userAgent);
}
);

if (targetEnv === 'safari') {
browser.runtime
.sendMessage({id: 'setTabLocation', token})
.catch(err => null);
const removeCallback = function () {
window.clearTimeout(timeoutId);
browser.webRequest.onBeforeRequest.removeListener(requestCallback);
};
const timeoutId = window.setTimeout(removeCallback, 10000); // 10 seconds

browser.webRequest.onBeforeRequest.addListener(
requestCallback,
{
urls: [getNewTabUrl(beaconToken)],
types: ['main_frame']
},
['blocking']
);
} else if (targetEnv === 'safari') {
// Safari 16.4 or later
if (browser.declarativeNetRequest?.updateSessionRules) {
await browser.declarativeNetRequest.updateSessionRules({
addRules: [
{
id: tabId,
action: {
type: 'modifyHeaders',
requestHeaders: [
{header: 'User-Agent', operation: 'set', value: userAgent}
]
},
condition: {
// Safari: tabIds is not supported
urlFilter: `${tabUrl}*`,
resourceTypes: ['main_frame', 'sub_frame']
}
}
]
});

browser.alarms.create(`delete-net-request-session-rule_${tabId}`, {
delayInMinutes: 1
});
} else {
await showNotification({messageId: 'error_engineSafariOutdated'});
}
} else {
browser.tabs
.sendMessage(tabId, {id: 'setTabLocation', token}, {frameId: 0})
.catch(err => null);
setUserAgentHeader(tabId, userAgent);
}
}

Expand Down Expand Up @@ -1257,7 +1271,7 @@ async function processMessage(request, sender) {
);
return Promise.resolve({response});
} else if (request.id === 'getPlatform') {
return getPlatform({fallback: false});
return getPlatform();
} else if (request.id === 'storageRequest') {
const data = await registry.getStorageItem({
storageId: request.storageId,
Expand Down Expand Up @@ -1310,6 +1324,8 @@ async function processMessage(request, sender) {
}
} else if (request.id === 'showPage') {
await showPage({url: request.url});
} else if (request.id === 'setupTab') {
return setupTab(sender, request.steps);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/storage/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ async function isStorageArea({area = 'local'} = {}) {
}
}

const storageReady = {};
const storageReady = {session: true};
async function isStorageReady({area = 'local'} = {}) {
if (storageReady[area]) {
return true;
Expand Down
46 changes: 15 additions & 31 deletions src/tab/main.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,37 @@
const token = new URL(window.location.href).searchParams.get('id');
async function getLocationData() {
const token = new URL(window.location.href).searchParams.get('id');

return browser.runtime.sendMessage({
id: 'storageRequest',
asyncResponse: true,
saveReceipt: true,
storageId: token
});
}

function setLocation(tabUrl, keepHistory) {
// Function may be called multiple times.
if (self.locationUpdated) {
return;
} else {
self.locationUpdated = true;
}

if (keepHistory) {
window.location.href = tabUrl;
} else {
window.location.replace(tabUrl);
}
}

async function getLocationData() {
if (token) {
return browser.runtime.sendMessage({
id: 'storageRequest',
asyncResponse: true,
saveReceipt: true,
storageId: token
});
}
async function setupTab(steps) {
return browser.runtime.sendMessage({id: 'setupTab', steps});
}

async function start() {
const data = await getLocationData();
if (data) {
setLocation(data.tabUrl, data.keepHistory);
}
}

function onMessage(request, sender) {
// Samsung Internet 13: extension messages are sometimes also dispatched
// to the sender frame.
if (sender.url === document.URL) {
return;
if (data.setupSteps) {
await setupTab(data.setupSteps);
}

if (request.id === 'setTabLocation' && request.token === token) {
start();
}
setLocation(data.tabUrl, data.keepHistory);
}

function init() {
browser.runtime.onMessage.addListener(onMessage);

start();
}

Expand Down
Loading

0 comments on commit 90a9066

Please sign in to comment.