mirror of
https://github.com/status-im/safe-react.git
synced 2026-08-31 05:31:06 +00:00
[Address Book v2] - Prevent name validation in AB reducer (#2356)
Co-authored-by: katspaugh <katspaugh@users.noreply.github.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
addressIsNotCurrentSafe,
|
||||
OWNER_ADDRESS_IS_SAFE_ADDRESS_ERROR,
|
||||
mustBeHexData,
|
||||
validAddressBookName,
|
||||
} from 'src/components/forms/validator'
|
||||
|
||||
describe('Forms > Validators', () => {
|
||||
@@ -249,4 +250,26 @@ describe('Forms > Validators', () => {
|
||||
expect(differentFrom('a')('a')).toEqual(getDifferentFromErrMsg('a'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('validAddressBookName validator', () => {
|
||||
it('Returns error for an empty string', () => {
|
||||
expect(validAddressBookName('')).toBe('Should be 1 to 50 symbols')
|
||||
})
|
||||
it('Returns error for a name longer than 50 chars', () => {
|
||||
expect(validAddressBookName('abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabc')).toBe(
|
||||
'Should be 1 to 50 symbols',
|
||||
)
|
||||
})
|
||||
it('Returns error for a blacklisted name', () => {
|
||||
const blacklistedErrorMessage = 'Name should not include: UNKNOWN, OWNER #, MY WALLET'
|
||||
|
||||
expect(validAddressBookName('unknown')).toBe(blacklistedErrorMessage)
|
||||
expect(validAddressBookName('unknown a')).toBe(blacklistedErrorMessage)
|
||||
expect(validAddressBookName('owner #1')).toBe(blacklistedErrorMessage)
|
||||
expect(validAddressBookName('My Wallet')).toBe(blacklistedErrorMessage)
|
||||
})
|
||||
it('Returns undefined for a non-blacklisted name', () => {
|
||||
expect(validAddressBookName('A valid name')).toBeUndefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ import { getWeb3 } from 'src/logic/wallets/getWeb3'
|
||||
import { isFeatureEnabled } from 'src/config'
|
||||
import { FEATURES } from 'src/config/networks/network.d'
|
||||
import { isValidAddress } from 'src/utils/isValidAddress'
|
||||
import { ADDRESS_BOOK_INVALID_NAMES, isValidAddressBookName } from 'src/logic/addressBook/utils'
|
||||
|
||||
type ValidatorReturnType = string | undefined
|
||||
export type GenericValidatorType = (...args: unknown[]) => ValidatorReturnType
|
||||
@@ -134,3 +135,15 @@ export const differentFrom = (diffValue: number | string) => (value: string): Va
|
||||
}
|
||||
|
||||
export const noErrorsOn = (name: string, errors: Record<string, unknown>): boolean => errors[name] === undefined
|
||||
|
||||
export const validAddressBookName = (name: string): string | undefined => {
|
||||
const lengthError = minMaxLength(1, 50)(name)
|
||||
|
||||
if (lengthError === undefined) {
|
||||
return isValidAddressBookName(name)
|
||||
? undefined
|
||||
: `Name should not include: ${ADDRESS_BOOK_INVALID_NAMES.join(', ')}`
|
||||
}
|
||||
|
||||
return lengthError
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Action, handleActions } from 'redux-actions'
|
||||
|
||||
import { AddressBookEntry, AddressBookState } from 'src/logic/addressBook/model/addressBook'
|
||||
import { ADDRESS_BOOK_ACTIONS } from 'src/logic/addressBook/store/actions'
|
||||
import { getEntryIndex, isValidAddressBookName } from 'src/logic/addressBook/utils'
|
||||
import { getEntryIndex } from 'src/logic/addressBook/utils'
|
||||
import { AppReduxState } from 'src/store'
|
||||
|
||||
export const ADDRESS_BOOK_REDUCER_ID = 'addressBook'
|
||||
@@ -15,11 +15,6 @@ export default handleActions<AppReduxState['addressBook'], Payloads>(
|
||||
const newState = [...state]
|
||||
const addressBookEntry = action.payload
|
||||
|
||||
if (!isValidAddressBookName(addressBookEntry.name)) {
|
||||
// prevent adding an invalid name
|
||||
return newState
|
||||
}
|
||||
|
||||
const entryIndex = getEntryIndex(newState, addressBookEntry)
|
||||
|
||||
// update
|
||||
@@ -48,20 +43,17 @@ export default handleActions<AppReduxState['addressBook'], Payloads>(
|
||||
const newState = [...state]
|
||||
const addressBookEntries = action.payload
|
||||
|
||||
addressBookEntries
|
||||
// exclude those entries with invalid name
|
||||
.filter(({ name }) => isValidAddressBookName(name))
|
||||
.forEach((addressBookEntry) => {
|
||||
const entryIndex = getEntryIndex(newState, addressBookEntry)
|
||||
addressBookEntries.forEach((addressBookEntry) => {
|
||||
const entryIndex = getEntryIndex(newState, addressBookEntry)
|
||||
|
||||
if (entryIndex >= 0) {
|
||||
// update
|
||||
newState[entryIndex] = addressBookEntry
|
||||
} else {
|
||||
// add
|
||||
newState.push(addressBookEntry)
|
||||
}
|
||||
})
|
||||
if (entryIndex >= 0) {
|
||||
// update
|
||||
newState[entryIndex] = addressBookEntry
|
||||
} else {
|
||||
// add
|
||||
newState.push(addressBookEntry)
|
||||
}
|
||||
})
|
||||
|
||||
return newState
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@ export type OldAddressBookType = {
|
||||
[safeAddress: string]: [OldAddressBookEntry]
|
||||
}
|
||||
|
||||
const ADDRESS_BOOK_INVALID_NAMES = ['UNKNOWN', 'OWNER #', 'MY WALLET', '']
|
||||
export const ADDRESS_BOOK_INVALID_NAMES = ['UNKNOWN', 'OWNER #', 'MY WALLET']
|
||||
|
||||
type GetNameFromAddressBookOptions = {
|
||||
filterOnlyValidName: boolean
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
noErrorsOn,
|
||||
required,
|
||||
composeValidators,
|
||||
minMaxLength,
|
||||
validAddressBookName,
|
||||
} from 'src/components/forms/validator'
|
||||
import Block from 'src/components/layout/Block'
|
||||
import Col from 'src/components/layout/Col'
|
||||
@@ -95,7 +95,7 @@ const DetailsForm = ({ errors, form }: DetailsFormProps): React.ReactElement =>
|
||||
placeholder="Name of the Safe*"
|
||||
text="Safe name"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(1, 50))}
|
||||
validate={composeValidators(required, validAddressBookName)}
|
||||
testId="load-safe-name-field"
|
||||
/>
|
||||
</Col>
|
||||
|
||||
@@ -5,7 +5,7 @@ import styled from 'styled-components'
|
||||
import OpenPaper from 'src/components/Stepper/OpenPaper'
|
||||
import Field from 'src/components/forms/Field'
|
||||
import TextField from 'src/components/forms/TextField'
|
||||
import { composeValidators, minMaxLength, required } from 'src/components/forms/validator'
|
||||
import { composeValidators, required, validAddressBookName } from 'src/components/forms/validator'
|
||||
import Block from 'src/components/layout/Block'
|
||||
import Paragraph from 'src/components/layout/Paragraph'
|
||||
import { FIELD_NAME } from 'src/routes/open/components/fields'
|
||||
@@ -56,7 +56,7 @@ const SafeNameForm = ({ safeName }: { safeName: string }): React.ReactElement =>
|
||||
placeholder="Name of the new Safe"
|
||||
text="Safe name"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(1, 50))}
|
||||
validate={composeValidators(required, validAddressBookName)}
|
||||
testId="create-safe-name-field"
|
||||
/>
|
||||
</Block>
|
||||
|
||||
@@ -9,7 +9,7 @@ import AddressInput from 'src/components/forms/AddressInput'
|
||||
import Field from 'src/components/forms/Field'
|
||||
import GnoForm from 'src/components/forms/GnoForm'
|
||||
import TextField from 'src/components/forms/TextField'
|
||||
import { composeValidators, minMaxLength, required, uniqueAddress } from 'src/components/forms/validator'
|
||||
import { composeValidators, required, uniqueAddress, validAddressBookName } from 'src/components/forms/validator'
|
||||
import Block from 'src/components/layout/Block'
|
||||
import Col from 'src/components/layout/Col'
|
||||
import Row from 'src/components/layout/Row'
|
||||
@@ -90,11 +90,11 @@ export const CreateEditEntryModal = ({
|
||||
<Field
|
||||
component={TextField}
|
||||
name="name"
|
||||
placeholder="Name"
|
||||
placeholder="Name*"
|
||||
testId={CREATE_ENTRY_INPUT_NAME_ID}
|
||||
text="Name"
|
||||
text="Name*"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(1, 50))}
|
||||
validate={composeValidators(required, validAddressBookName)}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
+2
-2
@@ -17,9 +17,9 @@ import TextField from 'src/components/forms/TextField'
|
||||
import {
|
||||
addressIsNotCurrentSafe,
|
||||
composeValidators,
|
||||
minMaxLength,
|
||||
required,
|
||||
uniqueAddress,
|
||||
validAddressBookName,
|
||||
} from 'src/components/forms/validator'
|
||||
import Block from 'src/components/layout/Block'
|
||||
import Col from 'src/components/layout/Col'
|
||||
@@ -118,7 +118,7 @@ export const OwnerForm = ({ onClose, onSubmit, initialValues }: OwnerFormProps):
|
||||
testId={ADD_OWNER_NAME_INPUT_TEST_ID}
|
||||
text="Owner name*"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(1, 50))}
|
||||
validate={composeValidators(required, validAddressBookName)}
|
||||
/>
|
||||
<OnChange name="ownerAddress">
|
||||
{async (address: string) => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useDispatch } from 'react-redux'
|
||||
import Field from 'src/components/forms/Field'
|
||||
import GnoForm from 'src/components/forms/GnoForm'
|
||||
import TextField from 'src/components/forms/TextField'
|
||||
import { composeValidators, minMaxLength, required } from 'src/components/forms/validator'
|
||||
import { composeValidators, required, validAddressBookName } from 'src/components/forms/validator'
|
||||
import Block from 'src/components/layout/Block'
|
||||
import Hairline from 'src/components/layout/Hairline'
|
||||
import Paragraph from 'src/components/layout/Paragraph'
|
||||
@@ -76,7 +76,7 @@ export const EditOwnerModal = ({ isOpen, onClose, owner }: OwnProps): React.Reac
|
||||
testId={RENAME_OWNER_INPUT_TEST_ID}
|
||||
text="Owner name*"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(1, 50))}
|
||||
validate={composeValidators(required, validAddressBookName)}
|
||||
/>
|
||||
</Row>
|
||||
<Row>
|
||||
|
||||
+2
-2
@@ -12,9 +12,9 @@ import TextField from 'src/components/forms/TextField'
|
||||
import {
|
||||
addressIsNotCurrentSafe,
|
||||
composeValidators,
|
||||
minMaxLength,
|
||||
required,
|
||||
uniqueAddress,
|
||||
validAddressBookName,
|
||||
} from 'src/components/forms/validator'
|
||||
import Block from 'src/components/layout/Block'
|
||||
import Col from 'src/components/layout/Col'
|
||||
@@ -146,7 +146,7 @@ export const OwnerForm = ({ onClose, onSubmit, owner, initialValues }: OwnerForm
|
||||
testId={REPLACE_OWNER_NAME_INPUT_TEST_ID}
|
||||
text="Owner name*"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(1, 50))}
|
||||
validate={composeValidators(required, validAddressBookName)}
|
||||
/>
|
||||
<OnChange name="ownerAddress">
|
||||
{async (address: string) => {
|
||||
|
||||
@@ -10,7 +10,7 @@ import Modal from 'src/components/Modal'
|
||||
import Field from 'src/components/forms/Field'
|
||||
import GnoForm from 'src/components/forms/GnoForm'
|
||||
import TextField from 'src/components/forms/TextField'
|
||||
import { composeValidators, minMaxLength, required } from 'src/components/forms/validator'
|
||||
import { composeValidators, required, validAddressBookName } from 'src/components/forms/validator'
|
||||
import Block from 'src/components/layout/Block'
|
||||
import Button from 'src/components/layout/Button'
|
||||
import Col from 'src/components/layout/Col'
|
||||
@@ -166,7 +166,7 @@ const SafeDetails = (): ReactElement => {
|
||||
testId={SAFE_NAME_INPUT_TEST_ID}
|
||||
text="Safe name*"
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(1, 50))}
|
||||
validate={composeValidators(required, validAddressBookName)}
|
||||
/>
|
||||
</Block>
|
||||
</Block>
|
||||
|
||||
Reference in New Issue
Block a user