mirror of
https://github.com/morten-olsen/parcel.git
synced 2026-02-08 01:36:24 +01:00
chore: quality of life improvements (#449)
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
import { Layout } from 'antd';
|
||||
import { HashRouter as Router } from 'react-router-dom';
|
||||
import { GithubProvider } from './contexts/Github';
|
||||
@@ -12,9 +11,9 @@ const App: React.FC = () => {
|
||||
<GithubProvider>
|
||||
<EncryptionProvider>
|
||||
<DecryptionProvider>
|
||||
<Layout style={{minHeight:"100vh"}}>
|
||||
<Layout style={{ minHeight: '100vh' }}>
|
||||
<Router>
|
||||
<AppRouter/>
|
||||
<AppRouter />
|
||||
</Router>
|
||||
</Layout>
|
||||
</DecryptionProvider>
|
||||
@@ -23,4 +22,4 @@ const App: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default hot(App);
|
||||
export default App;
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Routes,
|
||||
Route,
|
||||
useNavigate,
|
||||
} from 'react-router-dom';
|
||||
import { HomeFilled } from '@ant-design/icons';
|
||||
import { Routes, Route, useNavigate } from 'react-router-dom';
|
||||
import { HomeFilled } from '@ant-design/icons';
|
||||
import { Layout, Button, Space } from 'antd';
|
||||
|
||||
import Intro from './screens/Intro';
|
||||
@@ -19,14 +15,18 @@ const AppRouter: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
<Button
|
||||
onClick={() => navigate('/')}
|
||||
icon={<HomeFilled />}
|
||||
>
|
||||
<Button onClick={() => navigate('/')} icon={<HomeFilled />}>
|
||||
Home
|
||||
</Button>
|
||||
</Space>
|
||||
<Layout.Content style={{ padding: '25px', maxWidth: '800px', width: '100%', margin: 'auto' }}>
|
||||
<Layout.Content
|
||||
style={{
|
||||
padding: '25px',
|
||||
maxWidth: '800px',
|
||||
width: '100%',
|
||||
margin: 'auto',
|
||||
}}
|
||||
>
|
||||
<Routes>
|
||||
<Route path="/debug" element={<Debug />} />
|
||||
<Route path="/welcome" element={<Welcome />} />
|
||||
@@ -38,6 +38,6 @@ const AppRouter: React.FC = () => {
|
||||
</Layout.Content>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default AppRouter;
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
List,
|
||||
Button,
|
||||
Popconfirm,
|
||||
} from 'antd';
|
||||
import { List, Button, Popconfirm } from 'antd';
|
||||
import {
|
||||
DeleteOutlined,
|
||||
SyncOutlined,
|
||||
@@ -25,24 +21,17 @@ const iconStyle = {
|
||||
},
|
||||
};
|
||||
|
||||
const icons: {[name: string]: any} = {
|
||||
const icons: { [name: string]: any } = {
|
||||
processing: <SyncOutlined spin {...iconStyle} />,
|
||||
failed: <IssuesCloseOutlined {...iconStyle} />,
|
||||
success: <LockOutlined {...iconStyle} />,
|
||||
};
|
||||
|
||||
const IconText = ({ icon, text, ...props }) => (
|
||||
<Button
|
||||
{...props}
|
||||
shape="round"
|
||||
icon={React.createElement(icon)}
|
||||
/>
|
||||
<Button {...props} shape="round" icon={React.createElement(icon)} />
|
||||
);
|
||||
|
||||
const FileView: React.FC<Props> = ({
|
||||
file,
|
||||
remove,
|
||||
}) => {
|
||||
const FileView: React.FC<Props> = ({ file, remove }) => {
|
||||
const icon = icons[file.status];
|
||||
const actions = [];
|
||||
|
||||
@@ -54,11 +43,7 @@ const FileView: React.FC<Props> = ({
|
||||
okText="Yes"
|
||||
cancelText="No"
|
||||
>
|
||||
<IconText
|
||||
icon={DeleteOutlined}
|
||||
danger
|
||||
text="Delete"
|
||||
/>
|
||||
<IconText icon={DeleteOutlined} danger text="Delete" />
|
||||
</Popconfirm>
|
||||
);
|
||||
}
|
||||
@@ -76,14 +61,8 @@ const FileView: React.FC<Props> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<List.Item
|
||||
actions={actions}
|
||||
className="msg-item"
|
||||
>
|
||||
<List.Item.Meta
|
||||
avatar={icon}
|
||||
title={file.name}
|
||||
/>
|
||||
<List.Item actions={actions} className="msg-item">
|
||||
<List.Item.Meta avatar={icon} title={file.name} />
|
||||
</List.Item>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -6,29 +6,22 @@ import File from './File';
|
||||
import FileType from '../types/File';
|
||||
|
||||
interface Props {
|
||||
files: {[id: string]: FileType};
|
||||
files: { [id: string]: FileType };
|
||||
deleteFile: (id: string) => void;
|
||||
}
|
||||
|
||||
const Encrypt: React.FC<Props> = ({
|
||||
files,
|
||||
deleteFile,
|
||||
}) => {
|
||||
const Encrypt: React.FC<Props> = ({ files, deleteFile }) => {
|
||||
const { status, downloadAll } = useDownloadAll();
|
||||
|
||||
if (Object.keys(files).length === 0) {
|
||||
return <Empty />
|
||||
return <Empty />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Space direction="vertical" style={{width: '100%' }}>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<List>
|
||||
{Object.entries(files).map(([id, file]) => (
|
||||
<File
|
||||
key={id}
|
||||
file={file}
|
||||
remove={() => deleteFile(id)}
|
||||
/>
|
||||
<File key={id} file={file} remove={() => deleteFile(id)} />
|
||||
))}
|
||||
</List>
|
||||
{downloadAll && (
|
||||
|
||||
@@ -20,10 +20,13 @@ const DropWrapper = styled(Layout)`
|
||||
|
||||
const AddFile: React.FC = () => {
|
||||
const { addFile } = useContext(DecryptionContext);
|
||||
const onDrop = useCallback(acceptedFiles => {
|
||||
acceptedFiles.forEach(addFile);
|
||||
}, [addFile])
|
||||
const {getRootProps, getInputProps} = useDropzone({ onDrop });
|
||||
const onDrop = useCallback(
|
||||
(acceptedFiles) => {
|
||||
acceptedFiles.forEach(addFile);
|
||||
},
|
||||
[addFile]
|
||||
);
|
||||
const { getRootProps, getInputProps } = useDropzone({ onDrop });
|
||||
return (
|
||||
<DropWrapper {...getRootProps()}>
|
||||
<input {...getInputProps()} />
|
||||
|
||||
@@ -12,9 +12,16 @@ const Add: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<Divider>
|
||||
<Radio.Group onChange={evt => setType(evt.target.value)} defaultValue={DEFAULT_VALUE}>
|
||||
<Radio.Button className="add-text-tab" value="text"><FileTextOutlined /> Text</Radio.Button>
|
||||
<Radio.Button className="add-file-tab" value="file"><FileOutlined /> File</Radio.Button>
|
||||
<Radio.Group
|
||||
onChange={(evt) => setType(evt.target.value)}
|
||||
defaultValue={DEFAULT_VALUE}
|
||||
>
|
||||
<Radio.Button className="add-text-tab" value="text">
|
||||
<FileTextOutlined /> Text
|
||||
</Radio.Button>
|
||||
<Radio.Button className="add-file-tab" value="file">
|
||||
<FileOutlined /> File
|
||||
</Radio.Button>
|
||||
</Radio.Group>
|
||||
</Divider>
|
||||
{type === 'text' && <AddText />}
|
||||
|
||||
@@ -20,10 +20,13 @@ const DropWrapper = styled(Layout)`
|
||||
|
||||
const AddFile: React.FC = () => {
|
||||
const { addFile } = useContext(EncryptionContext);
|
||||
const onDrop = useCallback(acceptedFiles => {
|
||||
acceptedFiles.forEach(addFile);
|
||||
}, [addFile])
|
||||
const {getRootProps, getInputProps} = useDropzone({ onDrop });
|
||||
const onDrop = useCallback(
|
||||
(acceptedFiles) => {
|
||||
acceptedFiles.forEach(addFile);
|
||||
},
|
||||
[addFile]
|
||||
);
|
||||
const { getRootProps, getInputProps } = useDropzone({ onDrop });
|
||||
return (
|
||||
<DropWrapper {...getRootProps()}>
|
||||
<input {...getInputProps()} />
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Input, Form, Button } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import EncryptionContext from '../../contexts/Encryption';
|
||||
|
||||
const AddText : React.FC = () => {
|
||||
const AddText: React.FC = () => {
|
||||
const { addText } = useContext(EncryptionContext);
|
||||
const [name, setName] = useState('');
|
||||
const [text, setText] = useState('');
|
||||
@@ -21,16 +21,16 @@ const AddText : React.FC = () => {
|
||||
placeholder="Title (Not encrypted)"
|
||||
className="msg-title"
|
||||
value={name}
|
||||
onChange={evt => setName(evt.target.value)}
|
||||
onChange={(evt) => setName(evt.target.value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Input.TextArea
|
||||
className="msg-body"
|
||||
placeholder="Your message here..."
|
||||
value={text}
|
||||
value={text}
|
||||
rows={6}
|
||||
onChange={evt => setText(evt.target.value)}
|
||||
onChange={(evt) => setText(evt.target.value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
@@ -49,4 +49,3 @@ const AddText : React.FC = () => {
|
||||
};
|
||||
|
||||
export default AddText;
|
||||
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
import React, { useState, useCallback, useContext, createContext, useEffect } from 'react';
|
||||
import { readMessage, readKey, decrypt as pgpDecrypt, readPrivateKeys, readPrivateKey, generateKey } from 'openpgp';
|
||||
import React, {
|
||||
useState,
|
||||
useCallback,
|
||||
useContext,
|
||||
createContext,
|
||||
useEffect,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import {
|
||||
readMessage,
|
||||
readKey,
|
||||
decrypt as pgpDecrypt,
|
||||
readPrivateKeys,
|
||||
readPrivateKey,
|
||||
generateKey,
|
||||
} from 'openpgp';
|
||||
import GithubContext from './Github';
|
||||
import FileType from '../types/File';
|
||||
import { createFile } from '../helpers/files';
|
||||
@@ -9,11 +23,15 @@ interface DecryptionContextType {
|
||||
privateKey: string | undefined;
|
||||
createKey: (name: string, email: string) => void;
|
||||
deleteKey: () => void;
|
||||
files: {[id: string]: FileType};
|
||||
files: { [id: string]: FileType };
|
||||
addFile: (file: File) => Promise<void>;
|
||||
deleteFile: (id: string) => void;
|
||||
}
|
||||
|
||||
type DecryptionProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const removeExtension = (name: string) => {
|
||||
const parts = name.split('.');
|
||||
parts.pop();
|
||||
@@ -24,21 +42,32 @@ const DecryptionContext = createContext<DecryptionContextType>({
|
||||
publicKey: undefined,
|
||||
privateKey: undefined,
|
||||
files: {},
|
||||
createKey: async () => { throw new Error('Not using provider'); },
|
||||
deleteKey: async () => { throw new Error('Not using provider'); },
|
||||
addFile: async () => { throw new Error('Not using provider'); },
|
||||
deleteFile: async () => { throw new Error('Not using provider'); },
|
||||
createKey: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
deleteKey: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
addFile: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
deleteFile: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
});
|
||||
|
||||
const decrypt = async (privateKey: string, keys: string[], content: string) => {
|
||||
const armoredKeys = await Promise.all(
|
||||
keys.map(key => readKey({ armoredKey: key })),
|
||||
keys.map((key) => readKey({ armoredKey: key }))
|
||||
);
|
||||
const message = await readMessage({ armoredMessage: content });
|
||||
const encrypted = await pgpDecrypt({
|
||||
message,
|
||||
decryptionKeys: await readPrivateKeys({ armoredKeys: privateKey }),
|
||||
verificationKeys: armoredKeys.reduce<any>((output, key: any) => [...output, ...key], []),
|
||||
verificationKeys: armoredKeys.reduce<any>(
|
||||
(output, key: any) => [...output, ...key],
|
||||
[]
|
||||
),
|
||||
});
|
||||
const { data } = encrypted;
|
||||
const blob = new Blob([data as any], {
|
||||
@@ -47,7 +76,7 @@ const decrypt = async (privateKey: string, keys: string[], content: string) => {
|
||||
return blob;
|
||||
};
|
||||
|
||||
const DecryptionProvider: React.FC = ({
|
||||
const DecryptionProvider: React.FC<DecryptionProviderProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { keys } = useContext(GithubContext);
|
||||
@@ -55,12 +84,15 @@ const DecryptionProvider: React.FC = ({
|
||||
const [publicKey, setPublicKey] = useState<string | undefined>(undefined);
|
||||
const [files, setFiles] = useState<DecryptionContextType['files']>({});
|
||||
|
||||
const deleteFile = useCallback((id: string) => {
|
||||
delete files[id];
|
||||
setFiles({
|
||||
...files,
|
||||
});
|
||||
}, [files]);
|
||||
const deleteFile = useCallback(
|
||||
(id: string) => {
|
||||
delete files[id];
|
||||
setFiles({
|
||||
...files,
|
||||
});
|
||||
},
|
||||
[files]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const run = async () => {
|
||||
@@ -83,29 +115,34 @@ const DecryptionProvider: React.FC = ({
|
||||
|
||||
const createKey = async () => {
|
||||
const key = await generateKey({
|
||||
userIDs: [{ name: 'unknown unknown', email: 'unknown@unknown.foo'}],
|
||||
userIDs: [{ name: 'unknown unknown', email: 'unknown@unknown.foo' }],
|
||||
curve: 'ed25519',
|
||||
});
|
||||
|
||||
setPrivateKey(key.privateKey);
|
||||
setPublicKey(key.publicKey);
|
||||
localStorage.setItem('key', key.privateKey);
|
||||
}
|
||||
};
|
||||
|
||||
const addFile = useCallback(async (file: File) => {
|
||||
if (!keys || !privateKey) return;
|
||||
const addedFile = createFile(setFiles, removeExtension(file.name));
|
||||
const reader = new FileReader()
|
||||
const addFile = useCallback(
|
||||
async (file: File) => {
|
||||
if (!keys || !privateKey) {
|
||||
return;
|
||||
}
|
||||
const addedFile = createFile(setFiles, removeExtension(file.name));
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onabort = addedFile.setFailed,
|
||||
reader.onerror = addedFile.setFailed,
|
||||
reader.onload = () => {
|
||||
addedFile.setContent(
|
||||
decrypt(privateKey, keys, reader.result as string),
|
||||
);
|
||||
}
|
||||
reader.readAsText(file);
|
||||
}, [keys, privateKey]);
|
||||
(reader.onabort = addedFile.setFailed),
|
||||
(reader.onerror = addedFile.setFailed),
|
||||
(reader.onload = () => {
|
||||
addedFile.setContent(
|
||||
decrypt(privateKey, keys, reader.result as string)
|
||||
);
|
||||
});
|
||||
reader.readAsText(file);
|
||||
},
|
||||
[keys, privateKey]
|
||||
);
|
||||
|
||||
return (
|
||||
<DecryptionContext.Provider
|
||||
@@ -124,8 +161,6 @@ const DecryptionProvider: React.FC = ({
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
DecryptionProvider,
|
||||
};
|
||||
export { DecryptionProvider };
|
||||
|
||||
export default DecryptionContext;;
|
||||
export default DecryptionContext;
|
||||
|
||||
@@ -1,31 +1,50 @@
|
||||
import React, { useState, useCallback, useContext, createContext } from 'react';
|
||||
import React, {
|
||||
useState,
|
||||
useCallback,
|
||||
useContext,
|
||||
createContext,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import * as openpgp from 'openpgp';
|
||||
import GithubContext from './Github';
|
||||
import { createFile } from '../helpers/files';
|
||||
import FileType from '../types/File';
|
||||
|
||||
interface EncryptionContextType {
|
||||
files: {[id: string]: FileType};
|
||||
files: { [id: string]: FileType };
|
||||
addFile: (file: File) => Promise<void>;
|
||||
addText: (text: string, name: string) => Promise<void>;
|
||||
deleteFile: (id: string) => void;
|
||||
}
|
||||
|
||||
type EncryptionProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const EncryptionContext = createContext<EncryptionContextType>({
|
||||
files: {},
|
||||
addFile: async () => { throw new Error('Not using provider'); },
|
||||
addText: async () => { throw new Error('Not using provider'); },
|
||||
deleteFile: async () => { throw new Error('Not using provider'); },
|
||||
addFile: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
addText: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
deleteFile: async () => {
|
||||
throw new Error('Not using provider');
|
||||
},
|
||||
});
|
||||
|
||||
const encrypt = async (keys: string[], content: string) => {
|
||||
const armoredKeys = await Promise.all(
|
||||
keys.map(key => openpgp.readKeys({ armoredKeys: key })),
|
||||
keys.map((key) => openpgp.readKeys({ armoredKeys: key }))
|
||||
);
|
||||
const message = await openpgp.createMessage({ text: content });
|
||||
const encrypted = await openpgp.encrypt({
|
||||
message,
|
||||
encryptionKeys: armoredKeys.reduce<any>((output, key: any) => [...output, ...key], []),
|
||||
encryptionKeys: armoredKeys.reduce<any>(
|
||||
(output, key: any) => [...output, ...key],
|
||||
[]
|
||||
),
|
||||
});
|
||||
const data = encrypted;
|
||||
const blob = new Blob([data as any], {
|
||||
@@ -34,41 +53,50 @@ const encrypt = async (keys: string[], content: string) => {
|
||||
return blob;
|
||||
};
|
||||
|
||||
const EncryptionProvider: React.FC = ({
|
||||
const EncryptionProvider: React.FC<EncryptionProviderProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { username, keys } = useContext(GithubContext);
|
||||
const [files, setFiles] = useState<EncryptionContextType['files']>({});
|
||||
|
||||
const deleteFile = useCallback((id: string) => {
|
||||
delete files[id];
|
||||
setFiles({
|
||||
...files,
|
||||
});
|
||||
}, [files]);
|
||||
const deleteFile = useCallback(
|
||||
(id: string) => {
|
||||
delete files[id];
|
||||
setFiles({
|
||||
...files,
|
||||
});
|
||||
},
|
||||
[files]
|
||||
);
|
||||
|
||||
const addFile = useCallback(async (file: File) => {
|
||||
if (!keys) return;
|
||||
const addedFile = createFile(setFiles, `${file.name}.acs`);
|
||||
const reader = new FileReader()
|
||||
const addFile = useCallback(
|
||||
async (file: File) => {
|
||||
if (!keys) {
|
||||
return;
|
||||
}
|
||||
const addedFile = createFile(setFiles, `${file.name}.acs`);
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onabort = addedFile.setFailed,
|
||||
reader.onerror = addedFile.setFailed,
|
||||
reader.onload = () => {
|
||||
addedFile.setContent(
|
||||
encrypt(keys, reader.result as string),
|
||||
);
|
||||
}
|
||||
reader.readAsText(file)
|
||||
}, [keys, username]);
|
||||
(reader.onabort = addedFile.setFailed),
|
||||
(reader.onerror = addedFile.setFailed),
|
||||
(reader.onload = () => {
|
||||
addedFile.setContent(encrypt(keys, reader.result as string));
|
||||
});
|
||||
reader.readAsText(file);
|
||||
},
|
||||
[keys, username]
|
||||
);
|
||||
|
||||
const addText = useCallback(async (text: string, name: string) => {
|
||||
if (!keys) return;
|
||||
const file = createFile(setFiles, `${name}.txt.asc`);
|
||||
file.setContent(
|
||||
encrypt(keys, text),
|
||||
);
|
||||
}, [keys, username]);
|
||||
const addText = useCallback(
|
||||
async (text: string, name: string) => {
|
||||
if (!keys) {
|
||||
return;
|
||||
}
|
||||
const file = createFile(setFiles, `${name}.txt.asc`);
|
||||
file.setContent(encrypt(keys, text));
|
||||
},
|
||||
[keys, username]
|
||||
);
|
||||
|
||||
return (
|
||||
<EncryptionContext.Provider
|
||||
@@ -84,9 +112,6 @@ const EncryptionProvider: React.FC = ({
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
EncryptionProvider,
|
||||
};
|
||||
export { EncryptionProvider };
|
||||
|
||||
export default EncryptionContext;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { createContext } from 'react';
|
||||
import React, { createContext, ReactNode } from 'react';
|
||||
|
||||
declare var data: any;
|
||||
|
||||
@@ -7,19 +7,17 @@ interface GithubContextType {
|
||||
keys?: string[];
|
||||
}
|
||||
|
||||
type GithubProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const GithubContext = createContext<GithubContextType>(data);
|
||||
const GithubProvider: React.FC = ({
|
||||
children,
|
||||
}) => (
|
||||
<GithubContext.Provider
|
||||
value={{ ...data }}
|
||||
>
|
||||
const GithubProvider: React.FC<GithubProviderProps> = ({ children }) => (
|
||||
<GithubContext.Provider value={{ ...data }}>
|
||||
{children}
|
||||
</GithubContext.Provider>
|
||||
);
|
||||
|
||||
export {
|
||||
GithubProvider,
|
||||
};
|
||||
export { GithubProvider };
|
||||
|
||||
export default GithubContext;
|
||||
|
||||
@@ -11,7 +11,7 @@ export const downloadLink = (name: string, blob: Blob) => {
|
||||
document.body.removeChild(downloadLink);
|
||||
};
|
||||
|
||||
//type SetFilesType = (fn: (files: {[id: string]: File}) => {[id: string]: File}) => any;
|
||||
//type SetFilesType = (fn: (files: {[id: string]: File}) => {[id: string]: File}) => any;
|
||||
type SetFilesType = any;
|
||||
|
||||
export const createFile = (setFiles: SetFilesType, name: string) => {
|
||||
@@ -38,7 +38,7 @@ export const createFile = (setFiles: SetFilesType, name: string) => {
|
||||
}));
|
||||
})
|
||||
.catch(setFailed);
|
||||
}
|
||||
};
|
||||
|
||||
const setFailed = (err: any) => {
|
||||
console.error(err);
|
||||
|
||||
@@ -8,7 +8,8 @@ type Statuses = 'packing' | 'ready';
|
||||
const useDownloadAll = () => {
|
||||
const [status, setStatus] = useState<Statuses>('ready');
|
||||
const { files } = useContext(EncryptionContext);
|
||||
const allFilesReady = Object.values(files).filter(f => f.status === 'success').length > 1;
|
||||
const allFilesReady =
|
||||
Object.values(files).filter((f) => f.status === 'success').length > 1;
|
||||
|
||||
const downloadAll = useCallback(() => {
|
||||
setStatus('packing');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import 'antd/dist/antd.css';
|
||||
import { render } from 'react-dom';
|
||||
import { render } from 'react-dom';
|
||||
import App from './App';
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
Table,
|
||||
} from 'antd';
|
||||
import { Table } from 'antd';
|
||||
import config from '../config';
|
||||
|
||||
const columns = [{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
}, {
|
||||
title: 'Value',
|
||||
dataIndex: 'value',
|
||||
key: 'value',
|
||||
}];
|
||||
const columns = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: 'Value',
|
||||
dataIndex: 'value',
|
||||
key: 'value',
|
||||
},
|
||||
];
|
||||
|
||||
const Debug: React.FC = () => {
|
||||
const data = useMemo(() => {
|
||||
const vals = {
|
||||
'Repository': config.repo,
|
||||
'User': config.user,
|
||||
Repository: config.repo,
|
||||
User: config.user,
|
||||
'Is Production': config.isProd,
|
||||
};
|
||||
|
||||
@@ -29,9 +30,7 @@ const Debug: React.FC = () => {
|
||||
}));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Table dataSource={data} columns={columns} />
|
||||
);
|
||||
return <Table dataSource={data} columns={columns} />;
|
||||
};
|
||||
|
||||
export default Debug;
|
||||
|
||||
@@ -13,10 +13,7 @@ const Decrypt: React.FC = () => {
|
||||
{Object.keys(files).length > 0 && (
|
||||
<>
|
||||
<Divider>Files</Divider>
|
||||
<FileList
|
||||
files={files}
|
||||
deleteFile={deleteFile}
|
||||
/>
|
||||
<FileList files={files} deleteFile={deleteFile} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -13,13 +13,18 @@ const Encrypt: React.FC = () => {
|
||||
{Object.keys(files).length > 0 && (
|
||||
<>
|
||||
<Divider>Files</Divider>
|
||||
<FileList
|
||||
files={files}
|
||||
deleteFile={deleteFile}
|
||||
/>
|
||||
<FileList files={files} deleteFile={deleteFile} />
|
||||
<Divider />
|
||||
<i style={{ textAlign: 'center', paddingTop: '10px', display: 'block', fontSize: 12 }}>
|
||||
Note: files are not send to me, you still have to download the encrypted files and send it to me.
|
||||
<i
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
paddingTop: '10px',
|
||||
display: 'block',
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
Note: files are not send to me, you still have to download the
|
||||
encrypted files and send it to me.
|
||||
</i>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import Welcome from './Welcome';
|
||||
import {
|
||||
Button,
|
||||
Space,
|
||||
} from 'antd';
|
||||
import { Button, Space } from 'antd';
|
||||
import {
|
||||
UploadOutlined,
|
||||
DownloadOutlined,
|
||||
KeyOutlined,
|
||||
} from '@ant-design/icons';
|
||||
|
||||
|
||||
const Thumb: React.FC = ({
|
||||
title,
|
||||
Icon,
|
||||
link,
|
||||
className,
|
||||
}) => {
|
||||
const Thumb: React.FC = ({ title, Icon, link, className }) => {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<Button
|
||||
@@ -43,7 +34,7 @@ const Intro = () => {
|
||||
link="/send"
|
||||
className="send-btn"
|
||||
Icon={UploadOutlined}
|
||||
/>
|
||||
/>
|
||||
<Thumb
|
||||
link="/key"
|
||||
className="want-to-receive-btn"
|
||||
|
||||
@@ -10,11 +10,7 @@ import {
|
||||
} from '@ant-design/icons';
|
||||
|
||||
const SetupKey: React.FC = () => {
|
||||
const {
|
||||
createKey,
|
||||
deleteKey,
|
||||
publicKey,
|
||||
} = useContext(DecryptionContext);
|
||||
const { createKey, deleteKey, publicKey } = useContext(DecryptionContext);
|
||||
|
||||
const [name, setName] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
@@ -33,15 +29,15 @@ const SetupKey: React.FC = () => {
|
||||
if (!publicKey) {
|
||||
return (
|
||||
<>
|
||||
<Space direction="vertical" style={{ textAlign: 'center' }} >
|
||||
<Space direction="vertical" style={{ textAlign: 'center' }}>
|
||||
<LockTwoTone style={{ fontSize: 150 }} />
|
||||
<Typography.Title>Create your sharing key</Typography.Title>
|
||||
<p>
|
||||
Before I can send protected information to you I need a "sharing" key, which is a key that gets stored this device, allowing this device (and this device only) to read the informations I am sending.
|
||||
</p>
|
||||
<p>
|
||||
After creating it you need to send it to me
|
||||
Before I can send protected information to you I need a "sharing"
|
||||
key, which is a key that gets stored this device, allowing this
|
||||
device (and this device only) to read the informations I am sending.
|
||||
</p>
|
||||
<p>After creating it you need to send it to me</p>
|
||||
</Space>
|
||||
<Form>
|
||||
<Form.Item>
|
||||
@@ -50,7 +46,7 @@ const SetupKey: React.FC = () => {
|
||||
size="large"
|
||||
prefix={<UserOutlined />}
|
||||
value={name}
|
||||
onChange={evt => setName(evt.target.value)}
|
||||
onChange={(evt) => setName(evt.target.value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
@@ -59,10 +55,10 @@ const SetupKey: React.FC = () => {
|
||||
size="large"
|
||||
prefix={<MailOutlined />}
|
||||
value={email}
|
||||
onChange={evt => setEmail(evt.target.value)}
|
||||
/>
|
||||
onChange={(evt) => setEmail(evt.target.value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item style={{ textAlign: 'center' }} >
|
||||
<Form.Item style={{ textAlign: 'center' }}>
|
||||
<Button
|
||||
disabled={!name || !email}
|
||||
type="primary"
|
||||
@@ -81,13 +77,12 @@ const SetupKey: React.FC = () => {
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<RocketTwoTone style={{ fontSize: 150 }} />
|
||||
<Typography.Title>Okay, you are all set.</Typography.Title>
|
||||
<p>Just send me your sharing key, and I will send files using it.</p>
|
||||
<p>
|
||||
Just send me your sharing key, and I will send files using it.
|
||||
Remember that you need to go to this website on this device to decrypt
|
||||
the files after receiving them
|
||||
</p>
|
||||
<p>
|
||||
Remember that you need to go to this website on this device to decrypt the files after receiving them
|
||||
</p>
|
||||
<Space direction="vertical" size="large">
|
||||
<Space direction="vertical" size="large">
|
||||
<Button
|
||||
onClick={downloadPublicKey}
|
||||
type="primary"
|
||||
@@ -96,15 +91,8 @@ const SetupKey: React.FC = () => {
|
||||
>
|
||||
Download sharing key
|
||||
</Button>
|
||||
<Popconfirm
|
||||
title="Are you sure?"
|
||||
onConfirm={deleteKey}
|
||||
>
|
||||
<Button
|
||||
danger
|
||||
size="small"
|
||||
type="link"
|
||||
>
|
||||
<Popconfirm title="Are you sure?" onConfirm={deleteKey}>
|
||||
<Button danger size="small" type="link">
|
||||
Delete sharing key
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
|
||||
@@ -8,15 +8,16 @@ const Welcome: React.FC = () => {
|
||||
<Space direction="vertical">
|
||||
<EyeInvisibleTwoTone style={{ fontSize: 200 }} />
|
||||
<Typography.Title level={1}>Protect before sending</Typography.Title>
|
||||
<p>The internet can seem like a scary place...</p>
|
||||
<p>
|
||||
The internet can seem like a scary place...
|
||||
Especially because a lot of the tools we use everyday (such as e-mail)
|
||||
wasn't build for the internet that we have today. This is why it is
|
||||
important to have an additional layer of security when sending
|
||||
sensitive information.
|
||||
</p>
|
||||
<p>
|
||||
Especially because a lot of the tools we use everyday (such as e-mail) wasn't build for the internet that we have today.
|
||||
This is why it is important to have an additional layer of security when sending sensitive information.
|
||||
</p>
|
||||
<p>
|
||||
This is a tool that will help you have that extra layer of security when sharing files with me.
|
||||
This is a tool that will help you have that extra layer of security
|
||||
when sharing files with me.
|
||||
</p>
|
||||
</Space>
|
||||
</Layout>
|
||||
|
||||
@@ -10,7 +10,7 @@ interface FileProcessing extends FileBase {
|
||||
}
|
||||
|
||||
interface FileFailed extends FileBase {
|
||||
status: 'failed',
|
||||
status: 'failed';
|
||||
error: any;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user