Added google recaptcha

This commit is contained in:
JKamsker 2022-09-01 00:00:52 +02:00
parent 0b02da06ef
commit 246a777878
4 changed files with 346 additions and 302 deletions

21
package-lock.json generated
View file

@ -22,6 +22,7 @@
"react-dom": "^16.14.0", "react-dom": "^16.14.0",
"react-dropzone": "^11.3.2", "react-dropzone": "^11.3.2",
"react-ga": "^3.3.0", "react-ga": "^3.3.0",
"react-google-recaptcha-v3": "^1.10.0",
"react-notifications-component": "^3.1.0", "react-notifications-component": "^3.1.0",
"react-scripts": "^4.0.3", "react-scripts": "^4.0.3",
"reactstrap": "^8.9.0", "reactstrap": "^8.9.0",
@ -18676,6 +18677,18 @@
"react": "^15.6.2 || ^16.0 || ^17" "react": "^15.6.2 || ^16.0 || ^17"
} }
}, },
"node_modules/react-google-recaptcha-v3": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/react-google-recaptcha-v3/-/react-google-recaptcha-v3-1.10.0.tgz",
"integrity": "sha512-JBoqU107X8klQmS8tQSbQh1IMsT1fH3kVoArIqnia0rtn0rPNG9Ld+9rD/dHJMculIczSZpGvIJTXXwtsolMcg==",
"dependencies": {
"hoist-non-react-statics": "^3.3.2"
},
"peerDependencies": {
"react": "^17.0 || ^18.0",
"react-dom": "^17.0 || ^18.0"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -38638,6 +38651,14 @@
"resolved": "https://registry.npmjs.org/react-ga/-/react-ga-3.3.0.tgz", "resolved": "https://registry.npmjs.org/react-ga/-/react-ga-3.3.0.tgz",
"integrity": "sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ==" "integrity": "sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ=="
}, },
"react-google-recaptcha-v3": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/react-google-recaptcha-v3/-/react-google-recaptcha-v3-1.10.0.tgz",
"integrity": "sha512-JBoqU107X8klQmS8tQSbQh1IMsT1fH3kVoArIqnia0rtn0rPNG9Ld+9rD/dHJMculIczSZpGvIJTXXwtsolMcg==",
"requires": {
"hoist-non-react-statics": "^3.3.2"
}
},
"react-is": { "react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",

View file

@ -18,6 +18,7 @@
"react-dom": "^16.14.0", "react-dom": "^16.14.0",
"react-dropzone": "^11.3.2", "react-dropzone": "^11.3.2",
"react-ga": "^3.3.0", "react-ga": "^3.3.0",
"react-google-recaptcha-v3": "^1.10.0",
"react-notifications-component": "^3.1.0", "react-notifications-component": "^3.1.0",
"react-scripts": "^4.0.3", "react-scripts": "^4.0.3",
"reactstrap": "^8.9.0", "reactstrap": "^8.9.0",

View file

@ -1,313 +1,325 @@
import React, { useState } from 'react'; import React, { useState } from 'react'
import { withStyles } from "@material-ui/core/styles"; import { withStyles } from '@material-ui/core/styles'
import Avatar from '@material-ui/core/Avatar'; import Avatar from '@material-ui/core/Avatar'
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button'
import CssBaseline from '@material-ui/core/CssBaseline'; import CssBaseline from '@material-ui/core/CssBaseline'
import TextField from '@material-ui/core/TextField'; import TextField from '@material-ui/core/TextField'
import Link from '@material-ui/core/Link'; import Link from '@material-ui/core/Link'
import Box from '@material-ui/core/Box'; import Box from '@material-ui/core/Box'
import LockOutlinedIcon from '@material-ui/icons/LockOutlined'; import LockOutlinedIcon from '@material-ui/icons/LockOutlined'
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography'
import Container from '@material-ui/core/Container'; import Container from '@material-ui/core/Container'
import Dropzone from 'react-dropzone' import Dropzone from 'react-dropzone'
import IconButton from '@material-ui/core/IconButton'; import IconButton from '@material-ui/core/IconButton'
import FileCopyOutlined from '@material-ui/icons/FileCopyOutlined'; import FileCopyOutlined from '@material-ui/icons/FileCopyOutlined'
import PublishOutlined from '@material-ui/icons/PublishOutlined'; import PublishOutlined from '@material-ui/icons/PublishOutlined'
// import { useFilePicker } from 'react-sage'
// import { FilePicker } from 'react-file-picker'
import { FilePicker } from '../src/Components' import { FilePicker } from '../src/Components'
import { CopyToClipboard } from 'react-copy-to-clipboard'
import { CopyToClipboard } from 'react-copy-to-clipboard';
import ControlledAccordions from './ControlledAccordions' import ControlledAccordions from './ControlledAccordions'
import OnlineConverter from "./OnlineConverter"; import OnlineConverter from './OnlineConverter'
import 'react-notifications-component/dist/theme.css' import 'react-notifications-component/dist/theme.css'
import ReactNotification from 'react-notifications-component' import ReactNotification from 'react-notifications-component'
import { store } from 'react-notifications-component'; import { store } from 'react-notifications-component'
// import 'animate.css/animate.compat.css'
import AaxHashAlgorithm from './Utils/AaxHashAlgorithm' import AaxHashAlgorithm from './Utils/AaxHashAlgorithm'
import {
GoogleReCaptchaProvider,
withGoogleReCaptcha,
} from 'react-google-recaptcha-v3'
const useStyles = theme => ({ const useStyles = (theme) => ({
paper: { paper: {
marginTop: theme.spacing(8), marginTop: theme.spacing(8),
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', alignItems: 'center',
}, },
avatar: { avatar: {
margin: theme.spacing(1), margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main, backgroundColor: theme.palette.secondary.main,
}, },
form: { form: {
width: '100%', // Fix IE 11 issue. width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1), marginTop: theme.spacing(1),
}, },
//Accordeon //Accordeon
heading: { heading: {
fontSize: theme.typography.pxToRem(15), fontSize: theme.typography.pxToRem(15),
flexBasis: '33.33%', flexBasis: '33.33%',
flexShrink: 0, flexShrink: 0,
}, },
secondaryHeading: { secondaryHeading: {
fontSize: theme.typography.pxToRem(15), fontSize: theme.typography.pxToRem(15),
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
}, },
}); })
class ChecksumResolver extends React.Component { class ChecksumResolver extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {
checksum: "", checksum: '',
fileName: "input.aax" fileName: 'input.aax',
}
} }
}
DarkerDisabledTextField = withStyles({ DarkerDisabledTextField = withStyles({
root: { root: {
marginRight: 8, marginRight: 8,
"& .MuiInputBase-root.Mui-disabled": { '& .MuiInputBase-root.Mui-disabled': {
color: "rgba(0, 0, 0, 0.6)" color: 'rgba(0, 0, 0, 0.6)',
} },
} },
})(TextField); })(TextField)
Copyright = (function () { Copyright = function () {
return ( return (
<Typography variant="body2" color="textSecondary" align="center"> <Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '} {'Copyright © '}
<Link color="inherit" href="https://audible-tools.github.io/"> <Link color="inherit" href="https://audible-tools.github.io/">
audible-tools audible-tools
</Link>{' '} </Link>{' '}
{new Date().getFullYear()} {new Date().getFullYear()}
{'. V 0.3'} {'. V 0.3'}
</Typography> </Typography>
); )
}
setChecksum = (value) => {
if (value.length > 40) {
return
}
this.setState({ checksum: value })
}
isChecksumValid = () => {
const { checksum } = this.state
const regex = RegExp('[a-f0-9]{40}')
const testResults = regex.test(checksum)
return testResults
}
isInputInvalid = () => {
const { checksum } = this.state
if (!checksum || checksum === '') {
return false
}
return !this.isChecksumValid()
}
addNotification = function (text, success = true) {
store.addNotification({
message: text,
type: success ? 'success' : 'danger',
// type: "danger",
insert: 'bottom-left',
container: 'top-full',
animationIn: ['animate__animated', 'animate__fadeIn'],
animationOut: ['animate__animated', 'animate__fadeOut'],
dismiss: {
duration: 3000,
onScreen: false,
},
}) })
}
setChecksum = (value) => { requestActivationBytes = async () => {
if (value.length > 40) { const { checksum } = this.state
return;
const { executeRecaptcha } = (this.props)
.googleReCaptchaProps;
if (!executeRecaptcha) {
console.log('Recaptcha has not been loaded');
return;
}
const token = await executeRecaptcha('homepage');
console.log(`XToken: ${token}`);
try {
let request = await fetch(
'https://api.audible-converter.ml/api/v2/activation/' + checksum,
)
let result = await request.json()
const { success, activationBytes } = result
if (success !== true) {
this.setState({ activationBytes: 'UNKNOWN' })
this.addNotification(
'An error occured while resolving the activation bytes, please check your inputs',
false,
)
return
}
if (success === true) {
const calculatedChecksum = await AaxHashAlgorithm.CalculateChecksum(
activationBytes,
)
if (calculatedChecksum == checksum) {
this.setState({ activationBytes: activationBytes })
this.addNotification('Successfully resolved the activation bytes')
return
} }
this.setState({ checksum: value })
this.setState({ activationBytes: 'API ERROR' })
this.addNotification(
'An unexpected error occured while resolving the activation bytes, please try again',
false,
)
}
} catch (error) {
this.setState({ activationBytes: error })
this.addNotification(
'An error occured while resolving the activation bytes, please check your inputs',
false,
)
} }
}
isChecksumValid = () => { buf2hex(buffer) {
const { checksum } = this.state; // buffer is an ArrayBuffer
const regex = RegExp('[a-f0-9]{40}'); return Array.prototype.map
const testResults = regex.test(checksum); .call(new Uint8Array(buffer), (x) => ('00' + x.toString(16)).slice(-2))
.join('')
}
return testResults; acceptFiles = async (files) => {
} const file = files[0]
await this.acceptFile(file)
}
isInputInvalid = () => { acceptFile = async (file) => {
const { checksum } = this.state; // if (!file.name.toLowerCase().endsWith(".aax")) {
if (!checksum || checksum === '') { // alert('FileType not supported!');
return false; // return;
} // }
return !this.isChecksumValid();
};
addNotification = function (text, success = true) { this.setState({ fileName: file.name, file: file })
store.addNotification({ const slic = file.slice(653, 653 + 20)
message: text, const results = this.buf2hex(await slic.arrayBuffer())
type: success ? "success" : "danger", this.setChecksum(results)
// type: "danger", this.requestActivationBytes()
insert: "bottom-left", }
container: "top-full",
animationIn: ["animate__animated", "animate__fadeIn"],
animationOut: ["animate__animated", "animate__fadeOut"],
dismiss: {
duration: 3000,
onScreen: false
}
});
}
requestActivationBytes = async () => { render() {
const { checksum } = this.state; const { classes } = this.props
try { const { checksum, activationBytes, fileName, file } = this.state
let request = await fetch("https://api.audible-converter.ml/api/v2/activation/" + checksum);
let result = await request.json();
const { success, activationBytes } = result;
if (success !== true) { return (
this.setState({ activationBytes: 'UNKNOWN' }); <Container component="main" maxWidth="md">
this.addNotification("An error occured while resolving the activation bytes, please check your inputs", false); <CssBaseline />
return; <div className={classes.paper}>
} <Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
AAX Checksum Resolver
</Typography>
if (success === true) { <form className={classes.form} noValidate>
const calculatedChecksum = await AaxHashAlgorithm.CalculateChecksum(activationBytes); <Dropzone
if (calculatedChecksum == checksum) { noClick
this.setState({ activationBytes: activationBytes }); onDrop={(acceptedFiles) => {
this.addNotification("Successfully resolved the activation bytes"); console.log(acceptedFiles)
return; this.acceptFiles(acceptedFiles)
} }}
>
this.setState({ activationBytes: "API ERROR" }); {({ getRootProps, getInputProps }) => (
this.addNotification("An unexpected error occured while resolving the activation bytes, please try again", false); <section>
<div {...getRootProps()}>
<input {...getInputProps()} />
<TextField
error={this.isInputInvalid()}
variant="outlined"
margin="normal"
required
fullWidth
id="checksum"
label="Checksum or Drag&Drop .aax file -"
name="checksum"
autoComplete="checksum"
autoFocus
onChange={(x) => this.setChecksum(x.target.value)}
onError={() => {}}
value={checksum}
InputProps={{
readOnly: false,
endAdornment: (
<FilePicker
extensions={['aax', 'AAX']}
maxSize={99999}
onChange={this.acceptFile}
onError={() => {}}
>
<IconButton>
<PublishOutlined />
</IconButton>
</FilePicker>
),
}}
/>
</div>
</section>
)}
</Dropzone>
} <Button
} catch (error) { fullWidth
this.setState({ activationBytes: error }); variant="contained"
this.addNotification("An error occured while resolving the activation bytes, please check your inputs", false); onClick={() => {
} this.requestActivationBytes()
} }}
disabled={!this.isChecksumValid()}
>
Request Activation Bytes
</Button>
buf2hex(buffer) { // buffer is an ArrayBuffer <this.DarkerDisabledTextField
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(''); value={activationBytes}
} disabled
variant="outlined"
acceptFiles = async files => { margin="normal"
const file = files[0]; fullWidth
await this.acceptFile(file); id="activationBytes"
} label={activationBytes ? '' : 'Activation Bytes'}
name="activationBytes"
acceptFile = async file => { autoComplete="activationBytes"
// if (!file.name.toLowerCase().endsWith(".aax")) { aria-readonly
// alert('FileType not supported!'); InputProps={{
// return; readOnly: true,
// } endAdornment: (
<CopyToClipboard text={activationBytes}>
this.setState({ fileName: file.name, file:file }); <IconButton>
const slic = file.slice(653, 653 + 20); <FileCopyOutlined />
const results = this.buf2hex(await slic.arrayBuffer()); </IconButton>
this.setChecksum(results) </CopyToClipboard>
this.requestActivationBytes(); ),
}}
} />
</form>
render() { </div>
const { classes } = this.props; <ControlledAccordions
const { checksum, activationBytes, fileName, file } = this.state; fileName={fileName}
activationBytes={activationBytes}
// const { files, onClick, errors, HiddenFileInput } = useFilePicker({ file={file}
// maxFileSize: 1000000, />
// maxImageWidth: 1000, <Box mt={1}>
// imageQuality: 0.92, <this.Copyright />
// resizeImage: true </Box>
// }); </Container>
)
return ( }
<Container component="main" maxWidth="md">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
AAX Checksum Resolver
</Typography>
<form className={classes.form} noValidate>
<Dropzone
noClick
onDrop={acceptedFiles => {
console.log(acceptedFiles);
this.acceptFiles(acceptedFiles);
}}>
{({ getRootProps, getInputProps }) => (
<section>
<div {...getRootProps()}>
<input {...getInputProps()} />
<TextField
error={this.isInputInvalid()}
variant="outlined"
margin="normal"
required
fullWidth
id="checksum"
label="Checksum or Drag&Drop .aax file -"
name="checksum"
autoComplete="checksum"
autoFocus
onChange={(x) => this.setChecksum(x.target.value)}
onError={()=>{}}
value={checksum}
InputProps={{
readOnly: false,
endAdornment: (
<FilePicker
extensions={['aax', 'AAX']}
maxSize={99999}
onChange={this.acceptFile}
>
<IconButton >
<PublishOutlined />
</IconButton>
</FilePicker>
)
}}
/>
</div>
</section>
)}
</Dropzone>
<Button
fullWidth
variant="contained"
onClick={() => {
this.requestActivationBytes();
}}
disabled={!this.isChecksumValid()}
>
Request Activation Bytes
</Button>
<this.DarkerDisabledTextField
value={activationBytes}
disabled
variant="outlined"
margin="normal"
fullWidth
id="activationBytes"
label={activationBytes ? '' : "Activation Bytes"}
name="activationBytes"
autoComplete="activationBytes"
aria-readonly
InputProps={{
readOnly: true,
endAdornment: (
<CopyToClipboard text={activationBytes}>
<IconButton >
<FileCopyOutlined />
</IconButton>
</CopyToClipboard>
)
}}
/>
</form>
</div>
<ControlledAccordions
fileName={fileName}
activationBytes={activationBytes}
file ={file}
/>
<Box mt={1}>
<this.Copyright />
</Box>
</Container>
);
}
} }
export default withStyles(useStyles)(ChecksumResolver); export default withGoogleReCaptcha(withStyles(useStyles)(ChecksumResolver))

