summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/renderer/components/WireguardKeys.tsx168
-rw-r--r--gui/src/renderer/components/WireguardKeysStyles.tsx48
-rw-r--r--gui/src/renderer/containers/WireguardKeysPage.tsx27
3 files changed, 243 insertions, 0 deletions
diff --git a/gui/src/renderer/components/WireguardKeys.tsx b/gui/src/renderer/components/WireguardKeys.tsx
new file mode 100644
index 0000000000..dadaca4b51
--- /dev/null
+++ b/gui/src/renderer/components/WireguardKeys.tsx
@@ -0,0 +1,168 @@
+import * as React from 'react';
+import { Component, Text, View } from 'reactxp';
+import { messages } from '../../shared/gettext';
+import { WgKeyState } from '../redux/settings/reducers';
+import * as AppButton from './AppButton';
+import ImageView from './ImageView';
+import { Container, Layout } from './Layout';
+import { BackBarItem, NavigationBar, NavigationContainer } from './NavigationBar';
+import SettingsHeader, { HeaderTitle } from './SettingsHeader';
+import styles from './WireguardKeysStyles';
+
+export interface IProps {
+ keyState: WgKeyState;
+ isOffline: boolean;
+
+ onGenerateKey: () => void;
+ onVerifyKey: (publicKey: string) => void;
+ onVisitWebsiteKey: () => void;
+ onClose: () => void;
+}
+
+export default class WireguardKeys extends Component<IProps> {
+ public render() {
+ return (
+ <Layout>
+ <Container>
+ <View>
+ <NavigationContainer>
+ <NavigationBar>
+ <BackBarItem action={this.props.onClose}>
+ {// TRANSLATORS: Back button in navigation bar
+ messages.pgettext('wireguard-keys-nav', 'Advanced')}
+ </BackBarItem>
+ </NavigationBar>
+ </NavigationContainer>
+
+ <View style={styles.wgkeys__container}>
+ <SettingsHeader>
+ <HeaderTitle>
+ {messages.pgettext('wireguard-keys-nav', 'WireGuard keys')}
+ </HeaderTitle>
+ </SettingsHeader>
+
+ <View style={styles.wgkeys__row}>
+ <Text style={styles.wgkeys__row_label}>
+ {messages.pgettext('wireguard-keys', 'Public key')}
+ </Text>
+ <View style={styles.wgkeys__row_value}>{this.getKeyRow()}</View>
+ <View style={styles.wgkeys__validity_row}>{this.keyValidityLabel()}</View>
+ </View>
+
+ <View style={styles.wgkeys__row}>{this.getActionButton()}</View>
+ <View style={styles.wgkeys__row}>
+ <AppButton.GreenButton
+ disabled={this.props.isOffline}
+ onPress={this.props.onVisitWebsiteKey}>
+ <AppButton.Label>
+ {messages.pgettext('wireguard-key-view', 'Manage keys in website')}
+ </AppButton.Label>
+ <AppButton.Icon source="icon-extLink" height={16} width={16} />
+ </AppButton.GreenButton>
+ </View>
+ </View>
+ </View>
+ </Container>
+ </Layout>
+ );
+ }
+
+ /// Action button can either generate or verify a key
+ private getActionButton() {
+ switch (this.props.keyState.type) {
+ case 'key-set':
+ const publicKey = this.props.keyState.publicKey;
+ // if the key is known to be invalid, allow the user to generate a new one
+ if (this.props.keyState.valid === false) {
+ break;
+ }
+
+ const verificationCallback = () => this.props.onVerifyKey(publicKey);
+
+ return (
+ <AppButton.GreenButton disabled={this.props.isOffline} onPress={verificationCallback}>
+ <AppButton.Label>
+ {messages.pgettext('wireguard-key-view', 'Verify key')}
+ </AppButton.Label>
+ </AppButton.GreenButton>
+ );
+
+ case 'being-verified':
+ return this.busyButton(messages.pgettext('wireguard-key-view', 'Verifying key'));
+ case 'being-generated':
+ return this.busyButton(messages.pgettext('wireguard-key-view', 'Generating key'));
+ }
+ return (
+ <AppButton.GreenButton disabled={this.props.isOffline} onPress={this.props.onGenerateKey}>
+ <AppButton.Label>{messages.pgettext('wireguard-key-view', 'Generate key')}</AppButton.Label>
+ </AppButton.GreenButton>
+ );
+ }
+
+ private busyButton(message: string) {
+ return (
+ <AppButton.GreenButton disabled={true}>
+ <AppButton.Label>{message}</AppButton.Label>
+ <AppButton.Icon source="icon-spinner" height={16} width={16} />
+ </AppButton.GreenButton>
+ );
+ }
+
+ private getKeyRow() {
+ switch (this.props.keyState.type) {
+ case 'being-verified':
+ case 'key-set':
+ // mimicking the truncating of the key from website
+ return (
+ <View title={this.props.keyState.publicKey}>
+ <Text style={styles.wgkeys__row_value}>
+ {this.props.keyState.publicKey.substring(0, 20) + '...'}
+ </Text>
+ </View>
+ );
+ case 'being-generated':
+ return <ImageView source="icon-spinner" height={25} width={25} />;
+ case 'too-many-keys':
+ return (
+ <Text style={styles.wgkeys__invalid_key}>
+ {messages.pgettext('wireguard-key-view', 'Account has too many keys already')}
+ </Text>
+ );
+ case 'generation-failure':
+ return (
+ <Text style={styles.wgkeys__invalid_key}>
+ {messages.pgettext('wireguard-key-view', 'Failed to generate key')}
+ </Text>
+ );
+ default:
+ return (
+ <Text style={styles.wgkeys__row_value}>
+ {messages.pgettext('wireguard-key-view', 'No key set')}
+ </Text>
+ );
+ }
+ }
+
+ private keyValidityLabel() {
+ switch (this.props.keyState.type) {
+ case 'being-verified':
+ return <ImageView source="icon-spinner" height={25} width={25} />;
+ case 'key-set':
+ if (this.props.keyState.valid === true) {
+ return (
+ <Text style={styles.wgkeys__valid_key}>
+ {messages.pgettext('account-view', 'Key is valid')}
+ </Text>
+ );
+ } else if (this.props.keyState.valid === false) {
+ return (
+ <Text style={styles.wgkeys__invalid_key}>
+ {messages.pgettext('wireguard-key-view', 'Key is invalid')}
+ </Text>
+ );
+ }
+ default:
+ return '';
+ }
+ }
+}
diff --git a/gui/src/renderer/components/WireguardKeysStyles.tsx b/gui/src/renderer/components/WireguardKeysStyles.tsx
new file mode 100644
index 0000000000..8f94bdcca6
--- /dev/null
+++ b/gui/src/renderer/components/WireguardKeysStyles.tsx
@@ -0,0 +1,48 @@
+import { Styles } from 'reactxp';
+import { colors } from '../../config.json';
+
+export default {
+ wgkeys__container: Styles.createViewStyle({
+ flexDirection: 'column',
+ flex: 1,
+ }),
+ wgkeys__row: Styles.createViewStyle({
+ paddingTop: 0,
+ paddingBottom: 0,
+ paddingLeft: 24,
+ paddingRight: 24,
+ marginBottom: 24,
+ }),
+ wgkeys__row_label: Styles.createTextStyle({
+ fontFamily: 'Open Sans',
+ fontSize: 13,
+ fontWeight: '600',
+ lineHeight: 20,
+ letterSpacing: -0.2,
+ color: colors.white60,
+ marginBottom: 9,
+ }),
+ wgkeys__validity_row: Styles.createViewStyle({
+ paddingTop: 5,
+ }),
+ wgkeys__row_value: Styles.createTextStyle({
+ fontFamily: 'Open Sans',
+ fontSize: 16,
+ lineHeight: 19,
+ fontWeight: '800',
+ color: colors.white,
+ }),
+ wgkeys__invalid_key: Styles.createTextStyle({
+ fontFamily: 'Open Sans',
+ fontSize: 16,
+ fontWeight: '800',
+ color: colors.red,
+ }),
+ wgkeys__valid_key: Styles.createTextStyle({
+ fontFamily: 'Open Sans',
+ fontSize: 16,
+ fontWeight: '600',
+ lineHeight: 20,
+ color: colors.green,
+ }),
+};
diff --git a/gui/src/renderer/containers/WireguardKeysPage.tsx b/gui/src/renderer/containers/WireguardKeysPage.tsx
new file mode 100644
index 0000000000..2fb185cb1d
--- /dev/null
+++ b/gui/src/renderer/containers/WireguardKeysPage.tsx
@@ -0,0 +1,27 @@
+import { goBack, push } from 'connected-react-router';
+import { shell } from 'electron';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import { links } from '../../config.json';
+import WireguardKeys from '../components/WireguardKeys';
+import { IReduxState, ReduxDispatch } from '../redux/store';
+import { ISharedRouteProps } from '../routes';
+
+const mapStateToProps = (state: IReduxState, _props: ISharedRouteProps) => ({
+ keyState: state.settings.wireguardKeyState,
+ isOffline: state.connection.isBlocked,
+});
+const mapDispatchToProps = (dispatch: ReduxDispatch, props: ISharedRouteProps) => {
+ const history = bindActionCreators({ push, goBack }, dispatch);
+ return {
+ onGenerateKey: () => props.app.generateWireguardKey(),
+ onVerifyKey: (publicKey: string) => props.app.verifyWireguardKey(publicKey),
+ onVisitWebsiteKey: () => shell.openExternal(links.manageKeys),
+ onClose: () => history.goBack(),
+ };
+};
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(WireguardKeys);