mirror of
https://github.com/skidoodle/hostinfo
synced 2026-04-28 09:37:37 +02:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
f2cc9a8c87
|
|||
|
bf5c5575f5
|
|||
|
6f0125896a
|
|||
| 9253e53ca1 | |||
|
d5a4fcbe5a
|
|||
|
c3be23d369
|
|||
|
90bb276622
|
|||
|
806072fbf1
|
|||
|
baa277fbd9
|
|||
|
3e9fe9a199
|
|||
|
a540f1eb0a
|
|||
|
940b8bbec4
|
|||
| 3419544ba4 | |||
| 87b4c93268 | |||
| feaaa65960 | |||
|
971a980def
|
+36
@@ -0,0 +1,36 @@
|
|||||||
|
# Privacy Policy
|
||||||
|
|
||||||
|
**Last Updated:** 2025-03-16
|
||||||
|
|
||||||
|
Thank you for using HostInfo (the "Extension"). This Privacy Policy explains how we handle your information when you use our Extension. Please read this policy carefully to understand our practices regarding your data.
|
||||||
|
|
||||||
|
## 1. **Information We Do Not Collect**
|
||||||
|
|
||||||
|
HostInfo does not collect, store, or transmit any personal or sensitive information from its users. This includes, but is not limited to:
|
||||||
|
|
||||||
|
- Personal identification information (e.g., name, email address, phone number).
|
||||||
|
- Browsing history or activity.
|
||||||
|
- IP addresses or location data (except as described below for GeoIP lookups).
|
||||||
|
- Any other data that could be used to identify you.
|
||||||
|
|
||||||
|
## 2. **Third-Party Services**
|
||||||
|
|
||||||
|
The Extension uses the following third-party services to provide functionality:
|
||||||
|
|
||||||
|
- **Cloudflare DNS (`cloudflare-dns.com`)**: The Extension queries hostnames using Cloudflare's DNS service to resolve website IP addresses. This is done to provide accurate and fast DNS resolution. Cloudflare's privacy policy can be found [here](https://www.cloudflare.com/privacypolicy/).
|
||||||
|
|
||||||
|
- **GeoIP Lookups (`ip.albert.lol`)**: The Extension uses `ip.albert.lol` to perform GeoIP lookups. This service may receive your IP address to determine your approximate geographic location (e.g., country or region). No other personal information is shared with this service.
|
||||||
|
|
||||||
|
Neither of these services is used to collect, store, or track your personal information. The data sent to these services is used solely for the purpose of providing the Extension's functionality.
|
||||||
|
|
||||||
|
## 3. **How We Use Information**
|
||||||
|
|
||||||
|
Since we do not collect any personal information, there is no data to use, share, or sell. The Extension operates locally on your device and only communicates with the aforementioned third-party services for DNS resolution and GeoIP lookups.
|
||||||
|
|
||||||
|
## 4. **Changes to This Privacy Policy**
|
||||||
|
|
||||||
|
We may update this Privacy Policy from time to time. If we make any changes, we will update the "Last Updated" date at the top of this policy. We encourage you to review this Privacy Policy periodically to stay informed about how we are protecting your information.
|
||||||
|
|
||||||
|
## 5. **Contact Us**
|
||||||
|
|
||||||
|
If you have any questions or concerns about this Privacy Policy, please feel free to contact us at `contact@albert.lol`.
|
||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
A browser extension built with [WXT.dev](https://wxt.dev) and React that lets you discover the origin of the website you're visiting. With a single click, you can view detailed information such as the **country of origin**, **IP address**, **ASN (Autonomous System Number)**, and more. You can also quickly search for the website's details on [Censys](https://censys.io) for deeper insights.
|
A browser extension built with [WXT.dev](https://wxt.dev) and React that lets you discover the origin of the website you're visiting. With a single click, you can view detailed information such as the **country of origin**, **IP address**, **ASN (Autonomous System Number)**, and more. You can also quickly search for the website's details on [Censys](https://censys.io) for deeper insights.
|
||||||
|
|
||||||
|
<img src="https://github.com/user-attachments/assets/83a6316c-54b8-41a8-8d43-c794a5f62696" alt="Showcase" width="200"/>
|
||||||
|
|
||||||
|
<a href="https://addons.mozilla.org/addon/hostinfo/"><img src="https://github.com/user-attachments/assets/4e69214c-c11a-4202-919a-fac7d58dbb55" alt="Get hostinfo for Firefox"></a>
|
||||||
|
<a href="https://chromewebstore.google.com/detail/hostinfo/ehleblniighmnfhfimcbfhmdpdhamcbp"><img src="https://github.com/user-attachments/assets/4bf31178-6244-467c-916d-79e926dec379" alt="Get hostinfo for Chrome"></a>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
|||||||
@@ -4,21 +4,21 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "wxt-react-starter",
|
"name": "wxt-react-starter",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^2.2.0",
|
"@heroicons/react": "latest",
|
||||||
"@tailwindcss/vite": "^4.0.14",
|
"@tailwindcss/vite": "latest",
|
||||||
"@types/psl": "^1.1.3",
|
"@types/psl": "latest",
|
||||||
"@types/webextension-polyfill": "^0.12.3",
|
"@types/webextension-polyfill": "latest",
|
||||||
"react": "^19.0.0",
|
"react": "latest",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "latest",
|
||||||
"tailwindcss": "^4.0.14",
|
"tailwindcss": "latest",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chrome": "^0.0.309",
|
"@types/chrome": "latest",
|
||||||
"@types/react": "^19.0.10",
|
"@types/react": "latest",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "latest",
|
||||||
"@wxt-dev/module-react": "^1.1.3",
|
"@wxt-dev/module-react": "latest",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "latest",
|
||||||
"wxt": "^0.19.29",
|
"wxt": "latest",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -194,33 +194,33 @@
|
|||||||
|
|
||||||
"@szmarczak/http-timer": ["@szmarczak/http-timer@5.0.1", "", { "dependencies": { "defer-to-connect": "^2.0.1" } }, "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw=="],
|
"@szmarczak/http-timer": ["@szmarczak/http-timer@5.0.1", "", { "dependencies": { "defer-to-connect": "^2.0.1" } }, "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw=="],
|
||||||
|
|
||||||
"@tailwindcss/node": ["@tailwindcss/node@4.0.14", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "tailwindcss": "4.0.14" } }, "sha512-Ux9NbFkKWYE4rfUFz6M5JFLs/GEYP6ysxT8uSyPn6aTbh2K3xDE1zz++eVK4Vwx799fzMF8CID9sdHn4j/Ab8w=="],
|
"@tailwindcss/node": ["@tailwindcss/node@4.0.15", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "tailwindcss": "4.0.15" } }, "sha512-IODaJjNmiasfZX3IoS+4Em3iu0fD2HS0/tgrnkYfW4hyUor01Smnr5eY3jc4rRgaTDrJlDmBTHbFO0ETTDaxWA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.0.14", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.0.14", "@tailwindcss/oxide-darwin-arm64": "4.0.14", "@tailwindcss/oxide-darwin-x64": "4.0.14", "@tailwindcss/oxide-freebsd-x64": "4.0.14", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.14", "@tailwindcss/oxide-linux-arm64-gnu": "4.0.14", "@tailwindcss/oxide-linux-arm64-musl": "4.0.14", "@tailwindcss/oxide-linux-x64-gnu": "4.0.14", "@tailwindcss/oxide-linux-x64-musl": "4.0.14", "@tailwindcss/oxide-win32-arm64-msvc": "4.0.14", "@tailwindcss/oxide-win32-x64-msvc": "4.0.14" } }, "sha512-M8VCNyO/NBi5vJ2cRcI9u8w7Si+i76a7o1vveoGtbbjpEYJZYiyc7f2VGps/DqawO56l3tImIbq2OT/533jcrA=="],
|
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.0.15", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.0.15", "@tailwindcss/oxide-darwin-arm64": "4.0.15", "@tailwindcss/oxide-darwin-x64": "4.0.15", "@tailwindcss/oxide-freebsd-x64": "4.0.15", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.15", "@tailwindcss/oxide-linux-arm64-gnu": "4.0.15", "@tailwindcss/oxide-linux-arm64-musl": "4.0.15", "@tailwindcss/oxide-linux-x64-gnu": "4.0.15", "@tailwindcss/oxide-linux-x64-musl": "4.0.15", "@tailwindcss/oxide-win32-arm64-msvc": "4.0.15", "@tailwindcss/oxide-win32-x64-msvc": "4.0.15" } }, "sha512-e0uHrKfPu7JJGMfjwVNyt5M0u+OP8kUmhACwIRlM+JNBuReDVQ63yAD1NWe5DwJtdaHjugNBil76j+ks3zlk6g=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.0.14", "", { "os": "android", "cpu": "arm64" }, "sha512-VBFKC2rFyfJ5J8lRwjy6ub3rgpY186kAcYgiUr8ArR8BAZzMruyeKJ6mlsD22Zp5ZLcPW/FXMasJiJBx0WsdQg=="],
|
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.0.15", "", { "os": "android", "cpu": "arm64" }, "sha512-EBuyfSKkom7N+CB3A+7c0m4+qzKuiN0WCvzPvj5ZoRu4NlQadg/mthc1tl5k9b5ffRGsbDvP4k21azU4VwVk3Q=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.0.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-U3XOwLrefGr2YQZ9DXasDSNWGPZBCh8F62+AExBEDMLDfvLLgI/HDzY8Oq8p/JtqkAY38sWPOaNnRwEGKU5Zmg=="],
|
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.0.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ObVAnEpLepMhV9VoO0JSit66jiN5C4YCqW3TflsE9boo2Z7FIjV80RFbgeL2opBhtxbaNEDa6D0/hq/EP03kgQ=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.0.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-V5AjFuc3ndWGnOi1d379UsODb0TzAS2DYIP/lwEbfvafUaD2aNZIcbwJtYu2DQqO2+s/XBvDVA+w4yUyaewRwg=="],
|
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.0.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-IElwoFhUinOr9MyKmGTPNi1Rwdh68JReFgYWibPWTGuevkHkLWKEflZc2jtI5lWZ5U9JjUnUfnY43I4fEXrc4g=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.0.14", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tXvtxbaZfcPfqBwW3f53lTcyH6EDT+1eT7yabwcfcxTs+8yTPqxsDUhrqe9MrnEzpNkd+R/QAjJapfd4tjWdLg=="],
|
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.0.15", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6BLLqyx7SIYRBOnTZ8wgfXANLJV5TQd3PevRJZp0vn42eO58A2LykRKdvL1qyPfdpmEVtF+uVOEZ4QTMqDRAWA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.0.14", "", { "os": "linux", "cpu": "arm" }, "sha512-cSeLNWWqIWeSTmBntQvyY2/2gcLX8rkPFfDDTQVF8qbRcRMVPLxBvFVJyfSAYRNch6ZyVH2GI6dtgALOBDpdNA=="],
|
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.0.15", "", { "os": "linux", "cpu": "arm" }, "sha512-Zy63EVqO9241Pfg6G0IlRIWyY5vNcWrL5dd2WAKVJZRQVeolXEf1KfjkyeAAlErDj72cnyXObEZjMoPEKHpdNw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.0.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-bwDWLBalXFMDItcSXzFk6y7QKvj6oFlaY9vM+agTlwFL1n1OhDHYLZkSjaYsh6KCeG0VB0r7H8PUJVOM1LRZyg=="],
|
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.0.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-2NemGQeaTbtIp1Z2wyerbVEJZTkAWhMDOhhR5z/zJ75yMNf8yLnE+sAlyf6yGDNr+1RqvWrRhhCFt7i0CIxe4Q=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.0.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-gVkJdnR/L6iIcGYXx64HGJRmlme2FGr/aZH0W6u4A3RgPMAb+6ELRLi+UBiH83RXBm9vwCfkIC/q8T51h8vUJQ=="],
|
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.0.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-342GVnhH/6PkVgKtEzvNVuQ4D+Q7B7qplvuH20Cfz9qEtydG6IQczTZ5IT4JPlh931MG1NUCVxg+CIorr1WJyw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.0.14", "", { "os": "linux", "cpu": "x64" }, "sha512-EE+EQ+c6tTpzsg+LGO1uuusjXxYx0Q00JE5ubcIGfsogSKth8n8i2BcS2wYTQe4jXGs+BQs35l78BIPzgwLddw=="],
|
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.0.15", "", { "os": "linux", "cpu": "x64" }, "sha512-g76GxlKH124RuGqacCEFc2nbzRl7bBrlC8qDQMiUABkiifDRHOIUjgKbLNG4RuR9hQAD/MKsqZ7A8L08zsoBrw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.0.14", "", { "os": "linux", "cpu": "x64" }, "sha512-KCCOzo+L6XPT0oUp2Jwh233ETRQ/F6cwUnMnR0FvMUCbkDAzHbcyOgpfuAtRa5HD0WbTbH4pVD+S0pn1EhNfbw=="],
|
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.0.15", "", { "os": "linux", "cpu": "x64" }, "sha512-Gg/Y1XrKEvKpq6WeNt2h8rMIKOBj/W3mNa5NMvkQgMC7iO0+UNLrYmt6zgZufht66HozNpn+tJMbbkZ5a3LczA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.0.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-AHObFiFL9lNYcm3tZSPqa/cHGpM5wOrNmM2uOMoKppp+0Hom5uuyRh0QkOp7jftsHZdrZUpmoz0Mp6vhh2XtUg=="],
|
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.0.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-7QtSSJwYZ7ZK1phVgcNZpuf7c7gaCj8Wb0xjliligT5qCGCp79OV2n3SJummVZdw4fbTNKUOYMO7m1GinppZyA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.0.14", "", { "os": "win32", "cpu": "x64" }, "sha512-rNXXMDJfCJLw/ZaFTOLOHoGULxyXfh2iXTGiChFiYTSgKBKQHIGEpV0yn5N25WGzJJ+VBnRjHzlmDqRV+d//oQ=="],
|
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.0.15", "", { "os": "win32", "cpu": "x64" }, "sha512-JQ5H+5MLhOjpgNp6KomouE0ZuKmk3hO5h7/ClMNAQ8gZI2zkli3IH8ZqLbd2DVfXDbdxN2xvooIEeIlkIoSCqw=="],
|
||||||
|
|
||||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.0.14", "", { "dependencies": { "@tailwindcss/node": "4.0.14", "@tailwindcss/oxide": "4.0.14", "lightningcss": "1.29.2", "tailwindcss": "4.0.14" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-y69ztPTRFy+13EPS/7dEFVl7q2Goh1pQueVO8IfGeyqSpcx/joNJXFk0lLhMgUbF0VFJotwRSb9ZY7Xoq3r26Q=="],
|
"@tailwindcss/vite": ["@tailwindcss/vite@4.0.15", "", { "dependencies": { "@tailwindcss/node": "4.0.15", "@tailwindcss/oxide": "4.0.15", "lightningcss": "1.29.2", "tailwindcss": "4.0.15" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-JRexava80NijI8cTcLXNM3nQL5A0ptTHI8oJLLe8z1MpNB6p5J4WCdJJP8RoyHu8/eB1JzEdbpH86eGfbuaezQ=="],
|
||||||
|
|
||||||
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
|
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@
|
|||||||
|
|
||||||
"@types/babel__traverse": ["@types/babel__traverse@7.20.6", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg=="],
|
"@types/babel__traverse": ["@types/babel__traverse@7.20.6", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg=="],
|
||||||
|
|
||||||
"@types/chrome": ["@types/chrome@0.0.309", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*" } }, "sha512-ZFADzcp8b+roUrux68U8pti4cmNOLJXWkShk8lfxj9SBcjYqpJt7NypBprSJUJDJVakGZgd2Tt00QePIGh7oPA=="],
|
"@types/chrome": ["@types/chrome@0.0.310", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*" } }, "sha512-2+C6NKe4DxGbT6v8noDOx5APEUtSxRL0Rzm2TVGYFkPi1fO36hiN9W1QIuGI93rdM34Qy4d+7orA+vXRZk5rjA=="],
|
||||||
|
|
||||||
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
|
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
|
||||||
|
|
||||||
@@ -248,7 +248,7 @@
|
|||||||
|
|
||||||
"@types/psl": ["@types/psl@1.1.3", "", {}, "sha512-Iu174JHfLd7i/XkXY6VDrqSlPvTDQOtQI7wNAXKKOAADJ9TduRLkNdMgjGiMxSttUIZnomv81JAbAbC0DhggxA=="],
|
"@types/psl": ["@types/psl@1.1.3", "", {}, "sha512-Iu174JHfLd7i/XkXY6VDrqSlPvTDQOtQI7wNAXKKOAADJ9TduRLkNdMgjGiMxSttUIZnomv81JAbAbC0DhggxA=="],
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.0.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g=="],
|
"@types/react": ["@types/react@19.0.12", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA=="],
|
||||||
|
|
||||||
"@types/react-dom": ["@types/react-dom@19.0.4", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg=="],
|
"@types/react-dom": ["@types/react-dom@19.0.4", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg=="],
|
||||||
|
|
||||||
@@ -926,7 +926,7 @@
|
|||||||
|
|
||||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||||
|
|
||||||
"tailwindcss": ["tailwindcss@4.0.14", "", {}, "sha512-92YT2dpt671tFiHH/e1ok9D987N9fHD5VWoly1CdPD/Cd1HMglvZwP3nx2yTj2lbXDAHt8QssZkxTLCCTNL+xw=="],
|
"tailwindcss": ["tailwindcss@4.0.15", "", {}, "sha512-6ZMg+hHdMJpjpeCCFasX7K+U615U9D+7k5/cDK/iRwl6GptF24+I/AbKgOnXhVKePzrEyIXutLv36n4cRsq3Sg=="],
|
||||||
|
|
||||||
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
|
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ export default function ServerInfo({ data }: { data: ServerData }) {
|
|||||||
Internal Network
|
Internal Network
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{data.ip && (
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3">
|
||||||
<ServerIcon className="w-6 h-6 text-yellow-400 flex-shrink-0" />
|
<ServerIcon className="w-6 h-6 text-yellow-400 flex-shrink-0" />
|
||||||
<div>
|
<div>
|
||||||
@@ -39,6 +41,17 @@ export default function ServerInfo({ data }: { data: ServerData }) {
|
|||||||
<p className="font-medium">{data.ip}</p>
|
<p className="font-medium">{data.ip}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{data.hostname && (
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
<LinkIcon className="w-6 h-6 text-green-400 flex-shrink-0" />
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-gray-400">Hostname</p>
|
||||||
|
<p className="font-medium break-all">{data.hostname}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+106
-33
@@ -4,80 +4,148 @@ let currentTabUrl: string | null = null
|
|||||||
|
|
||||||
async function resolveARecord(hostname: string): Promise<string | null> {
|
async function resolveARecord(hostname: string): Promise<string | null> {
|
||||||
try {
|
try {
|
||||||
const dnsResponse = await fetch(
|
let dnsResponse = await fetch(
|
||||||
`https://cloudflare-dns.com/dns-query?name=${hostname}&type=A`,
|
`https://cloudflare-dns.com/dns-query?name=${hostname}&type=A`,
|
||||||
{
|
{ headers: { Accept: 'application/dns-json' } }
|
||||||
headers: { Accept: 'application/dns-json' },
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
if (dnsResponse.ok) {
|
||||||
if (!dnsResponse.ok) {
|
|
||||||
console.error(`DNS query failed: ${dnsResponse.status}`)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const dnsData = await dnsResponse.json()
|
const dnsData = await dnsResponse.json()
|
||||||
return (
|
const aRecord = dnsData.Answer?.find(
|
||||||
dnsData.Answer?.find((entry: DNSEntry) => entry.type === 1)?.data || null
|
(entry: DNSEntry) => entry.type === 1
|
||||||
|
)?.data
|
||||||
|
if (aRecord) return aRecord
|
||||||
|
}
|
||||||
|
|
||||||
|
dnsResponse = await fetch(
|
||||||
|
`https://cloudflare-dns.com/dns-query?name=${hostname}&type=AAAA`,
|
||||||
|
{ headers: { Accept: 'application/dns-json' } }
|
||||||
)
|
)
|
||||||
|
if (dnsResponse.ok) {
|
||||||
|
const dnsData = await dnsResponse.json()
|
||||||
|
const aaaaRecord = dnsData.Answer?.find(
|
||||||
|
(entry: DNSEntry) => entry.type === 28
|
||||||
|
)?.data
|
||||||
|
if (aaaaRecord) return aaaaRecord
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch DNS data:', error)
|
console.error('Failed to fetch DNS data:', error)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isIP(host: string): boolean {
|
||||||
|
const cleanedHost = host.replace(/^\[|\]$/g, '')
|
||||||
|
|
||||||
|
const ipv4Regex =
|
||||||
|
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
||||||
|
|
||||||
|
const ipv6Regex =
|
||||||
|
/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/
|
||||||
|
|
||||||
|
return ipv4Regex.test(cleanedHost) || ipv6Regex.test(cleanedHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getIPInfo(host: string): Promise<any | null> {
|
||||||
|
const cleanedHost = host.replace(/^\[|\]$/g, '')
|
||||||
|
|
||||||
|
if (isIP(cleanedHost)) {
|
||||||
|
const response = await fetch(`https://ip.albert.lol/${cleanedHost}`)
|
||||||
|
const data = await response.json()
|
||||||
|
return data.ip ? data : null
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvedIp = await resolveARecord(cleanedHost)
|
||||||
|
if (!resolvedIp) return null
|
||||||
|
|
||||||
|
const response = await fetch(`https://ip.albert.lol/${resolvedIp}`)
|
||||||
|
return await response.json()
|
||||||
|
}
|
||||||
|
|
||||||
async function handleTabUpdate(url: string) {
|
async function handleTabUpdate(url: string) {
|
||||||
if (url === currentTabUrl) return
|
if (url === currentTabUrl) return
|
||||||
currentTabUrl = url
|
currentTabUrl = url
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const hostname = new URL(url).hostname
|
const hostname = new URL(url).hostname
|
||||||
const ip = await resolveARecord(hostname)
|
const apiData = await getIPInfo(hostname)
|
||||||
|
if (!apiData || !apiData.ip) {
|
||||||
if (!ip) {
|
|
||||||
await updateIcon(null)
|
await updateIcon(null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiResponse = await fetch(`https://ip.albert.lol/${ip}`)
|
if (apiData.bogon === true) {
|
||||||
const apiData = await apiResponse.json()
|
await updateIcon(null)
|
||||||
|
return
|
||||||
await updateIcon(apiData.country || null)
|
}
|
||||||
|
const country = apiData.country || null
|
||||||
|
const asn = apiData.org?.split(' ')[0]
|
||||||
|
let iconCode = country
|
||||||
|
if (!iconCode && asn === 'AS13335') {
|
||||||
|
iconCode = 'cloudflare'
|
||||||
|
}
|
||||||
|
await updateIcon(iconCode)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to handle tab update:', error)
|
console.error('Failed to handle tab update:', error)
|
||||||
await updateIcon(null)
|
await updateIcon(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.tabs.onActivated.addListener(async activeInfo => {
|
browser.tabs.onActivated.addListener(async activeInfo => {
|
||||||
const tab = await chrome.tabs.get(activeInfo.tabId)
|
const tab = await browser.tabs.get(activeInfo.tabId)
|
||||||
if (tab.url) await handleTabUpdate(tab.url)
|
if (tab.url) await handleTabUpdate(tab.url)
|
||||||
})
|
})
|
||||||
|
|
||||||
chrome.tabs.onUpdated.addListener(async (_tabId, changeInfo) => {
|
browser.tabs.onUpdated.addListener(async (_tabId, changeInfo) => {
|
||||||
if (changeInfo.url) await handleTabUpdate(changeInfo.url)
|
if (changeInfo.url) await handleTabUpdate(changeInfo.url)
|
||||||
})
|
})
|
||||||
|
|
||||||
export default defineBackground({
|
export default defineBackground({
|
||||||
main() {
|
main() {
|
||||||
chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
|
browser.runtime.onMessage.addListener(
|
||||||
|
(request: any, _sender, sendResponse) => {
|
||||||
if (request.type === 'FETCH_SERVER_INFO') {
|
if (request.type === 'FETCH_SERVER_INFO') {
|
||||||
;(async () => {
|
;(async () => {
|
||||||
try {
|
try {
|
||||||
const ip = await resolveARecord(request.hostname)
|
const cleanHostname =
|
||||||
if (!ip) {
|
request.hostname.startsWith('[') &&
|
||||||
|
request.hostname.endsWith(']')
|
||||||
|
? request.hostname.slice(1, -1)
|
||||||
|
: request.hostname
|
||||||
|
|
||||||
|
const apiData = await getIPInfo(cleanHostname)
|
||||||
|
if (!apiData || !apiData.ip) {
|
||||||
sendResponse({ error: 'DNS resolution failed', data: null })
|
sendResponse({ error: 'DNS resolution failed', data: null })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (apiData.bogon === true) {
|
||||||
|
await updateIcon(null)
|
||||||
|
sendResponse({
|
||||||
|
error: null,
|
||||||
|
data: {
|
||||||
|
origin: '',
|
||||||
|
ip: cleanHostname,
|
||||||
|
hostname: '',
|
||||||
|
country: '',
|
||||||
|
city: '',
|
||||||
|
org: '',
|
||||||
|
isLocal: true,
|
||||||
|
isBrowserResource: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const apiResponse = await fetch(`https://ip.albert.lol/${ip}`)
|
const parsed = psl.parse(cleanHostname)
|
||||||
const apiData = await apiResponse.json()
|
|
||||||
|
|
||||||
const parsed = psl.parse(request.hostname)
|
|
||||||
const origin = 'domain' in parsed ? parsed.domain : null
|
const origin = 'domain' in parsed ? parsed.domain : null
|
||||||
|
const country = apiData.country || null
|
||||||
await updateIcon(apiData.country)
|
const asn = apiData.org?.split(' ')[0]
|
||||||
|
let iconCode = country
|
||||||
|
if (!iconCode && asn === 'AS13335') {
|
||||||
|
iconCode = 'cloudflare'
|
||||||
|
}
|
||||||
|
await updateIcon(iconCode)
|
||||||
sendResponse({
|
sendResponse({
|
||||||
error: null,
|
error: null,
|
||||||
data: {
|
data: {
|
||||||
@@ -87,6 +155,8 @@ export default defineBackground({
|
|||||||
country: apiData.country || null,
|
country: apiData.country || null,
|
||||||
city: apiData.city || null,
|
city: apiData.city || null,
|
||||||
org: apiData.org,
|
org: apiData.org,
|
||||||
|
isLocal: false,
|
||||||
|
isBrowserResource: false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -99,6 +169,9 @@ export default defineBackground({
|
|||||||
})()
|
})()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
sendResponse({ error: 'Unknown request type', data: null })
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
+16
-18
@@ -6,7 +6,7 @@ export function useTabData() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const [tab] = await chrome.tabs.query({
|
const [tab] = await browser.tabs.query({
|
||||||
active: true,
|
active: true,
|
||||||
currentWindow: true,
|
currentWindow: true,
|
||||||
})
|
})
|
||||||
@@ -29,21 +29,10 @@ export function useTabData() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const isInternal = isPrivateIP(hostname)
|
const response = await browser.runtime.sendMessage<
|
||||||
if (isInternal) {
|
FetchServerInfoRequest,
|
||||||
return setData({
|
FetchServerInfoResponse
|
||||||
origin: '',
|
>({
|
||||||
ip: hostname,
|
|
||||||
hostname: url.href,
|
|
||||||
country: '',
|
|
||||||
city: '',
|
|
||||||
org: '',
|
|
||||||
isLocal: true,
|
|
||||||
isBrowserResource: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await chrome.runtime.sendMessage({
|
|
||||||
type: 'FETCH_SERVER_INFO',
|
type: 'FETCH_SERVER_INFO',
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
})
|
})
|
||||||
@@ -53,7 +42,16 @@ export function useTabData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
throw new Error(response.error)
|
return setData({
|
||||||
|
origin: '',
|
||||||
|
ip: '',
|
||||||
|
hostname: hostname,
|
||||||
|
country: '',
|
||||||
|
city: '',
|
||||||
|
org: '',
|
||||||
|
isLocal: true,
|
||||||
|
isBrowserResource: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response.data?.ip) {
|
if (!response.data?.ip) {
|
||||||
@@ -63,7 +61,7 @@ export function useTabData() {
|
|||||||
setData(response.data)
|
setData(response.data)
|
||||||
setError(null)
|
setError(null)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err instanceof Error ? err.message : 'Failed to fetch data')
|
setError(err instanceof Error ? err.message : 'No data found')
|
||||||
setData(null)
|
setData(null)
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
|
|||||||
+5
-5
@@ -2,7 +2,7 @@
|
|||||||
"name": "hostinfo",
|
"name": "hostinfo",
|
||||||
"description": "Receive information of a domain directly in the browser when browsing a website",
|
"description": "Receive information of a domain directly in the browser when browsing a website",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.1",
|
"version": "1.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "wxt",
|
"dev": "wxt",
|
||||||
@@ -16,16 +16,16 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^2.2.0",
|
"@heroicons/react": "^2.2.0",
|
||||||
"@tailwindcss/vite": "^4.0.14",
|
"@tailwindcss/vite": "^4.0.15",
|
||||||
"@types/psl": "^1.1.3",
|
"@types/psl": "^1.1.3",
|
||||||
"@types/webextension-polyfill": "^0.12.3",
|
"@types/webextension-polyfill": "^0.12.3",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"tailwindcss": "^4.0.14"
|
"tailwindcss": "^4.0.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chrome": "^0.0.309",
|
"@types/chrome": "^0.0.310",
|
||||||
"@types/react": "^19.0.10",
|
"@types/react": "^19.0.12",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@wxt-dev/module-react": "^1.1.3",
|
"@wxt-dev/module-react": "^1.1.3",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
+12
-5
@@ -1,11 +1,18 @@
|
|||||||
|
import { browser } from 'webextension-polyfill-ts'
|
||||||
|
|
||||||
export async function updateIcon(countryCode: string | null) {
|
export async function updateIcon(countryCode: string | null) {
|
||||||
const validCode =
|
let validCode
|
||||||
|
if (countryCode === 'cloudflare') {
|
||||||
|
validCode = 'cloudflare'
|
||||||
|
} else {
|
||||||
|
validCode =
|
||||||
countryCode?.match(/^[A-Z]{2}$/i)?.[0]?.toLowerCase() || 'unknown'
|
countryCode?.match(/^[A-Z]{2}$/i)?.[0]?.toLowerCase() || 'unknown'
|
||||||
|
}
|
||||||
|
|
||||||
const loadImageBitmap = async (code: string): Promise<ImageBitmap> => {
|
const loadImageBitmap = async (code: string): Promise<ImageBitmap> => {
|
||||||
const url = chrome.runtime.getURL(`${code}.webp`)
|
const url = browser.runtime.getURL('/')
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url)
|
const response = await fetch(url + `${code}.webp`)
|
||||||
if (!response.ok) throw new Error('Flag not found')
|
if (!response.ok) throw new Error('Flag not found')
|
||||||
const blob = await response.blob()
|
const blob = await response.blob()
|
||||||
return await createImageBitmap(blob)
|
return await createImageBitmap(blob)
|
||||||
@@ -52,12 +59,12 @@ export async function updateIcon(countryCode: string | null) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const bitmap = await loadImageBitmap(validCode)
|
const bitmap = await loadImageBitmap(validCode)
|
||||||
chrome.action.setIcon({ imageData: await processImage(bitmap) })
|
browser.action.setIcon({ imageData: await processImage(bitmap) })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Primary flag failed, trying unknown:', error)
|
console.error('Primary flag failed, trying unknown:', error)
|
||||||
try {
|
try {
|
||||||
const unknownBitmap = await loadImageBitmap('unknown')
|
const unknownBitmap = await loadImageBitmap('unknown')
|
||||||
chrome.action.setIcon({ imageData: await processImage(unknownBitmap) })
|
browser.action.setIcon({ imageData: await processImage(unknownBitmap) })
|
||||||
} catch (fallbackError) {
|
} catch (fallbackError) {
|
||||||
console.error('Both flag assets failed:', fallbackError)
|
console.error('Both flag assets failed:', fallbackError)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
export function isPrivateIP(host: string): boolean {
|
|
||||||
try {
|
|
||||||
const rawIp = host.startsWith('[') ? host.slice(1, -1) : host
|
|
||||||
|
|
||||||
if (rawIp === 'localhost') return true
|
|
||||||
|
|
||||||
if (rawIp.includes('.')) {
|
|
||||||
const parts = rawIp.split('.').map(Number)
|
|
||||||
if (parts.length !== 4 || parts.some(isNaN)) return false
|
|
||||||
|
|
||||||
return (
|
|
||||||
parts[0] === 10 ||
|
|
||||||
(parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) ||
|
|
||||||
(parts[0] === 192 && parts[1] === 168) ||
|
|
||||||
(parts[0] === 169 && parts[1] === 254)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawIp.includes(':')) {
|
|
||||||
const ip = rawIp.split('%')[0]
|
|
||||||
|
|
||||||
if (ip === '::1') return true
|
|
||||||
|
|
||||||
const firstHextet = parseInt(ip.split(':')[0], 16)
|
|
||||||
if ((firstHextet & 0xfe00) === 0xfc00) return true
|
|
||||||
|
|
||||||
if ((firstHextet & 0xffc0) === 0xfe80) return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,3 +13,13 @@ export interface DNSEntry {
|
|||||||
type: number
|
type: number
|
||||||
data: string
|
data: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FetchServerInfoRequest {
|
||||||
|
type: 'FETCH_SERVER_INFO'
|
||||||
|
hostname: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FetchServerInfoResponse {
|
||||||
|
error?: string
|
||||||
|
data?: ServerData
|
||||||
|
}
|
||||||
|
|||||||
+9
-7
@@ -1,17 +1,19 @@
|
|||||||
import { defineConfig } from 'wxt';
|
import { defineConfig } from 'wxt'
|
||||||
import tailwindcss from "@tailwindcss/vite";
|
import tailwindcss from '@tailwindcss/vite'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
extensionApi: 'chrome',
|
|
||||||
modules: ['@wxt-dev/module-react'],
|
modules: ['@wxt-dev/module-react'],
|
||||||
manifest: {
|
manifest: {
|
||||||
permissions: ['tabs', 'activeTab', 'webRequest', 'file://*', 'debugger'],
|
permissions: ['tabs', 'activeTab'],
|
||||||
host_permissions: ['https://ip.albert.lol/*', 'https://dns.google/*', 'https://flagcdn.com/*'],
|
host_permissions: [
|
||||||
|
'https://ip.albert.lol/*',
|
||||||
|
'https://cloudflare-dns.com/*',
|
||||||
|
],
|
||||||
action: {
|
action: {
|
||||||
default_title: 'Host Info',
|
default_title: 'Host Info',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
vite: () => ({
|
vite: () => ({
|
||||||
plugins: [tailwindcss()],
|
plugins: [tailwindcss()],
|
||||||
})
|
}),
|
||||||
});
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user