View file

@ -1,37 +1,47 @@
import React from 'react'; import React from 'react'
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom'
import './index.css'; import './index.css'
import * as serviceWorker from './serviceWorker'; import * as serviceWorker from './serviceWorker'
import ChecksumResolver from './ChecksumResolver'; import ChecksumResolver from './ChecksumResolver'
import ReactNotification from 'react-notifications-component' import ReactNotification from 'react-notifications-component'
import ForkMeOnGithub from 'fork-me-on-github'; import ForkMeOnGithub from 'fork-me-on-github'
import ReactGA from 'react-ga'
import {
GoogleReCaptchaProvider,
GoogleReCaptcha,
} from 'react-google-recaptcha-v3'
import ReactGA from 'react-ga'; fetch('https://api.audible-converter.ml/api/v2/WakeUpNeo').then((data) =>
console.log('Woke up, im ready to serve :D'),
)
fetch("https://api.audible-converter.ml/api/v2/WakeUpNeo") ReactGA.initialize('UA-174657678-1')
.then(data => console.log("Woke up, im ready to serve :D")) ReactGA.pageview(window.location.pathname + window.location.search)
ReactGA.initialize('UA-174657678-1');
ReactGA.pageview(window.location.pathname + window.location.search);
ReactDOM.render( ReactDOM.render(
<div> <div>
<div style={{display:'flex'}}> <GoogleReCaptchaProvider reCaptchaKey="6LeZhMMhAAAAAH2cwtbCRYys5WawPj4KS5pw-GNd">
<ReactNotification /> {/* <GoogleReCaptcha
onVerify={(a, b, c) => {
</div> console.log(`Token: ${a}`);
<ForkMeOnGithub }}
repo="https://github.com/audible-tools/audible-tools.github.io" /> */}
colorOctocat="black" <div style={{ display: 'flex' }}>
isPride <ReactNotification />
/> </div>
<ChecksumResolver /> <ForkMeOnGithub
repo="https://github.com/audible-tools/audible-tools.github.io"
colorOctocat="black"
isPride
/>
<ChecksumResolver />
</GoogleReCaptchaProvider>
</div>, </div>,
document.getElementById('root') document.getElementById('root'),
); )
// If you want your app to work offline and load faster, you can change // If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls. // unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA // Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister(); serviceWorker.unregister()