Files

225 lines
7.7 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useEffect, useState } from "react"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { RefreshCw, Shield, AlertTriangle, CheckCircle, Lock } from "lucide-react"
interface IpInfo {
ip: string
isAllowed: boolean
enableIpWhitelist: boolean
allowedIps: string[]
timestamp: string
}
export default function IpBlockingTestPage() {
const [ipInfo, setIpInfo] = useState<IpInfo | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const fetchIpInfo = async () => {
setLoading(true)
setError(null)
try {
const response = await fetch('/api/ip')
if (!response.ok) {
throw new Error('無法獲取IP信息')
}
const data = await response.json()
setIpInfo(data)
} catch (error) {
console.error("無法獲取IP信息:", error)
setError("無法獲取IP信息")
} finally {
setLoading(false)
}
}
useEffect(() => {
fetchIpInfo()
}, [])
if (loading) {
return (
<div className="container mx-auto p-6">
<div className="flex items-center justify-center min-h-[400px]">
<div className="flex items-center gap-2">
<RefreshCw className="w-4 h-4 animate-spin" />
<span>...</span>
</div>
</div>
</div>
)
}
if (error || !ipInfo) {
return (
<div className="container mx-auto p-6">
<Card className="border-red-200 bg-red-50">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-red-600">
<AlertTriangle className="w-5 h-5" />
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-red-600">{error}</p>
<Button onClick={fetchIpInfo} className="mt-4">
<RefreshCw className="w-4 h-4 mr-2" />
</Button>
</CardContent>
</Card>
</div>
)
}
return (
<div className="container mx-auto p-6 space-y-6">
<div className="flex items-center justify-between">
<h1 className="text-3xl font-bold">IP </h1>
<Button onClick={fetchIpInfo} variant="outline">
<RefreshCw className="w-4 h-4 mr-2" />
</Button>
</div>
{/* IP狀態卡片 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
{ipInfo.enableIpWhitelist && !ipInfo.isAllowed ? (
<>
<Lock className="w-5 h-5 text-red-500" />
IP
</>
) : (
<>
<CheckCircle className="w-5 h-5 text-green-500" />
IP
</>
)}
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="text-sm font-medium text-gray-500">IP</label>
<p className="text-lg font-mono bg-gray-100 p-2 rounded">
{ipInfo.ip}
</p>
</div>
<div>
<label className="text-sm font-medium text-gray-500"></label>
<div className="mt-1">
<Badge variant={ipInfo.isAllowed ? "default" : "destructive"}>
{ipInfo.isAllowed ? "允許" : "阻擋"}
</Badge>
</div>
</div>
</div>
<div>
<label className="text-sm font-medium text-gray-500"></label>
<div className="flex items-center gap-2 mt-1">
<Shield className="w-4 h-4 text-blue-500" />
<span className="text-sm">
{ipInfo.enableIpWhitelist ? "已啟用" : "未啟用"}
</span>
</div>
</div>
</CardContent>
</Card>
{/* 允許的IP列表 */}
{ipInfo.enableIpWhitelist && ipInfo.allowedIps.length > 0 && (
<Card>
<CardHeader>
<CardTitle>IP列表</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2">
{ipInfo.allowedIps.map((ip, index) => (
<div key={index} className="flex items-center gap-2">
<Badge variant={ip === ipInfo.ip ? "default" : "outline"}>
{ip === ipInfo.ip ? "當前" : ""}
</Badge>
<span className="text-sm font-mono">{ip}</span>
</div>
))}
</div>
</CardContent>
</Card>
)}
{/* 阻擋測試說明 */}
<Card>
<CardHeader>
<CardTitle>IP </CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="p-4 bg-blue-50 border border-blue-200 rounded-lg">
<h3 className="font-medium text-blue-900 mb-2"> </h3>
<p className="text-sm text-blue-800">
IP ({ipInfo.ip})
</p>
</div>
<div className="p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
<h3 className="font-medium text-yellow-900 mb-2"> </h3>
<p className="text-sm text-yellow-800">
IP阻擋功能
</p>
<ul className="text-sm text-yellow-800 mt-2 ml-4 list-disc">
<li> .env.local ALLOWED_IPS IP</li>
<li></li>
<li>403</li>
<li>IP加回白名單</li>
</ul>
</div>
<div className="p-4 bg-red-50 border border-red-200 rounded-lg">
<h3 className="font-medium text-red-900 mb-2">🚫 </h3>
<p className="text-sm text-red-800">
IP不在白名單中
</p>
<ul className="text-sm text-red-800 mt-2 ml-4 list-disc">
<li>403 Forbidden </li>
<li>IP地址</li>
<li></li>
<li>IP檢測API可以訪問</li>
</ul>
</div>
</CardContent>
</Card>
{/* 當前配置 */}
<Card>
<CardHeader>
<CardTitle></CardTitle>
</CardHeader>
<CardContent className="space-y-2">
<div className="flex justify-between">
<span className="text-sm font-medium text-gray-500">:</span>
<Badge variant={ipInfo.enableIpWhitelist ? "default" : "secondary"}>
{ipInfo.enableIpWhitelist ? "已啟用" : "未啟用"}
</Badge>
</div>
<div className="flex justify-between">
<span className="text-sm font-medium text-gray-500">IP:</span>
<span className="text-sm font-mono">{ipInfo.ip}</span>
</div>
<div className="flex justify-between">
<span className="text-sm font-medium text-gray-500">:</span>
<Badge variant={ipInfo.isAllowed ? "default" : "destructive"}>
{ipInfo.isAllowed ? "允許" : "阻擋"}
</Badge>
</div>
</CardContent>
</Card>
</div>
)
}