Teycir/SeekYou
GitHub: Teycir/SeekYou
SeekYou 是一个用于 IP、域名和 ASN 的开源情报聚合工具,通过整合多个数据源提供快速统一的情报查询。
Stars: 17 | Forks: 1
# SeekYou
**实时地址:** https://seekyou.seekyou.workers.dev
```
$ curl "https://seekyou.seekyou.workers.dev/api/lookup?q=1.1.1.1"
{
"query": { "raw": "1.1.1.1", "type": "ip", "normalised": "1.1.1.1" },
"core": {
"internetdb": { "status": "ok", "data": { "ports": [80,443], "vulns": [] } },
"geo": { "status": "cached", "data": { "country": "US", "org": "AS13335 Cloudflare" } },
"bgp": { "status": "ok", "data": { "name": "CLOUDFLARENET", "rir": "ARIN" } },
...
},
"meta": { "durationMs": 312, "cacheHits": 4, "sourcesQueried": 15, "sourcesFailed": 0 }
}
```
## 目录
- [SeekYou](#seekyou)
- [目录](#table-of-contents)
- [SeekYou 的功能](#what-seekyou-does)
- [用例](#use-cases)
- [合法使用政策](#lawful-use-policy)
- [相关工具](#related-tools)
- [架构概览](#architecture-overview)
- [执行模型](#execution-model)
- [数据源](#data-sources)
- [项目结构](#project-structure)
- [关键设计决策](#key-design-decisions)
- [边缘优先,无 Node.js](#edge-first-no-nodejs)
- [分层并行执行](#layered-parallel-execution)
- [优雅降级](#graceful-degradation)
- [激进 KV 缓存](#aggressive-kv-caching)
- [免费层级优化](#free-tier-optimization)
- [Fire-and-forget D1 写入](#fire-and-forget-d1-writes)
- [缓存策略](#caching-strategy)
- [速率限制](#rate-limiting)
- [熔断器](#circuit-breakers)
- [密钥轮换 — GrayHatWarfare](#key-rotation--grayhatwarfare)
- [D1 持久化](#d1-persistence)
- [Schema (`schema.sql`)](#schema-schemasql)
- [应用 Schema](#apply-schema)
- [辅助函数](#helper-functions)
- [Cron Worker](#cron-worker)
- [开发环境设置](#development-setup)
- [前置条件](#prerequisites)
- [本地开发](#local-development)
- [创建 Cloudflare 资源(首次)](#create-cloudflare-resources-first-time)
- [部署](#deployment)
- [构建与部署](#build-and-deploy)
- [Wrangler 配置 (`wrangler.toml`)](#wrangler-configuration-wranglertoml)
- [密钥与环境变量](#secrets-and-environment-variables)
- [必需的密钥](#required-secrets)
- [`.env.example`(仅限本地开发)](#envexample-local-dev-only)
- [运行测试](#running-tests)
- [Cloudflare 免费层级限制](#cloudflare-free-tier-limits)
- [路线图](#roadmap)
- [许可证](#license)
- [作者](#author)
- [致谢](#acknowledgments)
## SeekYou 的功能
SeekYou 是一个**主机情报工具** —— 输入一个 IP 地址、域名或 ASN,即可获得一份涵盖以下内容的统一报告:
| 类别 | 获得的信息 |
|---|---|
| 网络 | 开放端口、CPE、BGP 前缀、上游、对等网络、RIR |
| 身份 | RDAP 注册信息、联系人、注册商、域名服务器 |
| 地理位置 | 国家、城市、ISP、代理/托管/移动标识 |
| 证书 | crt.sh 历史记录、SANs、颁发者链 |
| DNS | 被动 DNS 记录、Robtex 反向/正向 DNS |
| 威胁 | URLhaus、ThreatFox、MalwareBazaar、Feodo、SSLBL |
| CVE | 针对 InternetDB 报告的每个 CVE ID 进行 NVD + CIRCL 富化 |
| 侦察 | GrayHatWarfare 暴露的存储桶、Wayback CDX 快照 |
所有数据源均并行查询。失败的数据源会降级为一个"不可用"标识——它绝不会导致页面中断。
## 用例
**安全运营** —— 快速分析日志中的可疑 IP,关联 IOC,识别暴露的服务和 CVE,追踪恶意域名。
**网络运营** —— 检查 BGP 路由、RDAP/WHOIS 分配数据、历史 DNS 记录、SSL 证书变更。
**渗透测试** —— 枚举端口/服务/CPE,发现暴露的存储桶、归档页面、子域和 ASN 关系。
**威胁情报** —— 在一次查询中对照五个威胁情报源检查 C2 基础设施。
**合规与风险** —— 评估供应商基础设施,检测暴露的云存储,识别影子 IT。
## 合法使用政策
SeekYou 旨在用于**合法的安全研究、网络运营和威胁情报**。使用本工具即表示您同意:
**允许的用途:**
- 对您拥有或有权监控的网络进行安全运营和事件响应
- 威胁情报研究和 IOC 关联
- 在组织内进行网络故障排查和基础设施审计
- 获得目标组织的明确书面授权后进行渗透测试
- 网络安全的学术研究与教育
- 在获得适当授权的情况下进行合规审计和供应商风险评估
**禁止的用途:**
- 未经授权访问、侦察或攻击您不拥有或没有明确测试许可的系统
- 骚扰、跟踪或侵犯个人或组织的隐私
- 协助包括欺诈、身份盗窃或网络犯罪在内的非法活动
- 未经授权绕过安全控制或访问限制
- 违反适用法律,包括《计算机欺诈与滥用法》(美国)、《计算机滥用法》(英国)、《通用数据保护条例》(欧盟) 或您所在司法管辖区的同等法规
**您的责任:**
- 确保在查询非您拥有的基础设施之前获得适当授权
- 尊重速率限制,不滥用服务或上游数据源
- 遵守您所在司法管辖区的所有适用法律和法规
- 负责任地使用数据,未经协调披露,不得将发现武器化
- 理解查询主机并不授予访问或利用它的权限
**免责声明:**
作者和贡献者对误用本工具不承担任何责任。用户全权负责确保其活动符合适用法律。从公共来源汇总的数据可能不完整、过时或不准确——在采取行动前,请务必通过权威渠道验证发现结果。
如果您通过 SeekYou 发现了漏洞,请遵循负责任的披露准则,并在公开披露前通知受影响方。
## 相关工具
SeekYou 是注重隐私的安全工具套件的一部分。探索完整套件:
| 工具 | 描述 | 在线地址 |
|---|---|---|
| **TimeSeal** | 加密时间戳服务 —— 在不泄露内容的情况下证明文档在特定时间的存在 | [timeseal.online](https://timeseal.online) |
| **SanctumVault** | 零知识加密保险库 —— 用于敏感数据存储的客户端加密 | [sanctumvault.online](https://sanctumvault.online) |
| **GhostChat** | 临时加密消息 —— 无服务器日志的自毁对话 | [ghost-chat.pages.dev](https://ghost-chat.pages.dev) |
| **XMRProof** | Monero 付款验证 —— 生成 XMR 交易的加密证明 | [xmrproof.pages.dev](https://xmrproof.pages.dev) |
| **GhostReceipt** | 匿名收据生成 —— 创建可验证的交易记录,无需暴露身份 | [ghostreceipt.pages.dev](https://ghostreceipt.pages.dev) |
| **SeekYou** | 主机情报聚合器 —— 跨 15 个数据源为 IP、域名和 ASN 提供统一 OSINT | [seekyou.seekyou.workers.dev](https://seekyou.seekyou.workers.dev) |
| **HoneypotScan** | 蜜罐检测服务 —— 识别诱饵系统,避免安全研究中的误报 | [honeypotscan.pages.dev](https://honeypotscan.pages.dev) |
所有工具均运行在 Cloudflare 的边缘网络上,遵循隐私优先的设计原则。
## 架构概览
```
Browser / curl
│
▼
┌─────────────────────────────────────┐
│ Cloudflare Pages │
│ Next.js App Router (SSR) │
│ │
│ app/page.tsx search form │
│ app/host/[query]/page.tsx │
│ └─ streams /api/stream?q=… │
│ app/api/recent/route.ts │
│ └─ recent searches for homepage │
│ app/targets/page.tsx │
│ └─ monitoring dashboard │
│ app/api/targets/route.ts │
│ └─ saved targets CRUD │
│ returns riskScore + lastDiff │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ app/api/lookup/route.ts │
│ (Workers runtime via opennextjs) │
│ • input validation │
│ • per-IP rate limiting (KV) │
│ • ctx.waitUntil(recordSearch()) │
└──────────────┬──────────────────────┘
│ runLookup()
▼
┌─────────────────────────────────────┐
│ worker/lookup.ts — orchestrator │
│ 4-layer Promise.allSettled │
└──┬──────────────────────────────────┘
│
├─► Layer 1+2 (parallel, 12 sources):
│ InternetDB · IPinfo · BGPView · RDAP · crt.sh · PassiveDNS · Robtex
│ URLhaus · ThreatFox · MalwareBazaar · Feodo · SSLBL
├─► Layer 3 (after L1): NVD CVE enrichment (only if vulns found, batched 10-at-a-time)
└─► Layer 4 (parallel): GrayHatWarfare · Wayback (domain queries only)
│
▼
┌──────────────┐ ┌──────────────────┐
│ KV │ │ D1 │
│ response │ │ searches │
│ cache (TTL │ │ saved_targets │
│ per source) │ │ │
└──────────────┘ └──────────────────┘
│
▼
┌─────────────────────────────────────┐
│ seekyou-cron (Worker) │
│ wrangler.cron.toml │
│ • hourly blocklist refresh │
│ • hourly saved-target re-query │
│ + typed diff (lib/diff.ts) │
│ + webhook on hasChanges │
└─────────────────────────────────────┘
```
## 执行模型
第 1 层和第 2 层同时触发(12 个源在单个 `Promise.allSettled` 中)。第 3 层在第 1 层完成后启动 —— InternetDB 发现的 CVE ID 驱动 NVD 富化,每批 10 个以避免 API 被冲击。第 4 层与第 3 层并行触发,但仅适用于域名查询;IP/ASN 查询完全跳过此层。总挂钟时间 ≈ 最大(第 1 层+第 2 层) + 最大(第 3 层+第 4 层)。
使用 `?refresh=1` 可强制刷新任何查询,绕过 KV 缓存并实时从所有上游拉取数据。
## 数据源
| 层级 | 数据源 | 提供的信息 | 需要认证 |
|---|---|---|---|
| 1 | InternetDB | 开放端口、CPE、CVE ID | 否 |
| 1 | IPinfo / ip-api | 地理位置、ISP、ASN、托管/代理/移动标识 | 否 |
| 1 | BGPView | BGP 前缀、上游、对等网络、RIR | 否 |
| 1 | RDAP | 注册信息、联系人、域名服务器、CIDR | 否 |
| 2 | crt.sh | 证书历史、SANs、颁发者链 | 否 |
| 2 | PassiveDNS | 历史 DNS 记录 | 否 |
| 2 | Robtex | 反向/正向 DNS、AS 信息 | 否 |
| 2 | URLhaus | 恶意软件分发 URL | `ABUSECH_KEY` |
| 2 | ThreatFox | IOC 数据库 | `ABUSECH_KEY` |
| 2 | MalwareBazaar | 恶意软件样本元数据 | `ABUSECH_KEY` |
| 2 | Feodo Tracker | 僵尸网络 C2 IP | 否(批量下载) |
| 2 | SSLBL | 恶意 SSL 证书 | 否(批量下载) |
| 3 | NVD + CIRCL | CVE 详情、CVSS v2/v3 评分 | `NVD_KEY`(可选) |
| 4 | GrayHatWarfare | 暴露的 S3/Azure/GCS 存储桶 | `GRAYHATWARFARE_API_KEY_1..18` |
| 4 | Wayback | 历史 CDX 快照 | 否 |
**Feodo 和 SSLBL** 作为批量阻止列表获取,并由 Cron Worker 每小时刷新 —— 无需每次查询都调用上游。
## 项目结构
```
SeekYou/
├── app/
│ ├── page.tsx # Homepage — search form + recent searches
│ ├── layout.tsx # Root layout
│ ├── globals.css
│ ├── about/ # About page
│ ├── faq/ # FAQ page
│ ├── targets/
│ │ └── page.tsx # /targets — monitoring dashboard (risk + diffs)
│ ├── host/[query]/
│ │ └── page.tsx # SSR host report page (streams via /api/stream)
│ ├── api/
│ │ ├── lookup/route.ts # GET /api/lookup?q=&refresh=1
│ │ ├── stream/route.ts # GET /api/stream?q= (SSE streaming)
│ │ ├── recent/route.ts # GET /api/recent?limit=5
│ │ ├── batch/route.ts # POST /api/batch (multi-query)
│ │ ├── targets/route.ts # GET /api/targets (+ riskScore, lastDiff) · POST
│ │ ├── targets/[id]/route.ts # DELETE /api/targets/:id
│ │ └── admin/reset-breaker/ # POST — manual circuit-breaker reset
│ └── components/
│ ├── AnimatedTagline.tsx
│ ├── Card.tsx
│ ├── CopyButton.tsx
│ ├── CveDrawer.tsx
│ ├── DecryptedText.tsx
│ ├── ExportButton.tsx # JSON export (client, zero backend)
│ ├── Footer.tsx
│ ├── RecentSearches.tsx # Recent queries from D1 (client)
│ ├── RiskBadge.tsx # Risk score pill with breakdown tooltip
│ ├── SaveButton.tsx # Save/unsave target
│ ├── ScrollProgress.tsx
│ ├── ShareButton.tsx
│ ├── VulnsStream.tsx # Streaming CVE results
│ └── ui/ # Shared UI primitives
├── worker/
│ ├── lookup.ts # 4-layer orchestrator
│ ├── cron.ts # Hourly blocklist refresh + target sweep w/ typed diff
│ ├── index.ts
│ └── sources/
│ ├── internetdb.ts
│ ├── ipapi.ts
│ ├── bgpview.ts
│ ├── rdap.ts
│ ├── crtsh.ts
│ ├── passivedns.ts
│ ├── robtex.ts
│ ├── abusech.ts # URLhaus + ThreatFox + MalwareBazaar
│ ├── nvd.ts # NVD + CIRCL CVE enrichment
│ ├── osv.ts # OSV.dev re-export (via nvd.ts)
│ ├── grayhatwarfare.ts
│ └── wayback.ts
├── lib/
│ ├── types.ts # All TypeScript interfaces
│ ├── cache.ts # KV cache wrapper (bypass on forceRefresh)
│ ├── config.ts # All magic numbers: TTLs, timeouts, limits
│ ├── diff.ts # TargetDiff — typed change detection between snapshots
│ ├── errors.ts # Unified error format + ErrorCode enum
│ ├── hooks.ts # Shared React hooks
│ ├── keyring.ts # GHW 18-key rotation
│ ├── logger.ts # Structured logging
│ ├── merge.ts # Result merging
│ ├── normalize.ts # Threat indicator normalization
│ ├── ratelimit.ts # KV-based per-IP rate limiter + circuit breakers
│ ├── results.ts # SourceResult helpers
│ ├── risk.ts # computeRiskScore — scored 0–100 with breakdown
│ ├── searches.ts # D1 helpers: recordSearch, getRecentSearches
│ ├── targets.ts # D1 helpers: saveTarget, listTargets, removeTarget
│ ├── textAnimation.ts # Text animation utility
│ ├── useHostStream.ts # SSE streaming hook for host results
│ ├── validate.ts # Query parsing (IPv4/v6/domain/ASN)
│ └── utils.ts
├── test/
│ ├── cache.test.ts
│ ├── diff.test.ts # Tests for diffHostResults + summariseDiff
│ ├── keyring.test.ts
│ ├── logger.test.ts
│ ├── merge.test.ts
│ ├── normalize.test.ts
│ ├── results.test.ts
│ ├── risk.test.ts
│ ├── validate.test.ts
│ └── sources/
├── docs/
│ ├── ROADMAP.md
│ ├── Spec.md
│ └── LICENSE.md
├── public/
│ └── publiceth.svg # Donation QR code
├── schema.sql # D1 schema (apply with wrangler d1 execute)
├── wrangler.toml # Pages build config (KV + D1 bindings)
├── wrangler.cron.toml # Cron worker config (separate deploy)
├── next.config.ts
├── open-next.config.ts
└── vitest.config.ts
```
## 关键设计决策
### 边缘优先,无 Node.js
通过 `@opennextjs/cloudflare` 使用 Workers 运行时 —— 无需 `runtime = 'edge'` 导出。全程使用纯 Web API。全球冷启动时间低于 50 毫秒。
### 分层并行执行
第 1 层+第 2 层同时触发(12 个源)。第 3 层(CVE 富化)仅在 InternetDB 发现漏洞时运行,每批 10 个。第 4 层(GHW + Wayback)与第 3 层并行运行,但针对 IP/ASN 查询会完全跳过。总时间 ≈ 每波中最慢的源,而非所有源之和。
### 优雅降级
每个数据源都包装在熔断器 + try/catch 中。失败的数据源会变成一个 `{ status: 'error' }` 标识。页面始终可以渲染。
### 激进 KV 缓存
每个数据源有自己的 TTL(CVE 为 30 天,BGP/RDAP 为 24 小时,核心地理位置/端口为 1 小时,abuse.ch 为 30 分钟)。缓存命中完全绕过外部调用。`?refresh=1` 通过每个获取器线程传递 `forceRefresh: true` 以按需绕过缓存。
### 免费层级优化
GrayHatWarfare 有 18 个密钥轮换(每天 1,800 次请求)。NVD 使用请求批处理(最多 10 个并发)。Feodo/SSLBL 由 Cron Worker 作为批量列表获取并缓存在 KV 中 —— 每次查询的上游成本为零。
### Fire-and-forget D1 写入
`recordSearch()` 在 `ctx.waitUntil()` 内部调用 —— 它不会给 API 响应增加任何延迟。D1 写入在响应刷新后发生。
## 缓存策略
```
// lib/cache.ts
export async function cacheGet(
kv: KVNamespace,
key: string,
bypass?: boolean, // true when ?refresh=1
): Promise
export async function cacheSet(
kv: KVNamespace,
key: string,
value: T,
ttlSeconds?: number,
): Promise
```
缓存键遵循 `source:normalized_query` 模式 —— 例如 `internetdb:1.1.1.1`、`crtsh:example.com`。
各数据源的 TTL(来自 `lib/config.ts`):
| 数据源 | TTL |
|---|---|
| CVE (NVD/CIRCL) | 30 天 |
| Wayback | 7 天 |
| BGP, RDAP, Robtex | 24 小时 |
| crt.sh, PassiveDNS | 12 小时 |
| GrayHatWarfare | 6 小时 |
| InternetDB, IPinfo | 1 小时 |
| Feodo, SSLBL (批量) | 1 小时 |
| URLhaus, ThreatFox, MalwareBazaar | 30 分钟 |
错误从不被缓存 —— 失败的获取在下一次请求时总会重试。
## 速率限制
基于 KV 的滑动窗口:**每个 IP 每小时 100 次请求**。在 `lib/ratelimit.ts` 中实现,在 `app/api/lookup/route.ts` 中的任何查询运行之前强制执行。
每个响应都返回速率限制头:
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1716912000
```
达到限制时,API 返回 `429` 和 `Retry-After`。
## 熔断器
每个数据源在 KV 中跟踪一个熔断器。如果某个数据源在 5 分钟窗口内(最少 4 次请求)的**失败率超过 50%**,熔断器将打开,该数据源将被跳过(返回 `{ status: 'skipped' }`)**15 分钟**,然后自动恢复。
每个 API 响应的 `meta.circuitBreakers` 中都包含每个熔断器的当前状态。
要在生产环境中手动重置熔断器:
```
curl -X POST https://seekyou.seekyou.workers.dev/api/admin/reset-breaker \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"source": "nvd"}'
```
## 密钥轮换 — GrayHatWarfare
GrayHatWarfare 每个 API 密钥允许每天 100 次请求。SeekYou 在多达 18 个密钥间轮换,实现每天有效 1,800 次请求:
```
// lib/keyring.ts — round-robin across keys with remaining quota
const key = await keyRing.next(env, 'GRAYHATWARFARE_API_KEY')
```
密钥命名为 `GRAYHATWARFARE_API_KEY_1` 到 `GRAYHATWARFARE_API_KEY_18`,并作为 Wrangler 密钥存储。
## D1 持久化
### 数据库架构(`schema.sql`)
```
CREATE TABLE IF NOT EXISTS searches (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
query TEXT NOT NULL,
query_type TEXT NOT NULL CHECK (query_type IN ('ip','domain','asn')),
result_json TEXT NOT NULL,
duration_ms INTEGER,
created_at INTEGER NOT NULL DEFAULT (unixepoch())
);
CREATE INDEX IF NOT EXISTS idx_searches_query
ON searches (query, created_at DESC);
CREATE TABLE IF NOT EXISTS saved_targets (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
query TEXT NOT NULL UNIQUE,
label TEXT,
notes TEXT,
result_json TEXT, -- snapshot of last cron lookup
checked_at INTEGER, -- unix seconds — when cron last re-queried
created_at INTEGER NOT NULL DEFAULT (unixepoch())
);
CREATE INDEX IF NOT EXISTS idx_saved_targets_created
ON saved_targets (created_at DESC);
```
### 应用 Schema
```
wrangler d1 execute seekyou --file=schema.sql
```
### 辅助函数
**`lib/searches.ts`** —— 搜索历史:
```
// Write a search row (fire-and-forget safe)
await recordSearch(db, query, queryType, resultJson, durationMs)
// Read last N distinct queries for the homepage (default 5)
const recent = await getRecentSearches(db, 5)
// → [{ query: '1.1.1.1', query_type: 'ip', created_at: 1716912000 }, ...]
```
**`lib/targets.ts`** —— 保存的目标:
```
// Upsert a target (idempotent on query)
const id = await saveTarget(db, query, label, notes)
// List all saved targets
const targets = await listTargets(db)
// Remove by id
await removeTarget(db, id)
// Fetch one (used by cron before re-querying)
const target = await getTarget(db, id)
// Write latest snapshot after cron re-query
await updateTargetSnapshot(db, id, resultJson)
```
## Cron Worker
一个独立的 Worker (`worker/cron.ts`) 通过 `wrangler.cron.toml` 单独部署。它在**每小时触发器**上运行,并执行两项任务:
1. **阻止列表刷新** —— 检查 Feodo/SSLBL 批量列表是否过时,如果需要则重新下载。
2. **保存目标扫描** —— 重新查询每个保存的目标,计算类型化的 `TargetDiff`,将新的快照持久化到 D1,并在检测到变更时发送 webhook 有效载荷。
### 类型化差异 (`lib/diff.ts`)
每次重新查询后,`diffHostResults(prev, next)` 产生一个结构化的 `TargetDiff`,涵盖:
| 信号 | 检测内容 |
|---|---|
| `ports` | 已打开/关闭的端口(每个端口的方向) |
| `cves` | 出现/解决的 CVE,包含 CVSS 严重性和评分 |
| `threats` | URLhaus、Feodo、SSLBL、ThreatFox 源变更 |
| `geo` | 国家、ASN 或主主机名变更 |
| `certExpiry` | 证书将在 30 天内过期或刚过期(每个证书触发一次) |
| `risk` | 风险评分变化 —— 仅当 Δ ≥ 5 分时在 `hasChanges` 中显示 |
`summariseDiff(diff, query)` 将结构转换为人类可读的字符串,用于日志和 webhook 中继。
### Webhook 有效载荷
当 `diff.hasChanges` 为真且设置了 `WEBHOOK_URL` 时,Cron Worker 会发送 POST:
```
{
"sentAt": 1716912000,
"events": [
{
"targetId": "abc123",
"query": "1.2.3.4",
"checkedAt": 1716912000,
"summary": "1.2.3.4:\n port 3389 opened\n CVE-2021-44228 appeared [CRITICAL 10]",
"diff": {
"diffedAt": 1716912000,
"hasChanges": true,
"ports": [{ "port": 3389, "direction": "opened" }],
"cves": [{ "id": "CVE-2021-44228", "direction": "appeared", "severity": "CRITICAL", "score": 10 }],
"threats": [],
"geo": [],
"certExpiry": [],
"risk": { "prev": 20, "next": 55, "delta": 35 }
}
}
]
}
```
`diff` 字段完全结构化 —— 消费者可以根据特定变更类型进行分支,而无需解析字符串行。`summary` 字段已预格式化,可用于 Slack/Discord 中继。
部署 Cron Worker:
```
wrangler deploy --config wrangler.cron.toml
```
Cron Worker 的密钥单独设置:
```
wrangler secret put NVD_KEY --config wrangler.cron.toml
wrangler secret put ABUSECH_KEY --config wrangler.cron.toml
wrangler secret put WEBHOOK_URL --config wrangler.cron.toml # optional — fires on any hasChanges
```
## 开发环境设置
### 前置条件
- Node.js 18+
- Wrangler CLI (`npm i -g wrangler`)
- Cloudflare 账户(免费层级足够)
### 本地开发
```
git clone https://github.com/Teycir/SeekYou
cd SeekYou
npm install
# 复制示例环境文件 — 填写你的密钥
cp .env.example .env
# 运行 Next.js 开发服务器(KV/D1 通过 Wrangler 本地模拟)
npm run dev
```
该应用可在 `http://localhost:3000` 访问。在本地开发中,KV 和 D1 使用 Wrangler 的本地 SQLite 支持的模拟 —— 基本测试无需 Cloudflare 账户访问。
### 创建 Cloudflare 资源(首次)
```
# 创建 KV 命名空间 — 将 ID 复制到 wrangler.toml
wrangler kv namespace create KV
# 创建 D1 数据库 — 将 ID 复制到 wrangler.toml
wrangler d1 create seekyou
# 应用数据库架构
wrangler d1 execute seekyou --file=schema.sql
```
## 部署
### 构建与部署
```
# 构建并部署到 Cloudflare Pages
bash scripts/deploy.sh
```
该脚本运行 `opennextjs-cloudflare build`,准备 Pages 输出目录,并调用 `wrangler pages deploy .open-next`。**不要**使用 `npm run deploy` 或裸露的 `wrangler deploy` —— 这些命令针对的是 Workers(非 Pages)运行时,将会失败。
要单独部署 Cron Worker:
```
wrangler deploy --config wrangler.cron.toml
```
### Wrangler 配置 (`wrangler.toml`)
```
name = "seekyou"
pages_build_output_dir = ".open-next"
compatibility_date = "2025-05-01"
compatibility_flags = ["nodejs_compat"]
[[kv_namespaces]]
binding = "KV"
id = ""
[[d1_databases]]
binding = "DB"
database_name = "seekyou"
database_id = ""
```
## 密钥与环境变量
所有密钥均作为 Wrangler 密钥存储 —— 从不放在源代码或 `.env` 中。
### 必需的密钥
```
wrangler secret put NVD_KEY # NVD API key (optional — higher rate limits)
wrangler secret put ABUSECH_KEY # abuse.ch API key (URLhaus/ThreatFox/MalwareBazaar)
wrangler secret put ADMIN_TOKEN # Bearer token for /api/admin/* endpoints
# GrayHatWarfare — 对你拥有的每个密钥重复此操作(1–18)
wrangler secret put GRAYHATWARFARE_API_KEY_1
wrangler secret put GRAYHATWARFARE_API_KEY_2
# ... 最多至 GRAYHATWARFARE_API_KEY_18
```
### `.env.example`(仅限本地开发)
```
NVD_KEY=your_nvd_key_here
ABUSECH_KEY=your_abusech_key_here
ADMIN_TOKEN=change_me
GRAYHATWARFARE_API_KEY_1=your_ghw_key_here
```
## 运行测试
```
# 所有单元测试
npm test
# 监视模式
npm run test:watch
# 特定文件
npm test -- test/cache.test.ts
```
测试使用 Vitest。参见 `vitest.config.ts`。
## Cloudflare 免费层级限制
| 服务 | 免费额度 | SeekYou 预计使用量 |
|---|---|---|
| Pages 构建 | 每月 500 次 | 每月约 10 次部署 |
| Workers 请求 | 每天 100k | 每天约 5k 次查询 |
| KV 读取 | 每天 100k | 每天约 75k 次读取(15 个源 × 5k) |
| KV 写入 | 每天 1k | 每天约 500 次写入 |
| D1 读取 | 每天 500 万行 | 每天约 5k 行 |
| D1 写入 | 每天 100k 行 | 每天约 500 行 |
**预估容量:** 每天约 5,000 次唯一查询,在免费层级内绰绰有余。
缓存意味着大多数查询消耗 0 次上游调用和极少的 KV 写入。热门查询在首次命中后几乎是免费的。
## 路线图
完整分阶段路线图见 [docs/ROADMAP.md](docs/ROADMAP.md)。
**已完成的重点:**
- ✅ 基于 IP 的速率限制(KV 滑动窗口,每小时 100 次请求)
- ✅ 统一错误格式 (`lib/errors.ts`, `ErrorCode` 枚举)
- ✅ 集中配置 (`lib/config.ts` — 所有 TTL、超时、限制)
- ✅ 每个数据源的熔断器,以及 `/api/admin/reset-breaker`
- ✅ `?refresh=1` 强制缓存绕过线程贯穿所有获取器
- ✅ JSON 导出按钮(客户端,零后端)
- ✅ 首页上的最近搜索(D1,去重,上限 5 条)
- ✅ 保存的目标(D1 CRUD,`/api/targets`)
- ✅ SSE 流式结果 (`/api/stream`, `useHostStream`)
- ✅ 批量 CVE 富化(10 个并发,`lib/config.ts CVE.MAX_CONCURRENT`)
- ✅ Cron Worker — 每小时阻止列表刷新 + 每小时目标重新查询
- ✅ 风险评分 (`lib/risk.ts`) — 0–100 分,按类别细分
- ✅ 类型化差异 (`lib/diff.ts`) — `TargetDiff` 包含端口、CVE、威胁、地理位置、证书过期、风险变化
- ✅ Webhook 差异 — 在 `hasChanges` 时从 Cron 发送结构化的 `TargetDiff` 有效载荷
- ✅ GET `/api/targets` 富化了每个目标的 `riskScore` 和 `lastDiff`
- ✅ `/targets` 监控仪表板 — 风险药丸、差异芯片、60 秒轮询
**接下来(按优先级排序):**
- [ ] Turnstile 滥用防御 — Cloudflare 组件 + `/api/lookup` 中的服务器端令牌验证
- [ ] `/api/admin/health` — 聚合熔断器状态、KV 命中率、近期错误趋势
- [ ] 批量查询的正确编排 — 去重的富化、共享缓存复用、逐项渐进式 NDJSON 流
- [ ] 在 `saved_targets` 中持久化 `last_diff_json` 列 — 跨多次 Cron 运行显示差异历史
## 许可证
**商业源代码许可证 1.1 (BSL)**
版权所有 © 2026 Teycir Ben Soltane
允许:个人使用、研究、教育、非商业项目、内部业务工具。
限制:商业 SaaS 产品、转售服务、竞争性产品。
自发布之日起 4 年后,本软件将转换为 Apache 2.0 许可证。
完整条款见 [docs/LICENSE.md](docs/LICENSE.md)。
## 作者
**Teycir Ben Soltane**
邮箱:teycir@pxdmail.net
GitHub:[@Teycir](https://github.com/Teycir)
## 致谢
- [InternetDB](https://internetdb.shodan.io) (Shodan)
- [IPinfo](https://ipinfo.io) / [ip-api](https://ip-api.com)
- [BGPView](https://bgpview.io)
- [RDAP](https://rdap.org)
- [crt.sh](https://crt.sh)
- [PassiveDNS](https://passivedns.cn)
- [Robtex](https://www.robtex.com)
- [abuse.ch](https://abuse.ch) — URLhaus、ThreatFox、MalwareBazaar、Feodo、SSLBL
- [NVD](https://nvd.nist.gov) (NIST)
- [CIRCL](https://www.circl.lu/services/cve-search/)
- [OSV.dev](https://osv.dev)
- [GrayHatWarfare](https://grayhatwarfare.com)
- [Internet Archive](https://web.archive.org) (Wayback Machine)
标签:API, ASN查询, BGP数据, CMS安全, IP查询, JavaScript, OSINT工具, SYN扫描, 地理位置查询, 域名解析, 威胁情报, 开发者工具, 情报分析, 情报收集, 数据库, 数据统计, 漏洞检查, 漏洞研究, 程序员工具, 端口扫描, 缓存, 网络安全, 网络诊断, 自动化攻击, 边缘计算, 隐私保护, 高对比度