Skip to content

Commit 8801b0f

Browse files
committed
* Display loading bar when data is loading
* Allow reading large files * Minor refactoring * Minor design changes
1 parent 05a2f0d commit 8801b0f

File tree

6 files changed

+156
-68
lines changed

6 files changed

+156
-68
lines changed

src/components/App/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {BrowserRouter, Switch, Route} from "react-router-dom";
33
import Home from "../../routes/Home";
44
import Settings from "../../routes/Settings";
55
import {createMuiTheme, ThemeProvider} from '@material-ui/core/styles';
6-
import {ThemeSelector} from "../../utils/ThemeSelector";
6+
import ThemeSelector from "../../utils/ThemeSelector";
77
import Topbar from "../Topbar";
88
import About from "../../routes/About";
99
import File from "../../routes/File";

src/routes/File/index.js

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,15 @@ import GridList from "../../components/GridList";
77
import Hash from "../../components/Hash";
88
import CopyPasteMenu from "../../components/CopyPasteMenu";
99
import TextField from "@material-ui/core/TextField";
10-
import CryptoJs from "crypto-js/crypto-js";
11-
import {FileDataReader} from "../../utils/FileDataReader";
12-
import {CryptoCalculator} from "../../utils/CryptoCalculator";
10+
import FileDataReader from "../../utils/FileDataReader";
1311
import BackButton from "../../components/BackButton";
1412
import CsvExport from "../../components/CsvExport";
1513
import {useHistory} from "react-router";
1614
import {setActiveListItem} from "../../reducers/MainReducer/Actions";
1715
import {MainContext} from "../../contexts/MainContextProvider";
1816
import {CryptoContext} from "../../contexts/CryptoContextReducer";
1917
import {setCurrentFile, setFileHashes} from "../../reducers/CryptoReducer/Actions";
18+
import Loadingbar from "../../components/Loadingbar";
2019

