Skip to content

Commit

Permalink
feat: allow adding websites without entering the password #29
Browse files Browse the repository at this point in the history
  • Loading branch information
AXeL-dev committed Sep 4, 2021
1 parent a157cb5 commit c100a66
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 70 deletions.
3 changes: 3 additions & 0 deletions public/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@
"passwordIsWrong": {
"message": "Wrong password!"
},
"allowAddingWebsitesWithoutPassword": {
"message": "Allow adding websites without entering the password"
},
"enable": {
"message": "Enable"
},
Expand Down
3 changes: 3 additions & 0 deletions public/_locales/fr/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@
"passwordIsWrong": {
"message": "Mot de passe incorrect!"
},
"allowAddingWebsitesWithoutPassword": {
"message": "Autoriser l'ajout de sites web sans entrer le mot de passe"
},
"enable": {
"message": "Activer"
},
Expand Down
3 changes: 3 additions & 0 deletions public/_locales/nl/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@
"passwordIsWrong": {
"message": "Het wachtwoord is onjuist!"
},
"allowAddingWebsitesWithoutPassword": {
"message": "Toestaan om websites toe te voegen zonder het wachtwoord in te voeren"
},
"enable": {
"message": "Inschakelen"
},
Expand Down
63 changes: 7 additions & 56 deletions src/components/Panel/index.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { Component, Fragment } from 'react';
import { Pane, Text, Position, Badge, PlusIcon, TickIcon, DisableIcon, SmallMinusIcon, SlashIcon, HistoryIcon, IssueNewIcon } from 'evergreen-ui';
import { translate } from 'helpers/i18n';
import { sendMessage, getActiveTab, getActiveTabHostname, storage, createWindow, indexUrl } from 'helpers/webext';
import { Mode, modes, isAccessible, blockUrl } from 'helpers/block';
import { sendMessage, storage } from 'helpers/webext';
import { Mode, modes, addCurrentWebsite, isActiveTabBlockable } from 'helpers/block';
import { ScheduleType, defaultSchedule, getTodaySchedule } from 'helpers/schedule';
import { defaultLogsSettings } from 'helpers/logger';
import { Header, SwitchField, SegmentedControlField, AnimatedIconButton, SettingsButton, LinkIconButton, TooltipIcon } from 'components';
Expand All @@ -17,7 +17,7 @@ export class Panel extends Component {
isEnabled: true,
mode: '', //defaultMode,
schedule: defaultSchedule,
isAddButtonVisible: true,
isAddButtonVisible: false,
enableLogs: false,
hideReportIssueButton: false,
showAddWebsitePrompt: false,
Expand All @@ -43,44 +43,9 @@ export class Panel extends Component {
});
}

toggleAddButton = (mode) => {
getActiveTab().then(async (tab) => {
if (tab) {
if (!isAccessible(tab.url)) {
this.hideAddButton();
} else {
switch (mode) {
case Mode.blacklist:
case Mode.combined:
const isBlacklisted = await sendMessage('isBlacklisted', tab.url);
if (isBlacklisted) {
this.hideAddButton();
return; // exit
}
break;
case Mode.whitelist:
const isWhitelisted = await sendMessage('isWhitelisted', tab.url);
if (isWhitelisted) {
this.hideAddButton();
return;
}
break;
default:
break;
}
// finally, show add button if tab is not blacklisted nor whitelisted
this.showAddButton();
}
}
});
}

hideAddButton = () => {
this.setAddButtonVisibility(false);
}

