Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow removal of nxdomains #4565

Merged
merged 3 commits into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions api/src/domain/mutations/__tests__/remove-domain.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3424,15 +3424,15 @@ describe('removing a domain', () => {
removeDomain: {
result: {
code: 403,
description: 'Permission Denied: Please contact super admin for help with removing domain.',
description: 'Permission Denied: Please contact organization admin for help with removing domain.',
},
},
},
}

expect(response).toEqual(error)
expect(consoleOutput).toEqual([
`User: 123 attempted to remove domain.gc.ca in temp-org but does not have permission to remove a domain from a verified check org.`,
`User: 123 attempted to remove domain.gc.ca in temp-org however they do not have permission in that org.`,
])
})
})
Expand Down Expand Up @@ -3499,15 +3499,15 @@ describe('removing a domain', () => {
removeDomain: {
result: {
code: 403,
description: 'Permission Denied: Please contact super admin for help with removing domain.',
description: 'Permission Denied: Please contact organization admin for help with removing domain.',
},
},
},
}

expect(response).toEqual(error)
expect(consoleOutput).toEqual([
`User: 123 attempted to remove domain.gc.ca in temp-org but does not have permission to remove a domain from a verified check org.`,
`User: 123 attempted to remove domain.gc.ca in temp-org however they do not have permission in that org.`,
])
})
})
Expand Down Expand Up @@ -4572,15 +4572,15 @@ describe('removing a domain', () => {
result: {
code: 403,
description:
"Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide sur la mise à jour de ce domaine.",
"Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide afin de supprimer le domaine.",
},
},
},
}

expect(response).toEqual(error)
expect(consoleOutput).toEqual([
`User: 123 attempted to remove domain.gc.ca in temp-org but does not have permission to remove a domain from a verified check org.`,
`User: 123 attempted to remove domain.gc.ca in temp-org however they do not have permission in that org.`,
])
})
})
Expand Down Expand Up @@ -4648,15 +4648,15 @@ describe('removing a domain', () => {
result: {
code: 403,
description:
"Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide sur la mise à jour de ce domaine.",
"Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide afin de supprimer le domaine.",
},
},
},
}

