Skip to content

Commit 38f1b8f

Browse files
authored
Merge pull request #203 from jason5ng32/dev
Add Whois Search
2 parents d35a2cc + 2111d0a commit 38f1b8f

26 files changed

+672
-139
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ Notes: You can use my demo for free, and you can also deploy it yourself.
3535
* 🛑 **DNS Leak Test**: Shows DNS endpoint data to evaluate the risk of DNS leaks when using VPNs or proxies.
3636
* 🚀 **Speed Test**:Test your network speed with edge networks.
3737
* 🚏 **Proxy Rule Testing**: Test the rule settings of proxy software to ensure their correctness.
38-
* 🌐 **Global Latency Test**: Performe lantency tests on servers located in different regions around the world.
38+
* ⏱️ **Global Latency Test**: Performe lantency tests on servers located in different regions around the world.
3939
* 📡 **MTR Test**: Perform MTR tests on servers located in different regions around the world.
4040
* 🔦 **DNS Resolver**: Performs DNS resolution of a domain name from multiple sources and obtains real-time resolution results that can be used for contamination determination.
4141
* 🚧 **Censorship Check**: Check if a website is blocked in some countries.
42+
* 📓 **Whois Search**: Perform whois information search for domain names or IP addresses
4243
* 🌗 **Dark Mode**: Automatically toggles between dark and daylight modes based on system settings, with an option for manual switching.
4344
* 📱 **Minimalist Mode**: A mobile-optimized mode that shortens page length for quick access to essential information..
4445
* 🔍 **Search IP Information**: Provides a tool for querying information about any IP address.

README_FR.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ Notes: Vous pouvez utiliser ma démo gratuitement et vous pouvez également la d
3535
* 🛑 **Test de fuite DNS** : Affiche les données de point de terminaison DNS pour évaluer le risque de fuites DNS lors de l'utilisation de VPN ou de proxies.
3636
* 🚀 **Test de vitesse** : Testez la vitesse de votre réseau avec des réseaux de pointe.
3737
* 🚏 **Test de règles** : Teste si les paramètres de règles fonctionnent correctement avec le logiciel de proxy.
38-
* 🌐 **Test de latence mondiale** : Effectue des tests de latence sur des serveurs situés dans différentes régions du monde.
38+
* ⏱️ **Test de latence mondiale** : Effectue des tests de latence sur des serveurs situés dans différentes régions du monde.
3939
* 📡 **Test MTR** : Effectue des tests MTR sur des serveurs situés dans différentes régions du monde.
4040
* 🔦 **Résolveur DNS** : effectue la résolution DNS d'un nom de domaine à partir de plusieurs sources, obtient les résultats de la résolution en temps réel et peut être utilisé pour la détermination de la contamination.
4141
* 🚧 **Test de Censorship**: Vérifier si un site est bloqué dans certains pays.
42+
* 📓 **Recherche Whois** : Effectuer une recherche d'informations Whois pour les noms de domaine ou les adresses IP
4243
* 🌗 **Mode sombre** : Bascule automatiquement entre les modes sombre et clair en fonction des paramètres du système, avec une option de basculement manuel.
4344
* 📱 **Mode minimaliste** : Un mode optimisé pour les mobiles qui réduit la longueur de la page pour un accès rapide aux informations essentielles.
4445
* 🔍 **Recherche d'informations sur l'adresse IP** : Fournit un outil pour interroger des informations sur n'importe quelle adresse IP.

