summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2022-02-22 11:29:46 +0100
committerOskar Nyberg <oskar@mullvad.net>2022-02-22 11:29:46 +0100
commit79702044ae55a4af48cfbdd4bc3f13d26b3e1672 (patch)
tree0ebb1377449f1889afd3babea66407a57f9a8204
parent7aea025585bf95654bdd216c48edd3769057aba0 (diff)
parentffc9971f8a5ab51b5b05b09f282fcae4b916b41b (diff)
downloadmullvadvpn-79702044ae55a4af48cfbdd4bc3f13d26b3e1672.tar.xz
mullvadvpn-79702044ae55a4af48cfbdd4bc3f13d26b3e1672.zip
Merge branch 'add-blocking-message-on-login-page'
-rw-r--r--CHANGELOG.md3
-rw-r--r--gui/locales/messages.pot26
-rw-r--r--gui/src/renderer/app.tsx4
-rw-r--r--gui/src/renderer/components/Login.tsx63
-rw-r--r--gui/src/renderer/components/LoginStyles.tsx37
-rw-r--r--gui/src/renderer/containers/LoginPage.tsx6
6 files changed, 129 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c4a31afc81..77852038c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,9 @@ Line wrap the file at 100 chars. Th
## [Unreleased]
### Added
+- Show warning message when blocking internet while logged out, and make it possible to unblock the
+ connection from the login view.
+
#### Windows
- Detect mounting and dismounting of volumes, such as VeraCrypt volumes or USB drives,
and exclude paths from the tunnel correctly when these occur. This sometimes only works
diff --git a/gui/locales/messages.pot b/gui/locales/messages.pot
index 760070ae6c..6effa79b61 100644
--- a/gui/locales/messages.pot
+++ b/gui/locales/messages.pot
@@ -78,6 +78,9 @@ msgstr ""
msgid "BLOCKED CONNECTION"
msgstr ""
+msgid "Blocking internet"
+msgstr ""
+
msgid "Buy credit"
msgstr ""
@@ -102,6 +105,9 @@ msgstr ""
msgid "Default"
msgstr ""
+msgid "Disable"
+msgstr ""
+
msgid "Disconnect"
msgstr ""
@@ -173,6 +179,9 @@ msgstr ""
msgid "UDP"
msgstr ""
+msgid "Unblock"
+msgstr ""
+
msgid "UNSECURED CONNECTION"
msgstr ""
@@ -565,6 +574,14 @@ msgctxt "launch-view"
msgid "Connecting to Mullvad system service..."
msgstr ""
+#. This is a warning message shown when the app is blocking the users
+#. internet connection while logged out.
+#. Available placeholder:
+#. %(alwaysRequireVpnSettingsName)s - The translation of "Always require VPN"
+msgctxt "login-view"
+msgid "**%(alwaysRequireVpnSettingsName)s** is enabled. Disable it to unblock your connection."
+msgstr ""
+
msgctxt "login-view"
msgid "Account created"
msgstr ""
@@ -613,6 +630,12 @@ msgctxt "login-view"
msgid "Login failed"
msgstr ""
+#. This is a warning message shown when the app is blocking the users
+#. internet connection while logged out.
+msgctxt "login-view"
+msgid "Our kill switch is currently blocking your connection."
+msgstr ""
+
msgctxt "login-view"
msgid "Please wait"
msgstr ""
@@ -1374,9 +1397,6 @@ msgstr ""
msgid "Blocking all connections"
msgstr ""
-msgid "Blocking internet"
-msgstr ""
-
msgid "Copied Mullvad account number to clipboard"
msgstr ""
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index e9aadedcc4..bd7b2865e6 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -381,11 +381,11 @@ export default class AppRenderer {
actions.settings.updateBridgeState(bridgeState);
}
- public async setBlockWhenDisconnected(blockWhenDisconnected: boolean) {
+ public setBlockWhenDisconnected = async (blockWhenDisconnected: boolean) => {
const actions = this.reduxActions;
await IpcRendererEventChannel.settings.setBlockWhenDisconnected(blockWhenDisconnected);
actions.settings.updateBlockWhenDisconnected(blockWhenDisconnected);
- }
+ };
public async setOpenVpnMssfix(mssfix?: number) {
const actions = this.reduxActions;
diff --git a/gui/src/renderer/components/Login.tsx b/gui/src/renderer/components/Login.tsx
index c7fd1f45cd..bdeb6bdb4b 100644
--- a/gui/src/renderer/components/Login.tsx
+++ b/gui/src/renderer/components/Login.tsx
@@ -17,6 +17,9 @@ import {
StyledAccountDropdownRemoveIcon,
StyledAccountInputBackdrop,
StyledAccountInputGroup,
+ StyledBlockMessage,
+ StyledBlockMessageContainer,
+ StyledBlockTitle,
StyledDropdownSpacer,
StyledFooter,
StyledInput,
@@ -27,16 +30,21 @@ import {
StyledStatusIcon,
StyledSubtitle,
StyledTitle,
+ StyledTopInfo,
} from './LoginStyles';
import { AccountToken } from '../../shared/daemon-rpc-types';
import { LoginState } from '../redux/account/reducers';
import { AriaControlGroup, AriaControlled, AriaControls } from './AriaGroup';
+import { useSelector } from '../redux/store';
+import { useAppContext } from '../context';
+import { formatMarkdown } from '../markdown-formatter';
interface IProps {
accountToken?: AccountToken;
accountHistory?: AccountToken;
loginState: LoginState;
+ showBlockMessage: boolean;
openExternalLink: (type: string) => void;
login: (accountToken: AccountToken) => void;
resetLoginError: () => void;
@@ -90,8 +98,11 @@ export default class Login extends React.Component<IProps, IState> {
<HeaderBarSettingsButton />
</Header>
<Container>
+ <StyledTopInfo>
+ {this.props.showBlockMessage ? <BlockMessage /> : this.getStatusIcon()}
+ </StyledTopInfo>
+
<StyledLoginForm>
- {this.getStatusIcon()}
<StyledTitle aria-live="polite">{this.formTitle()}</StyledTitle>
{this.createLoginForm()}
@@ -392,3 +403,53 @@ function AccountDropdownItem(props: IAccountDropdownItemProps) {
</>
);
}
+
+function BlockMessage() {
+ const { setBlockWhenDisconnected, disconnectTunnel } = useAppContext();
+ const tunnelState = useSelector((state) => state.connection.status);
+ const blockWhenDisconnected = useSelector((state) => state.settings.blockWhenDisconnected);
+
+ const unlock = useCallback(() => {
+ if (blockWhenDisconnected) {
+ void setBlockWhenDisconnected(false);
+ }
+
+ if (tunnelState.state === 'error') {
+ void disconnectTunnel();
+ }
+ }, [blockWhenDisconnected, tunnelState, setBlockWhenDisconnected, disconnectTunnel]);
+
+ const alwaysRequireVpnSettingsName = messages.pgettext(
+ 'advanced-settings-view',
+ 'Always require VPN',
+ );
+ const message = formatMarkdown(
+ blockWhenDisconnected
+ ? sprintf(
+ // TRANSLATORS: This is a warning message shown when the app is blocking the users
+ // TRANSLATORS: internet connection while logged out.
+ // TRANSLATORS: Available placeholder:
+ // TRANSLATORS: %(alwaysRequireVpnSettingsName)s - The translation of "Always require VPN"
+ messages.pgettext(
+ 'login-view',
+ '**%(alwaysRequireVpnSettingsName)s** is enabled. Disable it to unblock your connection.',
+ ),
+ { alwaysRequireVpnSettingsName },
+ )
+ : // This makes the translator comment appear on it's own line.
+ // TRANSLATORS: This is a warning message shown when the app is blocking the users
+ // TRANSLATORS: internet connection while logged out.
+ messages.pgettext('login-view', 'Our kill switch is currently blocking your connection.'),
+ );
+ const buttonText = blockWhenDisconnected
+ ? messages.gettext('Disable')
+ : messages.gettext('Unblock');
+
+ return (
+ <StyledBlockMessageContainer>
+ <StyledBlockTitle>{messages.gettext('Blocking internet')}</StyledBlockTitle>
+ <StyledBlockMessage>{message}</StyledBlockMessage>
+ <AppButton.RedButton onClick={unlock}>{buttonText}</AppButton.RedButton>
+ </StyledBlockMessageContainer>
+ );
+}
diff --git a/gui/src/renderer/components/LoginStyles.tsx b/gui/src/renderer/components/LoginStyles.tsx
index 6d2a6328f4..f3302a397b 100644
--- a/gui/src/renderer/components/LoginStyles.tsx
+++ b/gui/src/renderer/components/LoginStyles.tsx
@@ -2,7 +2,7 @@ import styled from 'styled-components';
import { colors } from '../../config.json';
import ImageView from './ImageView';
import * as Cell from './cell';
-import { hugeText, largeText, tinyText } from './common-styles';
+import { hugeText, largeText, smallText, tinyText } from './common-styles';
import FormattableTextInput from './FormattableTextInput';
export const StyledAccountDropdownContainer = styled.ul({
@@ -67,12 +67,19 @@ export const StyledAccountDropdownItemButtonLabel = styled(Cell.Label)(largeText
},
});
+export const StyledTopInfo = styled.div({
+ display: 'flex',
+ justifyContent: 'center',
+ flex: 1,
+});
+
export const StyledFooter = styled.div({}, (props: { show: boolean }) => ({
- position: 'absolute',
+ position: 'relative',
width: '100%',
bottom: 0,
transform: `translateY(${props.show ? 0 : 100}%)`,
display: 'flex',
+ flex: '0',
flexDirection: 'column',
padding: '18px 22px 22px',
backgroundColor: colors.darkBlue,
@@ -81,6 +88,7 @@ export const StyledFooter = styled.div({}, (props: { show: boolean }) => ({
export const StyledStatusIcon = styled.div({
display: 'flex',
+ alignSelf: 'end',
flex: 0,
marginBottom: '30px',
justifyContent: 'center',
@@ -90,11 +98,10 @@ export const StyledStatusIcon = styled.div({
export const StyledLoginForm = styled.div({
display: 'flex',
- flex: 1,
+ flex: '0 1 225px',
flexDirection: 'column',
overflow: 'visible',
padding: '0 22px',
- margin: '83px 0 0',
});
interface IStyledAccountInputGroupProps {
@@ -164,3 +171,25 @@ export const StyledInput = styled(FormattableTextInput)(largeText, {
color: colors.blue40,
},
});
+
+export const StyledBlockMessageContainer = styled.div({
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ alignSelf: 'start',
+ backgroundColor: colors.darkBlue,
+ borderRadius: '8px',
+ margin: '5px 16px 10px',
+ padding: '16px',
+});
+
+export const StyledBlockTitle = styled.div(smallText, {
+ color: colors.white,
+ marginBottom: '5px',
+ fontWeight: 700,
+});
+
+export const StyledBlockMessage = styled.div(tinyText, {
+ color: colors.white,
+ marginBottom: '10px',
+});
diff --git a/gui/src/renderer/containers/LoginPage.tsx b/gui/src/renderer/containers/LoginPage.tsx
index 6797f40d3e..a6c494c601 100644
--- a/gui/src/renderer/containers/LoginPage.tsx
+++ b/gui/src/renderer/containers/LoginPage.tsx
@@ -6,11 +6,17 @@ import accountActions from '../redux/account/actions';
import { IReduxState, ReduxDispatch } from '../redux/store';
const mapStateToProps = (state: IReduxState) => {
+ const tunnelState = state.connection.status;
+ const blockWhenDisconnected = state.settings.blockWhenDisconnected;
const { accountToken, accountHistory, status } = state.account;
+
+ const showBlockMessage = tunnelState.state === 'error' || blockWhenDisconnected;
+
return {
accountToken,
accountHistory,
loginState: status,
+ showBlockMessage,
};
};
const mapDispatchToProps = (dispatch: ReduxDispatch, props: IAppContext) => {