chore: add risk checkbox

This commit is contained in:
AP 2020-02-12 08:26:18 +01:00
parent cf1e579c1d
commit 420cbbfa8f
15 changed files with 233 additions and 85 deletions

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-alert-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>

After

Width:  |  Height:  |  Size: 356 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg>

After

Width:  |  Height:  |  Size: 262 B

View file

@ -1,7 +1,7 @@
import React from 'react';
import { useSpring, animated } from 'react-spring';
import { getValue } from 'helpers/Helpers';
import { useSettings } from 'context/SettingsContext';
import { getValue } from '../../helpers/Helpers';
import { useSettings } from '../../context/SettingsContext';
interface AnimatedProps {
amount: number;

View file

@ -1,5 +1,6 @@
import styled from 'styled-components';
import { Sub4Title } from '../generic/Styled';
import { fontColors, textColor } from 'styles/Themes';
export const Line = styled.div`
margin: 16px 0;
@ -10,3 +11,25 @@ export const StyledTitle = styled(Sub4Title)`
width: 100%;
margin-bottom: 0px;
`;
export const CheckboxText = styled.div`
font-size: 13px;
color: ${fontColors.grey7};
text-align: justify;
`;
export const StyledContainer = styled.div`
color: ${textColor};
display: flex;
justify-content: flex-start;
align-items: center;
padding-right: 32px;
margin: 32px 0 8px;
`;
export const FixedWidth = styled.div`
height: 18px;
width: 18px;
margin: 0px;
margin-right: 8px;
`;

View file

@ -12,6 +12,7 @@ import { ColorButton } from '../buttons/colorButton/ColorButton';
import { Input } from 'components/input/Input';
import { Line, StyledTitle } from './Auth.styled';
import { ChevronLeft } from 'components/generic/Icons';
import { RiskCheckboxAndConfirm } from './Checkboxes';
interface AuthProps {
available: number;
@ -31,6 +32,7 @@ export const BTCLoginForm = ({
const [isName, setName] = useState('');
const [isJson, setJson] = useState('');
const [checked, setChecked] = useState(false);
const [hasInfo, setHasInfo] = useState(false);
const [isPass, setPass] = useState('');
@ -113,7 +115,7 @@ export const BTCLoginForm = ({
};
const renderContent = () => {
const canConnect = isJson !== '' && !!available;
const canConnect = isJson !== '' && !!available && checked;
return (
<>
{goBack && (
@ -129,17 +131,12 @@ export const BTCLoginForm = ({
<StyledTitle>BTCPayServer Connect JSON:</StyledTitle>
<Input onChange={e => setJson(e.target.value)} />
</Line>
{canConnect && (
<ColorButton
disabled={!canConnect}
onClick={handleClick}
withMargin={'16px 0 0'}
fullWidth={true}
arrow={true}
>
Connect
</ColorButton>
)}
<RiskCheckboxAndConfirm
disabled={!canConnect}
handleClick={handleClick}
checked={checked}
onChange={setChecked}
/>
</>
);
};

View file

@ -0,0 +1,55 @@
import React from 'react';
import { Checkbox } from 'components/checkbox/Checkbox';
import { CheckboxText, StyledContainer, FixedWidth } from './Auth.styled';
import { AlertCircle } from 'components/generic/Icons';
import { fontColors } from 'styles/Themes';
import { ColorButton } from 'components/buttons/colorButton/ColorButton';
type CheckboxProps = {
handleClick: () => void;
disabled: boolean;
checked: boolean;
onChange: (state: boolean) => void;
};
export const RiskCheckboxAndConfirm = ({
handleClick,
disabled,
checked,
onChange,
}: CheckboxProps) => (
<>
<WarningBox />
<Checkbox checked={checked} onChange={onChange}>
<CheckboxText>
I'm feeling reckless - I understand that Lightning, LND and
ThunderHub are under constant development and that there is
always a risk of losing funds.
</CheckboxText>
</Checkbox>
<ColorButton
disabled={disabled}
onClick={handleClick}
withMargin={'32px 0 0'}
fullWidth={true}
arrow={true}
>
Connect
</ColorButton>
</>
);
export const WarningBox = () => {
return (
<StyledContainer>
<FixedWidth>
<AlertCircle color={fontColors.grey7} />
</FixedWidth>
<CheckboxText>
Macaroons are handled by the ThunderHub server to connect to
your LND node but are never stored. Still, this involves a
certain degree of trust you must be aware of.
</CheckboxText>
</StyledContainer>
);
};

View file

@ -18,6 +18,7 @@ import { ColorButton } from '../buttons/colorButton/ColorButton';
import { Input } from 'components/input/Input';
import { Line, StyledTitle } from './Auth.styled';
import { ChevronLeft } from 'components/generic/Icons';
import { RiskCheckboxAndConfirm } from './Checkboxes';
interface AuthProps {
available: number;
@ -37,6 +38,7 @@ export const ConnectLoginForm = ({
const [isName, setName] = useState('');
const [isUrl, setUrl] = useState('');
const [checked, setChecked] = useState(false);
const [hasInfo, setHasInfo] = useState(false);
const [isPass, setPass] = useState('');
@ -106,7 +108,7 @@ export const ConnectLoginForm = ({
};
const renderContent = () => {
const canConnect = isUrl !== '' && !!available;
const canConnect = isUrl !== '' && !!available && checked;
return (
<>
{goBack && (
@ -122,17 +124,12 @@ export const ConnectLoginForm = ({
<StyledTitle>LND Connect Url:</StyledTitle>
<Input onChange={e => setUrl(e.target.value)} />
</Line>
{canConnect && (
<ColorButton
disabled={!canConnect}
onClick={() => setHasInfo(true)}
withMargin={'16px 0 0'}
fullWidth={true}
arrow={true}
>
Connect
</ColorButton>
)}
<RiskCheckboxAndConfirm
disabled={!canConnect}
handleClick={() => setHasInfo(true)}
checked={checked}
onChange={setChecked}
/>
</>
);
};

View file

@ -17,6 +17,7 @@ import {
SingleButton,
} from 'components/buttons/multiButton/MultiButton';
import { ChevronLeft } from 'components/generic/Icons';
import { RiskCheckboxAndConfirm } from './Checkboxes';
interface AuthProps {
available: number;
@ -35,6 +36,7 @@ export const LoginForm = ({
const { push } = useHistory();
const [viewOnly, setViewOnly] = useState(true);
const [checked, setChecked] = useState(false);
const [isName, setName] = useState('');
const [isHost, setHost] = useState('');
@ -131,7 +133,8 @@ export const LoginForm = ({
isName !== '' &&
isHost !== '' &&
(isAdmin !== '' || isRead !== '') &&
!!available;
!!available &&
checked;
return (
<>
<SingleLine>
@ -193,17 +196,12 @@ export const LoginForm = ({
onChange={e => setCert(e.target.value)}
/>
</Line>
{canConnect && (
<ColorButton
disabled={!canConnect}
onClick={handleClick}
withMargin={'16px 0 0'}
fullWidth={true}
arrow={true}
>
Connect
</ColorButton>
)}
<RiskCheckboxAndConfirm
disabled={!canConnect}
handleClick={handleClick}
checked={checked}
onChange={setChecked}
/>
</>
);
};

View file

@ -1,20 +1,15 @@
import React from 'react';
import { SingleLine, Sub4Title, SubTitle } from '../generic/Styled';
import { Sub4Title, SubTitle } from '../generic/Styled';
import zxcvbn from 'zxcvbn';
import styled from 'styled-components';
import { progressBackground } from '../../styles/Themes';
import { Loader } from '../generic/Icons';
import { ColorButton } from '../buttons/colorButton/ColorButton';
import { Input } from 'components/input/Input';
import { Line } from './Auth.styled';
const Progress = styled.div`
width: 80%;
margin: 10px 10px 10px 15px;
padding: 3px;
border-radius: 15px;
width: 100%;
background: ${progressBackground};
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.25),
0 1px rgba(255, 255, 255, 0.08);
`;
interface ProgressBar {
@ -24,12 +19,6 @@ interface ProgressBar {
const ProgressBar = styled.div`
height: 10px;
border-radius: 15px;
background-image: linear-gradient(
to bottom,
rgba(255, 255, 255, 0.3),
rgba(0, 0, 0, 0.05)
);
background-color: ${({ barColor }: ProgressBar) =>
barColor ? barColor : 'blue'};
width: ${({ percent }: ProgressBar) => `${percent}%`};
@ -66,15 +55,15 @@ export const PasswordInput = ({
loading = false,
}: PasswordProps) => {
const strength = (100 * Math.min(zxcvbn(isPass).guesses_log10, 40)) / 40;
const needed = 1;
const needed = 20;
return (
<>
<SubTitle>Please Input a Password</SubTitle>
<SingleLine>
<Line>
<Sub4Title>Password:</Sub4Title>
<Input onChange={e => setPass(e.target.value)} />
</SingleLine>
<SingleLine>
</Line>
<Line>
<Sub4Title>Strength:</Sub4Title>
<Progress>
<ProgressBar
@ -82,23 +71,17 @@ export const PasswordInput = ({
barColor={getColor(strength)}
/>
</Progress>
</SingleLine>
{strength >= needed && !loading && (
<ColorButton
disabled={strength < needed}
onClick={callback}
withMargin={'16px 0 0'}
fullWidth={true}
arrow={true}
>
Connect
</ColorButton>
)}
{loading && (
<ColorButton disabled={true} color={'grey'}>
<Loader />
</ColorButton>
)}
</Line>
<ColorButton
disabled={strength < needed}
onClick={callback}
withMargin={'32px 0 0'}
fullWidth={true}
arrow={true}
loading={loading}
>
Connect
</ColorButton>
</>
);
};

View file

@ -0,0 +1,16 @@
import React, { useState } from 'react';
import { Checkbox } from './Checkbox';
export default {
title: 'Checkbox',
};
export const Default = () => {
const [checked, set] = useState<boolean>(false);
return (
<Checkbox checked={checked} onChange={set}>
This is a checkbox
</Checkbox>
);
};

View file

@ -0,0 +1,58 @@
import React from 'react';
import styled from 'styled-components';
import {
colorButtonBackground,
buttonBorderColor,
themeColors,
} from '../../styles/Themes';
const StyledContainer = styled.div`
display: flex;
justify-content: flex-start;
align-items: center;
padding-right: 32px;
cursor: pointer;
`;
const FixedWidth = styled.div`
height: 18px;
width: 18px;
margin: 0px;
margin-right: 8px;
`;
const StyledCheckbox = styled.div`
height: 16px;
width: 16px;
margin: 0;
border: 1px solid ${buttonBorderColor};
border-radius: 4px;
outline: none;
transition-duration: 0.3s;
background-color: ${colorButtonBackground};
box-sizing: border-box;
border-radius: 50%;
${({ checked }: { checked: boolean }) =>
checked && `background-color: ${themeColors.blue2}`}
`;
type CheckboxProps = {
checked: boolean;
onChange: (state: boolean) => void;
};
export const Checkbox: React.FC<CheckboxProps> = ({
children,
checked,
onChange,
}) => {
return (
<StyledContainer onClick={() => onChange(!checked)}>
<FixedWidth>
<StyledCheckbox checked={checked} />
</FixedWidth>
{children}
</StyledContainer>
);
};

View file

@ -30,6 +30,7 @@ import { ReactComponent as LayersIcon } from '../../assets/icons/layers.svg';
import { ReactComponent as LoaderIcon } from '../../assets/icons/loader.svg';
import { ReactComponent as CircleIcon } from '../../assets/icons/circle.svg';
import { ReactComponent as AlertTriangleIcon } from '../../assets/icons/alert-triangle.svg';
import { ReactComponent as AlertCircleIcon } from '../../assets/icons/alert-circle.svg';
import { ReactComponent as GitCommitIcon } from '../../assets/icons/git-commit.svg';
import { ReactComponent as GitBranchIcon } from '../../assets/icons/git-branch.svg';
import { ReactComponent as RadioIcon } from '../../assets/icons/radio.svg';
@ -45,6 +46,7 @@ import { ReactComponent as Menu } from '../../assets/icons/menu.svg';
import { ReactComponent as Mail } from '../../assets/icons/mail.svg';
import { ReactComponent as Github } from '../../assets/icons/github.svg';
import { ReactComponent as Repeat } from '../../assets/icons/repeat.svg';
import { ReactComponent as CheckIcon } from '../../assets/icons/check.svg';
interface IconProps {
color?: string;
@ -97,6 +99,7 @@ export const Layers = styleIcon(LayersIcon);
export const Loader = styleIcon(LoaderIcon);
export const Circle = styleIcon(CircleIcon);
export const AlertTriangle = styleIcon(AlertTriangleIcon);
export const AlertCircle = styleIcon(AlertCircleIcon);
export const GitCommit = styleIcon(GitCommitIcon);
export const GitBranch = styleIcon(GitBranchIcon);
export const Radio = styleIcon(RadioIcon);
@ -112,3 +115,4 @@ export const MenuIcon = styleIcon(Menu);
export const MailIcon = styleIcon(Mail);
export const GithubIcon = styleIcon(Github);
export const RepeatIcon = styleIcon(Repeat);
export const Check = styleIcon(CheckIcon);

View file

@ -68,7 +68,18 @@ export const getAuthParams = (available: string) => {
export const getAuthLnd = (lndconnect: string) => {
const auth = lndconnect.replace('lndconnect', 'https');
const url = new URL(auth);
let url;
try {
url = new URL(auth);
} catch (error) {
return {
cert: '',
macaroon: '',
socket: '',
};
}
const cert = url.searchParams.get('cert') || '';
const macaroon = url.searchParams.get('macaroon') || '';

View file

@ -24,8 +24,8 @@ export const FaqView = () => {
<Section color={themeColors.grey} padding={'60px 0 16px'}>
<Question>What is ThunderHub?</Question>
<Text>
ThunderHub is a <b>LND node manager</b> that you can open on
any browser and any device.
ThunderHub is a <b>LND node manager</b> that you can open in
any browser and on any device.
</Text>
</Section>
<Section color={themeColors.grey} padding={'19px 0 16px'}>
@ -38,7 +38,7 @@ export const FaqView = () => {
<Section color={themeColors.grey} padding={'19px 0 16px'}>
<Question>What is the value of ThunderHub?</Question>
<Text>
ThunderHub brings a <b>full LND lightning node manager </b>
ThunderHub brings a <b>full lightning node manager </b>
directly to your device without the need of installing
plugins, extensions or apps, having specific browsers or
operating systems and is completely <b>open-source.</b>
@ -51,10 +51,7 @@ export const FaqView = () => {
with a password only you know.
</Text>
<Text>
<b>
No need to trust us, the code is public and available
for anyone to audit.
</b>
<b>The code is public and available for anyone to audit.</b>
</Text>
</Section>
<Section color={themeColors.grey} padding={'19px 0 16px'}>
@ -72,9 +69,15 @@ export const FaqView = () => {
<b> stored only in your browser. </b>
The password is only known by you and you need to unlock
your account everytime you want to perform an admin only
change such as managing channels or sending and recieving
change such as managing channels or sending and receiving
bitcoin or lightning payments.
</Text>
<Text>
The ThunderHub server uses your credentials to connect to
your node but they are never stored outside of your browser.
Still, this involves a certain degree of trust you must be
aware of.
</Text>
<Text>
If you want a more secure alternative, you can connect using
a view-only macaroon and use ThunderHub only for monitoring

View file

@ -26,7 +26,7 @@ export const PrivacyView = () => {
<Title>Privacy Policy</Title>
</Section>
<Section color={themeColors.grey} padding={'60px 0 16px'}>
<Text>Last Updated: January 30, 2020</Text>
<Text>Last Updated: February 12, 2020</Text>
</Section>
<Section color={themeColors.grey} padding={'19px 0 16px'}>
<Text>
@ -69,8 +69,9 @@ export const PrivacyView = () => {
Lightning node, we ask for sensitive information to do so.
This information is stored using your browser's own storage
APIs, and is encrypted using a password only known to the
user. This information is never recorded outside of the
user's browser storage.
user. This information is used by the server to connect to
your node but is never recorded outside of the user's
browser storage.
</Text>
<Text>
<b>Error Reporting / Usage Statistics</b> - No information