README_ZH.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@
3737
* 🛑 **DNS 泄露检测**:查看 DNS 出口信息,以便查看在 VPN/代理的情况下,是否存在 DNS 泄露隐私的风险
3838
* 🚀 **网速测试**:利用边缘网络进行网速测试
3939
* 🚏 **代理规则测试**:配合代理软件的规则设置,测试规则设置是否正常
40-
* 🌐 **全球延迟测试**:从分布在全球的多个服务器进行延迟测试,了解你与全球网络的连接速度
40+
* ⏱️ **全球延迟测试**:从分布在全球的多个服务器进行延迟测试,了解你与全球网络的连接速度
4141
* 📡 **MTR 测试**:从分布在全球的多个服务器进行 MTR 测试,了解你与全球的连接路径
4242
* 🔦 **DNS 解析器**:从多个渠道对域名进行 DNS 解析,获取实时的解析结果,可用于污染判断
4343
* 🚧 **封锁测试**:检查特定的网站在部分国家是否被封锁
44+
* 📓 **Whois 查询**:对域名或 IP 进行 whois 信息查询
4445
* 🌗 **暗黑模式**:根据系统设置自动切换暗黑/白天模式,也可以手动切换
4546
* 📱 **简约模式**:为移动版提供的专门模式,缩短页面长度,快速查看最重要的信息
4647
* 🔍 **查任意 IP 信息**:可以通过小工具查询任意 IP 的信息

