Skip to content

Commit

Permalink
fix: broken Firefox communication without tabs permission
Browse files Browse the repository at this point in the history
  • Loading branch information
JalilArfaoui committed Feb 13, 2020
1 parent 74dff8e commit 67e9573
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 39 deletions.
2 changes: 1 addition & 1 deletion manifest/development/firefox.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const base = require('../base');
module.exports = {
...base,
name: 'Bulles - development',
permissions: [...base.permissions, 'tabs', '*://*/*'],
permissions: [...base.permissions, '*://*/*'],
content_security_policy: csp({
directives: {
'script-src': ["'self'", "'unsafe-eval'"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
ListeningActionsReadyAction,
TosAcceptedAction
} from 'app/actions';
import assocTabIfNotGiven from 'webext/assocTabIfNotGiven';
import assocMetaIfNotGiven from 'webext/assocMetaIfNotGiven';
import { getInstallationDetails } from '../selectors/installationDetails';
import { areTosAccepted } from '../selectors/prefs';
import sendToTabSaga from './lib/sendToTab.saga';
Expand All @@ -24,7 +24,7 @@ function* sendTosStateToOptionsTab(
action: ListeningActionsReadyAction | TosAcceptedAction
) {
const tab = action.meta!.tab as chrome.tabs.Tab & Tab;
const transmitAction = assocTabIfNotGiven(tab)(
const transmitAction = assocMetaIfNotGiven('tab', tab)(
transmitTosStatus(yield select(areTosAccepted))
);
yield sendToTabSaga(tab, transmitAction);
Expand All @@ -35,7 +35,7 @@ function* sendInstallationDetailsToOptionsTab(
) {
const tab = action.meta.tab as chrome.tabs.Tab & Tab;
const installationDetails = yield select(getInstallationDetails);
const transmitAction = assocTabIfNotGiven(tab)(
const transmitAction = assocMetaIfNotGiven('tab', tab)(
updateInstallationDetails(installationDetails)
);
yield sendToTabSaga(tab, transmitAction);
Expand Down
4 changes: 2 additions & 2 deletions src/app/background/sagas/transmitContributors.saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import {
UPDATE_CONTRIBUTORS,
ListeningActionsReadyAction
} from 'app/actions';
import assocTabIfNotGiven from 'webext/assocTabIfNotGiven';
import assocMetaIfNotGiven from 'webext/assocMetaIfNotGiven';
import { getContributorsWithSubscriptionState } from '../selectors/subscriptions.selectors';
import { getTabsList } from '../selectors/tabs';
import sendToTabSaga from './lib/sendToTab.saga';

function* sendContributorsToTab(tab: chrome.tabs.Tab & Tab) {
const contributors = yield select(getContributorsWithSubscriptionState);
const contributorsTransmittedAction = assocTabIfNotGiven(tab)(
const contributorsTransmittedAction = assocMetaIfNotGiven('tab', tab)(
contributorsTransmitted(contributors)
);
yield sendToTabSaga(tab, contributorsTransmittedAction);
Expand Down
10 changes: 8 additions & 2 deletions src/app/background/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createStore, applyMiddleware } from 'redux';
import { createStore, applyMiddleware, Action } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import createBrowserStorage from 'webext/createBrowserStorage';
import autoMergeLevel2 from 'redux-persist/es/stateReconciler/autoMergeLevel2';
Expand Down Expand Up @@ -37,7 +37,13 @@ const enhancer =
require('redux-immutable-state-invariant').default(),
require('redux-logger').createLogger({
level: 'info',
collapsed: true
collapsed: true,
titleFormatter: (
action: Action,
time: string,
took: number
): string =>
`[BACKGROUND] @ ${time} ${action.type} (in ${took.toFixed(2)} ms)`
})
])
)
Expand Down
10 changes: 8 additions & 2 deletions src/app/content/store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { applyMiddleware, createStore } from 'redux';
import { Action, applyMiddleware, createStore } from 'redux';
import { routerMiddleware, RouterState } from 'connected-react-router';
import { createMemoryHistory } from 'history';
import { FormStateMap } from 'redux-form';
Expand Down Expand Up @@ -37,7 +37,13 @@ const enhancer =
require('redux-immutable-state-invariant').default(),
require('redux-logger').createLogger({
level: 'info',
collapsed: true
collapsed: true,
titleFormatter: (
action: Action,
time: string,
took: number
): string =>
`[CONTENT] @ ${time} ${action.type} (in ${took.toFixed(2)} ms)`
})
])
)
Expand Down
10 changes: 8 additions & 2 deletions src/app/options/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { applyMiddleware, compose, createStore } from 'redux';
import { Action, applyMiddleware, compose, createStore } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import { createHashHistory } from 'history';
import rootReducer from './reducers';
Expand All @@ -18,7 +18,13 @@ const applyMiddlewares =
require('redux-immutable-state-invariant').default(),
require('redux-logger').createLogger({
level: 'info',
collapsed: true
collapsed: true,
titleFormatter: (
action: Action,
time: string,
took: number
): string =>
`[OPTIONS] @ ${time} ${action.type} (in ${took.toFixed(2)} ms)`
})
])
)
Expand Down
22 changes: 22 additions & 0 deletions src/webext/assocMetaIfNotGiven.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as R from 'ramda';
import { Action } from 'redux';

