import * as Tooltip from '@radix-ui/react-tooltip' import { Address4 } from 'ip-address' import { useState } from 'react' import { Button, Form, IconHelpCircle, Input, Modal } from 'ui' import { useParams } from 'common/hooks' import InformationBox from 'components/ui/InformationBox' import { useNetworkRestrictionsApplyMutation } from 'data/network-restrictions/network-retrictions-apply-mutation' import { useStore } from 'hooks' import { checkIfPrivate, getAddressEndRange } from './NetworkRestrictions.utils' interface AddRestrictionModalProps { restrictedIps: string[] visible: boolean hasOverachingRestriction: boolean onClose: () => void } const AddRestrictionModal = ({ restrictedIps, visible, hasOverachingRestriction, onClose, }: AddRestrictionModalProps) => { const formId = 'add-restriction-form' const { ui } = useStore() const { ref } = useParams() const { mutate: applyNetworkRestrictions, isLoading: isApplying } = useNetworkRestrictionsApplyMutation({ onSuccess: () => onClose() }) const validate = (values: any) => { const errors: any = {} const { ipAddress, cidrBlockSize } = values // Validate CIDR block size const isOutOfCidrSizeRange = cidrBlockSize < 0 || cidrBlockSize > 32 if (cidrBlockSize.length === 0 || isOutOfCidrSizeRange) { errors.cidrBlockSize = 'Size has to be between 0 to 32' } // Validate IP address const isValid = Address4.isValid(ipAddress) if (!isValid) { errors.ipAddress = 'Please enter a valid IP address' return errors } const isPrivate = checkIfPrivate(ipAddress) if (isPrivate) errors.ipAddress = 'Private IP addresses are not supported' return errors } const onSubmit = async (values: any) => { if (!ref) return console.error('Project ref is required') const cidr = `${values.ipAddress}/${values.cidrBlockSize}` const alreadyExists = restrictedIps.includes(cidr) if (alreadyExists) { return ui.setNotification({ category: 'info', message: `The address ${cidr} is already restricted`, }) } const dbAllowedCidrs = hasOverachingRestriction ? [cidr] : [...restrictedIps, cidr] applyNetworkRestrictions({ projectRef: ref, dbAllowedCidrs }) } return (
{({ values, resetForm }: any) => { const isPrivate = Address4.isValid(values.ipAddress) ? checkIfPrivate(values.ipAddress) : false const isValidBlockSize = values.cidrBlockSize !== '' && values.cidrBlockSize >= 0 && values.cidrBlockSize <= 32 const availableAddresses = Math.pow(2, 32 - (values?.cidrBlockSize ?? 0)) const addressRange = getAddressEndRange(`${values.ipAddress}/${values.cidrBlockSize}`) const isValidCIDR = isValidBlockSize && !isPrivate && addressRange !== undefined // [Alaister] although this "technically" is breaking the rules of React hooks // it won't error because the hooks are always rendered in the same order // eslint-disable-next-line react-hooks/rules-of-hooks const [isFetchingAddress, setIsFetchingAddress] = useState(false) const getClientIpAddress = async () => { setIsFetchingAddress(true) const res = await fetch('http://www.geoplugin.net/json.gp', { method: 'GET' }) const { geoplugin_request } = await res.json() if (geoplugin_request) { const updatedValues = { ...values, ipAddress: geoplugin_request, cidrBlockSize: 32 } resetForm({ initialValues: updatedValues, values: updatedValues }) } else { ui.setNotification({ category: 'error', duration: 4000, message: 'Failed to retrieve client IP address, please enter address manually', }) } setIsFetchingAddress(false) } return ( <>

This will add an IP address range to a list of allowed ranges that can access your database. Only IPv4 addresses are supported at the moment.

CIDR Block Size

Classless inter-domain routing (CIDR) notation is the notation used to identify networks and hosts in the networks. The block size tells us how many bits we need to take for the network prefix, and is a value between 0 to 32.
} id="cidrBlockSize" name="cidrBlockSize" type="number" placeholder="32" min={0} max={32} />
{isValidCIDR ? (

The address range{' '} {values.ipAddress}/{values.cidrBlockSize} {' '} will be restricted

Selected address space: {addressRange.start}{' '} to {addressRange.end}{' '}

Number of addresses: {availableAddresses}

) : (

A summary of your restriction will be shown here after entering a valid IP address and CIDR block size

)}
) }}
) } export default AddRestrictionModal