@ botbye/ 节点核心
再见! node.js的核心模块——所有BotBye框架集成所使用的低层构件.
当环境没有特定框架集成时使用此软件包,或者当您需要完全控制请求信息如何传递到SDK时使用此软件包.
对于大多数使用的情况,更喜欢针对具体框架的一揽子方案:
@botbye/express——快递@botbye/fastify- 速报@botbye/node-http- 节点.jshttp模块@botbye/cloudflare-worker——云花岗工人@botbye/nextjs下一个.js@botbye/nuxt- 坚果
完整文档: https://botbye.com/docs/server-side/node-js/core 页面存档备份,存于互联网档案馆
安装
npm i @botbye/node-core
yarn add @botbye/node-core
配置
@botbye/node-core 不导出 init 财务报告和审定财务报表 evaluate 直接说 打电话 moduleApiFactory 创建 SDK 实例 :
import { moduleApiFactory } from "@botbye/node-core";
import { nodeHttpClient } from "@botbye/node-core/node-http-client";
const { init, evaluate, dev } = moduleApiFactory({
httpClient: nodeHttpClient,
});
init({
// Use your project server-key
serverKey: "00000000-0000-0000-0000-000000000000",
});
打电话 init 在应用程序启动时,在呼叫之前 evaluate。 。 。 .
moduleApiFactory 选项
| 选项 | 类型 | 需求 | 说明 |
|---|---|---|---|
httpClient | THttpClient | 对 | HTTP客户端用于API呼叫. 见 HTTP 客户端。 。 。 . |
requestInfoExtractor | (request: R, global: TGlobalOptions) => TRequestInfo | 没有 | 将自定义请求对象转换为请求信息, 启用 { request: R } 内 evaluate。见 建立定制一体化。 。 。 . |
url | string | 没有 | 取代Bot Bye API的终点. 也可以通过 init。 。 。 . |
HTTP 客户端
有两个内置的HTTP客户端:
| 导入路径 | 何时使用 |
|---|---|
@botbye/node-core/node-http-client | 标准节点.js环境(使用内置) http编号 :https(中文(简体) ) |
@botbye/node-core/fetch-http-client | 带有获取 API (Deno, Bun, 边缘运行时间) 的运行时间 |
如果两者都不符合(海关代理、特殊认证头、重试逻辑),则执行 THttpClient 接口 :
import type { THttpClient } from "@botbye/node-core";
const myHttpClient: THttpClient = {
type: "my-client",
call(url, init) {
const controller = new AbortController();
const result = fetch(url, {
method: init.method,
headers: init.headers,
body: JSON.stringify(init.body),
signal: controller.signal,
}).then((r) => r.text());
return { result, abort: () => controller.abort() };
},
};
init 选项
| 选项 | 类型 | 需求 | 说明 |
|---|---|---|---|
serverKey | string | 对 | 来自您的 BotBye 项目的服务器密钥 |
url | string | 没有 | 覆盖 Bot Bye API 端点( 默认 : https://verify.botbye.com(中文(简体) ) |
logger.level | "error" | "warn" | "info" | "debug" | "log" | 没有 | 日志级别( 默认 ): "info"(中文(简体) ) |
logger.logger | TLogger | 没有 | 自定义日志实例执行 { error, warn, info, debug, log } |
timeouts.evaluate | number | 没有 | 每个超时( 毫秒) evaluate 调用 |
建立定制一体化
requestInfoExtractor 允许您为任何尚未被官方软件包覆盖的框架构建一等集成。 它弥合了框架的本地请求对象与 TRequestInfo 形状 evaluate 内部需要.
它会做什么:
何时 requestInfoExtractor 提供, evaluate 获得第二个调用表: 而不是明确通过字段, 您可以通过 { request: YourRequestObject }。提取器被自动调用以获取 ip, (中文(简体) ), headers, (中文(简体) ), requestMethod,以及 requestUri 从它.
// Without requestInfoExtractor — explicit fields only
evaluate({ type: "validate", request: { ip, headers, requestMethod, requestUri, token } });
// With requestInfoExtractor — framework request object accepted directly
evaluate({ type: "validate", request: { request: req, token } });
这两种形式并存有效。 已经通过球场的路线继续明确发挥作用.
控件处理 :
提取器也可返回 a token 字段(例如从已知标题中取出)。 如果打电话者也通过 token 事件的价值优先。 这样可以让提取器提供合理的默认,同时允许每个调用时的覆盖.
类型脚本 :
通用参数 R 打开 moduleApiFactory<R> 流动到 evaluate 签名。 提供 requestInfoExtractor 是什么让输入 { request: R } 窗体有效 :
import { moduleApiFactory } from "@botbye/node-core";
import { nodeHttpClient } from "@botbye/node-core/node-http-client";
import type { Request } from "express";
const { init, evaluate, dev } = moduleApiFactory<Request>({
httpClient: nodeHttpClient,
requestInfoExtractor: (req, global) => {
try {
return {
ip: req.ip ?? req.socket.remoteAddress ?? "0.0.0.0",
headers: req.headers as Record<string, string>,
requestMethod: req.method,
requestUri: req.url,
token: req.headers["x-botbye-token"] as string ?? null,
};
} catch {
global.logger.warn("Failed to extract request info from Express request");
return { ip: "0.0.0.0", headers: {} };
}
},
});
init({
// Use your project server-key
serverKey: "00000000-0000-0000-0000-000000000000",
});
// Now evaluate accepts Express Request directly
app.use(async (req, res, next) => {
const result = await evaluate({
type: "validate",
request: {
request: req,
// "x-botbye-token" is an example — pass the token from wherever you store it
token: req.headers["x-botbye-token"] as string,
},
});
if (result.decision === "BLOCK") {
return res.status(403).json({ error: "Forbidden" });
}
next();
});
这个 global 移交给提取器的参数 global.logger ——当请求对象畸形或出乎意料时用于警告.
使用量
打电话 evaluate 带有事件对象描述您对请求的了解。 它还带来一个决定决定的承诺.
有三种活动类型—— validate, (中文(简体) ), risk,以及 full 每一个都适合你申请的不同层次.
无 requestInfoExtractor,所有请求字段必须明确提供——没有任何框架请求可以通过.
validate --边缘级机器人检查
在边缘使用 — API网关, 路由处理器, 中间软件—— 当你只想知道时 : 这是机器人提出的要求吗? 不需要用户或域名上下文 .
活动字段 :
{
type: "validate";
request:
// Option A: custom request object — only available when requestInfoExtractor is configured
| { request: R; token?: string | null }
// Option B: explicit fields
| { ip: string; headers: Record<string, string>; requestMethod?: string | null; requestUri?: string | null; token?: string | null };
customFields?: Record<string, string>;
}
从您的运行时请求对象中取出 IP 和信头 。 备选案文A——直接传递框架请求对象——要求 requestInfoExtractor 将配置在 moduleApiFactory; 见 建立定制一体化编辑 token 是一个一次性符号,由 Bot 再见客户端 SDK 包含关于用户设备的信息。 不论客户寄给什么,都通过;如果没有收到任何信使,将作出决定 "BLOCK" 由于一个无效的符号.
async function handleRequest(ip, headers, method, url, token) {
const result = await evaluate({
type: "validate",
request: {
ip,
headers,
requestMethod: method,
requestUri: url,
token,
},
});
if (result.decision === "BLOCK") {
return { status: 403 };
}
// proceed normally
}
risk ——域级风险评分
使用已经了解用户的内部服务:认证,支付,账户管理等. 目的从"这是机器人吗?"转移到了 "对于这个用户来说,有什么可疑的吗?" ——凭证填充,账户接管,账户共享,登录新地物.
活动字段 :
{
type: "risk";
request:
// Option A: custom request object — only available when requestInfoExtractor is configured
| { request: R }
// Option B: explicit fields
| { ip: string; headers?: Record<string, string>; requestMethod?: string | null; requestUri?: string | null; token?: string | null };
event: {
type: string;
status: "ATTEMPTED" | "SUCCESSFUL" | "FAILED" | "UNKNOWN";
};
user: {
accountId: string;
username?: string | null;
email?: string | null;
phone?: string | null;
};
customFields?: Record<string, string>;
botbyeResult?: string;
}
event 财务报告和审定财务报表 user 它们是关键的领域——它们界定了正在采取什么行动,以及由谁采取行动,这是促使风险得分的因素. ip 同样重要的是: IP访问账户的 Bot Bye 轨迹可以探测到诸如账户共享、认证输入和可疑地理登录等模式。 直接传过来 { ip },或者如果 requestInfoExtractor 已配置 - 见 建立定制一体化。 。 。 .
// Inside an auth service, after a login attempt
async function onLoginAttempt({ ip, userId, email, loginSucceeded }) {
const result = await evaluate({
type: "risk",
request: { ip },
event: {
type: "login",
status: loginSucceeded ? "SUCCESSFUL" : "FAILED",
// "SUCCESSFUL" | "FAILED" | "ATTEMPTED" | "UNKNOWN"
},
user: {
accountId: userId,
email,
},
});
if (result.decision === "BLOCK") {
// Lock account, trigger MFA, send alert, etc.
}
}
链接 validate 财务报告和审定财务报表 risk 事件
当对同一请求进行两层评价时——例如,一次在边缘(type: "validate"),然后再次在域服务内(type: "risk") —— Bot Bye可以将这两起事件联系起来,并在仪表板上作为单个事件展示.
这个 validate 答复包括 botbye_result 绳子。 通过它作为 botbyeResult 输入 risk 要求建立链接:
// Edge layer — validate the bot token
const edgeResult = await evaluate({
type: "validate",
request: {
ip,
headers,
requestMethod: method,
requestUri: url,
token,
},
});
// Pass edgeResult.botbye_result to your domain service however you like —
// a request header, a context object, a function argument, etc.
const edgeBotbyeResult = edgeResult.botbye_result;
// Domain service — risk scoring linked to the edge validation above
const riskResult = await evaluate({
type: "risk",
request: { ip },
event: {
type: "login",
status: loginSucceeded ? "SUCCESSFUL" : "FAILED",
},
user: {
accountId: userId,
email,
},
botbyeResult: edgeBotbyeResult,
});
botbye_result 在答复中是可选的——如果没有,删去 botbyeResult 事件将被独立记录.
full ——边缘检查和域评分在一个呼叫中
当您同时拥有全部上下文时使用:原始请求、 令牌、 用户和事件 。 登录端点是一个典型的例子——它接收到HTTP请求并立即知道用户和结果.
活动字段 :
{
type: "full";
request:
// Option A: custom request object — only available when requestInfoExtractor is configured
| { request: R; token?: string | null }
// Option B: explicit fields
| { ip: string; headers: Record<string, string>; requestMethod?: string | null; requestUri?: string | null; token?: string | null };
event: {
type: string;
status: "ATTEMPTED" | "SUCCESSFUL" | "FAILED" | "UNKNOWN";
};
user: {
accountId: string;
username?: string | null;
email?: string | null;
phone?: string | null;
};
customFields?: Record<string, string>;
}
等同运行 validate 财务报告和审定财务报表 risk 在一个电话。 备选案文A要求 requestInfoExtractor 看到了吗 建立定制一体化。 。 。 .
async function handleLogin({ ip, headers, method, url, token, email, password }) {
const user = await findUser(email);
const loginSucceeded = user && (await checkPassword(user, password));
const result = await evaluate({
type: "full",
request: {
ip,
headers,
requestMethod: method,
requestUri: url,
token,
},
event: {
type: "login",
status: loginSucceeded ? "SUCCESSFUL" : "FAILED",
},
user: {
accountId: user?.id ?? "unknown",
email,
},
});
if (result.decision === "BLOCK") {
return { status: 403 };
}
// proceed normally
}
回应
evaluate 总是返回 a Promise<TEvaluationResult>数字 :
type TEvaluationResult =
| {
decision: "ALLOW" | "BLOCK" | "CHALLENGE";
request_id: string;
risk_score: number;
scores: Record<string, number>;
signals: string[];
botbye_result?: string;
}
| {
decision: "ALLOW";
botbye_result?: string;
error: { message: string };
};
检查 result.decision 决定如何处理请求:
"ALLOW"- 请求似乎合法,正常进行"BLOCK"- 探测到机器人或可疑活动,阻止请求"CHALLENGE"- 不确定,考虑发布CAPTCHA、外交部或额外的核查步骤
当答复中包含 error 字段,该请求没有得到充分评价。 一个 集成错误 失败 关闭 与 decision: "BLOCK" 财务报告和审定财务报表 signals: ["evaluation_error"] 成型不良的有效载荷,或解决任何项目的钥匙(Invalid server key,或 Invalid site key 用于调用; 密钥是 UUID , 所以错误的密钥会清晰地分析, 并且只检查失败 。 A 类 Bot Bye-side 失败 失败 打开 与 decision: "ALLOW",所以我们自己的过失 并不阻挡真正的用户,和 SDK 软件 做同样的,没有 request_id,当它从未收到任何决定时——请求超时,连接出错,或无法解析的反应. 监视器 error.message 无论是哪种方式,并解决根本原因.
你的计划是什么
risk_score, (中文(简体) ), scores 和探测器 signals 现从 启动器 计划好 打开 免费 页:1
判决是一样的,而且 request_id 仍然在那里, 但这三个回来空白: risk_score 实值 0.0, (中文(简体) ),
scores 实值 {},以及 signals 只保留你身边名字的原因 而不是
我们的探测器.. token_expected, (中文(简体) ), script_loading_error, (中文(简体) ), token_generation_error, (中文(简体) ), raw_token_changed
财务报告和审定财务报表 banned_by_rule你写的规则的判决.
每项计划的保护行为都相同;只有对决定的解释才不予考虑。 所以,分支
打开 decision永远不要 risk_score 上面的门槛 将每个自由计划请求都视为低风险.
反应实例
被屏蔽( 检测到的机器人) :
{
"request_id": "f77b2abd-c5d7-44f0-be4f-174b04876583",
"decision": "BLOCK",
"risk_score": 0.95,
"scores": { "bot": 0.95 },
"signals": ["AutomationTool"]
}
允许 :
{
"request_id": "f77b2abd-c5d7-44f0-be4f-174b04876583",
"decision": "ALLOW",
"risk_score": 0.05,
"scores": { "bot": 0.05, "ato": 0.02 },
"signals": []
}
挑战:
{
"request_id": "f77b2abd-c5d7-44f0-be4f-174b04876583",
"decision": "CHALLENGE",
"risk_score": 0.65,
"scores": { "bot": 0.65 },
"signals": ["SuspiciousFingerprint"],
"challenge": { "type": "CAPTCHA", "token": "..." }
}
无效 serverKey 已知项目(未关闭):
{
"request_id": "f77b2abd-c5d7-44f0-be4f-174b04876583",
"decision": "BLOCK",
"risk_score": 1.0,
"scores": {},
"signals": ["evaluation_error"],
"error": { "message": "Invalid server key" }
}
SDK从未收到决定( 未打开) :
{
"decision": "ALLOW",
"error": { "message": "connection error" }
}
高级: 多个实例
使用 moduleApiFactory 创建独立的 SDK 实例( 当保护多个项目不受一个服务的影响时有用) :
import { moduleApiFactory } from "@botbye/node-core";
import { nodeHttpClient } from "@botbye/node-core/node-http-client";
const sdkA = moduleApiFactory({ httpClient: nodeHttpClient });
const sdkB = moduleApiFactory({ httpClient: nodeHttpClient });
sdkA.init({
// Use your project server-key
serverKey: "00000000-0000-0000-0000-000000000000",
});
sdkB.init({
// Use your project server-key
serverKey: "11111111-1111-1111-1111-111111111111",
});
水电费
import { moduleApiFactory } from "@botbye/node-core";
import { nodeHttpClient } from "@botbye/node-core/node-http-client";
const { dev } = moduleApiFactory({ httpClient: nodeHttpClient });
// Change log verbosity at runtime
dev.setLoggerLevel("debug"); // "error" | "warn" | "info" | "debug" | "log"
反钓鱼
Bot Bye的反钓鱼探测器 看起来像是复制你页面的站点 此集成为检测服务 捕捉器 因此,BotBye域名对客户端保持隐藏.
反钓鱼是由它自己识别出 clientKey (可在Dashboard上的您 Phishing 工程中找到),而不是用于 evaluate,因此它被配置和连接 单独,通过 phishingModuleApiFactory。 。 。 .
配置
import { phishingModuleApiFactory } from "@botbye/node-core";
import { nodePhishingHttpClient } from "@botbye/node-core/phishing-node-http-client";
const phishing = phishingModuleApiFactory({
httpClient: nodePhishingHttpClient,
});
phishing.init({
// clientKey from your Phishing Project on the Admin Dashboard
clientKey: "00000000-0000-0000-0000-000000000000",
});
打电话 phishing.init 在应用程序启动时,在满足任何捕捉者请求之前.
phishingModuleApiFactory 选项
| 选项 | 类型 | 需求 | 说明 |
|---|---|---|---|
httpClient | TPhishingHttpClient | 对 | HTTP客户端用于捕捉者呼叫. 见 HTTP 客户端 见下文. |
catcherRequestInfoExtractor | (request: R, global: TPhishingGlobalOptions) => TPhishingCatcherRequestInfo | 没有 | 将自定义请求对象转换为 { headers },启用 { request: R } 内 fetchCatcher相同的想法 requestInfoExtractor 以上——见 建立定制一体化。 。 。 . |
url | string | 没有 | 取代Bot Bye API的终点. 也可以通过 phishing.init。 。 。 . |
Phishing HTTP 客户端
Phishing呼叫使用自己的HTTP客户端接口(TPhishingHttpClient页:1 evaluate是因为 THttpClient ——两者不可互换. 有两个内置客户端:
| 导入路径 | 何时使用 |
|---|---|
@botbye/node-core/phishing-node-http-client | 标准节点.js环境(使用内置) http编号 :https(中文(简体) ) |
@botbye/node-core/phishing-fetch-http-client | 带有获取 API (Deno, Bun, 边缘运行时间) 的运行时间 |
phishing.init 选项
| 选项 | 类型 | 需求 | 说明 |
|---|---|---|---|
clientKey | string | 对 | clientKey 从您管理板上的 Phishing 工程 |
url | string | 没有 | 覆盖 Bot Bye API 端点( 默认 : https://verify.botbye.com(中文(简体) ) |
logger.level | "error" | "warn" | "info" | "debug" | "log" | 没有 | 日志级别( 默认 ): "info"(中文(简体) ) |
logger.logger | TLogger | 没有 | 自定义日志实例执行 { error, warn, info, debug, log } |
timeouts.fetchCatcher | number | 没有 | 每个超时( 毫秒) fetchCatcher 调用 |
使用量
反钓鱼需要 两条路线的原产地,每个代理通过 fetchCatcher数字 :
- SVG 路线 - 为SVG捕手服务。 这是您的 URL 客户端 通行证给
getCatcher({ url })。 。 。 . - PNG 路线 ——服务于SVG参考的PNG(通过
innerPngUrl) (中文(简体) ).
无 catcherRequestInfoExtractor,通过 headers 明确而不是请求对象。 对于SVG, innerPngUrl 应该是 绝对 URL 您的 PNG 路由 —— 浏览器直接从您的源头装入 PNG .
// Absolute URL of your PNG endpoint — the SVG catcher references it through innerPngUrl.
const PNG_CATCHER_URL = "https://your-site.example/botbye-catcher.png";
async function serveSvgCatcher(headers) {
const catcher = await phishing.fetchCatcher({
headers,
format: "svg",
innerPngUrl: PNG_CATCHER_URL, // absolute URL of the PNG endpoint below
});
return { status: catcher.status, headers: catcher.headers, body: catcher.body };
}
async function servePngCatcher(headers) {
const catcher = await phishing.fetchCatcher({ headers, format: "png" });
return { status: catcher.status, headers: catcher.headers, body: catcher.body };
}
fetchCatcher 总是返回 a Promise<TUpstreamFetchCatcherResult>数字 :
type TUpstreamFetchCatcherResult = {
status: number;
headers: Record<string, string>;
body: Uint8Array;
error?: { message: string };
};
中继 status, (中文(简体) ), headers,以及 body 确切的电话取决于您的运行时间(res.writeHead编号 :res.end, (中文(简体) ), new Response(...)(见a/c.5/49/70,附件).
我们建议嵌入 SVG 捕捉器:它旨在继续跟踪,即使一个钓鱼网站将您的所有资产复制到自己的基础设施(PNG路线存在是因为SVG捕捉者依赖于它).
建立定制一体化
碞钩 requestInfoExtractor 页:1 evaluate, (中文(简体) ), catcherRequestInfoExtractor 让我们 fetchCatcher 直接接受框架的本地请求对象—— { request: R } ——改为 { headers }。 。 。 .
import { phishingModuleApiFactory } from "@botbye/node-core";
import { nodePhishingHttpClient } from "@botbye/node-core/phishing-node-http-client";
import type { Request } from "express";
const phishing = phishingModuleApiFactory<Request>({
httpClient: nodePhishingHttpClient,
catcherRequestInfoExtractor: (request) => ({
headers: request.headers as Record<string, string>,
}),
});
phishing.init({
clientKey: "00000000-0000-0000-0000-000000000000",
});
// Now fetchCatcher accepts an Express Request directly
app.get("/botbye-catcher.svg", async (req, res) => {
const catcher = await phishing.fetchCatcher({
request: req,
format: "svg",
innerPngUrl: PNG_CATCHER_URL,
});
res.status(catcher.status).set(catcher.headers).send(Buffer.from(catcher.body));
});
高级: 多个实例
使用 phishingModuleApiFactory 创建独立的 SDK 实例( 当保护多个项目不受一个服务的影响时有用) :
import { phishingModuleApiFactory } from "@botbye/node-core";
import { nodePhishingHttpClient } from "@botbye/node-core/phishing-node-http-client";
const phishingA = phishingModuleApiFactory({ httpClient: nodePhishingHttpClient });
const phishingB = phishingModuleApiFactory({ httpClient: nodePhishingHttpClient });
phishingA.init({
clientKey: "00000000-0000-0000-0000-000000000000",
});
phishingB.init({
clientKey: "11111111-1111-1111-1111-111111111111",
});