type ActionWithMeta<A, M extends string, V> = A & { meta: { [key in M]: V } };

/**
* Associate any meta to an `Action`, but only if no existing value.
* @param meta
* @param value
*/
const assocMetaIfNotGiven = <M extends string, V>(meta: M, value: V) => <
A extends Action
>(
action: A
): ActionWithMeta<A, M, V> =>
R.over(
R.lensPath(['meta', meta]),
R.defaultTo(value),
action
) as ActionWithMeta<A, M, V>;

export default assocMetaIfNotGiven;
15 changes: 0 additions & 15 deletions src/webext/assocTabIfNotGiven.ts

This file was deleted.

54 changes: 42 additions & 12 deletions src/webext/createMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Action } from 'redux';
import * as R from 'ramda';
import Tab from 'app/lmem/tab';
import { BaseAction } from 'app/actions';
import assocTabIfNotGiven from './assocTabIfNotGiven';
import assocMetaIfNotGiven from './assocMetaIfNotGiven';
import { getOptionsUrl } from './openOptionsTab';

type MessageSender = chrome.runtime.MessageSender;
Expand All @@ -15,20 +15,50 @@ const isOptionsPage = (url: string): boolean => url.includes(getOptionsUrl());

type PossibleOriginInBackground = 'options' | 'content';

const getTabContext = (tab?: chrome.tabs.Tab) =>
tab && tab.url && isOptionsPage(tab.url) ? 'options' : 'content';
/**
* If `from` is specified by sender, we keep it,
* otherwise we try to detect it from URL.
* @param action
* @param tab
*/
const getTabFrom = (
action: Action,
tab?: chrome.tabs.Tab
): PossibleOriginInBackground =>
R.pipe<
Action,
PossibleOriginInBackground | undefined,
PossibleOriginInBackground
>(
R.path(['meta', 'from']),
R.defaultTo<PossibleOriginInBackground>(
tab && tab.url && isOptionsPage(tab.url) ? 'options' : 'content'
)
)(action);

type SetMetaFrom<A> = (
a: A
) => A & { meta: { from: PossibleOriginInBackground } };
const setMetaFrom = <A>(from: PossibleOriginInBackground) =>
R.assocPath(['meta', 'from'], from) as SetMetaFrom<A>;
/**
* Chrome keeps the `url` property in `sender.tab` but Firefox does not,
* without the `tabs` permission, but still gives it in `sender.url` for some reason.
* @param sender
*/
const getTabFromSender = (sender: MessageSender): chrome.tabs.Tab => ({
...(sender.tab as chrome.tabs.Tab),
url: sender.tab && sender.tab.url ? sender.tab.url : sender.url
});

type ActionWithTab = Action & { meta: { tab: chrome.tabs.Tab } };

type ActionWithTab = Action & { meta: { tab: chrome.tabs.Tab & Tab } };
const addSenderToAction = <A extends BaseAction>(sender: MessageSender) =>
R.pipe<A, ActionWithTab, ReceivedAction>(
assocTabIfNotGiven(sender.tab),
setMetaFrom(getTabContext(sender.tab))
assocMetaIfNotGiven<'tab', chrome.tabs.Tab>(
'tab',
getTabFromSender(sender)
),
action =>
assocMetaIfNotGiven<'from', PossibleOriginInBackground>(
'from',
getTabFrom(action, sender.tab)
)(action)
);

const stripSendMeta = R.pipe<ReceivedAction, ReceivedAction, ReceivedAction>(
Expand All @@ -38,7 +68,7 @@ const stripSendMeta = R.pipe<ReceivedAction, ReceivedAction, ReceivedAction>(

export interface ReceivedAction extends Action {
meta: {
tab: chrome.tabs.Tab & Tab;
tab: chrome.tabs.Tab;
from: PossibleOriginInBackground;
};
}
Expand Down

0 comments on commit 67e9573

Please sign in to comment.