generates secure API key within admin UI

This commit is contained in:
James
2020-06-15 19:09:48 -04:00
parent 045dc69bb7
commit 697acbe6ba
6 changed files with 111 additions and 10 deletions

View File

@@ -7,5 +7,7 @@ module.exports = [
{
name: 'apiKey',
type: 'text',
minLength: 24,
maxLength: 48,
},
];

View File

@@ -0,0 +1,71 @@
import React from 'react';
import PropTypes from 'prop-types';
import useFieldType from '../../useFieldType';
import Label from '../../Label';
import Button from '../../../elements/Button';
import generateAPIKey from './generateAPIKey';
import { text } from '../../../../../fields/validations';
import './index.scss';
const path = 'apiKey';
const validate = val => text(val, { minLength: 24, maxLength: 48 });
const APIKey = (props) => {
const {
initialData,
} = props;
const fieldType = useFieldType({
path: 'apiKey',
initialData: initialData || generateAPIKey(),
validate,
});
const {
value,
setValue,
} = fieldType;
const classes = [
'field-type',
'api-key',
'read-only',
].filter(Boolean).join(' ');
return (
<>
<div className={classes}>
<Label
htmlFor={path}
label="API Key"
/>
<input
value={value || ''}
disabled="disabled"
type="text"
id="apiKey"
name="apiKey"
/>
</div>
<Button
onClick={() => setValue(generateAPIKey())}
size="small"
buttonStyle="secondary"
>
Generate new API Key
</Button>
</>
);
};
APIKey.defaultProps = {
initialData: undefined,
};
APIKey.propTypes = {
initialData: PropTypes.string,
};
export default APIKey;

View File

@@ -0,0 +1,16 @@
function generateAPIKey() {
let pass = '';
const str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ 'abcdefghijklmnopqrstuvwxyz0123456789@#$';
for (let i = 1; i <= 36; i += 1) {
const char = Math.floor(Math.random()
* str.length + 1);
pass += str.charAt(char);
}
return pass;
}
export default generateAPIKey;

View File

@@ -8,6 +8,7 @@ import Button from '../../../elements/Button';
import ConfirmPassword from '../ConfirmPassword';
import useForm from '../../Form/useForm';
import CopyToClipboard from '../../../elements/CopyToClipboard';
import APIKey from './APIKey';
import './index.scss';
@@ -76,14 +77,7 @@ const Auth = (props) => {
name="enableAPIKey"
/>
{enableAPIKey?.value && (
<div className={`${baseClass}__api-key-generator`}>
<Text
label={APIKeyLabel}
initialData={initialData?.apiKey}
name="apiKey"
readOnly
/>
</div>
<APIKey initialData={initialData?.apiKey} />
)}
</div>
)}

View File

@@ -1,4 +1,5 @@
@import '../../../../scss/styles.scss';
@import '../shared.scss';
.auth-fields {
padding: base(2) base(2) base(1.5);
@@ -13,3 +14,9 @@
position: relative;
}
}
.field-type.api-key {
input {
@include formInput;
}
}

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import useFieldType from '../../useFieldType';
import withCondition from '../../withCondition';
@@ -21,16 +21,23 @@ const Text = (props) => {
label,
placeholder,
readOnly,
minLength,
maxLength,
} = props;
const path = pathFromProps || name;
const memoizedValidate = useCallback((value) => {
const validationResult = validate(value, { minLength, maxLength });
return validationResult;
}, [validate, maxLength, minLength]);
const fieldType = useFieldType({
path,
required,
initialData,
defaultValue,
validate,
validate: memoizedValidate,
enableDebouncedValue: true,
});
@@ -89,6 +96,8 @@ Text.defaultProps = {
style: {},
validate: text,
path: '',
minLength: undefined,
maxLength: undefined,
};
Text.propTypes = {
@@ -106,6 +115,8 @@ Text.propTypes = {
PropTypes.string,
PropTypes.node,
]),
minLength: PropTypes.number,
maxLength: PropTypes.number,
};
export default withCondition(Text);