From 6c08d90a8d51c886e958cb6ec5625e26bb9cd286 Mon Sep 17 00:00:00 2001 From: Ilya Melnikov <70610034+melil02@users.noreply.github.com> Date: Fri, 23 Jun 2023 16:44:11 -0700 Subject: [PATCH] 5.2.1 release (#63) * 5.2.1 release --- package.json | 1 + packages/layer7-apihub/package.json | 4 +- .../layer7-apihub/src/apis/ApiAssetsField.js | 9 +- .../src/apis/Application/ApiApplications.js | 16 +- .../apis/Application/ApiApplications.test.js | 45 +- .../src/applications/ApplicationDetails.js | 15 + .../ApplicationDetailsKeyClient.js | 106 ++- .../src/applications/ApplicationEditView.js | 660 ++++++++---------- .../src/applications/ApplicationKeyClient.js | 38 +- .../src/applications/ApplicationKeySecret.js | 172 +++-- .../src/applications/ApplicationNew.js | 1 + .../src/applications/ApplicationToolbar.js | 1 + .../src/applications/isApplicationPending.js | 10 +- .../AccountSetup/AccountSetupForm.js | 18 +- .../NewPassword/NewPasswordForm.js | 24 +- .../src/authentication/validatePassword.js | 21 + .../layer7-apihub/src/dataProvider/apiKeys.js | 28 +- .../src/dataProvider/applications.js | 32 +- packages/layer7-apihub/src/i18n/en.js | 8 +- packages/layer7-apihub/src/i18n/es.js | 6 + packages/layer7-apihub/src/i18n/fr.js | 6 + .../src/userProfiles/UserProfileEdit.js | 30 +- pom.xml | 2 +- yarn.lock | 16 +- 24 files changed, 755 insertions(+), 514 deletions(-) diff --git a/package.json b/package.json index 41ff4c772..237998709 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "get-intrinsic": "~1.1.3", "serialize-javascript": "~3.1.0", "qs": "6.9.7", + "ua-parser-js": "0.7.35", "url-parse": "^1.5.9", "fast-json-patch": "3.1.1" } diff --git a/packages/layer7-apihub/package.json b/packages/layer7-apihub/package.json index ae7610888..75d0b32fa 100644 --- a/packages/layer7-apihub/package.json +++ b/packages/layer7-apihub/package.json @@ -17,6 +17,7 @@ "@material-ui/core": "~4.9.3", "@material-ui/lab": "~4.0.0-alpha.45", "@rehooks/local-storage": "~2.4.0", + "decode-uri-component": "0.2.1", "final-form-calculate": "~1.3.2", "focus-trap-react": "~6.0.0", "jsencrypt": "~3.0.0-rc.1", @@ -28,12 +29,13 @@ "react-dnd": "~10.0.2", "react-dnd-html5-backend": "~10.0.2", "react-markdown-editor-lite": "~1.0.2", - "trim": "0.0.3", + "recompose":"~0.30.0", "remark-parse": "9.0.0", "remark-react": "~7.0.1", "remove-markdown": "~0.3.0", "slugify": "~1.4.4", "swagger-ui-react": "~3.27.0", + "trim": "0.0.3", "unified": "~8.4.2" }, "peerDependencies": { diff --git a/packages/layer7-apihub/src/apis/ApiAssetsField.js b/packages/layer7-apihub/src/apis/ApiAssetsField.js index f65c399f1..a6ef8568d 100755 --- a/packages/layer7-apihub/src/apis/ApiAssetsField.js +++ b/packages/layer7-apihub/src/apis/ApiAssetsField.js @@ -61,7 +61,10 @@ export const ApiAssetsField = props => { export const AssetsList = ({ record, links, ...rest }) => { const { urlWithTenant } = useApiHub(); + const { apiServiceType, publishedByPortal } = record; + const isGatewayPublishedSoapApi = + apiServiceType === 'SOAP' && !publishedByPortal; return ( <> @@ -70,7 +73,11 @@ export const AssetsList = ({ record, links, ...rest }) => { {link.name} diff --git a/packages/layer7-apihub/src/apis/Application/ApiApplications.js b/packages/layer7-apihub/src/apis/Application/ApiApplications.js index 3cfc7e15d..9dc2e9106 100755 --- a/packages/layer7-apihub/src/apis/Application/ApiApplications.js +++ b/packages/layer7-apihub/src/apis/Application/ApiApplications.js @@ -59,10 +59,6 @@ export const ApiApplications = ({ id }) => { React.useEffect(() => { let active = true; - if (!search || search.length < 2) { - return undefined; - } - (async () => { const [data, total] = await fetchApplications(search); @@ -71,10 +67,8 @@ export const ApiApplications = ({ id }) => { setApplications(data); setLoading(false); } else if (applications.length < total) { - setApplications( - uniqBy([ ...applications, ...data ], 'uuid') - ); - setCurrentPage(currentPage+1); + setApplications(uniqBy([...applications, ...data], 'uuid')); + setCurrentPage(currentPage + 1); } else { setLoading(false); } @@ -102,10 +96,10 @@ export const ApiApplications = ({ id }) => { open={open} onOpen={() => setOpen(true)} onClose={(event, reason) => setOpen(false)} - onChange={(event, app, reason) => { - setSelectedApp(app) + onChange={(event, app, reason) => { + setSelectedApp(app); if (reason == 'clear') { - setApplications([]) + setApplications([]); } }} getOptionSelected={(option, value) => diff --git a/packages/layer7-apihub/src/apis/Application/ApiApplications.test.js b/packages/layer7-apihub/src/apis/Application/ApiApplications.test.js index fbfd09d4d..92d65d75f 100755 --- a/packages/layer7-apihub/src/apis/Application/ApiApplications.test.js +++ b/packages/layer7-apihub/src/apis/Application/ApiApplications.test.js @@ -52,8 +52,16 @@ describe('Applications', () => { id: 3, name: 'application 3', }, + { + id: 4, + name: 'app 4', + }, + { + id: 5, + name: 'app 5', + }, ], - total: 3, + total: 5, }), }; @@ -64,22 +72,29 @@ describe('Applications', () => { initialState ); - await wait(() => { - const select = getByLabelText( - 'resources.apis.specification.actions.search_or_select_application' - ); - fireEvent.mouseDown(select); - // Enter search criteria - fireEvent.change(select, { target: { value: 'application' } }); - }); + const select = getByLabelText( + 'resources.apis.specification.actions.search_or_select_application' + ); - await wait(() => { - expect(queryByText('application 1')).not.toBeNull(); - expect(queryByText('application 2')).not.toBeNull(); - expect(queryByText('application 3')).not.toBeNull(); - }); + // Show all applications when select when no search criteria + await wait(() => fireEvent.mouseDown(select)); + expect(queryByText('application 1')).not.toBeNull(); + expect(queryByText('application 2')).not.toBeNull(); + expect(queryByText('application 3')).not.toBeNull(); + expect(queryByText('app 4')).not.toBeNull(); + expect(queryByText('app 5')).not.toBeNull(); - expect.assertions(3); + // Enter search criteria + await wait(() => + fireEvent.change(select, { target: { value: 'application' } }) + ); + expect(queryByText('application 1')).not.toBeNull(); + expect(queryByText('application 2')).not.toBeNull(); + expect(queryByText('application 3')).not.toBeNull(); + expect(queryByText('app 4')).toBeNull(); + expect(queryByText('app 5')).toBeNull(); + + expect.assertions(10); }); test('should display the selected application credentials', async () => { diff --git a/packages/layer7-apihub/src/applications/ApplicationDetails.js b/packages/layer7-apihub/src/applications/ApplicationDetails.js index f7122b56c..0cc031a5f 100755 --- a/packages/layer7-apihub/src/applications/ApplicationDetails.js +++ b/packages/layer7-apihub/src/applications/ApplicationDetails.js @@ -7,6 +7,7 @@ import Typography from '@material-ui/core/Typography'; import List from '@material-ui/core/List'; import { makeStyles } from '@material-ui/core/styles'; import sortBy from 'lodash/sortBy'; +import get from 'lodash/get'; import { useUserContext } from '../userContexts'; import { ApplicationApisList } from './ApplicationApisList'; @@ -54,6 +55,19 @@ export const ApplicationDetails = ({ record }) => { resource: 'applications', payload: { id: record.id }, }); + + const { data: applicationApiKeyExpirySettings } = useQuery({ + type: 'getKeyExpirySettings', + resource: 'applications', + payload: {}, + }); + + const isKeyExpiryEnabled = get( + applicationApiKeyExpirySettings, + 'enabled', + false + ); + React.useEffect(() => { if (apisData && apisData.length > 0) { setApiIds(apisData.map(item => item.uuid)); @@ -256,6 +270,7 @@ export const ApplicationDetails = ({ record }) => { key={apiKey.id} data={apiKey} includeSecret={true} + isKeyExpiryEnabled={isKeyExpiryEnabled} labelClasses={contentLabelClasses} dataProvider={dataProvider} refreshApiKeys={fetchApiKeys} diff --git a/packages/layer7-apihub/src/applications/ApplicationDetailsKeyClient.js b/packages/layer7-apihub/src/applications/ApplicationDetailsKeyClient.js index a6593dc43..0fe27d8b8 100755 --- a/packages/layer7-apihub/src/applications/ApplicationDetailsKeyClient.js +++ b/packages/layer7-apihub/src/applications/ApplicationDetailsKeyClient.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Fragment } from 'react'; import { Labeled, TextField } from 'react-admin'; import { useTranslate } from 'ra-core'; import Grid from '@material-ui/core/Grid'; @@ -13,6 +13,7 @@ import ExpansionPanel from '@material-ui/core/ExpansionPanel'; import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'; import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'; import classnames from 'classnames'; +import moment from 'moment'; import { useCopyToClipboard } from '../ui'; @@ -33,6 +34,11 @@ const getStatusColor = (classes, status) => { statusLabel: 'Delete_Failed', statusColorClass: classes.disabled, }; + case 'EXPIRED': + return { + statusLabel: 'Expired', + statusColorClass: classes.expired, + }; default: return { statusLabel: 'Disabled', @@ -42,7 +48,7 @@ const getStatusColor = (classes, status) => { }; export const ApplicationDetailsKeyClient = props => { - const { data, includeSecret } = props; + const { data, includeSecret, isKeyExpiryEnabled } = props; const classes = useStyles(); const translate = useTranslate(); const copyToClipboard = useCopyToClipboard({ @@ -58,6 +64,56 @@ export const ApplicationDetailsKeyClient = props => { data.status ); + const getExpiryDateText = data => { + let expiryDateText = translate( + 'resources.applications.fields.none' + ); + const secretExpiryTs = data.secretExpiryTs; + if (isKeyExpiryEnabled && secretExpiryTs) { + const keyExpiryDate = moment(secretExpiryTs); + expiryDateText = keyExpiryDate.format( + 'dddd, MMMM Do YYYY, HH:mm:ss' + ); + } + return expiryDateText; + }; + + const getExpiryDateSubText = data => { + let expiryDateSubText = ''; + const secretExpiryTs = data.secretExpiryTs; + const keyStatus = data.status; + if (isKeyExpiryEnabled && secretExpiryTs) { + const keyExpiryDate = moment(secretExpiryTs); + const currentTime = moment(); + if (keyStatus === 'EXPIRED') { + expiryDateSubText = translate( + 'resources.applications.status.expired' + ); + } else { + const days = keyExpiryDate.diff(currentTime, 'days'); + let suffix = translate( + 'resources.applications.fields.days' + ); + if (days === 1) { + suffix = translate( + 'resources.applications.fields.day' + ); + } + expiryDateSubText = `${days} ${suffix}`; + } + } + return expiryDateSubText; + }; + + const getExpiryDateSubTextClass = data => { + let expiryDateSubTextClass = ''; + const keyStatus = data.status; + if (keyStatus === 'EXPIRED') { + expiryDateSubTextClass = classes.expiredKeyStatus; + } + return expiryDateSubTextClass; + }; + return ( { )} - + {data.oauthType && ( { )} + {isKeyExpiryEnabled && ( + + , this will translate in a correct `for` attribute on the label + id="expiryDate" + label={ + 'resources.applications.fields.expiryDate' + } + classes={classes} + className={classes.fieldLabel} + > + + + + {getExpiryDateText(data)} + + + + {getExpiryDateSubText(data)} + + + + + )} @@ -277,6 +367,16 @@ const useStyles = makeStyles( backgroundColor: '#4CAF50', }, }, + expired: { + color: '#B30303', + '&:before': { + backgroundColor: '#B30303', + }, + }, + expiredKeyStatus: { + color: '#B30303', + fontFamily: 'clear-sans-bold', + }, disabled: { color: '#696969', '&:before': { diff --git a/packages/layer7-apihub/src/applications/ApplicationEditView.js b/packages/layer7-apihub/src/applications/ApplicationEditView.js index 6529d2798..489d2877a 100755 --- a/packages/layer7-apihub/src/applications/ApplicationEditView.js +++ b/packages/layer7-apihub/src/applications/ApplicationEditView.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, Fragment } from 'react'; import { ArrayInput, FormDataConsumer, @@ -17,6 +17,7 @@ import { } from 'react-admin'; import { useHistory } from 'react-router-dom'; import { FormSpy } from 'react-final-form'; +import moment from 'moment'; import debounce from 'lodash/debounce'; import get from 'lodash/get'; @@ -133,6 +134,7 @@ export const ApplicationEditView = ({ const [keyDeleting, setKeyDeleting] = React.useState(false); const [deleteKeyConfirm, setDeleteKeyConfirm] = React.useState(false); const [proxyCheckFailed, setProxyCheckFailed] = React.useState(false); + const [updatedKeyDetails, setUpdatedKeyDetails] = useState(); const [deletingKeyId, setDeletingKeyId] = useState(); const isAppIncomplete = record.status === APPLICATION_STATUS_INCOMPLETE; const isAppRejected = record.status === APPLICATION_STATUS_REJECTED; @@ -310,11 +312,7 @@ export const ApplicationEditView = ({ apiApiPlanIdsData, apiGroupsIdsData, ]); - const { - data: secretHashMetaData, - error, - loading: isGetSecretHashMetadataLoading, - } = useQuery({ + const { data: secretHashMetaData, error } = useQuery({ type: 'getSecretHashMetadata', resource: 'applications', payload: {}, @@ -332,6 +330,12 @@ export const ApplicationEditView = ({ } }, [secretHashMetaData, error]); + const { data: applicationApiKeyExpirySettings } = useQuery({ + type: 'getKeyExpirySettings', + resource: 'applications', + payload: {}, + }); + // get api keys data const [ fetchApiKeys, @@ -400,8 +404,6 @@ export const ApplicationEditView = ({ const keyData = { applicationUuid: apiKeyObject.applicationUuid, defaultKey: apiKeyObject.defaultKey, - keySecret: form.keySecret, - keySecretHashed: form.ShouldHash, name: apiKeyObject.name, oauthCallbackUrl: apiKeyObject.oauthCallbackUrl, oauthScope: apiKeyObject.oauthScope, @@ -737,6 +739,7 @@ export const ApplicationEditView = ({ ) : ( + + { + setDeleteKeyConfirm(false); + setKeyDeleting(true); + const apiKeyObj = apiKeys.find( + item => item.apiKey === deletingKeyId + ); + const isForceDelete = + isPortalAdmin(userContext) && + apiKeyObj.status === 'DELETE_FAILED'; + deleteApiKey( + proxyCheckFailed || isForceDelete, + isForceDelete + ); + }} + onCancel={() => setDeleteKeyConfirm(false)} + /> + + + + + + + + {isKeyExpiryEnabled && currentItemAPIKey && ( +
+ + + {expiryDateText} + + + + {expiryDateSubText} + +
+ )} + {!currentItemAPIKey && allowSelectHashing && ( + setSecretHashing(id)} + defaultValue="HASHED" + label="resources.applications.fields.secretType" + className={classes.input} + required + choices={[ + { + id: 'HASHED', + name: translate( + 'resources.applications.fields.hashed' + ), + }, + { + id: 'PLAIN', + name: translate( + 'resources.applications.fields.plain' + ), + }, + ]} + /> + )} + {currentItemAPIKey && ( + + )} + {get(scopedFormData, 'keySecret') && ( +
+ +
+ )} + + ); + }; + + const renderKeys = () => ( + + } + getItemLabel={() => ''} + TransitionProps={{ timeout: 0 }} + > + {renderKey} + + + ); + return ( @@ -1197,6 +1471,7 @@ export const ApplicationEditView = ({ validate={validateAppEdit} > @@ -1219,6 +1494,7 @@ export const ApplicationEditView = ({ className={classes.field} > )} {keysSummaryLabelContent} - {!apiKeysLoading && ( - - } - getItemLabel={() => ''} - TransitionProps={{ timeout: 0 }} - > - - {({ getSource, scopedFormData }) => { - if ( - !getSource('apiKey') && - !addingKeyEntry - ) { - return ; - } - return ( - - onPanelClick( - expanded, - `${PANEL_ID_KEY_PREFIX}${get( - scopedFormData, - 'apiKey' - ) || NEW_KEY}` - ) - } - > - -
- -
- { - setDeleteKeyConfirm( - false - ); - setKeyDeleting( - true - ); - const apiKeyObj = apiKeys.find( - item => - item.apiKey === - deletingKeyId - ); - const isForceDelete = - isPortalAdmin( - userContext - ) && - apiKeyObj.status === - 'DELETE_FAILED'; - deleteApiKey( - proxyCheckFailed || - isForceDelete, - isForceDelete - ); - }} - onCancel={() => - setDeleteKeyConfirm( - false - ) - } - /> - -
- - - - - - {!get( - scopedFormData, - 'apiKey' - ) && - allowSelectHashing && ( - - setSecretHashing( - id - ) - } - defaultValue="HASHED" - label="resources.applications.fields.secretType" - className={ - classes.input - } - required - choices={[ - { - id: - 'HASHED', - name: translate( - 'resources.applications.fields.hashed' - ), - }, - { - id: - 'PLAIN', - name: translate( - 'resources.applications.fields.plain' - ), - }, - ]} - /> - )} - {get( - scopedFormData, - 'apiKey' - ) && ( - - )} - {get( - scopedFormData, - 'keySecret' - ) && ( -
- -
- )} -
- ); - }} -
-
-
- )} + {!apiKeysLoading && renderKeys()}
{() => } @@ -1752,6 +1681,13 @@ const useStyles = makeStyles( marginTop: 16, width: '100%', }, + expiredKeyStatus: { + color: '#B30303', + fontWeight: theme.typography.fontWeightBold, + }, + keyExpiryStatus: { + marginBottom: 20, + }, }), { name: 'Layer7ApplicationDetails', diff --git a/packages/layer7-apihub/src/applications/ApplicationKeyClient.js b/packages/layer7-apihub/src/applications/ApplicationKeyClient.js index 97c3b68e3..2976eb1e3 100755 --- a/packages/layer7-apihub/src/applications/ApplicationKeyClient.js +++ b/packages/layer7-apihub/src/applications/ApplicationKeyClient.js @@ -7,6 +7,7 @@ import { makeStyles } from '@material-ui/core/styles'; import IconButton from '@material-ui/core/IconButton'; import IconFileCopy from '@material-ui/icons/FileCopy'; import Chip from '@material-ui/core/Chip'; +import get from 'lodash/get'; import { useCopyToClipboard } from '../ui'; @@ -34,7 +35,7 @@ export const ApplicationKeyClient = props => { 'resources.applications.fields.apiKeyClientID' )} - {isEditMode ? ( + {isEditMode && get(data, 'defaultKey') ? ( { className={classes.fieldContent} > - {data.keySecret} + {data.keySecretHashed + ? '********' + : data.keySecret} - {data.keySecret && - !data.keySecret.includes('****') && ( - - - - )} + {data.keySecret && !data.keySecretHashed && ( + + + + )}
diff --git a/packages/layer7-apihub/src/applications/ApplicationKeySecret.js b/packages/layer7-apihub/src/applications/ApplicationKeySecret.js index 1db5e9201..eee93a473 100755 --- a/packages/layer7-apihub/src/applications/ApplicationKeySecret.js +++ b/packages/layer7-apihub/src/applications/ApplicationKeySecret.js @@ -3,6 +3,7 @@ import { useTranslate } from 'ra-core'; import { Labeled, useQuery, useMutation } from 'react-admin'; import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; +import WarningIcon from '@material-ui/icons/Warning'; import Typography from '@material-ui/core/Typography'; import IconButton from '@material-ui/core/IconButton'; import IconFileCopy from '@material-ui/icons/FileCopy'; @@ -19,7 +20,14 @@ import { useLayer7Notify } from '../useLayer7Notify'; import { useCopyToClipboard } from '../ui'; export const ApplicationKeySecret = props => { - const { id: appUuid, record, isEditDisabled, labelClasses } = props; + const { + id: apiKey, + record, + isEditDisabled, + labelClasses, + onUpdateKeyDetails, + onGenerateKey, + } = props; const [open, setOpen] = useState(false); const classes = useStyles(props); @@ -31,11 +39,14 @@ export const ApplicationKeySecret = props => { const notify = useLayer7Notify(); const form = useForm(); - const [keySecret, setKeySecret] = useState(record.keySecret); + const keySecret = record.keySecret; + const isSecretHashed = get(record, 'keySecretHashed'); + const [generatedKeySecret, setGeneratedKeySecret] = useState(); const [isPlainTextSelected, setIsPlainTextSelected] = useState(true); const [isHashedSecretSetting, setIsHashedSecretSetting] = useState(false); const [allowSelectHashing, setAllowSelectHashing] = useState(false); - const [oneTimePassword, setOneTimePassword] = useState(false); + const [showPasswordDialog, setShowPasswordDialog] = useState(false); + const [hashSelected, setHashSelected] = useState(false); const handleClick = event => { const value = event.target.value; @@ -53,21 +64,66 @@ export const ApplicationKeySecret = props => { }; const handleClose = () => { - setOneTimePassword(false); + onGenerateKey(); + getKeyDetails(); + setShowPasswordDialog(false); setOpen(false); }; + const appUuid = record.applicationUuid; - const handleSecretClearAndClose = () => { - setKeySecret('***********'); - setOneTimePassword(false); - setOpen(false); - }; + const [ + getKeyDetails, + { data: updatedKeyDetails, loading: apiKeyDetailsLoading }, + ] = useMutation({ + type: 'getOne', + resource: 'apiKeys', + payload: { + appUuid, + apiKey, + }, + }); + + React.useEffect(() => { + if (!apiKeyDetailsLoading && updatedKeyDetails) { + onUpdateKeyDetails(updatedKeyDetails); + } + }, [apiKeyDetailsLoading, updatedKeyDetails]); + + const [ + regenerateMutate, + { + data: regeneratedSecret, + error: regenerateFailed, + loading: regeneratingSecret, + }, + ] = useMutation(); + + const regenerateSecret = hashSelectedParam => + regenerateMutate({ + type: 'generateSecret', + resource: 'applications', + payload: { + apiKey, + appUuid, + keySecretHashed: hashSelectedParam, + }, + }); + + React.useEffect(() => { + if (!regeneratingSecret && regeneratedSecret && !regenerateFailed) { + setGeneratedKeySecret(regeneratedSecret.keySecret); + notify( + 'resources.applications.notifications.secret_generated_heading' + ); + } + }, [regeneratedSecret, regeneratingSecret, regenerateFailed]); const { data, error, loading: isGetSecretHashMetadataLoading } = useQuery({ type: 'getSecretHashMetadata', resource: 'applications', payload: {}, }); + useEffect(() => { if (data && data.value) { const isPlainTextAllowed = get( @@ -83,31 +139,16 @@ export const ApplicationKeySecret = props => { } }, [data, error]); - /* - To generate random uuid - */ - const uuidv4 = () => { - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => - ( - c ^ - (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4))) - ).toString(16) - ); - }; - const generateKeySecret = () => { - const key = uuidv4().replace(/-/g, ''); - notify('resources.applications.notifications.secret_generated_heading'); + let keySecretHashed = false; if (isHashedSecretSetting && !isPlainTextSelected) { - setOneTimePassword(true); - setKeySecret(key); - form.change('ShouldHash', true); + keySecretHashed = true; } else { - setKeySecret(key); - setOpen(false); - form.change('ShouldHash', false); + keySecretHashed = false; } - form.change('keySecret', key); + setShowPasswordDialog(true); + setHashSelected(keySecretHashed); + regenerateSecret(keySecretHashed); }; if (isGetSecretHashMetadataLoading) { @@ -127,8 +168,10 @@ export const ApplicationKeySecret = props => { variant="body2" className={classes.fieldContent} > - {keySecret} - {keySecret && !keySecret.includes('****') && ( + + {isSecretHashed ? '********' : keySecret} + + {keySecret && !isSecretHashed && ( { )} - {oneTimePassword ? ( + {showPasswordDialog ? ( ) : ( { +const OneTimePasswordDialog = ({ + handleClose, + keySecretToShow, + showHashWarning, +}) => { const classes = useOneTimePasswordDialogStyles(); const copyToClipboard = useCopyToClipboard({ successMessage: 'resources.applications.notifications.copy_success', @@ -312,9 +364,6 @@ const OneTimePasswordDialog = ({ handleClose, keySecret }) => { const translate = useTranslate(); return (
-
- -
{translate( @@ -332,11 +381,6 @@ const OneTimePasswordDialog = ({ handleClose, keySecret }) => { 'resources.applications.notifications.copy_secret_now' )} - - {translate( - 'resources.applications.notifications.secret_generated_message' - )} -
{translate( @@ -344,11 +388,11 @@ const OneTimePasswordDialog = ({ handleClose, keySecret }) => { )} - {keySecret} + {keySecretToShow}
+ {showHashWarning && ( +
+ + + {translate( + 'resources.applications.notifications.hashed_secret_generated_message' + )} + +
+ )}