feat: add Registry Lock and Registrar Lock badges

This commit is contained in:
Maël Gangloff 2024-12-29 22:31:40 +01:00
parent f86153049b
commit 23fca8602e
No known key found for this signature in database
GPG Key ID: 11FDC81C24A7F629
10 changed files with 98 additions and 66 deletions

View File

@ -11,21 +11,32 @@ import {regionNames} from "../../i18n";
import {getCountryCode} from "../../utils/functions/getCountryCode";
import {eppStatusCodeToColor} from "../../utils/functions/eppStatusCodeToColor";
import {DomainLifecycleSteps} from "./DomainLifecycleSteps";
import useBreakpoint from "../../hooks/useBreakpoint";
import {BankOutlined, SafetyCertificateOutlined} from '@ant-design/icons'
export function DomainResult({domain}: { domain: Domain }) {
const rdapStatusCodeDetailTranslated = rdapStatusCodeDetailTranslation()
const {tld, events} = domain
const domainEvents = events.sort((e1, e2) => new Date(e2.date).getTime() - new Date(e1.date).getTime())
const xxl = useBreakpoint('xxl')
const clientStatus = domain.status.filter(s => s.startsWith('client'))
const serverStatus = domain.status.filter(s => !clientStatus.includes(s))
const isLocked = (type: 'client' | 'server'): boolean =>
(domain.status.includes(type + ' update prohibited') && domain.status.includes(type + ' delete prohibited'))
|| domain.status.includes(type + ' transfer prohibited')
const statusToTag = (s: string) => <Tooltip
placement='bottomLeft'
title={rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] || undefined}>
<Tag color={eppStatusCodeToColor(s)}>{s}</Tag>
</Tooltip>
return <Space direction="vertical" size="middle" style={{width: '100%'}}>
<Badge.Ribbon text={
<Tooltip
title={tld.type === 'ccTLD' ? regionNames.of(getCountryCode(tld.tld)) : tld.type === 'gTLD' ? tld?.registryOperator : undefined}>
{`${(domain.tld.tld === '.' ? '' : '.') + domain.tld.tld.toUpperCase()} (${tld.type})`}
{`${domain.tld.tld.toUpperCase()} (${tld.type})`}
</Tooltip>
}
color={
@ -43,21 +54,34 @@ export function DomainResult({domain}: { domain: Domain }) {
domain.events.length > 0 && <DomainLifecycleSteps status={domain.status}/>
}
<Row gutter={8}>
<Col span={xxl ? 24 : 12}>
<Col span={24} xl={12} xxl={12}>
<Flex justify='center' align='center' style={{margin: 10}}>
<Tooltip
title={t`Registry-level protection, ensuring the highest level of security by preventing unauthorized, unwanted, or accidental changes to the domain name at the registry level`}>
<Tag bordered={false} color={isLocked('server') ? 'green' : 'default'}
icon={<SafetyCertificateOutlined
style={{fontSize: '16px'}}/>}>{t`Registry Lock`}</Tag>
</Tooltip>
<Tooltip
title={t`Registrar-level protection, safeguarding the domain from unauthorized, unwanted, or accidental changes through registrar controls`}>
<Tag bordered={false} color={isLocked('client') ? 'green' : 'default'}
icon={<BankOutlined
style={{fontSize: '16px'}}/>}>{t`Registrar Lock`}</Tag>
</Tooltip>
</Flex>
{domain.status.length > 0 &&
<>
<Divider orientation="left">{t`EPP Status Codes`}</Divider>
<Flex gap="4px 0" wrap>
{
domain.status.map(s =>
<Tooltip
placement='bottomLeft'
title={s in rdapStatusCodeDetailTranslated ? rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] : undefined}>
<Tag color={eppStatusCodeToColor(s)}>{s}</Tag>
</Tooltip>
)
}
</Flex>
{
serverStatus && <Flex gap="4px 0" wrap>
{serverStatus.map(statusToTag)}
</Flex>
}
{
clientStatus && <Flex gap="4px 0" wrap>
{clientStatus.map(statusToTag)}
</Flex>
}
</>
}
{
@ -74,14 +98,11 @@ export function DomainResult({domain}: { domain: Domain }) {
</>
}
</Col>
{!xxl &&
<Col span={12}>
<DomainDiagram domain={domain}/>
</Col>
}
<Col span={24} xl={12} xxl={12}>
<DomainDiagram domain={domain}/>
</Col>
</Row>
</Card>
</Badge.Ribbon>
{xxl && <DomainDiagram domain={domain}/>}
</Space>
}

View File

