Skip to content

Commit

Permalink
Merge pull request #798 from jhaals/pw-retry
Browse files Browse the repository at this point in the history
Add ability to retry decryption, merge routes
  • Loading branch information
jhaals committed Mar 4, 2021
2 parents 7354e48 + 9e422e1 commit 6075b07
Show file tree
Hide file tree
Showing 15 changed files with 169 additions and 177 deletions.
2 changes: 1 addition & 1 deletion website/cypress/integration/create_secret.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('Create Secret', () => {

cy.get(linkSelector).should(
'contain',
'http://localhost:3000/#/c/75c3383d-a0d9-4296-8ca8-026cc2272271',
'http://localhost:3000/#/s/75c3383d-a0d9-4296-8ca8-026cc2272271',
);

cy.wait('@post').then(mockGetResponse);
Expand Down
10 changes: 3 additions & 7 deletions website/cypress/integration/upload_file.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ describe('Upload/Download File', () => {
.invoke('text')
.then((text) => {
cy.visit(text);
cy.contains(
'Downloading file and decrypting in browser, please hold...',
);
cy.contains('File downloaded');
// File downloads not supported in headless mode.
// https://github.com/cypress-io/cypress/issues/949
cy.readFile('cypress/downloads/data.txt').then((f) => {
Expand All @@ -38,7 +36,7 @@ describe('Upload/Download File', () => {
cy.get('input').attachFile('data.txt');
cy.get(linkSelector).should(
'contain',
'http://localhost:3000/#/d/75c3383d-a0d9-4296-8ca8-026cc2272271',
'http://localhost:3000/#/f/75c3383d-a0d9-4296-8ca8-026cc2272271',
);
cy.wait('@post').then(mockGetResponse);

Expand All @@ -48,9 +46,7 @@ describe('Upload/Download File', () => {
cy.visit(text);
cy.get('input').type(password);
cy.get('button').click();
cy.contains(
'Downloading file and decrypting in browser, please hold...',
);
cy.contains('File downloaded');
// File downloads not supported in headless mode.
// https://github.com/cypress-io/cypress/issues/949
cy.readFile('cypress/downloads/data.txt').then((f) => {
Expand Down
3 changes: 2 additions & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"react-i18next": "^11.8.8",
"react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3",
"react-use": "^17.1.1"
"react-use": "^17.1.1",
"swr": "^0.4.2"
},
"scripts": {
"start": "react-scripts start",
Expand Down
4 changes: 3 additions & 1 deletion website/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
"Generate decryption key": "Generate decryption key",
"Checkbox for toggling manual decryption key input": "Checkbox for toggling manual decryption key input",
"Encrypting message...": "Encrypting message...",
"File downloaded": "File downloaded",
"Encrypt Message": "Encrypt Message",
"One-time download": "One-time download",
"One Hour": "One Hour",
"One Day": "One Day",
"One Week": "One Week",
"The decryption key is randomly generated by default": "The decryption key is randomly generated by default. You can optionally set this value manually.",
"The encrypted message will be deleted automatically after": "The encrypted message will be deleted automatically after",
"Fetching from database and decrypting in browser, please hold...": "Fetching from database and decrypting in browser, please hold...",
"Fetching from database, please hold...": "Fetching from database, please hold...",
"Decrypting, please hold...": "Decrypting, please hold...",
"This secret might not be viewable again, make sure to save it now!": "This secret might not be viewable again, make sure to save it now!",
"Downloading file and decrypting in browser, please hold...": "Downloading file and decrypting in browser, please hold...",
"Make sure to download the file since it is only available once": "Make sure to download the file since it is only available once",
Expand Down
9 changes: 2 additions & 7 deletions website/src/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Route } from 'react-router-dom';

import CreateSecret from './createSecret/CreateSecret';
import DisplaySecret from './displaySecret/DisplaySecret';
import Download from './displaySecret/Download';
import Upload from './createSecret/Upload';

export const Routes = () => {
Expand All @@ -11,13 +10,9 @@ export const Routes = () => {
<Route path="/" exact={true} component={CreateSecret} />
<Route path="/upload" exact={true} component={Upload} />
<Route exact={true} path="/s/:key/:password" component={DisplaySecret} />
<Route exact={true} path="/c/:key/:password" component={DisplaySecret} />
<Route exact={true} path="/s/:key" component={DisplaySecret} />
<Route exact={true} path="/c/:key" component={DisplaySecret} />
<Route exact={true} path="/f/:key/:password" component={Download} />
<Route exact={true} path="/f/:key" component={Download} />
<Route exact={true} path="/d/:key" component={Download} />
<Route exact={true} path="/d/:key/:password" component={Download} />
<Route exact={true} path="/f/:key/:password" component={DisplaySecret} />
<Route exact={true} path="/f/:key" component={DisplaySecret} />
</div>
);
};
7 changes: 4 additions & 3 deletions website/src/createSecret/CreateSecret.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ const CreateSecret = () => {
const [loading, setLoading] = useState(false);
const [result, setResult] = useState({
password: '',
prefix: '',
uuid: '',
customPassword: false,
});

const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
Expand All @@ -61,7 +61,7 @@ const CreateSecret = () => {
setError('secret', { type: 'submit', message: data.message });
} else {
setResult({
prefix: form.password ? 'c' : 's',
customPassword: form.password ? true : false,
password: pw,
uuid: data.message,
});
Expand All @@ -79,7 +79,8 @@ const CreateSecret = () => {
<Result
password={result.password}
uuid={result.uuid}
prefix={result.prefix}
prefix="s"
customPassword={result.customPassword}
/>
);
}
Expand Down
54 changes: 0 additions & 54 deletions website/src/createSecret/Form.tsx

This file was deleted.

7 changes: 4 additions & 3 deletions website/src/createSecret/Upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const Upload = () => {
const { t } = useTranslation();
const [result, setResult] = useState({
password: '',
prefix: '',
customPassword: false,
uuid: '',
});

Expand Down Expand Up @@ -65,7 +65,7 @@ const Upload = () => {
setResult({
uuid: data.message,
password: pw,
prefix: form.password ? 'd' : 'f',
customPassword: form.password ? true : false,
});
}
};
Expand Down Expand Up @@ -98,7 +98,8 @@ const Upload = () => {
<Result
uuid={result.uuid}
password={result.password}
prefix={result.prefix}
prefix="f"
customPassword={result.customPassword}
/>
);
}
Expand Down
131 changes: 106 additions & 25 deletions website/src/displaySecret/DisplaySecret.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,123 @@
import React, { useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import Error from './Error';
import Form from '../createSecret/Form';
import useSWR from 'swr';
import { backendDomain, decryptMessage } from '../utils/utils';
import { useAsync } from 'react-use';
import Loading from '../shared/Loading';
import Secret from './Secret';
import ErrorPage from './Error';
import {
Container,
Grid,
TextField,
Button,
Typography,
} from '@material-ui/core';
import { useTranslation } from 'react-i18next';
import { useAsync } from 'react-use';

export type DisplayParams = {
key: string;
password: string;
const fetcher = async (url: string) => {
const request = await fetch(url);
if (!request.ok) {
throw new Error('Failed to fetch secret');
}
const data = await request.json();
return data.message;
};

const DisplaySecret = () => {
const { key, password } = useParams<DisplayParams>();
const { key, password: paramsPassword } = useParams<{
key: string;
password: string;
}>();
const location = useLocation();
const isEncoded = null !== location.pathname.match(/\/c\//);
const isFile = null !== location.pathname.match(/\/d|f\//);
const [password, setPassword] = useState(
paramsPassword ? paramsPassword : '',
);
const [secret, setSecret] = useState('');
const [fileName, setFileName] = useState('');
const [invalidPassword, setInvalidPassword] = useState(false);
const { t } = useTranslation();

const url = isFile
? `${backendDomain}/file/${key}`
: `${backendDomain}/secret/${key}`;
const { data, error } = useSWR(url, fetcher, {
shouldRetryOnError: false,
revalidateOnFocus: false,
});

const { value, error, loading } = useAsync(async () => {
if (!password) {
useAsync(async () => {
return decrypt();
}, [paramsPassword, data]);

const decrypt = async () => {
if (!data || !password) {
return;
}
const request = await fetch(`${backendDomain}/secret/${key}`);
const data = await request.json();
const r = await decryptMessage(
data.message,
isEncoded ? atob(password) : password,
'utf8',
try {
const r = await decryptMessage(
data,
password,
isFile ? 'binary' : 'utf8',
);
if (isFile) {
setFileName(r.filename);
}
setSecret(r.data);
} catch (e) {
setInvalidPassword(true);
return false;
}
return true;
};

if (error) return <ErrorPage error={error} />;
if (!data)
return (
<Typography variant="h4">
{t('Fetching from database, please hold...')}
</Typography>
);
if (secret) {
return <Secret secret={secret} fileName={fileName} />;
}
if (paramsPassword && !secret && !invalidPassword) {
return (
<Typography variant="h4">{t('Decrypting, please hold...')}</Typography>
);
return r.data as string;
}, [isEncoded, password, key]);
}

return (
<div>
{loading && <Loading />}
<Error error={error} />
<Secret secret={value} />
{!password && <Form uuid={key} prefix={isEncoded ? 'c' : 's'} />}
</div>
<Container maxWidth="lg">
<Grid container direction="column" spacing={1}>
<Grid item xs={12}>
<Typography variant="h5">Enter decryption key</Typography>
<Typography variant="caption">
Do not refresh this window as secret might be restricted to one time
download.
</Typography>
</Grid>
<Grid item xs={12}>
<TextField
fullWidth
autoFocus
name="decryptionKey"
id="decryptionKey"
placeholder={t('Decryption Key')}
label={t('A decryption key is required, please enter it below')}
value={password}
error={invalidPassword}
helperText={invalidPassword && 'Invalid password, please try again'}
onChange={(e) => setPassword(e.target.value)}
/>
</Grid>
<Grid item xs={12}>
<Button variant="contained" onClick={decrypt}>
{t('Decrypt Secret')}
</Button>
</Grid>
</Grid>
</Container>
);
};

Expand Down
Loading

0 comments on commit 6075b07

Please sign in to comment.