expect(response).toEqual(error)
expect(consoleOutput).toEqual([
`User: 123 attempted to remove domain.gc.ca in temp-org but does not have permission to remove a domain from a verified check org.`,
`User: 123 attempted to remove domain.gc.ca in temp-org however they do not have permission in that org.`,
])
})
})
Expand Down
15 changes: 8 additions & 7 deletions api/src/domain/mutations/remove-domain.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,26 +84,27 @@ export const removeDomain = new mutationWithClientMutationId({
// Get permission
const permission = await checkPermission({ orgId: org._id })

// Check to see if domain belongs to verified check org
if (org.verified && permission !== 'super_admin') {
if (permission !== 'super_admin' && permission !== 'admin') {
console.warn(
`User: ${userKey} attempted to remove ${domain.domain} in ${org.slug} but does not have permission to remove a domain from a verified check org.`,
`User: ${userKey} attempted to remove ${domain.domain} in ${org.slug} however they do not have permission in that org.`,
)
return {
_type: 'error',
code: 403,
description: i18n._(t`Permission Denied: Please contact super admin for help with removing domain.`),
description: i18n._(t`Permission Denied: Please contact organization admin for help with removing domain.`),
}
}

if (permission !== 'super_admin' && permission !== 'admin') {
// Check to see if domain belongs to verified check org
// if domain returns NXDOMAIN, allow removal
if (org.verified && permission !== 'super_admin' && domain.rcode !== 'NXDOMAIN') {
console.warn(
`User: ${userKey} attempted to remove ${domain.domain} in ${org.slug} however they do not have permission in that org.`,
`User: ${userKey} attempted to remove ${domain.domain} in ${org.slug} but does not have permission to remove a domain from a verified check org.`,
)
return {
_type: 'error',
code: 403,
description: i18n._(t`Permission Denied: Please contact organization admin for help with removing domain.`),
description: i18n._(t`Permission Denied: Please contact super admin for help with removing domain.`),
}
}

Expand Down
8 changes: 7 additions & 1 deletion frontend/src/admin/AdminDomainCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ExternalLinkIcon } from '@chakra-ui/icons'

import { sanitizeUrl } from '../utilities/sanitizeUrl'

export function AdminDomainCard({ url, tags, isHidden, isArchived, ...rest }) {
export function AdminDomainCard({ url, tags, isHidden, isArchived, rcode, ...rest }) {
return (
<ListItem {...rest}>
<Grid templateColumns={{ base: 'auto', md: '40% 60%' }} columnGap="1.5rem">
Expand Down Expand Up @@ -35,6 +35,11 @@ export function AdminDomainCard({ url, tags, isHidden, isArchived, ...rest }) {
</Tag>
)
})}
{rcode === 'NXDOMAIN' && (
<Tag colorScheme="red" mr="auto" alignSelf="center">
NXDOMAIN
</Tag>
)}
{isHidden && (
<Tag m="1" borderRadius="full" borderWidth="1px" borderColor="gray.900">
<TagLabel mx="auto">
Expand All @@ -59,4 +64,5 @@ AdminDomainCard.propTypes = {
tags: array,
isHidden: bool,
isArchived: bool,
rcode: string,
}
124 changes: 36 additions & 88 deletions frontend/src/admin/AdminDomains.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId, permission }) {
const { i18n } = useLingui()

const [newDomainUrl, setNewDomainUrl] = useState('')
const [selectedRemoveDomainUrl, setSelectedRemoveDomainUrl] = useState()
const [selectedRemoveDomainId, setSelectedRemoveDomainId] = useState()
const [selectedRemoveProps, setSelectedRemoveProps] = useState({
domain: '',
domainId: '',
rcode: '',
})
// const [selectedRemoveDomainId, setSelectedRemoveDomainId] = useState()
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState('')
const [modalProps, setModalProps] = useState({
hidden: false,
Expand All @@ -61,34 +65,19 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId, permission }) {
editingDomainUrl: '',
})

const {
isOpen: updateIsOpen,
onOpen: updateOnOpen,
onClose: updateOnClose,
} = useDisclosure()
const {
isOpen: removeIsOpen,
onOpen: removeOnOpen,
onClose: removeOnClose,
} = useDisclosure()
const { isOpen: updateIsOpen, onOpen: updateOnOpen, onClose: updateOnClose } = useDisclosure()
const { isOpen: removeIsOpen, onOpen: removeOnOpen, onClose: removeOnClose } = useDisclosure()

const {
loading,
isLoadingMore,
error,
nodes,
next,
previous,
hasNextPage,
hasPreviousPage,
} = usePaginatedCollection({
fetchForward: FORWARD,
recordsPerPage: domainsPerPage,
variables: { orgSlug, search: debouncedSearchTerm },
relayRoot: 'findOrganizationBySlug.domains',
fetchPolicy: 'cache-and-network',
nextFetchPolicy: 'cache-first',
})
const { loading, isLoadingMore, error, nodes, next, previous, hasNextPage, hasPreviousPage } = usePaginatedCollection(
{
fetchForward: FORWARD,
recordsPerPage: domainsPerPage,
variables: { orgSlug, search: debouncedSearchTerm },
relayRoot: 'findOrganizationBySlug.domains',
fetchPolicy: 'cache-and-network',
nextFetchPolicy: 'cache-first',
},
)

const memoizedSetDebouncedSearchTermCallback = useCallback(() => {
setDebouncedSearchTerm(newDomainUrl)
Expand Down Expand Up @@ -157,26 +146,14 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId, permission }) {
</Text>
)}
>
{(
{
id: domainId,
domain,
selectors,
claimTags,
hidden,
archived,
organizations,
},
index,
) => (
{({ id: domainId, domain, selectors, claimTags, hidden, archived, rcode, organizations }, index) => (
<Box key={'admindomain' + index}>
<Stack isInline align="center">
<Stack direction="row" flexGrow="0">
<IconButton
data-testid={`remove-${index}`}
onClick={() => {
setSelectedRemoveDomainUrl(domain)
setSelectedRemoveDomainId(domainId)
setSelectedRemoveProps({ domain, domainId, rcode })
removeOnOpen()
}}
variant="danger"
Expand Down Expand Up @@ -210,6 +187,7 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId, permission }) {
tags={claimTags}
isHidden={hidden}
isArchived={archived}
rcode={rcode}
locale={i18n.locale}
flexGrow={1}
fontSize={{ base: '75%', sm: '100%' }}
Expand Down Expand Up @@ -241,21 +219,10 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId, permission }) {
}}
>
<Flex flexDirection={{ base: 'column', md: 'row' }} align="center">
<Text
as="label"
htmlFor="Search-for-domain-field"
fontSize="md"
fontWeight="bold"
textAlign="center"
mr={2}
>
<Text as="label" htmlFor="Search-for-domain-field" fontSize="md" fontWeight="bold" textAlign="center" mr={2}>
<Trans>Search: </Trans>
</Text>
<InputGroup
width={{ base: '100%', md: '75%' }}
mb={{ base: '8px', md: '0' }}
mr={{ base: '0', md: '4' }}
>
<InputGroup width={{ base: '100%', md: '75%' }} mb={{ base: '8px', md: '0' }} mr={{ base: '0', md: '4' }}>
<InputLeftElement aria-hidden="true">
<PlusSquareIcon color="gray.300" />
</InputLeftElement>
Expand All @@ -267,12 +234,7 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId, permission }) {
onChange={(e) => setNewDomainUrl(e.target.value)}
/>
</InputGroup>
<Button
id="addDomainBtn"
width={{ base: '100%', md: '25%' }}
variant="primary"
type="submit"
>
<Button id="addDomainBtn" width={{ base: '100%', md: '25%' }} variant="primary" type="submit">
<AddIcon mr={2} aria-hidden="true" />
<Trans>Add Domain</Trans>
</Button>
Expand Down Expand Up @@ -300,31 +262,27 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId, permission }) {
permission={permission}
/>

<Modal
isOpen={removeIsOpen}
onClose={removeOnClose}
motionPreset="slideInBottom"
>
<Modal isOpen={removeIsOpen} onClose={removeOnClose} motionPreset="slideInBottom">
<ModalOverlay />
<ModalContent pb={4}>
<Formik
initialValues={{
reason: '',
reason: selectedRemoveProps.rcode === 'NXDOMAIN' ? 'NONEXISTENT' : '',
}}
initialTouched={{
reason: true,
}}
onSubmit={async (values) => {
removeDomain({
variables: {
domainId: selectedRemoveDomainId,
domainId: selectedRemoveProps.selectedRemoveDomainId,
orgId: orgId,
reason: values.reason,
},
})
}}
>
{({ handleSubmit, isSubmitting, handleChange }) => (
{({ values, handleSubmit, isSubmitting, handleChange }) => (
<form id="form" onSubmit={handleSubmit}>
<ModalHeader>
<Trans>Remove Domain</Trans>
Expand All @@ -335,15 +293,13 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId, permission }) {
<Text>
<Trans>Confirm removal of domain:</Trans>
</Text>
<Text fontWeight="bold">{selectedRemoveDomainUrl}</Text>
<Text fontWeight="bold">{selectedRemoveProps.selectedRemoveDomainUrl}</Text>

<Text>
<Trans>
A domain may only be removed for one of the reasons
below. For a domain to no longer exist, it must be
removed from the DNS. If you need to remove this domain
for a different reason, please contact TBS Cyber
Security.
A domain may only be removed for one of the reasons below. For a domain to no longer exist, it
must be removed from the DNS. If you need to remove this domain for a different reason, please
contact TBS Cyber Security.
</Trans>
</Text>

Expand All @@ -353,36 +309,28 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId, permission }) {
</FormLabel>
<Select
isRequired
defaultValue={values.reason}
borderColor="black"
name="reason"
id="reason"
onChange={handleChange}
>
<option hidden value="">
<Trans>
Select a reason for removing this domain
</Trans>
<Trans>Select a reason for removing this domain</Trans>
</option>
<option value="NONEXISTENT">
<Trans>This domain no longer exists</Trans>
</option>
<option value="WRONG_ORG">
<Trans>
This domain does not belong to this organization
</Trans>
<Trans>This domain does not belong to this organization</Trans>
</option>
</Select>
</FormControl>
</Stack>
</ModalBody>

<ModalFooter>
<Button
variant="primary"
mr={4}
isLoading={isSubmitting}
type="submit"
>
<Button variant="primary" mr={4} isLoading={isSubmitting} type="submit">
<Trans>Confirm</Trans>
</Button>
</ModalFooter>
Expand Down
Loading