Skip to content
This repository has been archived by the owner on Apr 11, 2023. It is now read-only.

URL blacklist #90

Merged
merged 2 commits into from
Oct 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/content/actions/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
export default {
// User input
// Enable/disable
ADDON_ENABLE: 'addon.enable',
ADDON_DISABLE: 'addon.disable',
ADDON_TOGGLE_ENABLED: 'addon.toggle.enabled',

// Settings
SETTING_SET: 'setting.set',

// User input
INPUT_KEY_PRESS: 'input.key,press',
INPUT_CLEAR_KEYS: 'input.clear.keys',
INPUT_SET_KEYMAPS: 'input.set.keymaps',

// Completion
COMPLETION_SET_ITEMS: 'completion.set.items',
Expand Down
9 changes: 1 addition & 8 deletions src/content/actions/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,4 @@ const clearKeys = () => {
};
};

const setKeymaps = (keymaps) => {
return {
type: actions.INPUT_SET_KEYMAPS,
keymaps,
};
};

export { keyPress, clearKeys, setKeymaps };
export { keyPress, clearKeys };
10 changes: 10 additions & 0 deletions src/content/actions/setting.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import actions from 'content/actions';

const set = (value) => {
return {
type: actions.SETTING_SET,
value,
};
};

export { set };
4 changes: 2 additions & 2 deletions src/content/components/common/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import InputComponent from './input';
import KeymapperComponent from './keymapper';
import FollowComponent from './follow';
import * as inputActions from 'content/actions/input';
import * as settingActions from 'content/actions/setting';
import messages from 'shared/messages';

export default class Common {
Expand Down Expand Up @@ -40,7 +40,7 @@ export default class Common {
browser.runtime.sendMessage({
type: messages.SETTINGS_QUERY,
}).then((settings) => {
this.store.dispatch(inputActions.setKeymaps(settings.keymaps));
this.store.dispatch(settingActions.set(settings));
});
}
}
15 changes: 8 additions & 7 deletions src/content/components/common/keymapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ export default class KeymapperComponent {
}

