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扫描, 地理位置查询, 域名解析, 威胁情报, 开发者工具, 情报分析, 情报收集, 数据库, 数据统计, 漏洞检查, 漏洞研究, 程序员工具, 端口扫描, 缓存, 网络安全, 网络诊断, 自动化攻击, 边缘计算, 隐私保护, 高对比度