@ -12,9 +12,8 @@ export function EntitiesList({domain}: { domain: Domain }) {
const rdapRoleDetailTranslated = rdapRoleDetailTranslation()
const roleToTag = (r: string) => <Tooltip
title={r in rdapRoleDetailTranslated ? rdapRoleDetailTranslated[r as keyof typeof rdapRoleDetailTranslated] : undefined}>
<Tag color={rolesToColor([r])}>{
r in rdapRoleTranslated ? rdapRoleTranslated[r as keyof typeof rdapRoleTranslated] : r
title={rdapRoleDetailTranslated[r as keyof typeof rdapRoleDetailTranslated] || undefined}>
<Tag color={rolesToColor([r])}>{rdapRoleTranslated[r as keyof typeof rdapRoleTranslated] || r
}</Tag>
</Tooltip>

View File

@ -18,14 +18,14 @@ export function EventTimeline({events}: { events: Event[] }) {
mode={sm ? "left" : "right"}
items={events.map(e => {
const eventName = <Typography.Text style={{color: e.deleted ? 'grey' : 'default'}}>
{e.action in rdapEventNameTranslated ? rdapEventNameTranslated[e.action as keyof typeof rdapEventNameTranslated] : e.action}
{rdapEventNameTranslated[e.action as keyof typeof rdapEventNameTranslated] || e.action}
</Typography.Text>
const dateStr = <Typography.Text
style={{color: e.deleted ? 'grey' : 'default'}}>{new Date(e.date).toLocaleString(locale)}
</Typography.Text>
const eventDetail = e.action in rdapEventDetailTranslated ? rdapEventDetailTranslated[e.action as keyof typeof rdapEventDetailTranslated] : undefined
const eventDetail = rdapEventDetailTranslated[e.action as keyof typeof rdapEventDetailTranslated] || undefined
const text = sm ? {
children: <Tooltip placement='bottom' title={eventDetail}>

View File

@ -47,7 +47,7 @@ export function TrackedDomainTable() {
expirationDate: expirationDate ? new Date(expirationDate).toLocaleString() : '-',
status: d.status.map(s => <Tooltip
placement='bottomLeft'
title={s in rdapStatusCodeDetailTranslated ? rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] : undefined}>
title={rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] || undefined}>
<Tag color={eppStatusCodeToColor(s)}>{s}</Tag>
</Tooltip>
),
@ -96,7 +96,7 @@ export function TrackedDomainTable() {
filters: [...new Set(dataTable.map((d: any) => d.domain.status).flat())].map(s => ({
text: <Tooltip
placement='bottomLeft'
title={s in rdapStatusCodeDetailTranslated ? rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] : undefined}>
title={rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] || undefined}>
<Tag color={eppStatusCodeToColor(s)}>{s}</Tag>
</Tooltip>,
value: s,

View File

@ -20,21 +20,9 @@ export function WatchlistCard({watchlist, onUpdateWatchlist, connectors, onDelet
connectors: (Connector & { id: string })[],
onDelete: () => void
}) {
const sm = useBreakpoint('sm')
const rdapEventNameTranslated = rdapEventNameTranslation()
const rdapEventDetailTranslated = rdapEventDetailTranslation()
const columns = [
{
title: t`Domain names`,
dataIndex: 'domains'
},
{
title: t`Tracked events`,
dataIndex: 'events'
}
]
return <>
<Card
type='inner'
@ -79,7 +67,7 @@ export function WatchlistCard({watchlist, onUpdateWatchlist, connectors, onDelet
<Col span={8}>
{watchlist.triggers?.filter(t => t.action === 'email')
.map(t => <Tooltip
title={t.event in rdapEventDetailTranslated ? rdapEventDetailTranslated[t.event as keyof typeof rdapEventDetailTranslated] : undefined}>
title={rdapEventDetailTranslated[t.event as keyof typeof rdapEventDetailTranslated] || undefined}>
<Tag color={actionToColor(t.event)}>
{rdapEventNameTranslated[t.event as keyof typeof rdapEventNameTranslated]}
</Tag>

View File

@ -43,7 +43,7 @@ export function WatchlistForm({form, connectors, onFinish, isCreation}: {
event.stopPropagation()
}
return (<Tooltip
title={value in rdapEventDetailTranslated ? rdapEventDetailTranslated[value as keyof typeof rdapEventDetailTranslated] : undefined}>
title={rdapEventDetailTranslated[value as keyof typeof rdapEventDetailTranslated] || undefined}>
<Tag
icon={actionToIcon(value)}
color={actionToColor(value)}
@ -164,7 +164,7 @@ export function WatchlistForm({form, connectors, onFinish, isCreation}: {
style={{width: '100%'}}
options={Object.keys(rdapEventNameTranslated).map(e => ({
value: e,
title: e in rdapEventDetailTranslated ? rdapEventDetailTranslated[e as keyof typeof rdapEventDetailTranslated] : undefined,
title: rdapEventDetailTranslated[e as keyof typeof rdapEventDetailTranslated] || undefined,
label: rdapEventNameTranslated[e as keyof typeof rdapEventNameTranslated]
}))}
/>

View File

@ -19,7 +19,7 @@ export function domainEntitiesToEdges(d: Domain, withRegistrar = false) {
target: e.roles.includes('registrant') || e.roles.includes('registrar') ? d.ldhName : e.entity.handle,
style: {stroke: rolesToColor(e.roles), strokeWidth: 3},
label: e.roles
.map(r => r in rdapRoleTranslated ? rdapRoleTranslated[r as keyof typeof rdapRoleTranslated] : r)
.map(r => rdapRoleTranslated[r as keyof typeof rdapRoleTranslated] || r)
.join(', '),
animated: e.roles.includes('registrant'),
}))

View File

@ -9,15 +9,18 @@ import {showErrorAPI} from "../../utils/functions/showErrorAPI";
import {useNavigate, useParams} from "react-router-dom";
export default function DomainSearchPage() {
const {query} = useParams()
const [domain, setDomain] = useState<Domain | null>()
const [loading, setLoading] = useState<boolean>(false)
const [messageApi, contextHolder] = message.useMessage()
const navigate = useNavigate()
const {query} = useParams()
const onFinish: FormProps<FieldType>['onFinish'] = (values) => {
navigate('/search/domain/' + values.ldhName)
if (loading) return
setLoading(true)
setDomain(null)
getDomain(values.ldhName).then(d => {
setDomain(d)
@ -25,14 +28,13 @@ export default function DomainSearchPage() {
}).catch((e: AxiosError) => {
setDomain(undefined)
showErrorAPI(e, messageApi)
})
}).finally(() => setLoading(false))
}
useEffect(() => {
if (query === undefined) return
onFinish({ldhName: query})
}, [query])
}, [])
return <Flex gap="middle" align="center" justify="center" vertical>
{contextHolder}

View File

@ -444,6 +444,9 @@ readonly class RDAPService
->setEntity($entity)
->setStatus(array_unique($rdapNameserver['status']))
->setRoles($roles));
$this->em->persist($nameserverEntity);
$this->em->flush();
}
}

View File

@ -97,15 +97,36 @@ msgstr ""
msgid "Pending Delete"
msgstr ""
#: assets/components/search/DomainResult.tsx:49
#: assets/components/search/DomainResult.tsx:60
msgid ""
"Registry-level protection, ensuring the highest level of security by "
"preventing unauthorized, unwanted, or accidental changes to the domain name "
"at the registry level"
msgstr ""
#: assets/components/search/DomainResult.tsx:63
msgid "Registry Lock"
msgstr ""
#: assets/components/search/DomainResult.tsx:66
msgid ""
"Registrar-level protection, safeguarding the domain from unauthorized, "
"unwanted, or accidental changes through registrar controls"
msgstr ""
#: assets/components/search/DomainResult.tsx:69
msgid "Registrar Lock"
msgstr ""
#: assets/components/search/DomainResult.tsx:74
msgid "EPP Status Codes"
msgstr ""
#: assets/components/search/DomainResult.tsx:65
#: assets/components/search/DomainResult.tsx:89
msgid "Timeline"
msgstr ""
#: assets/components/search/DomainResult.tsx:72
#: assets/components/search/DomainResult.tsx:96
msgid "Entities"
msgstr ""
@ -429,21 +450,11 @@ msgstr ""
msgid "Cancel"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistCard.tsx:29
#: assets/components/tracking/watchlist/WatchlistForm.tsx:106
msgid "Domain names"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistCard.tsx:33
#: assets/components/tracking/watchlist/WatchlistForm.tsx:148
msgid "Tracked events"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistCard.tsx:47
#: assets/components/tracking/watchlist/WatchlistCard.tsx:35
msgid "This Watchlist is not linked to a Connector."
msgstr ""
#: assets/components/tracking/watchlist/WatchlistCard.tsx:52
#: assets/components/tracking/watchlist/WatchlistCard.tsx:40
msgid "Watchlist"
msgstr ""
@ -463,6 +474,10 @@ msgstr ""
msgid "At least one domain name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:106
msgid "Domain names"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:124
msgid "Domain name"
msgstr ""
@ -471,6 +486,10 @@ msgstr ""
msgid "Add a Domain name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:148
msgid "Tracked events"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:150
msgid "At least one trigger"
msgstr ""
@ -514,11 +533,11 @@ msgstr ""
msgid "Sorry, the page you visited does not exist."
msgstr ""
#: assets/pages/search/DomainSearchPage.tsx:24
#: assets/pages/search/DomainSearchPage.tsx:27
msgid "Found !"
msgstr ""
#: assets/pages/search/DomainSearchPage.tsx:46
#: assets/pages/search/DomainSearchPage.tsx:48
msgid ""
"Although the domain exists in my database, it has been deleted from the "
"WHOIS by its registrar."