2120
const useStyles = makeStyles(theme => ({
2221
heroContent: {
@@ -29,6 +28,7 @@ const useStyles = makeStyles(theme => ({
2928
},
3029
paper: {
3130
padding: theme.spacing(2),
31+
marginBottom: theme.spacing(1),
3232
display: 'flex',
3333
overflow: 'auto',
3434
flexDirection: 'column'
@@ -50,12 +50,6 @@ const File = () => {
5050

5151
const hashes = crypto.fileHashes;
5252
const file = crypto.currentFile;
53-
const language = state.languages[state.languageIndex];
54-
55-
const [compare, setCompare] = useState(false);
56-
const [compareHash, setCompareHash] = useState("");
57-
58-
const fileRef = useRef(null);
5953

6054
const md5 = crypto.md5;
6155
const sha1 = crypto.sha1;
@@ -66,6 +60,14 @@ const File = () => {
6660
const sha512 = crypto.sha512;
6761
const ripemd160 = crypto.ripemd160;
6862

63+
const language = state.languages[state.languageIndex];
64+
65+
const [compare, setCompare] = useState(false);
66+
const [compareHash, setCompareHash] = useState("");
67+
const [loading, setLoading] = useState(false);
68+
69+
const fileRef = useRef(null);
70+
6971
const history = useHistory();
7072
const classes = useStyles();
7173

@@ -105,21 +107,21 @@ const File = () => {
105107

106108
/**
107109
* Calculate the hashes of a specific file
108-
* @returns {Promise<void>}
109110
*/
110-
const calculateHashes = async () => {
111+
const calculateHashes = (e) => {
112+
if (e) e.preventDefault();
111113
if (!file || file.length === 0) return;
112114

113115
d2(setFileHashes(null));
116+
setLoading(true);
114117

115-
const data = await FileDataReader(file);
116-
if (!data || data.length === 0) return;
117-
118-
const encoded = CryptoJs.enc.Latin1.parse(data);
119-
let newHashes = CryptoCalculator(encoded, md5, sha1, sha224, sha256, sha3, sha384, sha512, ripemd160);
120-
121-
if (newHashes.length === 0) newHashes = null;
122-
d2(setFileHashes(newHashes));
118+
FileDataReader(file, md5, sha1, sha224, sha256, sha3, sha384, sha512, ripemd160)
119+
.then(data => {
120+
d2(setFileHashes(data));
121+
})
122+
.finally(() => {
123+
setLoading(false);
124+
});
123125
};
124126

125127
/**
@@ -146,7 +148,7 @@ const File = () => {
146148
* Change the currently selected file
147149
* @param event The event that called this function
148150
*/
149-
const onFileChange = function (event) {
151+
const onFileChange = (event) => {
150152
d2(setCurrentFile(event.target.files[0]));
151153
fileRef.current.value = "";
152154
};
@@ -179,7 +181,9 @@ const File = () => {
179181
<Paper className={classes.paper}>
180182
<TextField
181183
margin="normal"
182-
onClick={() => fileRef.current.click()}
184+
onClick={() => {
185+
if (!loading) fileRef.current.click()
186+
}}
183187
disabled
184188
id="filled-disabled"
185189
value={file && file.path ? file.path : ""}
@@ -190,7 +194,7 @@ const File = () => {
190194
<input ref={fileRef} type="file" onChange={onFileChange}
191195
style={{display: 'none'}}/>
192196

193-
<Button color={"primary"} variant={"contained"}
197+
<Button color={"primary"} variant={"contained"} disabled={loading}
194198
onClick={() => fileRef.current.click()}>{language.select}</Button>
195199

196200
<FormControlLabel
@@ -206,6 +210,7 @@ const File = () => {
206210
/>
207211
{compareField}
208212
</Paper>
213+
{loading ? <Loadingbar/> : null}
209214
{hashes && hashes.length > 0 ? (
210215
<>
211216
<Button className={classes.button} color={"primary"} variant={"contained"}
@@ -223,8 +228,8 @@ const File = () => {
223228

224229
) : null}
225230
<Button className={classes.button} color={"primary"} variant={"contained"}
226-
disabled={!file || file.length === 0}
227-
style={{float: 'right'}} onClick={async () => calculateHashes()}>
231+
disabled={!file || file.length === 0 || loading}
232+
style={{float: 'right'}} onClick={calculateHashes}>
228233
{language.calculate}
229234
</Button>
230235
{output}

src/routes/Text/index.js

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import TextField from '@material-ui/core/TextField';
66
import Hash from "../../components/Hash";
77
import GridList from "../../components/GridList";
88
import CopyPasteMenu from "../../components/CopyPasteMenu";
9-
import {CryptoCalculator} from "../../utils/CryptoCalculator";
9+
import CryptoCalculator from "../../utils/CryptoCalculator";
1010
import BackButton from "../../components/BackButton";
1111
import CsvExport from "../../components/CsvExport";
1212
import {useHistory} from "react-router";
1313
import {setActiveListItem} from "../../reducers/MainReducer/Actions";
1414
import {MainContext} from "../../contexts/MainContextProvider";
1515
import {CryptoContext} from "../../contexts/CryptoContextReducer";
1616
import {setTextHashes, setTextInput} from "../../reducers/CryptoReducer/Actions";
17+
import Loadingbar from "../../components/Loadingbar";
1718

1819
const useStyles = makeStyles(theme => ({
1920
heroContent: {
@@ -30,6 +31,7 @@ const useStyles = makeStyles(theme => ({
3031
},
3132
paper: {
3233
padding: theme.spacing(2),
34+
marginBottom: theme.spacing(1),
3335
display: 'flex',
3436
overflow: 'auto',
3537
flexDirection: 'column'
@@ -63,6 +65,7 @@ const Text = () => {
6365

6466
const [compare, setCompare] = useState(false);
6567
const [compareHash, setCompareHash] = useState("");
68+
const [loading, setLoading] = useState(false);
6669

6770
const compareField = compare ? (
6871
<CopyPasteMenu id={1} copyData={() => navigator.clipboard.writeText(compareHash)}
@@ -109,21 +112,28 @@ const Text = () => {
109112
*/
110113
const calculateHashes = () => {
111114
if (!input || input.length === 0) return;
112-
d2(setTextHashes(null));
113-
114-
let newHashes = CryptoCalculator(input, md5, sha1, sha224, sha256, sha3, sha384, sha512, ripemd160);
115115

116-
if (newHashes.length === 0) newHashes = null;
117-
d2(setTextHashes(newHashes));
116+
d2(setTextHashes(null));
117+
setLoading(true);
118+
119+
CryptoCalculator(input, md5, sha1, sha224, sha256, sha3, sha384, sha512, ripemd160)
120+
.then(res => {
121+
d2(setTextHashes(res));
122+
})
123+
.finally(() => {
124+
setLoading(false);
125+
});
118126
};
119127

120128
/**
121129
* Clear the user interface
122130
*/
123131
const clearData = () => {
124132
d2(setTextInput(""));
133+
125134
setCompare(false);
126135
setCompareHash("");
136+
127137
d2(setTextHashes(""));
128138
};
129139

@@ -164,6 +174,7 @@ const Text = () => {
164174
label={language.yourTextHere}
165175
margin="normal"
166176
value={input}
177+
disabled={loading}
167178
onChange={(e) => d2(setTextInput(e.target.value))}
168179
multiline
169180
rowsMax={6}
@@ -183,6 +194,7 @@ const Text = () => {
183194
/>
184195
{compareField}
185196
</Paper>
197+
{loading ? <Loadingbar/> : null}
186198
{hashes && hashes.length > 0 ? (
187199
<>
188200
<Button className={classes.button} color={"primary"} variant={"contained"}
@@ -199,7 +211,7 @@ const Text = () => {
199211
</>
200212
) : null}
201213
<Button className={classes.button} color={"primary"} variant={"contained"}
202-
disabled={!input || input.length === 0}
214+
disabled={!input || input.length === 0 || loading}
203215
style={{float: 'right'}} onClick={() => calculateHashes()}>
204216
{language.calculate}
205217
</Button>

src/utils/CryptoCalculator/index.js

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,38 @@ import CryptoSha384 from "crypto-js/sha384";
77
import CryptoSha512 from "crypto-js/sha512";
88
import CryptoRipemd160 from "crypto-js/ripemd160";
99

10-
export const CryptoCalculator = (input, md5, sha1, sha224, sha256, sha3, sha384, sha512, ripemd160) => {
11-
const newHashes = [];
10+
const CryptoCalculator = (input, md5, sha1, sha224, sha256, sha3, sha384, sha512, ripemd160) => {
11+
return new Promise(resolve => {
12+
const newHashes = [];
1213

13-
if (md5) {
14-
newHashes.push({type: "MD5", hash: CryptoMd5(input).toString()});
15-
}
16-
if (sha1) {
17-
newHashes.push({type: "SHA-1", hash: CryptoSha1(input).toString()});
18-
}
19-
if (sha224) {
20-
newHashes.push({type: "SHA-224", hash: CryptoSha224(input).toString()});
21-
}
22-
if (sha256) {
23-
newHashes.push({type: "SHA-256", hash: CryptoSha256(input).toString()});
24-
}
25-
if (sha3) {
26-
newHashes.push({type: "SHA-3", hash: CryptoSha3(input).toString()});
27-
}
28-
if (sha384) {
29-
newHashes.push({type: "SHA-384", hash: CryptoSha384(input).toString()});
30-
}
31-
if (sha512) {
32-
newHashes.push({type: "SHA-512", hash: CryptoSha512(input).toString()});
33-
}
34-
if (ripemd160) {
35-
newHashes.push({type: "RIPEMD-160", hash: CryptoRipemd160(input).toString()});
36-
}
14+
if (md5) {
15+
newHashes.push({type: "MD5", hash: CryptoMd5(input).toString()});
16+
}
17+
if (sha1) {
18+
newHashes.push({type: "SHA-1", hash: CryptoSha1(input).toString()});
19+
}
20+
if (sha224) {
21+
newHashes.push({type: "SHA-224", hash: CryptoSha224(input).toString()});
22+
}
23+
if (sha256) {
24+
newHashes.push({type: "SHA-256", hash: CryptoSha256(input).toString()});
25+
}
26+
if (sha3) {
27+
newHashes.push({type: "SHA-3", hash: CryptoSha3(input).toString()});
28+
}
29+
if (sha384) {
30+
newHashes.push({type: "SHA-384", hash: CryptoSha384(input).toString()});
31+
}
32+
if (sha512) {
33+
newHashes.push({type: "SHA-512", hash: CryptoSha512(input).toString()});
34+
}
35+
if (ripemd160) {
36+
newHashes.push({type: "RIPEMD-160", hash: CryptoRipemd160(input).toString()});
37+
}
3738

38-
return newHashes;
39-
};
39+
if (newHashes.length === 0) resolve(null);
40+
resolve(newHashes);
41+
});
42+
};
43+
44+
export default CryptoCalculator;

src/utils/FileDataReader/index.js

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,75 @@
1-
export const FileDataReader = (file) => {
2-
return new Promise(resolve => {
3-
const reader = new FileReader();
1+
import CryptoJS from "crypto-js";
42

5-
reader.onload = function (event) {
6-
resolve(event.target.result);
7-
};
3+
const FileDataReader = (file, md5, sha1, sha224, sha256, sha3, sha384, sha512, ripemd160) => {
84

9-
reader.readAsBinaryString(file);
5+
const MD5 = CryptoJS.algo.MD5.create();
6+
const SHA1 = CryptoJS.algo.SHA1.create();
7+
const SHA224 = CryptoJS.algo.SHA224.create();
8+
const SHA256 = CryptoJS.algo.SHA256.create();
9+
const SHA3 = CryptoJS.algo.SHA3.create();
10+
const SHA384 = CryptoJS.algo.SHA384.create();
11+
const SHA512 = CryptoJS.algo.SHA512.create();
12+
const RIPEMD160 = CryptoJS.algo.RIPEMD160.create();
13+
14+
return new Promise((resolve, reject) => {
15+
const chunkSize = 1024 * 1024;
16+
17+
let offset = 0;
18+
let partial;
19+
let index = 0;
20+
21+
if (file.size === 0) {
22+
resolve(null);
23+
}
24+
25+
while (offset < file.size) {
26+
partial = file.slice(offset, offset + chunkSize);
27+
28+
const reader = new FileReader();
29+
30+
reader.size = chunkSize;
31+
reader.offset = offset;
32+
reader.index = index;
33+
34+
reader.onload = (evt) => {
35+
const wordBuffer = CryptoJS.lib.WordArray.create(evt.target.result);
36+
37+
if (md5) MD5.update(wordBuffer);
38+
if (sha1) SHA1.update(wordBuffer);
39+
if (sha224) SHA224.update(wordBuffer);
40+
if (sha256) SHA256.update(wordBuffer);
41+
if (sha3) SHA3.update(wordBuffer);
42+
if (sha384) SHA384.update(wordBuffer);
43+
if (sha512) SHA512.update(wordBuffer);
44+
if (ripemd160) RIPEMD160.update(wordBuffer);
45+
46+
if (reader.offset + reader.size >= file.size) {
47+
const newHashes = [];
48+
49+
if (md5) newHashes.push({type: "MD5", hash: MD5.finalize().toString()});
50+
if (sha1) newHashes.push({type: "SHA-1", hash: SHA1.finalize().toString()});
51+
if (sha224) newHashes.push({type: "SHA-224", hash: SHA224.finalize().toString()});
52+
if (sha256) newHashes.push({type: "SHA-256", hash: SHA256.finalize().toString()});
53+
if (sha3) newHashes.push({type: "SHA-3", hash: SHA3.finalize().toString()});
54+
if (sha384) newHashes.push({type: "SHA-384", hash: SHA384.finalize().toString()});
55+
if (sha512) newHashes.push({type: "SHA-512", hash: SHA512.finalize().toString()});
56+
if (ripemd160) newHashes.push({type: "RIPEMD-160", hash: RIPEMD160.finalize().toString()});
57+
58+
if (newHashes.length === 0) resolve(null);
59+
else resolve(newHashes);
60+
}
61+
};
62+
63+
reader.onerror = (error) => {
64+
reject(error);
65+
};
66+
67+
reader.readAsArrayBuffer(partial);
68+
69+
offset += chunkSize;
70+
index += 1;
71+
}
1072
});
1173
};
74+
75+
export default FileDataReader;

0 commit comments

Comments
 (0)