showAddButton = () => {
this.setAddButtonVisibility(true);
toggleAddButton = async (mode) => {
const isVisible = await isActiveTabBlockable(mode);
this.setAddButtonVisibility(isVisible);
}

setAddButtonVisibility = (value) => {
Expand All @@ -100,20 +65,6 @@ export class Panel extends Component {
this.toggleAddButton(value);
}

addCurrentWebsite = async () => {
const hostname = await getActiveTabHostname();
if (hostname) {
const url = `*.${hostname}`;
if (this.state.showAddWebsitePrompt) {
createWindow(`${indexUrl}#addWebsitePrompt?url=${url}&mode=${this.state.mode}`, 600, 140);
} else {
blockUrl(url, this.state.mode);
return true;
}
}
return false;
}

renderScheduleRange = (range) => {
const start = range.time.start.length ? range.time.start : '00:00';
const end = range.time.end.length ? range.time.end : '23:59';
Expand Down Expand Up @@ -226,7 +177,7 @@ export class Panel extends Component {
icon={PlusIcon}
iconSize={26}
iconColor="#47b881"
onClick={this.addCurrentWebsite}
onClick={() => addCurrentWebsite(this.state.mode, this.state.showAddWebsitePrompt)}
hideOnClick={true}
hideAnimationIcon={TickIcon}
isVisible={this.state.isAddButtonVisible}
Expand Down
62 changes: 52 additions & 10 deletions src/components/PasswordPrompt/index.jsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,48 @@
import React, { Component } from 'react';
import { Pane, TextInput, UnlockIcon, toaster, HistoryIcon } from 'evergreen-ui';
import { Pane, TextInput, UnlockIcon, toaster, HistoryIcon, Position, PlusIcon, TickIcon } from 'evergreen-ui';
import { translate } from 'helpers/i18n';
import { storage } from 'helpers/webext';
import { storage, sendMessage } from 'helpers/webext';
import { compare } from 'helpers/crypt';
import { debug } from 'helpers/debug';
import { Header, IconButton, SettingsButton, LinkIconButton } from 'components';
import { defaultLogsSettings } from 'helpers/logger';
import { Header, IconButton, SettingsButton, LinkIconButton, AnimatedIconButton } from 'components';
import { defaultMode, Mode, addCurrentWebsite, isActiveTabBlockable } from 'helpers/block';

const defaultHash = process.env.REACT_APP_HASH;

export class PasswordPrompt extends Component {

constructor(props) {
super(props);
this.mode = defaultMode;
this.hash = defaultHash || null;
this.redirectPath = this.props.path || '/';
this.showAddWebsitePrompt = false;
debug.log({ hash: this.hash, redirectPath: this.redirectPath });
this.state = {
password: '',
isAddButtonVisible: false,
enableLogs: false,
};
}

componentDidMount() {
sendMessage('getLogsSettings').then(logs => this.setState({ enableLogs: (logs || defaultLogsSettings).isEnabled }));
storage.get({
mode: this.mode,
password: {
hash: this.hash
}
hash: this.hash,
allowAddingWebsitesWithoutPassword: false,
},
showAddWebsitePrompt: this.showAddWebsitePrompt,
}).then((items) => {
if (items) {
this.mode = items.mode;
this.hash = items.password.hash;
this.showAddWebsitePrompt = items.showAddWebsitePrompt;
if (items.password.allowAddingWebsitesWithoutPassword) {
this.toggleAddButton(this.mode);
}
}
});
}
Expand All @@ -40,6 +55,15 @@ export class PasswordPrompt extends Component {
}
}

toggleAddButton = async (mode) => {
const isVisible = await isActiveTabBlockable(mode);
this.setAddButtonVisibility(isVisible);
}

setAddButtonVisibility = (value) => {
this.setState({ isAddButtonVisible: value });
}

redirectTo = (path, state = null) => {
debug.log('redirecting to:', path, state);
this.props.history.location.state = state;
Expand Down Expand Up @@ -147,11 +171,29 @@ export class PasswordPrompt extends Component {
<Pane display="flex" paddingX={16} paddingY={10} alignItems="start" justifyContent="space-between" borderTop>
<Pane display="flex" gap={10}>
<SettingsButton history={this.props.history} />
<LinkIconButton
icon={HistoryIcon}
link="/logs"
tooltip={translate('logs')}
history={this.props.history}
{this.state.enableLogs && (
<LinkIconButton
icon={HistoryIcon}
link="/logs"
tooltip={translate('logs')}
history={this.props.history}
/>
)}
</Pane>
<Pane>
<AnimatedIconButton
appearance="minimal"
tooltip={this.mode === Mode.whitelist ? translate('addToWhitelist') : translate('addToBlacklist')}
tooltipPosition={Position.LEFT}
className="fill-green"
icon={PlusIcon}
iconSize={26}
iconColor="#47b881"
onClick={() => addCurrentWebsite(this.mode, this.showAddWebsitePrompt)}
hideOnClick={true}
hideAnimationIcon={TickIcon}
isVisible={this.state.isAddButtonVisible}
onVisibilityChange={this.setAddButtonVisibility}
/>
</Pane>
</Pane>
Expand Down
10 changes: 10 additions & 0 deletions src/components/Settings/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export class Settings extends Component {
isSet: false,
value: '',
hash: '',
allowAddingWebsitesWithoutPassword: false,
},
logs: defaultLogsSettings,
misc: {
Expand Down Expand Up @@ -231,6 +232,7 @@ export class Settings extends Component {
unblock: this.state.options.unblock,
password: {
isEnabled: this.state.options.password.isEnabled,
allowAddingWebsitesWithoutPassword: this.state.options.password.allowAddingWebsitesWithoutPassword,
hash: this.state.options.password.isEnabled // if password protection is enabled
? this.state.options.password.value.length // + password length is > 0
? hash(this.state.options.password.value) // hash & save the new password
Expand Down Expand Up @@ -580,8 +582,16 @@ export class Settings extends Component {
onChange={(event) => this.setOptions('password.value', event.target.value)}
disabled={!this.state.options.password.isEnabled}
//data-testid="password"
marginBottom={16}
hasRandomButton
/>
<Checkbox
label={translate('allowAddingWebsitesWithoutPassword')}
checked={this.state.options.password.allowAddingWebsitesWithoutPassword}
onChange={(event) => this.setOptions('password.allowAddingWebsitesWithoutPassword', event.target.checked)}
disabled={!this.state.options.password.isEnabled}
margin={0}
/>
</Fragment>
)

Expand Down
3 changes: 2 additions & 1 deletion src/components/shared/AnimatedIconButton/index.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React, { Component } from 'react';
import { debug } from 'helpers/debug';
import { IconButton } from 'components';
import _ from 'lodash';
import './styles.scss';

export class AnimatedIconButton extends Component {

constructor(props) {
super(props);
this.state = {
isVisible: this.props.isVisible ? this.props.isVisible : true, // do not use || operator with boolean values that takes "true" by default
isVisible: _.isBoolean(this.props.isVisible) ? this.props.isVisible : true, // do not use || operator with boolean values that takes "true" by default
className: '',
icon: this.props.icon,
hideOnClick: this.props.hideOnClick,
Expand Down
4 changes: 2 additions & 2 deletions src/components/shared/PasswordInput/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
}

.random-button {
box-shadow: inset 0 0 0 1px rgba(67, 90, 111, 0.3), inset 0 1px 2px rgba(67, 90, 111, 0.14);
box-shadow: inset 0 0 0 1px rgba(67, 90, 111, 0.3), inset 0 1px 2px rgba(67, 90, 111, 0.14) !important;
&[disabled] {
box-shadow: inset 0 0 0 1px rgba(67, 90, 111, 0.14);
box-shadow: inset 0 0 0 1px rgba(67, 90, 111, 0.14) !important;
}
}
45 changes: 44 additions & 1 deletion src/helpers/block.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { translate } from './i18n';
import { sendMessage, storage } from 'helpers/webext';
import { sendMessage, storage, getActiveTabHostname, getActiveTab, createWindow, indexUrl } from 'helpers/webext';

export const Mode = {
blacklist: 'blacklist',
Expand Down Expand Up @@ -112,3 +112,46 @@ export function blockUrl(url, mode = Mode.blacklist) {
}
});
}

export async function addCurrentWebsite(mode, isPrompt = false) {
const hostname = await getActiveTabHostname();
if (hostname) {
const url = `*.${hostname}`;
if (isPrompt) {
createWindow(`${indexUrl}#addWebsitePrompt?url=${url}&mode=${mode}`, 600, 140);
} else {
blockUrl(url, mode);
return true;
}
}
return false;
}

export async function isActiveTabBlockable(mode) {
const tab = await getActiveTab();
if (!tab) {
return false;
}
if (!isAccessible(tab.url)) {
return false;
} else {
switch (mode) {
case Mode.blacklist:
case Mode.combined:
const isBlacklisted = await sendMessage('isBlacklisted', tab.url);
if (isBlacklisted) {
return false;
}
break;
case Mode.whitelist:
const isWhitelisted = await sendMessage('isWhitelisted', tab.url);
if (isWhitelisted) {
return false;
}
break;
default:
break;
}
}
return true;
}
2 changes: 2 additions & 0 deletions src/helpers/debug.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

export const isDevEnv = !process.env.NODE_ENV || process.env.NODE_ENV === 'development';
export const isTestEnv = process.env.NODE_ENV === 'test';
export const isProdEnv = process.env.NODE_ENV === 'production';

export class debug {

Expand Down

0 comments on commit c100a66

Please sign in to comment.