first commit

This commit is contained in:
skidoodle 2025-03-14 23:25:41 +01:00
commit 38e6f714cb
No known key found for this signature in database
26 changed files with 1856 additions and 0 deletions

90
entrypoints/background.ts Normal file
View file

@ -0,0 +1,90 @@
import psl from 'psl';
export default defineBackground({
main() {
chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
if (request.type === 'FETCH_SERVER_INFO') {
(async () => {
try {
const dnsResponse = await fetch(`https://dns.google/resolve?name=${request.hostname}&type=A`);
const dnsData = await dnsResponse.json();
const ip = dnsData.Answer?.[0]?.data;
if (!ip) {
sendResponse({ error: 'DNS resolution failed', data: null });
return;
}
const apiResponse = await fetch(`https://ip.albert.lol/${ip}`);
const apiData = await apiResponse.json();
const parsed = psl.parse(request.hostname);
const origin = 'domain' in parsed ? parsed.domain : null;
await updateIcon(apiData.country);
sendResponse({
error: null,
data: {
origin: origin,
ip: apiData.ip,
hostname: apiData.hostname ? apiData.hostname : "N/A",
country: apiData.country ? apiData.country : null,
city: apiData.city ? apiData.city : null,
org: apiData.org
}
});
} catch (error) {
await updateIcon(null);
sendResponse({
error: error instanceof Error ? error.message : 'Unknown error',
data: null
});
}
})();
return true;
}
});
},
});
chrome.tabs.onActivated.addListener(async (activeInfo) => {
const tab = await chrome.tabs.get(activeInfo.tabId);
if (!tab.url) return;
try {
const url = new URL(tab.url);
const dnsResponse = await fetch(`https://dns.google/resolve?name=${url.hostname}&type=A`);
const dnsData = await dnsResponse.json();
const ip = dnsData.Answer?.[0]?.data;
if (!ip) return;
const apiResponse = await fetch(`https://ip.albert.lol/${ip}`);
const apiData = await apiResponse.json();
await updateIcon(apiData.country);
} catch {
await updateIcon(null);
}
});
chrome.tabs.onUpdated.addListener(async (_tabId, changeInfo) => {
if (!changeInfo.url) return;
try {
const url = new URL(changeInfo.url);
const dnsResponse = await fetch(`https://dns.google/resolve?name=${url.hostname}&type=A`);
const dnsData = await dnsResponse.json();
const ip = dnsData.Answer?.[0]?.data;
if (!ip) return;
const apiResponse = await fetch(`https://ip.albert.lol/${ip}`);
const apiData = await apiResponse.json();
await updateIcon(apiData.country);
} catch {
await updateIcon(null);
}
});

6
entrypoints/content.ts Normal file
View file

@ -0,0 +1,6 @@
export default defineContentScript({
matches: ['*://*.google.com/*'],
main() {
console.log('Hello content.');
},
});

View file

@ -0,0 +1,29 @@
import { Spinner } from '@/components/Spinner';
import ServerInfo from '@/components/ServerInfo';
import Error from '@/components/Error';
export default function Popup() {
const { data, loading, error } = useTabData();
if (loading) {
return (
<div className="flex items-center justify-center h-48 bg-gray-900">
<Spinner className="w-12 h-12 text-purple-500" />
</div>
);
}
if (error) {
return (
<Error error={error} />
);
}
if (!data) {
return (
<Error error="No data found" />
);
}
return <ServerInfo data={data} />;
}

View file

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>hostinfo</title>
<meta name="manifest.type" content="browser_action" />
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>

View file

@ -0,0 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import Popup from '@/entrypoints/popup/Popup';
import '@/assets/tailwind.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<Popup />
</React.StrictMode>,
);