mirror of
https://github.com/skidoodle/hostinfo
synced 2026-04-28 09:37:37 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
f2cc9a8c87
|
|||
|
bf5c5575f5
|
|||
|
6f0125896a
|
|||
| 9253e53ca1 |
@@ -5,6 +5,7 @@ A browser extension built with [WXT.dev](https://wxt.dev) and React that lets yo
|
|||||||
<img src="https://github.com/user-attachments/assets/83a6316c-54b8-41a8-8d43-c794a5f62696" alt="Showcase" width="200"/>
|
<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://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>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -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=="],
|
||||||
|
|
||||||
|
|||||||
+83
-28
@@ -4,51 +4,87 @@ 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
|
||||||
|
}
|
||||||
const country = apiData.country || null
|
const country = apiData.country || null
|
||||||
const asn = apiData.org?.split(' ')[0]
|
const asn = apiData.org?.split(' ')[0]
|
||||||
let iconCode = country
|
let iconCode = country
|
||||||
if (!iconCode && asn === 'AS13335') {
|
if (!iconCode && asn === 'AS13335') {
|
||||||
iconCode = 'cloudflare'
|
iconCode = 'cloudflare'
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateIcon(iconCode)
|
await updateIcon(iconCode)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to handle tab update:', error)
|
console.error('Failed to handle tab update:', error)
|
||||||
@@ -72,18 +108,37 @@ export default defineBackground({
|
|||||||
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
|
const country = apiData.country || null
|
||||||
const asn = apiData.org?.split(' ')[0]
|
const asn = apiData.org?.split(' ')[0]
|
||||||
let iconCode = country
|
let iconCode = country
|
||||||
@@ -91,7 +146,6 @@ export default defineBackground({
|
|||||||
iconCode = 'cloudflare'
|
iconCode = 'cloudflare'
|
||||||
}
|
}
|
||||||
await updateIcon(iconCode)
|
await updateIcon(iconCode)
|
||||||
|
|
||||||
sendResponse({
|
sendResponse({
|
||||||
error: null,
|
error: null,
|
||||||
data: {
|
data: {
|
||||||
@@ -101,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) {
|
||||||
@@ -113,7 +169,6 @@ export default defineBackground({
|
|||||||
})()
|
})()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
sendResponse({ error: 'Unknown request type', data: null })
|
sendResponse({ error: 'Unknown request type', data: null })
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
import { useState, useEffect } from 'react'
|
|
||||||
import { isPrivateIP } from '@/utils'
|
|
||||||
import {
|
|
||||||
FetchServerInfoRequest,
|
|
||||||
FetchServerInfoResponse,
|
|
||||||
ServerData,
|
|
||||||
} from '@/utils/model'
|
|
||||||
import browser from 'webextension-polyfill'
|
|
||||||
|
|
||||||
export function useTabData() {
|
export function useTabData() {
|
||||||
const [data, setData] = useState<ServerData | null>(null)
|
const [data, setData] = useState<ServerData | null>(null)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
@@ -38,20 +29,6 @@ export function useTabData() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const isInternal = isPrivateIP(hostname)
|
|
||||||
if (isInternal) {
|
|
||||||
return setData({
|
|
||||||
origin: '',
|
|
||||||
ip: hostname,
|
|
||||||
hostname: '',
|
|
||||||
country: '',
|
|
||||||
city: '',
|
|
||||||
org: '',
|
|
||||||
isLocal: true,
|
|
||||||
isBrowserResource: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await browser.runtime.sendMessage<
|
const response = await browser.runtime.sendMessage<
|
||||||
FetchServerInfoRequest,
|
FetchServerInfoRequest,
|
||||||
FetchServerInfoResponse
|
FetchServerInfoResponse
|
||||||
|
|||||||
+4
-4
@@ -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",
|
||||||
|
|||||||
+4
-2
@@ -1,3 +1,5 @@
|
|||||||
|
import { browser } from 'webextension-polyfill-ts'
|
||||||
|
|
||||||
export async function updateIcon(countryCode: string | null) {
|
export async function updateIcon(countryCode: string | null) {
|
||||||
let validCode
|
let validCode
|
||||||
if (countryCode === 'cloudflare') {
|
if (countryCode === 'cloudflare') {
|
||||||
@@ -57,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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-4
@@ -15,11 +15,11 @@ export interface DNSEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchServerInfoRequest {
|
export interface FetchServerInfoRequest {
|
||||||
type: 'FETCH_SERVER_INFO';
|
type: 'FETCH_SERVER_INFO'
|
||||||
hostname: string;
|
hostname: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchServerInfoResponse {
|
export interface FetchServerInfoResponse {
|
||||||
error?: string;
|
error?: string
|
||||||
data?: ServerData;
|
data?: ServerData
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user