+ {loading ? (
+
+
+
+ ) : !content ? (
+
+
Data could not be fetched.
+
) : (
- | Registrar |
- {content.result!.registrar} |
+ Registrar |
+ {content?.result!.registrar} |
-
- | Name Servers |
+
+ | Name Servers |
- {content.result!.name_servers.map(
+ {content?.result!.name_servers.map(
(ns: string, idx: number) => (
- {ns}
)
@@ -32,31 +35,39 @@ const WhoisTable: React.FC<{ content: Record | string }> = ({
|
- | Registered On |
+ Registered On |
- {new Date(content.result!.creation_date).toLocaleDateString()}
+ {new Date(content?.result!.creation_date).toLocaleDateString()}
|
- | Expires On |
+ Expires On |
- {new Date(content.result!.expiration_date).toLocaleDateString()}
+ {new Date(
+ content?.result!.expiration_date
+ ).toLocaleDateString()}{' '}
+ ({getDays(content?.result!.expiration_date)} days)
|
- | Last updated On |
+ Last updated On |
- {new Date(content.result!.updated_date).toLocaleDateString()}
+ {new Date(content?.result!.updated_date).toLocaleDateString()}
|
| Status |
- {typeof content.result!.status === 'string' ? (
- content.result!.status
+ {typeof content?.result!.status === 'string' ? (
+
+ {content?.result!.status.substring(
+ 0,
+ content?.result!.status.indexOf(' ')
+ )}
+
) : (
- {content.result!.status.map((row: string, idx: number) => (
+ {content?.result!.status.map((row: string, idx: number) => (
- {row.substring(0, row.indexOf(' '))}
))}
@@ -64,8 +75,8 @@ const WhoisTable: React.FC<{ content: Record | string }> = ({
|
- | DNSSEC |
- {content.result!.dnssec} |
+ DNSSEC |
+ {content?.result!.dnssec} |
diff --git a/src/enums/Shortcut.enum.ts b/src/enums/Shortcut.enum.ts
new file mode 100644
index 0000000..74469bd
--- /dev/null
+++ b/src/enums/Shortcut.enum.ts
@@ -0,0 +1,5 @@
+export enum Shortcut {
+ T = 't',
+ ENTER = 'enter',
+ ESCAPE = 'escape',
+}
diff --git a/src/enums/Theme.enum.ts b/src/enums/Theme.enum.ts
index 2d0932b..f91eb90 100644
--- a/src/enums/Theme.enum.ts
+++ b/src/enums/Theme.enum.ts
@@ -3,4 +3,5 @@ export enum Theme {
SOLARIZED_LIGHT = 'solarizedLight',
SERIKA_DARK = 'serikaDark',
SERIKA_LIGHT = 'serikaLight',
+ DEFAULT_DARK = 'dark',
}
diff --git a/src/helpers/getDays.ts b/src/helpers/getDays.ts
new file mode 100644
index 0000000..2f8f7c4
--- /dev/null
+++ b/src/helpers/getDays.ts
@@ -0,0 +1,5 @@
+export const getDays = (ms: number): number => {
+ return Math.floor(
+ (new Date(ms).getTime() - Date.now()) / 1000 / 60 / 60 / 24
+ );
+};
diff --git a/src/hoc/ViewContainer.tsx b/src/hoc/ViewContainer.tsx
index 1be0450..d9f97b0 100644
--- a/src/hoc/ViewContainer.tsx
+++ b/src/hoc/ViewContainer.tsx
@@ -1,8 +1,17 @@
import React, { ReactNode } from 'react';
+import { cn } from '../helpers/cn.helper';
-const ViewContainer: React.FC<{ children: ReactNode }> = ({ children }) => {
+const ViewContainer: React.FC<{ children: ReactNode; className?: string }> = ({
+ children,
+ className,
+}) => {
return (
-
+
{children}
);
diff --git a/src/providers/HistoryProvider.tsx b/src/providers/HistoryProvider.tsx
index ca59559..3015821 100644
--- a/src/providers/HistoryProvider.tsx
+++ b/src/providers/HistoryProvider.tsx
@@ -11,6 +11,7 @@ interface HistoryContextType {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
history: any;
historyPush: (newDomain: string) => void;
+ clearHistory: () => void;
handleOpenCloseModal: (event: KeyboardEvent) => void;
setIsModalOpen: React.Dispatch
>;
}
@@ -39,6 +40,10 @@ export const HistoryProvider: React.FC<{ children: ReactNode }> = ({
setHistory([...history, { domain: newDomain, searchedOn: Date.now() }]);
};
+ const clearHistory = () => {
+ setHistory([]);
+ };
+
const handleOpenCloseModal = (event: KeyboardEvent) => {
if (event.key === 'Escape') setIsModalOpen(prev => !prev);
};
@@ -51,6 +56,7 @@ export const HistoryProvider: React.FC<{ children: ReactNode }> = ({
isModalOpen,
handleOpenCloseModal,
setIsModalOpen,
+ clearHistory,
}}
>
{children}
diff --git a/src/services/cdnCheck.service.ts b/src/services/cdnCheck.service.ts
new file mode 100644
index 0000000..cb1d140
--- /dev/null
+++ b/src/services/cdnCheck.service.ts
@@ -0,0 +1,18 @@
+import axios from 'axios';
+
+export const isCdnActive = async (domain: string) => {
+ try {
+ const response = await axios.get(
+ `https://api-dl.nikola-nenovski.info/api/v1/cdn-check?domain=${domain}`,
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ }
+ );
+
+ return response.data.data;
+ } catch (error) {
+ console.error(error);
+ }
+};
diff --git a/src/services/http/whois.get.endpoints.http b/src/services/http/whois.get.endpoints.http
index e43fdfe..f6fb4e8 100644
--- a/src/services/http/whois.get.endpoints.http
+++ b/src/services/http/whois.get.endpoints.http
@@ -12,3 +12,11 @@ GET {{WHOIS_API_URL}}
?domain={{MISSPELLED_DOMAIN}}
apikey:{{WHOIS_API_KEY}}
// WhoIS request with a misspelled domain name
+
+
+###
+# @import ./variables.http
+
+GET {{WHOIS_API_URL}}
+ ?domain=nikolanenovski.com
+ apikey:{{WHOIS_API_KEY}}
\ No newline at end of file
diff --git a/src/services/wpCheck.service.ts b/src/services/wpCheck.service.ts
index 3f63004..08c2ef9 100644
--- a/src/services/wpCheck.service.ts
+++ b/src/services/wpCheck.service.ts
@@ -3,7 +3,7 @@ import axios from 'axios';
export const isWordpressInstalled = async (domain: string) => {
try {
const response = await axios.get(
- `https://domainlookup.nicknenovski.workers.dev/wp-check?domain=${domain}`,
+ `https://api-dl.nikola-nenovski.info/api/v1/wp-check?domain=${domain}`,
{
headers: {
'Content-Type': 'application/json',
@@ -11,7 +11,7 @@ export const isWordpressInstalled = async (domain: string) => {
}
);
- return response.data;
+ return response.data.data;
} catch (error) {
console.error(error);
}
diff --git a/src/views/Results.tsx b/src/views/Results.tsx
index b0cf656..8ff7d64 100644
--- a/src/views/Results.tsx
+++ b/src/views/Results.tsx
@@ -7,7 +7,6 @@ import { useSearchParams } from 'react-router-dom';
import { getDomainSslInfo } from '../services/ssl.service';
import { getDomainInfo } from '../services/whois.service';
import { getDnsRecordInfo } from '../services/dns.service';
-import ProgressBar from '../components/ProgressBar';
import Table from '../components/Table';
import React from 'react';
import { DnsRecordAnswer } from '../types/DnsRecordAnswer';
@@ -17,6 +16,7 @@ import WhoisTable from '../components/WhoisTable';
import { H1 } from '../hoc/H1';
import Markers from '../components/Markers';
import { isWordpressInstalled } from '../services/wpCheck.service';
+import { isCdnActive } from '../services/cdnCheck.service';
interface WhoIsData {
result?: Record;
@@ -25,16 +25,13 @@ interface WhoIsData {
const Results = () => {
const [searchParams] = useSearchParams();
-
const [sslData, setSslData] = useState>();
-
const [whoIsData, setWhoIsData] = useState();
const [dnsData, setDnsData] =
useState>();
const [hasWp, setHasWp] = useState(false);
+ const [cdnInfo, setCdnInfo] = useState([]);
const [hasWwwRecord, setHasWwwRecord] = useState(false);
- const [progress, setProgress] = useState(0);
- const [isLoading, setIsLoading] = useState(false);
const wwwSsl = useMemo(() => {
const domain = searchParams.get('domain');
@@ -45,93 +42,110 @@ const Results = () => {
);
}, [sslData, searchParams]);
- useEffect(() => {
- setProgress(0);
- setIsLoading(true);
+ const [isWhoIsLoading, setIsWhoisLoading] = useState(false);
+ const [isDnsLoading, setIsDnsLoading] = useState(false);
+ const [isSslLoading, setIsSslLoading] = useState(false);
+ const [isWpCheckLoading, setIsWpCheckLoading] = useState(false);
+ const [isCdnCheckLoading, setIsCdnCheckLoading] = useState(false);
+ useEffect(() => {
const domain = searchParams.get('domain');
if (!domain) return;
- const fetchData = async () => {
- try {
+ setIsWhoisLoading(true);
+ setIsSslLoading(true);
+ setIsDnsLoading(true);
+ setIsWpCheckLoading(true);
+ setIsCdnCheckLoading(true);
+
+ try {
+ const fetchData = async () => {
const tasks = [
getDomainSslInfo(domain).then(data => {
setSslData(data[data.length - 1]);
- setProgress(prevValue => prevValue + 1);
+ setIsSslLoading(false);
}),
getDomainInfo(domain).then(data => {
setWhoIsData(data);
- setProgress(prevValue => prevValue + 1);
+ setIsWhoisLoading(false);
}),
getDnsRecordInfo(domain).then(data => {
setDnsData(data);
- setProgress(prevValue => prevValue + 1);
+ setIsDnsLoading(false);
}),
getDnsRecordInfo(`www.${domain}`).then(data => {
const answer = Array.isArray(data.A) || Array.isArray(data.CNAME);
setHasWwwRecord(answer);
- setProgress(prevValue => prevValue + 1);
}),
isWordpressInstalled(domain).then(data => {
- setHasWp(data.isInstalled);
- setProgress(prevValue => prevValue + 1);
+ setHasWp(data.wordpressInstalled);
+ setIsWpCheckLoading(false);
+ }),
+ isCdnActive(domain).then(data => {
+ setCdnInfo(Object.keys(data));
+ setIsCdnCheckLoading(false);
}),
];
await Promise.all(tasks);
- } catch (error) {
- console.error(error);
- } finally {
- setIsLoading(false);
- }
- };
+ };
- fetchData();
+ fetchData();
+ } catch (error) {
+ console.error(error);
+ }
}, [searchParams]);
return (
<>
-
- {isLoading ? (
-
- ) : (
- <>
-
- Looking up {searchParams.get('domain')}
-
-
-
-
DNS Info
-
- {dnsData &&
- Object.entries(dnsData).map(([type, answer]) => {
- return (
-
-
-
- );
- })}
-
-
-
-
-
WHOIS Info
- {whoIsData && }
-
-
-
SSL Info
- {sslData &&
}
+
+
+ Looking up {searchParams.get('domain')}
+
+
+
+
DNS Info
+
+ {isDnsLoading ? (
+
+
-
- >
- )}
+ ) : (
+ dnsData &&
+ Object.entries(dnsData).map(([type, answer]) => {
+ return (
+
+
+
+ );
+ })
+ )}
+
+
+
+
+
WHOIS Info
+
+
+
+
SSL Info
+
+
+
>
diff --git a/tailwind.config.js b/tailwind.config.js
index 24ce6ef..d50b881 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -8,6 +8,7 @@ export default {
},
daisyui: {
themes: [
+ "dark",
{
serikaDark: {
primary: '#e2b714',