mirror of
https://github.com/maelgangloff/domain-watchdog.git
synced 2025-12-29 16:15:04 +00:00
chore: merge master
This commit is contained in:
47
assets/components/search/DomainDiagram.tsx
Normal file
47
assets/components/search/DomainDiagram.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {Background, Controls, MiniMap, ReactFlow, useEdgesState, useNodesState} from "@xyflow/react";
|
||||
import {Flex} from "antd";
|
||||
import {Domain} from "../../utils/api";
|
||||
import {getLayoutedElements} from "../tracking/watchlist/diagram/getLayoutedElements";
|
||||
import {domainEntitiesToNode, domainToNode, nsToNode, tldToNode} from "../tracking/watchlist/diagram/watchlistToNodes";
|
||||
import {domainEntitiesToEdges, domainNSToEdges, tldToEdge} from "../tracking/watchlist/diagram/watchlistToEdges";
|
||||
|
||||
export function DomainDiagram({domain}: { domain: Domain }) {
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([])
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const e = getLayoutedElements([
|
||||
domainToNode(domain),
|
||||
...domainEntitiesToNode(domain),
|
||||
tldToNode(domain.tld),
|
||||
...domain.nameservers.map(nsToNode)
|
||||
].flat(), [
|
||||
domainEntitiesToEdges(domain),
|
||||
tldToEdge(domain),
|
||||
...domainNSToEdges(domain)
|
||||
].flat())
|
||||
|
||||
setNodes(e.nodes)
|
||||
setEdges(e.edges)
|
||||
}, [])
|
||||
|
||||
return <Flex style={{width: '80vw', height: '80vh'}}>
|
||||
<ReactFlow
|
||||
fitView
|
||||
colorMode='system'
|
||||
nodesConnectable={false}
|
||||
edgesReconnectable={false}
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
style={{width: '100%', height: '100%'}}
|
||||
>
|
||||
<MiniMap/>
|
||||
<Controls/>
|
||||
<Background/>
|
||||
</ReactFlow>
|
||||
</Flex>
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import punycode from "punycode/punycode";
|
||||
import {Connector} from "../../../utils/api/connectors";
|
||||
import {UpdateWatchlistButton} from "./UpdateWatchlistButton";
|
||||
import {DeleteWatchlistButton} from "./DeleteWatchlistButton";
|
||||
import {ViewDiagramWatchlistButton} from "../diagram/ViewDiagramWatchlistButton";
|
||||
import {ViewDiagramWatchlistButton} from "./diagram/ViewDiagramWatchlistButton";
|
||||
|
||||
export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connectors}: {
|
||||
watchlists: Watchlist[],
|
||||
|
||||
@@ -2,72 +2,26 @@ import {Button, Flex, Modal, Space, Typography} from "antd"
|
||||
import {t} from "ttag"
|
||||
import React, {useEffect, useState} from "react"
|
||||
import {ApartmentOutlined} from "@ant-design/icons"
|
||||
import vCard from "vcf";
|
||||
|
||||
import '@xyflow/react/dist/style.css'
|
||||
import {Background, Controls, MiniMap, ReactFlow, useEdgesState, useNodesState} from "@xyflow/react";
|
||||
import {getWatchlist, Watchlist} from "../../../utils/api";
|
||||
import {translateRoles} from "../../search/EntitiesList";
|
||||
import {getWatchlist} from "../../../../utils/api";
|
||||
import {getLayoutedElements} from "./getLayoutedElements";
|
||||
import {watchlistToNodes} from "./watchlistToNodes";
|
||||
import {watchlistToEdges} from "./watchlistToEdges";
|
||||
|
||||
|
||||
function watchlistToNodes(watchlist: Watchlist) {
|
||||
const domains = watchlist.domains.map(d => ({
|
||||
id: d.ldhName,
|
||||
data: {label: <b>{d.ldhName}</b>},
|
||||
style: {
|
||||
width: 200
|
||||
}
|
||||
}))
|
||||
const entities = [...new Set(watchlist.domains
|
||||
.map(d => d.entities
|
||||
.filter(e => !e.roles.includes('registrar'))
|
||||
.map(e => e.entity
|
||||
)
|
||||
).flat())].map(e => {
|
||||
const jCard = vCard.fromJSON(e.jCard)
|
||||
let label = e.handle
|
||||
if (jCard.data.fn !== undefined && !Array.isArray(jCard.data.fn)) label = jCard.data.fn.valueOf()
|
||||
|
||||
return {
|
||||
id: e.handle,
|
||||
data: {label},
|
||||
style: {
|
||||
width: 200
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return [...domains, ...entities]
|
||||
}
|
||||
|
||||
const rolesToColor = (roles: string[]) => roles.includes('registrant') ? 'green' :
|
||||
roles.includes('administrative') ? 'blue' :
|
||||
roles.includes('technical') ? 'orange' : 'violet'
|
||||
|
||||
function watchlistToEdges(watchlist: Watchlist) {
|
||||
const domainRole = translateRoles()
|
||||
|
||||
return watchlist.domains
|
||||
.map(d => d.entities
|
||||
.filter(e => !e.roles.includes('registrar'))
|
||||
.map(e => ({
|
||||
id: `${d.ldhName}-${e.entity.handle}`,
|
||||
source: e.roles.includes('technical') ? d.ldhName : e.entity.handle,
|
||||
target: e.roles.includes('technical') ? e.entity.handle : d.ldhName,
|
||||
style: {stroke: rolesToColor(e.roles), strokeWidth: 3},
|
||||
label: e.roles.map(r => Object.keys(domainRole).includes(r) ? domainRole[r as keyof typeof domainRole] : r).join(', '),
|
||||
animated: e.roles.includes('registrant'),
|
||||
}))
|
||||
).flat(2)
|
||||
export type DiagramConfig = {
|
||||
tld?: boolean
|
||||
nameserver?: boolean
|
||||
entities?: boolean
|
||||
}
|
||||
|
||||
export function ViewDiagramWatchlistButton({token}: { token: string }) {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const [open, setOpen] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([])
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([])
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
@@ -0,0 +1,47 @@
|
||||
import {Domain, Watchlist} from "../../../../utils/api";
|
||||
import {translateRoles} from "../../../search/EntitiesList";
|
||||
import {t} from "ttag";
|
||||
|
||||
const rolesToColor = (roles: string[]) => roles.includes('registrant') ? 'green' :
|
||||
roles.includes('administrative') ? 'blue' :
|
||||
roles.includes('technical') ? 'orange' : 'violet'
|
||||
|
||||
export function domainEntitiesToEdges(d: Domain) {
|
||||
const domainRole = translateRoles()
|
||||
return d.entities
|
||||
.filter(e => !e.roles.includes('registrar')) //
|
||||
.map(e => ({
|
||||
id: `e-${d.ldhName}-${e.entity.handle}`,
|
||||
source: e.roles.includes('registrant') ? e.entity.handle : d.ldhName,
|
||||
target: e.roles.includes('registrant') ? d.ldhName : e.entity.handle,
|
||||
style: {stroke: rolesToColor(e.roles), strokeWidth: 3},
|
||||
label: e.roles
|
||||
.map(r => Object.keys(domainRole).includes(r) ? domainRole[r as keyof typeof domainRole] : r)
|
||||
.join(', '),
|
||||
animated: e.roles.includes('registrant'),
|
||||
}))
|
||||
}
|
||||
|
||||
export const domainNSToEdges = (d: Domain) => d.nameservers
|
||||
.map(ns => ({
|
||||
id: `ns-${d.ldhName}-${ns.ldhName}`,
|
||||
source: d.ldhName,
|
||||
target: ns.ldhName,
|
||||
style: {stroke: 'grey', strokeWidth: 3},
|
||||
label: 'DNS'
|
||||
}))
|
||||
|
||||
export const tldToEdge = (d: Domain) => ({
|
||||
id: `tld-${d.ldhName}-${d.tld.tld}`,
|
||||
source: d.tld.tld,
|
||||
target: d.ldhName,
|
||||
style: {stroke: 'yellow', strokeWidth: 3},
|
||||
label: t`Registry`
|
||||
})
|
||||
|
||||
export function watchlistToEdges(watchlist: Watchlist) {
|
||||
const entitiesEdges = watchlist.domains.map(domainEntitiesToEdges).flat()
|
||||
const nameserversEdges = watchlist.domains.map(domainNSToEdges).flat()
|
||||
|
||||
return [...entitiesEdges, ...nameserversEdges]
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import {Domain, Nameserver, Tld, Watchlist} from "../../../../utils/api";
|
||||
import vCard from "vcf";
|
||||
import React from "react";
|
||||
import {t} from 'ttag'
|
||||
|
||||
export const domainToNode = (d: Domain) => ({
|
||||
id: d.ldhName,
|
||||
data: {label: <b>{d.ldhName}</b>},
|
||||
style: {
|
||||
width: 200
|
||||
}
|
||||
})
|
||||
|
||||
export const domainEntitiesToNode = (d: Domain) => d.entities
|
||||
.filter(e => !e.roles.includes('registrar')) //
|
||||
.map(e => {
|
||||
const jCard = vCard.fromJSON(e.entity.jCard)
|
||||
let label = e.entity.handle
|
||||
if (jCard.data.fn !== undefined && !Array.isArray(jCard.data.fn)) label = jCard.data.fn.valueOf()
|
||||
|
||||
return {
|
||||
id: e.entity.handle,
|
||||
data: {label},
|
||||
style: {
|
||||
width: 200
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const tldToNode = (tld: Tld) => ({
|
||||
id: tld.tld,
|
||||
data: {label: t`.${tld.tld} Registry`},
|
||||
style: {
|
||||
width: 200
|
||||
}
|
||||
})
|
||||
|
||||
export const nsToNode = (ns: Nameserver) => ({
|
||||
id: ns.ldhName,
|
||||
data: {label: ns.ldhName},
|
||||
style: {
|
||||
width: 200
|
||||
}
|
||||
})
|
||||
|
||||
export function watchlistToNodes(watchlist: Watchlist) {
|
||||
|
||||
const domains = watchlist.domains.map(domainToNode)
|
||||
const entities = [...new Set(watchlist.domains.map(domainEntitiesToNode).flat())]
|
||||
const tlds = [...new Set(watchlist.domains.map(d => d.tld))].map(tldToNode)
|
||||
const nameservers = [...new Set(watchlist.domains.map(d => d.nameservers))].flat().map(nsToNode)
|
||||
|
||||
return [...domains, ...entities, ...nameservers]
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import {DomainSearchBar, FieldType} from "../../components/search/DomainSearchBa
|
||||
import {EventTimeline} from "../../components/search/EventTimeline";
|
||||
import {EntitiesList} from "../../components/search/EntitiesList";
|
||||
import {showErrorAPI} from "../../utils";
|
||||
import {DomainDiagram} from "../../components/search/DomainDiagram";
|
||||
|
||||
const {Text} = Typography;
|
||||
|
||||
@@ -68,6 +69,7 @@ export default function DomainSearchPage() {
|
||||
}
|
||||
</Card>
|
||||
</Badge.Ribbon>
|
||||
<DomainDiagram domain={domain}/>
|
||||
</Space>
|
||||
: <Empty
|
||||
description={t`Although the domain exists in my database, it has been deleted from the WHOIS by its registrar.`}/>)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {Card, Divider, Flex, Form, message} from "antd";
|
||||
import {EventAction, getWatchlists, putWatchlist, postWatchlist} from "../../utils/api";
|
||||
import {EventAction, getWatchlists, postWatchlist, putWatchlist} from "../../utils/api";
|
||||
import {AxiosError} from "axios";
|
||||
import {t} from 'ttag'
|
||||
import {WatchlistForm} from "../../components/tracking/watchlist/WatchlistForm";
|
||||
@@ -37,9 +37,12 @@ export default function WatchlistPage() {
|
||||
connector?: string,
|
||||
dsn?: string[]
|
||||
}) => {
|
||||
const domainsURI = values.domains.map(d => '/api/domains/' + d)
|
||||
let triggers = values.triggers.map(t => ({event: t, action: 'email'}))
|
||||
if(values.dsn !== undefined) triggers = [...triggers, ...values.triggers.map(t => ({event: t, action: 'chat'}))]
|
||||
const domainsURI = values.domains.map(d => '/api/domains/' + d.toLowerCase())
|
||||
let triggers = values.triggers.map(t => ({event: t, action: 'email'}))
|
||||
if (values.dsn !== undefined) triggers = [...triggers, ...values.triggers.map(t => ({
|
||||
event: t,
|
||||
action: 'chat'
|
||||
}))]
|
||||
|
||||
postWatchlist({
|
||||
name: values.name,
|
||||
@@ -64,10 +67,12 @@ export default function WatchlistPage() {
|
||||
connector?: string,
|
||||
dsn?: string[]
|
||||
}) => {
|
||||
const domainsURI = values.domains.map(d => '/api/domains/' + d)
|
||||
let triggers = values.triggers.map(t => ({event: t, action: 'email'}))
|
||||
if(values.dsn !== undefined) triggers = [...triggers, ...values.triggers.map(t => ({event: t, action: 'chat'}))]
|
||||
|
||||
const domainsURI = values.domains.map(d => '/api/domains/' + d.toLowerCase())
|
||||
let triggers = values.triggers.map(t => ({event: t, action: 'email'}))
|
||||
if (values.dsn !== undefined) triggers = [...triggers, ...values.triggers.map(t => ({
|
||||
event: t,
|
||||
action: 'chat'
|
||||
}))]
|
||||
|
||||
return putWatchlist({
|
||||
token: values.token,
|
||||
|
||||
@@ -43,7 +43,7 @@ class JWTAuthenticator implements AuthenticationSuccessHandlerInterface
|
||||
new Cookie(
|
||||
'BEARER',
|
||||
$jwt,
|
||||
time() + 7200, // expiration
|
||||
time() + 604800, // expiration
|
||||
'/',
|
||||
null,
|
||||
true,
|
||||
|
||||
@@ -75,7 +75,7 @@ class OAuthAuthenticator extends OAuth2Authenticator implements AuthenticationEn
|
||||
new Cookie(
|
||||
'BEARER',
|
||||
$token,
|
||||
time() + 7200, // expiration
|
||||
time() + 604800, // expiration
|
||||
'/',
|
||||
null,
|
||||
true,
|
||||
|
||||
@@ -278,6 +278,8 @@ readonly class RDAPService
|
||||
}
|
||||
|
||||
if (array_key_exists('nameservers', $res) && is_array($res['nameservers'])) {
|
||||
$domain->getNameservers()->clear();
|
||||
|
||||
foreach ($res['nameservers'] as $rdapNameserver) {
|
||||
$nameserver = $this->nameserverRepository->findOneBy([
|
||||
'ldhName' => strtolower($rdapNameserver['ldhName']),
|
||||
|
||||
@@ -246,11 +246,16 @@ msgstr "Ja"
|
||||
msgid "No"
|
||||
msgstr "Nein"
|
||||
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:86
|
||||
#: assets/components/tracking/diagram/WatchlistToNodes.tsx:37
|
||||
#, javascript-format
|
||||
msgid ".${ tld.tld } Registry"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:40
|
||||
msgid "View the Watchlist Entity Diagram"
|
||||
msgstr "Sehen Sie sich das Watchlist-Entitätsdiagramm an"
|
||||
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:91
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:45
|
||||
msgid "Watchlist Entity Diagram"
|
||||
msgstr "Watchlist-Entitäten Diagramm"
|
||||
|
||||
|
||||
@@ -246,11 +246,16 @@ msgstr "Oui"
|
||||
msgid "No"
|
||||
msgstr "Non"
|
||||
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:86
|
||||
#: assets/components/tracking/diagram/WatchlistToNodes.tsx:37
|
||||
#, javascript-format
|
||||
msgid ".${ tld.tld } Registry"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:40
|
||||
msgid "View the Watchlist Entity Diagram"
|
||||
msgstr "Afficher le diagramme d'entités de la Watchlist"
|
||||
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:91
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:45
|
||||
msgid "Watchlist Entity Diagram"
|
||||
msgstr "Diagramme d'entités de la Watchlist"
|
||||
|
||||
|
||||
@@ -236,14 +236,6 @@ msgstr ""
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:86
|
||||
msgid "View the Watchlist Entity Diagram"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:91
|
||||
msgid "Watchlist Entity Diagram"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/watchlist/WatchlistForm.tsx:66
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
@@ -329,6 +321,23 @@ msgstr ""
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/watchlist/diagram/ViewDiagramWatchlistButton.tsx:40
|
||||
msgid "View the Watchlist Entity Diagram"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/watchlist/diagram/ViewDiagramWatchlistButton.tsx:45
|
||||
msgid "Watchlist Entity Diagram"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/watchlist/diagram/watchlistToEdges.tsx:39
|
||||
msgid "Registry"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/watchlist/diagram/watchlistToNodes.tsx:32
|
||||
#, javascript-format
|
||||
msgid ".${ tld.tld } Registry"
|
||||
msgstr ""
|
||||
|
||||
#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:12
|
||||
#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:19
|
||||
msgid "Delete the Watchlist"
|
||||
@@ -427,27 +436,27 @@ msgstr ""
|
||||
msgid "Register"
|
||||
msgstr ""
|
||||
|
||||
#: assets/pages/search/DomainSearchPage.tsx:21
|
||||
#: assets/pages/search/DomainSearchPage.tsx:22
|
||||
msgid "Found !"
|
||||
msgstr ""
|
||||
|
||||
#: assets/pages/search/DomainSearchPage.tsx:29
|
||||
#: assets/pages/search/DomainSearchPage.tsx:30
|
||||
msgid "Domain finder"
|
||||
msgstr ""
|
||||
|
||||
#: assets/pages/search/DomainSearchPage.tsx:50
|
||||
#: assets/pages/search/DomainSearchPage.tsx:51
|
||||
msgid "EPP Status Codes"
|
||||
msgstr ""
|
||||
|
||||
#: assets/pages/search/DomainSearchPage.tsx:60
|
||||
#: assets/pages/search/DomainSearchPage.tsx:61
|
||||
msgid "Timeline"
|
||||
msgstr ""
|
||||
|
||||
#: assets/pages/search/DomainSearchPage.tsx:65
|
||||
#: assets/pages/search/DomainSearchPage.tsx:66
|
||||
msgid "Entities"
|
||||
msgstr ""
|
||||
|
||||
#: assets/pages/search/DomainSearchPage.tsx:73
|
||||
#: assets/pages/search/DomainSearchPage.tsx:75
|
||||
msgid ""
|
||||
"Although the domain exists in my database, it has been deleted from the "
|
||||
"WHOIS by its registrar."
|
||||
|
||||
Reference in New Issue
Block a user