api/whois.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import whoiser from 'whoiser';
2+
3+
function isValidIP(ip) {
4+
const ipv4Pattern =
5+
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
6+
const ipv6Pattern =
7+
/^(([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4})|(([0-9a-fA-F]{1,4}:){0,6}([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:){0,6}([0-9a-fA-F]{1,4})?))$/;
8+
return ipv4Pattern.test(ip) || ipv6Pattern.test(ip);
9+
};
10+
11+
function isValidDomain(domain) {
12+
const domainPattern = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i;
13+
return domainPattern.test(domain);
14+
}
15+
16+
export default async (req, res) => {
17+
18+
// 限制只能从指定域名访问
19+
const allowedDomains = ['localhost', ...(process.env.ALLOWED_DOMAINS || '').split(',')];
20+
const referer = req.headers.referer;
21+
22+
if (referer) {
23+
const domain = new URL(referer).hostname;
24+
if (!allowedDomains.includes(domain)) {
25+
return res.status(403).json({ error: 'Access denied' });
26+
}
27+
} else {
28+
return res.status(403).json({ error: 'What are you doing?' });
29+
}
30+
31+
const query = req.query.q;
32+
if (!query) {
33+
return res.status(400).json({ error: 'No address provided' });
34+
}
35+
36+
// 检查 IP 地址是否合法
37+
if (!isValidIP(query) && !isValidDomain(query)) {
38+
return res.status(400).json({ error: 'Invalid IP or address' });
39+
}
40+
41+
if (isValidIP(query)) {
42+
try {
43+
const ipinfo = await whoiser.ip(query, { timeout: 5000,raw: true});
44+
res.json(ipinfo);
45+
} catch (e) {
46+
res.status(500).json({ error: e.message });
47+
}
48+
} else {
49+
try {
50+
const domaininfo = await whoiser.domain(query, { ignorePrivacy: false, timeout: 5000, follow: 2,raw: true});
51+
res.json(domaininfo);
52+
} catch (e) {
53+
res.status(500).json({ error: e.message });
54+
}
55+
}
56+
};

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
"vue": "^3.4.26",
3333
"vue-i18n": "^9.13.1",
3434
"vue-router": "^4.3.2",
35-
"vuex": "^4.1.0"
35+
"vuex": "^4.1.0",
36+
"whoiser": "^1.17.3"
3637
},
3738
"devDependencies": {
3839
"@vitejs/plugin-vue": "^5.0.4",

server.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import validateConfigs from './api/configs.js';
1515
import dnsResolver from './api/dnsresolver.js';
1616
import rateLimit from 'express-rate-limit';
1717
import { slowDown } from 'express-slow-down'
18+
import whois from './api/whois.js';
1819

1920
dotenv.config();
2021

@@ -131,6 +132,7 @@ app.get('/api/ipsb', ipsbHandler);
131132
app.get('/api/cfradar', cfHander);
132133
app.get('/api/recaptcha', recaptchaHandler);
133134
app.get('/api/dnsresolver', dnsResolver);
135+
app.get('/api/whois', whois);
134136

135137
// 使用查询参数处理所有配置请求
136138
app.get('/api/configs', validateConfigs);

src/App.vue

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ import { mappingKeys, navigateCards, keyMap } from "./shortcut.js";
5555
5656
import { ref, computed, watch } from 'vue';
5757
import { useStore } from 'vuex';
58-
import { Modal, Toast } from 'bootstrap';
58+
import { Modal, Toast, Offcanvas } from 'bootstrap';
5959
6060
export default {
6161
@@ -235,10 +235,10 @@ export default {
235235
infoMask() {
236236
if (this.infoMaskLevel === 0) {
237237
this.$refs.IPCheckRef.ipDataCards.forEach((card) => {
238-
if(card.id === "cloudflare_v6" || card.id === "ipify_v6") {
238+
if (card.id === "cloudflare_v6" || card.id === "ipify_v6") {
239239
card.ip = "2001:4860:4860::8888";
240240
} else {
241-
card.ip = "8.8.8.8";
241+
card.ip = "8.8.8.8";
242242
}
243243
});
244244
this.$refs.webRTCRef.stunServers.forEach((server) => {
@@ -259,7 +259,7 @@ export default {
259259
card.isp = "Google LLC";
260260
card.asn = "AS15169";
261261
card.asnlink = "https://radar.cloudflare.com/AS15169",
262-
card.mapUrl = '/defaultMap.webp';
262+
card.mapUrl = '/defaultMap.webp';
263263
card.mapUrl_dark = '/defaultMap_dark.webp';
264264
card.showASNInfo = false;
265265
card.isProxy = this.$t('ipInfos.proxyDetect.no');
@@ -462,6 +462,15 @@ export default {
462462
},
463463
description: this.$t('shortcutKeys.CensorshipCheck'),
464464
},
465+
{
466+
keys: "w",
467+
action: () => {
468+
this.scrollToElement("AdvancedTools", 80);
469+
this.$refs.advancedToolsRef.navigateAndToggleOffcanvas('/whois');
470+
this.$trackEvent('Nav', 'NavClick', 'Whois');
471+
},
472+
description: this.$t('shortcutKeys.Whois'),
473+
},
465474
{
466475
keys: "m",
467476
action: () => {
@@ -548,13 +557,40 @@ export default {
548557
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
549558
);
550559
},
560+
561+
// 监听所有 offcanvas,避免同时打开多个导致浏览器崩溃
562+
listenOffcanvas() {
563+
const offcanvasElements = document.querySelectorAll('.offcanvas');
564+
const navElements = document.getElementById('navbarNavAltMarkup');
565+
const navElementsButton = document.querySelector('.navbar-toggler');
566+
offcanvasElements.forEach((element) => {
567+
const instance = Offcanvas.getOrCreateInstance(element); // 确保实例创建成功
568+
element.addEventListener('show.bs.offcanvas', () => {
569+
// 存在 Offcanvas 时关闭导航栏
570+
navElements.classList.remove('show');
571+
navElementsButton.setAttribute('aria-expanded', 'false');
572+
navElementsButton.classList.add('collapsed');
573+
// 关闭所有其他的 offcanvas
574+
offcanvasElements.forEach((offcanvas) => {
575+
if (offcanvas !== element) {
576+
const offcanvasInstance = Offcanvas.getInstance(offcanvas);
577+
if (offcanvasInstance) { // 确保实例有效
578+
offcanvasInstance.hide();
579+
}
580+
}
581+
});
582+
});
583+
});
584+
},
585+
551586
},
552587
mounted() {
553588
this.registerShortcutKeys();
554589
this.setupModalFocus();
555590
this.keyMap = keyMap;
556591
this.sendKeyMap();
557592
this.setInfosLoaded();
593+
this.listenOffcanvas();
558594
window.addEventListener('scroll', this.checkSectionsAndTrack);
559595
},
560596
beforeDestroy() {

0 commit comments

Comments
 (0)