key(key) {
let enabled = this.store.getState().addon.enabled;

this.store.dispatch(inputActions.keyPress(key));

let input = this.store.getState().input;
let matched = Object.keys(input.keymaps).filter((keyStr) => {
let state = this.store.getState();
let input = state.input;
let keymaps = state.setting.keymaps;

let matched = Object.keys(keymaps).filter((keyStr) => {
return keyStr.startsWith(input.keys);
});
if (!enabled) {
if (!state.addon.enabled) {
// available keymaps are only ADDON_ENABLE and ADDON_TOGGLE_ENABLED if
// the addon disabled
matched = matched.filter((keys) => {
let type = input.keymaps[keys].type;
let type = keymaps[keys].type;
return type === operations.ADDON_ENABLE ||
type === operations.ADDON_TOGGLE_ENABLED;
});
Expand All @@ -35,7 +36,7 @@ export default class KeymapperComponent {
matched.length === 1 && input.keys !== matched[0]) {
return true;
}
let operation = input.keymaps[matched];
let operation = keymaps[matched];
this.store.dispatch(operationActions.exec(operation));
this.store.dispatch(inputActions.clearKeys());
return true;
Expand Down
26 changes: 25 additions & 1 deletion src/content/components/top-content/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import CommonComponent from '../common';
import FollowController from './follow-controller';
import * as consoleFrames from '../../console-frames';
import * as addonActions from '../../actions/addon';
import messages from 'shared/messages';
import * as re from 'shared/utils/re';

export default class TopContent {

Expand All @@ -11,17 +13,39 @@ export default class TopContent {
new CommonComponent(win, store),
new FollowController(win, store),
];
this.store = store;
this.prevBlacklist = undefined;

// TODO make component
consoleFrames.initialize(window.document);
consoleFrames.initialize(this.win.document);

messages.onMessage(this.onMessage.bind(this));
}

update() {
let blacklist = this.store.getState().setting.blacklist;
if (JSON.stringify(this.prevBlacklist) !== JSON.stringify(blacklist)) {
this.disableIfBlack(blacklist);
this.prevBlacklist = blacklist;
}

this.children.forEach(c => c.update());
}

disableIfBlack(blacklist) {
let loc = this.win.location;
let partial = loc.host + loc.pathname;
let matched = blacklist
.map((item) => {
let pattern = item.includes('/') ? item : item + '/*';
return re.fromWildcard(pattern);
})
.some(regex => regex.test(partial));
if (matched) {
this.store.dispatch(addonActions.disable());
}
}

onMessage(message) {
switch (message.type) {
case messages.CONSOLE_HIDE_COMMAND:
Expand Down
3 changes: 3 additions & 0 deletions src/content/reducers/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import addonReducer from './addon';
import settingReducer from './setting';
import inputReducer from './input';
import followReducer from './follow';

// Make setting reducer instead of re-use
const defaultState = {
addon: addonReducer(undefined, {}),
setting: settingReducer(undefined, {}),
input: inputReducer(undefined, {}),
follow: followReducer(undefined, {}),
};

export default function reducer(state = defaultState, action = {}) {
return Object.assign({}, state, {
addon: addonReducer(state.addon, action),
setting: settingReducer(state.setting, action),
input: inputReducer(state.input, action),
follow: followReducer(state.follow, action),
});
Expand Down
7 changes: 1 addition & 6 deletions src/content/reducers/input.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import actions from 'content/actions';

const defaultState = {
keys: '',
keymaps: {},
keys: ''
};

export default function reducer(state = defaultState, action = {}) {
Expand All @@ -15,10 +14,6 @@ export default function reducer(state = defaultState, action = {}) {
return Object.assign({}, state, {
keys: '',
});
case actions.INPUT_SET_KEYMAPS:
return Object.assign({}, state, {
keymaps: action.keymaps,
});
default:
return state;
}
Expand Down
13 changes: 13 additions & 0 deletions src/content/reducers/setting.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import actions from 'content/actions';

const defaultState = {};

export default function reducer(state = defaultState, action = {}) {
switch (action.type) {
case actions.SETTING_SET:
return Object.assign({}, action.value);
default:
return state;
}
}

6 changes: 6 additions & 0 deletions src/shared/utils/re.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const fromWildcard = (pattern) => {
let regexStr = '^' + pattern.replace(/\*/g, '.*') + '$';
return new RegExp(regexStr);
};

export { fromWildcard };
2 changes: 1 addition & 1 deletion src/shared/validators/setting.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import operations from 'shared/operations';

const VALID_TOP_KEYS = ['keymaps', 'search'];
const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist'];
const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => {
return operations[key];
});
Expand Down
13 changes: 13 additions & 0 deletions test/content/actions/setting.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { expect } from "chai";
import actions from 'content/actions';
import * as settingActions from 'content/actions/setting';

describe("setting actions", () => {
describe("set", () => {
it('create SETTING_SET action', () => {
let action = settingActions.set({ red: 'apple', yellow: 'banana' });
expect(action.type).to.equal(actions.SETTING_SET);
expect(action.value).to.deep.equal({ red: 'apple', yellow: 'banana' });
});
});
});
18 changes: 18 additions & 0 deletions test/content/reducers/setting.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { expect } from "chai";
import actions from 'content/actions';
import settingReducer from 'content/reducers/setting';

describe("content setting reducer", () => {
it('return the initial state', () => {
let state = settingReducer(undefined, {});
expect(state).to.deep.equal({});
});

it('return next state for SETTING_SET', () => {
let newSettings = { red: 'apple', yellow: 'banana' };
let action = { type: actions.SETTING_SET, value: newSettings };
let state = settingReducer(undefined, action);
expect(state).to.deep.equal(newSettings);
expect(state).not.to.equal(newSettings); // assert deep copy
});
});
20 changes: 20 additions & 0 deletions test/shared/util/re.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { expect } from 'chai';
import * as re from 'shared/utils/re';

describe("re util", () => {
it('matches by pattern', () => {
let regex = re.fromWildcard('*.example.com/*');
expect('foo.example.com/bar').to.match(regex);
expect('foo.example.com').not.to.match(regex);
expect('example.com/bar').not.to.match(regex);

regex = re.fromWildcard('example.com/*')
expect('example.com/foo').to.match(regex);
expect('example.com/').to.match(regex);

regex = re.fromWildcard('example.com/*bar')
expect('example.com/foobar').to.match(regex);
expect('example.com/bar').to.match(regex);
expect('example.com/foobarfoo').not.to.match(regex);
})
});