第一次提交
This commit is contained in:
parent
5ad838c5f3
commit
1ca7e58f24
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
7
app.vue
Normal file
7
app.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<NuxtLoadingIndicator />
|
||||
<NuxtLayout>
|
||||
<UNotifications />
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</template>
|
64
components/common/ColorChange.vue
Normal file
64
components/common/ColorChange.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<script lang="ts" setup>
|
||||
const colorMode = useColorMode()
|
||||
const availableColor = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: 'system',
|
||||
icon: 'ph:laptop-duotone',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'dark',
|
||||
icon: 'ph:moon-stars-duotone',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'light',
|
||||
icon: 'ph:sun-dim-duotone',
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<HeadlessListbox
|
||||
v-model="$colorMode.preference"
|
||||
as="div"
|
||||
class="relative flex items-center"
|
||||
>
|
||||
<HeadlessListboxLabel class="sr-only">
|
||||
Theme
|
||||
</HeadlessListboxLabel>
|
||||
<HeadlessListboxButton type="button" title="Change Color">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
>
|
||||
<Icon name="ph:palette-duotone" class=" text-lg dark:text-white" />
|
||||
</div>
|
||||
</HeadlessListboxButton>
|
||||
<HeadlessListboxOptions
|
||||
class="absolute top-full right-0 z-[999] mt-2 w-40 overflow-hidden rounded-lg bg-white text-sm font-semibold text-gray-700 shadow-lg shadow-gray-300 outline-none dark:bg-gray-800 dark:text-white dark:shadow-gray-500 dark:ring-0"
|
||||
>
|
||||
<HeadlessListboxOption
|
||||
v-for="color in availableColor"
|
||||
:key="color.id"
|
||||
:value="color.name"
|
||||
class="flex w-full cursor-pointer items-center justify-between py-2 px-3"
|
||||
:class="{
|
||||
'text-white-500 bg-gray-200 dark:bg-gray-500/50':
|
||||
colorMode.preference === color.name,
|
||||
'hover:bg-gray-200 dark:hover:bg-gray-700/30':
|
||||
colorMode.preference !== color.name,
|
||||
}"
|
||||
>
|
||||
<span class="truncate">
|
||||
{{ color.name }}
|
||||
</span>
|
||||
<span class="flex items-center justify-center text-sm">
|
||||
<Icon :name="color.icon" class="text-base" />
|
||||
</span>
|
||||
</HeadlessListboxOption>
|
||||
</HeadlessListboxOptions>
|
||||
</HeadlessListbox>
|
||||
</div>
|
||||
</template>
|
43
components/common/DomainList.vue
Normal file
43
components/common/DomainList.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import {SupportedTLDs} from "~/utils/domain";
|
||||
|
||||
const isOpen = ref(false)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div title="Change Color">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
@click="isOpen = true"
|
||||
>
|
||||
<Icon name="mdi:about-circle-outline" class=" text-lg dark:text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<USlideover
|
||||
v-model="isOpen"
|
||||
side="left"
|
||||
>
|
||||
<button>
|
||||
<Icon name="lets-icons:close-ring-light" class="absolute top-2 right-2 text-gray-500 cursor-pointer" @click="isOpen = false" />
|
||||
</button>
|
||||
<div class="p-4 flex-1">
|
||||
<div>目前仅支持以下后缀:</div>
|
||||
<div class="flex flex-wrap mt-2 p-5 overflow-y-auto max-h-[95vh]">
|
||||
<span
|
||||
v-for="item in SupportedTLDs"
|
||||
:key="item"
|
||||
class="m-1 px-2 py-1 text-sm font-semibold text-gray-800 bg-gray-200 rounded hover:bg-gray-300"
|
||||
>
|
||||
{{ item }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</USlideover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
61
components/common/LanguageChange.vue
Normal file
61
components/common/LanguageChange.vue
Normal file
@ -0,0 +1,61 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
const switchLocalePath = useSwitchLocalePath()
|
||||
|
||||
const { locale } = useI18n()
|
||||
|
||||
const local = computed(() => {
|
||||
return locale.value
|
||||
})
|
||||
|
||||
const availableLocales = [
|
||||
{ iso: 'en', name: 'English', flag: 'twemoji:flag-us-outlying-islands' },
|
||||
{ iso: 'zh', name: '中文简体', flag: 'emojione-v1:flag-for-china' },
|
||||
{ iso: 'tw', name: '中文繁体', flag: 'flag:tw-4x3' },
|
||||
// 添加更多语言...
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<HeadlessListbox
|
||||
v-model="local"
|
||||
as="div"
|
||||
class="relative flex items-center"
|
||||
>
|
||||
<HeadlessListboxLabel class="sr-only">
|
||||
Change Language
|
||||
</HeadlessListboxLabel>
|
||||
<HeadlessListboxButton type="button" title="Change Language">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
>
|
||||
<Icon name="i-ph:translate-bold" class=" text-lg dark:text-white" size="20" />
|
||||
</div>
|
||||
</HeadlessListboxButton>
|
||||
<HeadlessListboxOptions
|
||||
class="absolute top-full right-0 z-[999] mt-2 w-40 overflow-hidden rounded-lg bg-white text-sm font-semibold text-gray-700 shadow-lg shadow-gray-300 outline-none dark:bg-gray-800 dark:text-white dark:shadow-gray-500 dark:ring-0"
|
||||
>
|
||||
<NuxtLink
|
||||
v-for="lang in availableLocales"
|
||||
:key="lang.iso"
|
||||
:to="switchLocalePath(lang.iso)"
|
||||
class="flex w-full cursor-pointer items-center justify-between py-2 px-3"
|
||||
:class="{
|
||||
'text-white-500 bg-gray-200 dark:bg-gray-500/50':
|
||||
local === lang.iso,
|
||||
'hover:bg-gray-200 dark:hover:bg-gray-700/30':
|
||||
local !== lang.iso,
|
||||
}"
|
||||
>
|
||||
<span class="truncate">
|
||||
{{ lang.name }}
|
||||
</span>
|
||||
<span class="flex items-center justify-center text-sm">
|
||||
<Icon :name="lang.flag" class="text-base" size="20" />
|
||||
</span>
|
||||
</NuxtLink>
|
||||
</HeadlessListboxOptions>
|
||||
</HeadlessListbox>
|
||||
</div>
|
||||
</template>
|
84
components/common/TimeZonesChange.vue
Normal file
84
components/common/TimeZonesChange.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {useTimeStore} from "~/stores/time";
|
||||
|
||||
const availableTimeZones = ref([
|
||||
{ id: 1, name: 'UTC-12', displayName: 'International Date Line West' },
|
||||
{ id: 2, name: 'UTC-11', displayName: 'Coordinated Universal Time-11' },
|
||||
{ id: 3, name: 'UTC-10', displayName: 'Hawaii' },
|
||||
{ id: 4, name: 'UTC-9', displayName: 'Alaska' },
|
||||
{ id: 5, name: 'UTC-8', displayName: 'Pacific Time (US & Canada)' },
|
||||
{ id: 6, name: 'UTC-7', displayName: 'Mountain Time (US & Canada)' },
|
||||
{ id: 7, name: 'UTC-6', displayName: 'Central Time (US & Canada), Mexico City' },
|
||||
{ id: 8, name: 'UTC-5', displayName: 'Eastern Time (US & Canada), Bogota, Lima' },
|
||||
{ id: 9, name: 'UTC-4', displayName: 'Atlantic Time (Canada), Caracas, La Paz' },
|
||||
{ id: 10, name: 'UTC-3', displayName: 'Buenos Aires, Georgetown' },
|
||||
{ id: 11, name: 'UTC-2', displayName: 'Coordinated Universal Time-02' },
|
||||
{ id: 12, name: 'UTC-1', displayName: 'Azores' },
|
||||
{ id: 13, name: 'UTC', displayName: 'Coordinated Universal Time' },
|
||||
{ id: 14, name: 'UTC+1', displayName: 'Brussels, Copenhagen, Madrid, Paris' },
|
||||
{ id: 15, name: 'UTC+2', displayName: 'Athens, Bucharest, Istanbul' },
|
||||
{ id: 16, name: 'UTC+3', displayName: 'Moscow, St. Petersburg, Nairobi' },
|
||||
{ id: 17, name: 'UTC+3:30', displayName: 'Tehran' },
|
||||
{ id: 18, name: 'UTC+4', displayName: 'Abu Dhabi, Muscat' },
|
||||
{ id: 19, name: 'UTC+4:30', displayName: 'Kabul' },
|
||||
{ id: 20, name: 'UTC+5', displayName: 'Islamabad, Karachi, Tashkent' },
|
||||
{ id: 21, name: 'UTC+5:30', displayName: 'Chennai, Kolkata, Mumbai, New Delhi' },
|
||||
{ id: 22, name: 'UTC+5:45', displayName: 'Kathmandu' },
|
||||
{ id: 23, name: 'UTC+6', displayName: 'Astana, Dhaka' },
|
||||
{ id: 24, name: 'UTC+6:30', displayName: 'Yangon (Rangoon)' },
|
||||
{ id: 25, name: 'UTC+7', displayName: 'Bangkok, Hanoi, Jakarta' },
|
||||
{ id: 26, name: 'UTC+8', displayName: 'Beijing, Hong Kong, Singapore, Taipei' },
|
||||
{ id: 27, name: 'UTC+9', displayName: 'Osaka, Sapporo, Tokyo' },
|
||||
{ id: 28, name: 'UTC+9:30', displayName: 'Adelaide, Darwin' },
|
||||
{ id: 29, name: 'UTC+10', displayName: 'Brisbane, Canberra, Melbourne, Sydney' },
|
||||
{ id: 30, name: 'UTC+11', displayName: 'Solomon Is., New Caledonia' },
|
||||
{ id: 31, name: 'UTC+12', displayName: 'Auckland, Wellington' },
|
||||
{ id: 32, name: 'UTC+13', displayName: 'Nuku alofa' }
|
||||
]);
|
||||
|
||||
const timeStore = useTimeStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<HeadlessListbox
|
||||
v-model="timeStore.timeZones"
|
||||
as="div"
|
||||
class="relative flex items-center"
|
||||
>
|
||||
<HeadlessListboxLabel class="sr-only">
|
||||
Theme
|
||||
</HeadlessListboxLabel>
|
||||
<HeadlessListboxButton type="button" title="Change Color">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700"
|
||||
>
|
||||
<Icon name="ri:time-zone-line" class=" text-lg dark:text-white" />
|
||||
</div>
|
||||
</HeadlessListboxButton>
|
||||
<HeadlessListboxOptions
|
||||
class="absolute top-full right-0 z-[999] mt-2 w-40 max-h-60 overflow-y-auto rounded-lg bg-white text-sm font-semibold text-gray-700 shadow-lg shadow-gray-300 outline-none dark:bg-gray-800 dark:text-white dark:shadow-gray-500 dark:ring-0"
|
||||
>
|
||||
<HeadlessListboxOption
|
||||
v-for="item in availableTimeZones"
|
||||
:key="item.id"
|
||||
:value="item.name"
|
||||
class="flex w-full cursor-pointer items-center justify-between py-2 px-3 hover:bg-gray-100 dark:hover:bg-gray-600"
|
||||
:class="{
|
||||
'text-white-500 bg-gray-200 dark:bg-gray-500/50':
|
||||
timeStore.timeZones === item.name,
|
||||
'hover:bg-gray-200 dark:hover:bg-gray-700/30':
|
||||
timeStore.timeZones !== item.name,
|
||||
}"
|
||||
>
|
||||
<span class="truncate">
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<span class="flex items-center justify-center text-sm">
|
||||
</span>
|
||||
</HeadlessListboxOption>
|
||||
</HeadlessListboxOptions>
|
||||
</HeadlessListbox>
|
||||
</div>
|
||||
</template>
|
BIN
img/home.png
Normal file
BIN
img/home.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
38
lang/en.ts
Normal file
38
lang/en.ts
Normal file
@ -0,0 +1,38 @@
|
||||
export default defineI18nLocale(async locale => {
|
||||
return {
|
||||
index: {
|
||||
tips: 'The information you submit for your query will not be recorded!',
|
||||
},
|
||||
error:{
|
||||
formatDomain: 'Error formatting domain name',
|
||||
validDomain: 'Domain must contain a valid top-level domain',
|
||||
notFound: 'Domain not found',
|
||||
},
|
||||
result: {
|
||||
result: 'Query Result',
|
||||
title: 'WHOIS Query Result',
|
||||
description: 'Here is the WHOIS information for the domain you queried',
|
||||
domain: 'Domain Name',
|
||||
//数据源
|
||||
source: 'Source',
|
||||
//注册商
|
||||
registrar: 'Registrar',
|
||||
//更新日
|
||||
updateDate: 'Updated Date',
|
||||
//注册日
|
||||
createDate: 'Creation Date',
|
||||
//到期日
|
||||
expirationDate: 'Registry Expiry Date',
|
||||
//IANAID
|
||||
ianaId: 'IANAID',
|
||||
//状态
|
||||
status: 'Domain Status',
|
||||
//DNS
|
||||
dns: 'DNS',
|
||||
//DNSSEC
|
||||
dnssec: 'DNSSEC',
|
||||
//原始数据
|
||||
rawData: 'Raw Data',
|
||||
}
|
||||
}
|
||||
})
|
38
lang/tw.ts
Normal file
38
lang/tw.ts
Normal file
@ -0,0 +1,38 @@
|
||||
export default defineI18nLocale(async locale => {
|
||||
return {
|
||||
index: {
|
||||
tips: '您提交的查詢信息不會被記錄!',
|
||||
},
|
||||
error:{
|
||||
formatDomain: '域名格式錯誤',
|
||||
validDomain: '域名必須包含有效的頂級域',
|
||||
notFound: '未找到域名資料',
|
||||
},
|
||||
result: {
|
||||
result: '查詢結果',
|
||||
title: 'WHOIS查詢結果',
|
||||
description: '以下是您查詢的域名的WHOIS資訊',
|
||||
domain: '域名',
|
||||
//数据源
|
||||
source: '資料來源',
|
||||
//注册商
|
||||
registrar: '註冊商',
|
||||
//更新日
|
||||
updateDate: '更新日',
|
||||
//注册日
|
||||
createDate: '註冊日',
|
||||
//到期日
|
||||
expirationDate: '到期日',
|
||||
//IANAID
|
||||
ianaId: 'IANAID',
|
||||
//状态
|
||||
status: '狀態',
|
||||
//DNS
|
||||
dns: 'DNS',
|
||||
//DNSSEC
|
||||
dnssec: 'DNSSEC',
|
||||
//原始数据
|
||||
rawData: '原始資料',
|
||||
}
|
||||
}
|
||||
})
|
39
lang/zh.ts
Normal file
39
lang/zh.ts
Normal file
@ -0,0 +1,39 @@
|
||||
export default defineI18nLocale(async locale => {
|
||||
return {
|
||||
index: {
|
||||
tips: '您提交的查询信息不会被记录!',
|
||||
},
|
||||
error:{
|
||||
formatDomain: '域名格式错误',
|
||||
//域名必须包含有效的顶级域
|
||||
validDomain: '域名必须包含有效的顶级域',
|
||||
notFound: '未找到域名信息',
|
||||
},
|
||||
result: {
|
||||
result: '查询结果',
|
||||
title: 'WHOIS查询结果',
|
||||
description: '以下是您查询的域名的WHOIS信息',
|
||||
domain: '域名',
|
||||
//数据源
|
||||
source: '数据源',
|
||||
//注册商
|
||||
registrar: '注册商',
|
||||
//更新日
|
||||
updateDate: '更新日',
|
||||
//注册日
|
||||
createDate: '注册日',
|
||||
//到期日
|
||||
expirationDate: '到期日',
|
||||
//IANAID
|
||||
ianaId: 'IANAID',
|
||||
//状态
|
||||
status: '状态',
|
||||
//DNS
|
||||
dns: 'DNS',
|
||||
//DNSSEC
|
||||
dnssec: 'DNSSEC',
|
||||
//原始数据
|
||||
rawData: '原始数据',
|
||||
}
|
||||
}
|
||||
})
|
128
layouts/default.vue
Normal file
128
layouts/default.vue
Normal file
@ -0,0 +1,128 @@
|
||||
<script setup lang="ts">
|
||||
import {SupportedTLDs} from "~/utils/domain";
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const state = reactive({
|
||||
domain: '',
|
||||
})
|
||||
|
||||
const toast = useToast();
|
||||
const router = useRouter();
|
||||
const handleAction = async (event: any) => {
|
||||
// 先拿到并处理域名
|
||||
const domain = state.domain.trim();
|
||||
|
||||
// 分割域名为各部分
|
||||
const parts = domain.split('.');
|
||||
|
||||
// 需要一个更严格的检查来确认域名格式是否正确
|
||||
if (parts.length < 2) {
|
||||
toast.add({
|
||||
title: '域名格式不正确',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取最后两个部分作为可能的顶级域名(TLD)
|
||||
const potentialTLD = parts.slice(-2).join('.');
|
||||
|
||||
// 判断后缀是否合法
|
||||
if (!SupportedTLDs.has(parts.slice(-1)[0]) && !SupportedTLDs.has(potentialTLD)) {
|
||||
toast.add({
|
||||
title: '域名后缀不合法',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 确定是否是二级顶级域名
|
||||
let domainToKeep = domain;
|
||||
if (SupportedTLDs.has(potentialTLD)) {
|
||||
// 如果是二级顶级域名,保留最后三个部分
|
||||
domainToKeep = parts.length > 2 ? parts.slice(-3).join('.') : domain;
|
||||
} else {
|
||||
// 否则,只保留最后两个部分
|
||||
domainToKeep = parts.slice(-2).join('.');
|
||||
}
|
||||
|
||||
// 更新state.domain为只包含顶级域名的版本
|
||||
state.domain = domainToKeep;
|
||||
|
||||
// 跳转到结果页
|
||||
await router.push('/result/' + state.domain.replace(/\./g, '_') + '.html');
|
||||
}
|
||||
|
||||
const timeStore = useTimeStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full min-h-screen text-xs bg-[#F1F3F4] dark:bg-transparent">
|
||||
<div class=" max-w-screen-lg mx-auto pt-[25vh] px-[1em] pb-[10vh] ">
|
||||
<nav class=" w-full text-[#464747] h-5 dark:bg-gray-700">
|
||||
<NuxtLink class="mb-3 font-bold text-2xl inline-block text-current no-underline dark:text-white"
|
||||
to="/"
|
||||
>
|
||||
<h1 class="inline-block text-current no-underline dark:text-white">Nuxt Whois</h1>
|
||||
<sup class="text-[#59a8d7] dark:text-[#ace4f8]">COM</sup>
|
||||
</NuxtLink>
|
||||
</nav>
|
||||
<div class="mt-6">
|
||||
<UForm :state="state"
|
||||
class="flex items-center space-x-2 mb-3 dark:text-white"
|
||||
@submit="handleAction">
|
||||
<!-- 容器div用于水平布局 -->
|
||||
<div class="flex-grow">
|
||||
<UInput
|
||||
v-model="state.domain"
|
||||
placeholder="输入域名"
|
||||
color="sky"
|
||||
size="xl"
|
||||
class="w-full " />
|
||||
</div>
|
||||
<!-- 使用v-if或v-show基于state.domain的值来控制按钮的显示 -->
|
||||
<UButton type="submit" color="sky" size="xl" v-if="state.domain">
|
||||
提交
|
||||
</UButton>
|
||||
</UForm>
|
||||
</div>
|
||||
<!-- 公告部分 -->
|
||||
<div class="bg-gray-200 p-3 rounded-md mb-5 dark:bg-[#5b77af]">
|
||||
<div class="flex items-center">
|
||||
<i aria-hidden="true" class="icon fas fa-bullhorn mr-3"></i>
|
||||
</div>
|
||||
<div class="flex-grow">
|
||||
<div class="text-sm text-gray-800 dark:text-white">
|
||||
➡️ {{ t('index.tips') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ClientOnly>
|
||||
<div class="flex justify-between w-full">
|
||||
<div>
|
||||
<!-- 左边的新元素 -->
|
||||
<UTooltip text="支持列表" :popper="{ placement: 'top' }">
|
||||
<CommonDomainList />
|
||||
</UTooltip>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<!-- 右边的现有元素 -->
|
||||
<UTooltip :text="timeStore.timeZones" :popper="{ placement: 'top' }">
|
||||
<CommonTimeZonesChange />
|
||||
</UTooltip>
|
||||
<UTooltip text="主题模式" :popper="{ placement: 'top' }">
|
||||
<CommonColorChange />
|
||||
</UTooltip>
|
||||
<UTooltip text="切换语言" :popper="{ placement: 'top' }">
|
||||
<CommonLanguageChange />
|
||||
</UTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
42
nuxt.config.ts
Normal file
42
nuxt.config.ts
Normal file
@ -0,0 +1,42 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
devtools: { enabled: true },
|
||||
modules: [
|
||||
'@nuxt/ui',
|
||||
'@nuxtjs/i18n',
|
||||
'nuxt-headlessui',
|
||||
'@pinia/nuxt', // needed
|
||||
'@pinia-plugin-persistedstate/nuxt',
|
||||
],
|
||||
app:{
|
||||
head: {
|
||||
title: 'Nuxt Whois',
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: 'Nuxt Whois' }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
|
||||
]
|
||||
}
|
||||
},
|
||||
i18n: {
|
||||
strategy: 'prefix_except_default',
|
||||
defaultLocale: 'zh',
|
||||
detectBrowserLanguage: {
|
||||
useCookie: true,
|
||||
cookieKey: 'i18n_redirected',
|
||||
redirectOn: 'root' // recommended
|
||||
},
|
||||
locales: [
|
||||
{ code: 'zh', iso: 'zh-Hans', file: 'zh.ts' },
|
||||
{ code: 'en', iso: 'en-US', file: 'en.ts' },
|
||||
{ code: 'tw', iso: 'zh-Hant', file: 'tw.ts' },
|
||||
],
|
||||
langDir: 'lang/',
|
||||
},
|
||||
headlessui: {
|
||||
prefix: 'Headless'
|
||||
},
|
||||
})
|
25
package.json
Normal file
25
package.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "nuxt-app",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/ui": "^2.14.1",
|
||||
"@pinia/nuxt": "^0.5.1",
|
||||
"nuxt": "^3.10.3",
|
||||
"vue": "^3.4.19",
|
||||
"vue-router": "^4.3.0",
|
||||
"xep-whois": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxtjs/i18n": "^8.1.1",
|
||||
"@pinia-plugin-persistedstate/nuxt": "^1.2.0",
|
||||
"nuxt-headlessui": "^1.1.5"
|
||||
}
|
||||
}
|
11
pages/index.vue
Normal file
11
pages/index.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
126
pages/result/[domain].html.vue
Normal file
126
pages/result/[domain].html.vue
Normal file
@ -0,0 +1,126 @@
|
||||
<script setup lang="ts">
|
||||
import {ParseWhois} from "~/utils/whoisToJson";
|
||||
import {AdjustTimeToUTCOffset} from "~/utils/utc";
|
||||
import {useTimeStore} from "~/stores/time";
|
||||
|
||||
const route = useRoute();
|
||||
const {domain} = route.params;
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
const domainData = domain.replace(/_/g, '.')
|
||||
|
||||
const {data, pending, error, refresh} = await useAsyncData(
|
||||
'mountains',
|
||||
() => $fetch('/api/whois', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({domain: domainData})
|
||||
})
|
||||
)
|
||||
|
||||
const parsedInfo = ParseWhois(data.value);
|
||||
const showRawData = ref(false);
|
||||
const timeStore = useTimeStore()
|
||||
|
||||
useHead({
|
||||
title: `${domainData} - ${t('result.title')}`,
|
||||
meta: [
|
||||
{
|
||||
hid: 'description',
|
||||
name: 'description',
|
||||
content: t('result.description', {domain: domainData})
|
||||
}
|
||||
]
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table
|
||||
v-if="parsedInfo.registrar"
|
||||
class="w-full bg-[#fffffe] p-4 shadow-lg rounded-lg mt-5 dark:bg-gray-800 dark:text-gray-200 text-white hover:bg-none">
|
||||
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<tr class="hover:bg-gray-100 text-gray-900 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">
|
||||
{{ t('result.domain') }}
|
||||
</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">
|
||||
<p>
|
||||
<NuxtLink :to="`//${parsedInfo.domainName}`" target="_blank" rel="nofollow"
|
||||
class="text-blue-600 hover:text-blue-800">
|
||||
{{ parsedInfo.domainName }}
|
||||
</NuxtLink>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">{{ t('result.registrar') }}</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">{{ parsedInfo.registrar }}</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-100 text-gray-900 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">{{ t('result.updateDate') }}</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">
|
||||
{{ AdjustTimeToUTCOffset(parsedInfo.updatedDate, timeStore.timeZones) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-100 text-gray-900 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">{{ t('result.createDate') }}</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">
|
||||
{{ AdjustTimeToUTCOffset(parsedInfo.creationDate, timeStore.timeZones) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-100 text-gray-900 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">{{ t('result.expirationDate') }}</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">
|
||||
{{ AdjustTimeToUTCOffset(parsedInfo.registryExpiryDate, timeStore.timeZones) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-100 text-gray-900 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">{{ t('result.ianaId') }}</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">{{ parsedInfo.registrarIANAID }}</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-100 text-gray-900 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">{{ t('result.status') }}</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">{{ parsedInfo.domainStatus?.join(', ') }}</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-100 text-gray-900 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">{{ t('result.dns') }}</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">
|
||||
<p v-for="item in parsedInfo.nameServers">{{ item }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-100 text-gray-900 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">{{ t('result.dnssec') }}</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">{{ parsedInfo.dnssec }}</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-100 text-gray-900 dark:hover:bg-gray-700 text-gray-200">
|
||||
<th class="p-4 text-left font-semibold text-gray-900 dark:text-gray-200">{{ t('result.rawData') }}</th>
|
||||
<td class="p-4 text-gray-900 dark:text-gray-200">
|
||||
<UToggle color="sky" v-model="showRawData"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 公告部分 -->
|
||||
<div v-else class="mt-5 bg-gray-200 p-3 rounded-md mb-5 dark:bg-[#5b77af]">
|
||||
<div class="flex items-center">
|
||||
<i aria-hidden="true" class="icon fas fa-bullhorn mr-3"></i>
|
||||
</div>
|
||||
<div class="flex-grow">
|
||||
<div class="text-sm text-gray-800 dark:text-white">
|
||||
<Icon name="bx:error" size="16px" color="red" />
|
||||
{{ t('error.notFound') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="w-full bg-[#fffffe] mt-5 p-4 shadow-lg rounded-lg whitespace-pre-wrap dark:text-gray-200 dark:bg-gray-800"
|
||||
v-if="showRawData">
|
||||
{{ data }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
7441
pnpm-lock.yaml
generated
Normal file
7441
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
48
server/api/whois.post.ts
Normal file
48
server/api/whois.post.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import {whois, WhoIsOptions} from 'xep-whois';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody(event)
|
||||
try {
|
||||
const res = await whois(body.domain)
|
||||
return res._raw
|
||||
}catch (e) {
|
||||
return `No match for "${body.domain}".
|
||||
` +
|
||||
`>>> Last update of whois database: ${new Date()} <<<
|
||||
` +
|
||||
'\n' +
|
||||
'NOTICE: The expiration date displayed in this record is the date the\n' +
|
||||
'registrar\'s sponsorship of the domain name registration in the registry is\n' +
|
||||
'currently set to expire. This date does not necessarily reflect the expiration\n' +
|
||||
'date of the domain name registrant\'s agreement with the sponsoring\n' +
|
||||
'registrar. Users may consult the sponsoring registrar\'s Whois database to\n' +
|
||||
'view the registrar\'s reported date of expiration for this registration.\n' +
|
||||
'\n' +
|
||||
'TERMS OF USE: You are not authorized to access or query our Whois\n' +
|
||||
'database through the use of electronic processes that are high-volume and\n' +
|
||||
'automated except as reasonably necessary to register domain names or\n' +
|
||||
'modify existing registrations; the Data in VeriSign Global Registry\n' +
|
||||
'Services\' ("VeriSign") Whois database is provided by VeriSign for\n' +
|
||||
'information purposes only, and to assist persons in obtaining information\n' +
|
||||
'about or related to a domain name registration record. VeriSign does not\n' +
|
||||
'guarantee its accuracy. By submitting a Whois query, you agree to abide\n' +
|
||||
'by the following terms of use: You agree that you may use this Data only\n' +
|
||||
'for lawful purposes and that under no circumstances will you use this Data\n' +
|
||||
'to: (1) allow, enable, or otherwise support the transmission of mass\n' +
|
||||
'unsolicited, commercial advertising or solicitations via e-mail, telephone,\n' +
|
||||
'or facsimile; or (2) enable high volume, automated, electronic processes\n' +
|
||||
'that apply to VeriSign (or its computer systems). The compilation,\n' +
|
||||
'repackaging, dissemination or other use of this Data is expressly\n' +
|
||||
'prohibited without the prior written consent of VeriSign. You agree not to\n' +
|
||||
'use electronic processes that are automated and high-volume to access or\n' +
|
||||
'query the Whois database except as reasonably necessary to register\n' +
|
||||
'domain names or modify existing registrations. VeriSign reserves the right\n' +
|
||||
'to restrict your access to the Whois database in its sole discretion to ensure\n' +
|
||||
'operational stability. VeriSign may restrict or terminate your access to the\n' +
|
||||
'Whois database for failure to abide by these terms of use. VeriSign\n' +
|
||||
'reserves the right to modify these terms at any time.\n' +
|
||||
'\n' +
|
||||
'The Registry database contains ONLY .COM, .NET, .EDU domains and\n' +
|
||||
'Registrars.'
|
||||
}
|
||||
})
|
3
server/tsconfig.json
Normal file
3
server/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../.nuxt/tsconfig.server.json"
|
||||
}
|
14
stores/time.ts
Normal file
14
stores/time.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useTimeStore = defineStore('timeZones', {
|
||||
state: () => {
|
||||
return {
|
||||
timeZones: 'UTC+8',
|
||||
}
|
||||
},
|
||||
persist: {
|
||||
storage: persistedState.cookiesWithOptions({
|
||||
sameSite: 'strict',
|
||||
}),
|
||||
},
|
||||
})
|
4
tsconfig.json
Normal file
4
tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
3
utils/domain.ts
Normal file
3
utils/domain.ts
Normal file
@ -0,0 +1,3 @@
|
||||
// br.com,cn.com,de.com,eu.com,gb.com,gb.net,gr.com,hu.com,in.net,no.com,qc.com,ru.com,sa.com,se.com,se.net,uk.com,uk.net,us.com,uy.com,za.com,jpn.com,web.com,com,za.net,net,eu.org,za.org,org,llyw.cymru,gov.scot,gov.wales,edu,gov,int,e164.arpa,arpa,aero,asia,biz,cat,coop,info,jobs,mobi,museum,name,post,pro,tel,travel,xxx,ac,ae,af,ag,ai,am,ar,as,priv.at,at,au,aw,ax,be,bf,bg,bh,bi,bj,bm,bn,bo,br,by,bw,bz,co.ca,ca,cc,cd,ch,ci,cl,cm,edu.cn,cn,uk.co,co,cr,cx,cz,de,dk,dm,do,dz,ec,ee,eu,fi,fj,fm,fo,fr,gd,ge,gf,gg,gh,gi,gl,gp,gq,gs,gy,hk,hm,hn,hr,ht,hu,id,ie,il,im,in,io,iq,ir,is,it,je,jp,ke,kg,ki,kn,kr,kw,ky,kz,la,lb,lc,li,lk,ls,lt,lu,lv,ly,ma,md,me,mg,mk,ml,mm,mn,mq,mr,ms,mt,mu,mw,mx,my,mz,na,nc,nf,ng,nl,no,nu,nz,om,pe,pf,pk,co.pl,pl,pm,pr,ps,pt,pw,qa,re,ro,rs,ac.ru,edu.ru,com.ru,msk.ru,net.ru,nov.ru,org.ru,pp.ru,spb.ru,ru,rw,sa,sb,sc,sd,se,sg,sh,si,sk,sl,sm,sn,so,ss,st,msk.su,nov.su,spb.su,su,sx,sy,tc,td,tf,tg,th,tk,tl,tm,tn,to,tr,tv,tw,tz,biz.ua,co.ua,pp.ua,ua,ug,ac.uk,gov.uk,uk,fed.us,us,uy,uz,vc,ve,vg,vu,wf,ws,yt,ac.za,co.za,gov.za,net.za,org.za,web.za,zm,xn--2scrj9c,xn--3e0b707e,xn--3hcrj9c,xn--45br5cyl,xn--45brj9c,xn--4dbrk0ce,xn--80ao21a,xn--90a3ac,xn--90ae,xn--90ais,xn--clchc0ea0b2g2a9gcd,xn--d1alf,xn--e1a4c,xn--fiqs8s,xn--fiqz9s,xn--fpcrj9c3d,xn--fzc2c9e2c,xn--gecrj9c,xn--h2breg3eve,xn--h2brj9c8c,xn--h2brj9c,xn--j1amh,xn--j6w193g,xn--kprw13d,xn--kpry57d,xn--lgbbat1ad8j,xn--mgb9awbf,xn--mgba3a4f16a,xn--mgbaam7a8h,xn--mgbah1a3hjkrd,xn--mgbbh1a71e,xn--mgbbh1a,xn--mgberp4a5d4ar,xn--mgbgu82a,xn--mgbtx2b,xn--mgbx4cd0ab,xn--node,xn--o3cw4h,xn--ogbpf8fl,xn--p1ai,xn--pgbs0dh,xn--q7ce6a,xn--qxa6a,xn--rvc1e0am3e,xn--s9brj9c,xn--wgbh1c,xn--wgbl6a,xn--xkc2al3hye2a,xn--xkc2dl3a5ee0h,xn--y9a3aq,xn--yfro4i67o,xn--ygbi2ammx
|
||||
|
||||
export const SupportedTLDs = new Set(["br.com", "cn.com", "de.com", "eu.com", "gb.com", "gb.net", "gr.com", "hu.com", "in.net", "no.com", "qc.com", "ru.com", "sa.com", "se.com", "se.net", "uk.com", "uk.net", "us.com", "uy.com", "za.com", "jpn.com", "web.com", "com", "za.net", "net", "eu.org", "za.org", "org", "llyw.cymru", "gov.scot", "gov.wales", "edu", "gov", "int", "e164.arpa", "arpa", "aero", "asia", "biz", "cat", "coop", "info", "jobs", "mobi", "museum", "name", "post", "pro", "tel", "travel", "xxx", "ac", "ae", "af", "ag", "ai", "am", "ar", "as", "priv.at", "at", "au", "aw", "ax", "be", "bf", "bg", "bh", "bi", "bj", "bm", "bn", "bo", "br", "by", "bw", "bz", "co.ca", "ca", "cc", "cd", "ch", "ci", "cl", "cm", "edu.cn", "cn", "uk.co", "co", "cr", "cx", "cz", "de", "dk", "dm", "do", "dz", "ec", "ee", "eu", "fi", "fj", "fm", "fo", "fr", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gp", "gq", "gs", "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir", "is", "it", "je", "jp", "ke", "kg", "ki", "kn", "kr", "kw", "ky", "kz", "la", "lb", "lc", "li", "lk", "ls", "lt", "lu", "lv", "ly", "ma", "md", "me", "mg", "mk", "ml", "mm", "mn", "mq", "mr", "ms", "mt", "mu", "mw", "mx", "my", "mz", "na", "nc", "nf", "ng", "nl", "no", "nu", "nz", "om", "pe", "pf", "pk", "co.pl", "pl", "pm", "pr", "ps", "pt", "pw", "qa", "re", "ro", "rs", "ac.ru", "edu.ru", "com.ru", "msk.ru", "net.ru", "nov.ru", "org.ru", "pp.ru", "spb.ru", "ru", "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", "si", "sk", "sl", "sm", "sn", "so", "ss", "st", "msk.su", "nov.su", "spb.su", "su", "sx", "sy", "tc", "td", "tf", "tg", "th", "tk", "tl", "tm", "tn", "to", "tr", "tv", "tw", "tz", "biz.ua", "co.ua", "pp.ua", "ua", "ug", "ac.uk", "gov.uk", "uk", "fed.us", "us", "uy", "uz", "vc", "ve", "vg", "vu", "wf", "ws", "yt", "ac.za", "co.za", "gov.za", "net.za", "org.za", "web.za", "zm", "xn--2scrj9c", "xn--3e0b707e", "xn--3hcrj9c", "xn--45br5cyl", "xn--45brj9c", "xn--4dbrk0ce", "xn--80ao21a", "xn--90a3ac", "xn--90ae", "xn--90ais", "xn--clchc0ea0b2g2a9gcd", "xn--d1alf", "xn--e1a4c", "xn--fiqs8s", "xn--fiqz9s", "xn--fpcrj9c3d", "xn--fzc2c9e2c", "xn--gecrj9c", "xn--h2breg3eve", "xn--h2brj9c8c", "xn--h2brj9c", "xn--j1amh", "xn--j6w193g", "xn--kprw13d", "xn--kpry57d", "xn--lgbbat1ad8j", "xn--mgb9awbf", "xn--mgba3a4f16a", "xn--mgbaam7a8h", "xn--mgbah1a3hjkrd", "xn--mgbbh1a71e", "xn--mgbbh1a", "xn--mgberp4a5d4ar", "xn--mgbgu82a", "xn--mgbtx2b", "xn--mgbx4cd0ab", "xn--node", "xn--o3cw4h", "xn--ogbpf8fl", "xn--p1ai", "xn--pgbs0dh", "xn--q7ce6a", "xn--qxa6a", "xn--rvc1e0am3e", "xn--s9brj9c", "xn--wgbh1c", "xn--wgbl6a", "xn--xkc2al3hye2a", "xn--xkc2dl3a5ee0h", "xn--y9a3aq", "xn--yfro4i67o", "xn--ygbi2ammx"]);
|
28
utils/utc.ts
Normal file
28
utils/utc.ts
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
// 定义一个函数来将单个UTC+8时间字符串转换为指定UTC偏移量的时间
|
||||
export function AdjustTimeToUTCOffset(timestamp: string, utcOffset: string): string {
|
||||
// 将时间字符串转换为Date对象
|
||||
const date = new Date(timestamp);
|
||||
|
||||
let offsetInMillis = 0; // 默认偏移量为0毫秒
|
||||
|
||||
if (utcOffset !== "UTC") {
|
||||
// 解析UTC偏移量(例如:"UTC+8")
|
||||
const offsetPattern = /UTC([+-])(\d+):?(\d+)?/;
|
||||
const match = offsetPattern.exec(utcOffset);
|
||||
if (!match) {
|
||||
throw new Error('Invalid UTC offset format');
|
||||
}
|
||||
|
||||
const sign = match[1] === '+' ? 1 : -1; // 确定是加时区还是减时区
|
||||
const hours = parseInt(match[2], 10); // 小时
|
||||
const minutes = match[3] ? parseInt(match[3], 10) : 0; // 分钟,如果没有定义,则为0
|
||||
offsetInMillis = sign * ((hours * 60 + minutes) * 60000); // 将偏移量转换为毫秒
|
||||
}
|
||||
|
||||
// 计算并返回调整后的时间
|
||||
const targetTime = new Date(date.getTime() + offsetInMillis);
|
||||
|
||||
// 返回调整后的时间的ISO字符串
|
||||
return targetTime.toISOString();
|
||||
}
|
65
utils/whoisToJson.ts
Normal file
65
utils/whoisToJson.ts
Normal file
@ -0,0 +1,65 @@
|
||||
interface WhoisInformation {
|
||||
domainName?: string;
|
||||
registryDomainID?: string;
|
||||
registrarWHOISServer?: string;
|
||||
registrarURL?: string;
|
||||
updatedDate?: string;
|
||||
creationDate?: string;
|
||||
registryExpiryDate?: string;
|
||||
registrar?: string;
|
||||
registrarIANAID?: string;
|
||||
domainStatus?: string[];
|
||||
nameServers?: string[];
|
||||
dnssec?: string;
|
||||
icannWhoisInaccuracyComplaintFormURL?: string;
|
||||
}
|
||||
export function ParseWhois(whoisText: string): WhoisInformation {
|
||||
const lines = whoisText.split('\n'); // 将文本分割成行
|
||||
const info: WhoisInformation = {}; // 创建一个空对象来存储提取的信息
|
||||
|
||||
lines.forEach(line => {
|
||||
const [key, value] = line.split(': ').map(part => part.trim());
|
||||
switch (key) {
|
||||
case 'Domain Name':
|
||||
info.domainName = value;
|
||||
break;
|
||||
case 'Registry Domain ID':
|
||||
info.registryDomainID = value;
|
||||
break;
|
||||
case 'Registrar WHOIS Server':
|
||||
info.registrarWHOISServer = value;
|
||||
break;
|
||||
case 'Registrar URL':
|
||||
info.registrarURL = value;
|
||||
break;
|
||||
case 'Updated Date':
|
||||
info.updatedDate = value;
|
||||
break;
|
||||
case 'Creation Date':
|
||||
info.creationDate = value;
|
||||
break;
|
||||
case 'Registry Expiry Date':
|
||||
info.registryExpiryDate = value;
|
||||
break;
|
||||
case 'Registrar':
|
||||
info.registrar = value;
|
||||
break;
|
||||
case 'Registrar IANA ID':
|
||||
info.registrarIANAID = value;
|
||||
break;
|
||||
case 'Domain Status':
|
||||
info.domainStatus = info.domainStatus ? [...info.domainStatus, value] : [value];
|
||||
break;
|
||||
case 'Name Server':
|
||||
info.nameServers = info.nameServers ? [...info.nameServers, value] : [value];
|
||||
break;
|
||||
case 'DNSSEC':
|
||||
info.dnssec = value;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
info.icannWhoisInaccuracyComplaintFormURL = "https://www.icann.org/wicf/";
|
||||
|
||||
return info;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user