ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

tamedevil 的 te.identifier():安全变量名 TE 节点的校验规则与实战

tamedevil 的 te.identifier():安全变量名 TE 节点的校验规则与实战 后端API网关【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址https://gitcode.com/gh_mirrors/cry/crystal点击查看免费下载te.identifier()是 Graphile 开源仓库中tamedevil代码生成工具库提供的一个安全辅助 API它接收一个字符串校验其是否能作为 JavaScript 变量名能则返回一个对应的 TEtamedevil expression节点否则直接抛错。本文以 utils/website/tamedevil/api/te-identifier.md 为骨架结合 utils/tamedevil/src/index.ts 的实现与 utils/tamedevil/tests/general.test.ts 的测试用例完整讲解该 API 的调用方式、命名校验规则、保留字清单来源、适用场景与安全边界帮助你安全地在动态生成的 JS 代码中引入变量名。一、API 概览签名、返回值与抛错行为在tamedevil中所有助手方法都挂在te这个标签模板函数上identifier也不例外因此你通常只需要导入te即可使用见 utils/website/tamedevil/importing.mdimport { te } from tamedevil; // 或 CommonJS // const { te } require(tamedevil);te.identifier(name)的契约非常简单入参一个字符串name成功如果name是合理的变量名返回一个 TE 节点该节点在编译时会被原样输出为对应的标识符失败如果name看起来不合理例如命中 JS 保留字或者像async这样容易引起混淆的名称直接抛出错误。对应的底层实现位于 utils/tamedevil/src/index.tsfunction identifier(name: string) { if (typeof name ! string || !isValidVariableName(name)) { throw new Error(Invalid identifier name ${name}); } return makeRawNode(name); }两点值得注意非字符串入参同样抛错。实现里显式检查了typeof name ! string所以传入数字、对象等类型都会抛出Invalid identifier name ...错误。返回值是一个 RAW 节点。makeRawNode(name)生成的是TERawNode[$$type] RAW意味着编译时这段文本会被逐字输出到最终代码里。这是它区别于te.ref()的关键identifier生成的是代码本身而ref生成的是闭包变量引用。二、为什么需要它动态代码生成中的标识符安全tamedevil的定位是驯服 eval它允许你用new Function动态构建高性能代码同时通过所有嵌入值都必须走受控 API的机制来降低代码注入风险。其背景与设计动机可参考 utils/website/tamedevil/index.md 与 utils/tamedevil/README.md。在动态生成代码时你经常需要把名字拼进代码里例如把某个对象的字符串键映射为代码中的变量名。最直接但最危险的写法是使用te.dangerouslyIncludeRawCode——该方法不经过任何转义或校验文档与源码都明确警告它极少有正当使用场景绝不应用于不可信输入见 utils/tamedevil/src/index.ts。te.identifier()正是为此场景提供的安全便利方法它替你完成了标识符合法性校验保留字、字符集、起始字符校验通过后返回的 RAW 节点仍然原样输出但你已经确认过这个名字是合理的变量名。按照文档的原话这个 API不适用于不可信的用户数据它只是一个便利方法典型用途是把对象中开发者自己可控的字符串键映射为变量名 TE 节点而无需动用dangerouslyIncludeRawCode。在绝大多数场景下你甚至不需要它——直接用标签模板temyVarNameHere就能定义一个变量名它被当作普通代码处理。只有当名字来自某个字符串变量、需要先经过合法性判定时te.identifier()才有用武之地。三、命名校验规则什么才算合理的变量名te.identifier()的校验逻辑集中在isValidVariableName函数位于 utils/tamedevil/src/index.tsfunction isValidVariableName(name: string): boolean { if (reservedWords.has(name)) { return false; } if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)) { return false; } return true; }规则可以归纳为两条硬性标准不得命中保留字集合reservedWords下面第四节详述必须匹配标识符正则/^[a-zA-Z_$][a-zA-Z0-9_$]*$/即首字符只能是字母a-z/A-Z、下划线_或美元符$后续字符只能是字母、数字、下划线或美元符不允许空字符串不允许以数字开头不允许包含空格、连字符、点号等任何其他字符。因此以下名字都会抛错te.identifier(null); // 保留字 → 抛错 te.identifier(true); // 保留字 → 抛错 te.identifier(async); // 易混淆 → 抛错 te.identifier(1foo); // 数字开头 → 抛错 te.identifier(my-var); // 非法字符 → 抛错 te.identifier(); // 空字符串 → 抛错 te.identifier(42); // 非字符串 → 抛错而myVar、_tmp、$el、foo1这类名字会正常通过返回一个输出对应文本的 RAW TE 节点。需要注意的是isValidVariableName并不是te.identifier的私有函数te.ref()的第二个可选参数建议的变量名也复用了同一套校验。测试 utils/tamedevil/tests/general.test.ts 中同时覆盖了两者expect(() te.identifier(null)).toThrowErrorMatchingInlineSnapshot( Invalid identifier name null, ); expect(() te.ref(null, null)).toThrowErrorMatchingInlineSnapshot( Invalid variable name null, ); // true / false / debugger / undefined 同理均成对抛错也就是说无论你想把名字用作代码中的标识符还是闭包参数的变量名tamedevil 都保证了同一套安全性下限。四、保留字清单reservedWords 的分类与变化警告te.identifier()判定名字不合理的一个重要来源是reservedWords集合完整清单位于 utils/tamedevil/src/reservedWords.ts。它是一个Set虽然源码中以数组形式列出但作为集合天然去重因此import、require、null、true、false、in、class等词即使出现在多个分类中也只生效一次。按源码注释可分为以下几类分类包含的关键词节选JS 保留字await、break、case、catch、class、const、continue、debugger、default、delete、do、else、export、extends、false、finally、for、function、if、import、in、instanceof、new、null、return、super、switch、this、throw、true、try、typeof、var、void、while、with、let、static、yield未来保留字enum、implements、interface、package、private、protected、public历史/其他保留字abstract、boolean、byte、char、double、final、float、goto、int、long、native、short、synchronized、throws、transient、volatile特殊词arguments、as、eval、Function、from、get、of、set、undefined、Math、Number、BigInt易混淆词async全局对象window、global、globalThis、process、constructor从这份清单可以看出reservedWords并不局限于 ECMAScript 规范里的严格保留字而是有意扩大覆盖范围像undefined、arguments、eval这类即使技术上可被覆盖、但极易引发困惑或安全问题的名字window/process这类全局对象名以及constructor这类原型链敏感词全部被列入禁用。重要警告原文档特别提示——这份清单是当前版本的清单这些词可能在某个 minor 版本中发生变化。也就是说你不能把这份名单当作永久契约来硬编码应该始终以仓库中 utils/tamedevil/src/reservedWords.ts 的实时内容为准。五、实战用法把字符串键映射为变量名te.identifier()最典型的场景是把一段动态收集到的字符串名安全地嵌入到一段te代码中。例如来自 utils/tamedevil/src/index.ts 中safeKeyOrThrow文档注释里的示例用te.identifier(frogs)构造对象字面量的键const obj te.runreturn { ${te.identifier(frogs)}: frogs }; // 等价于执行 return { frogs: frogs }更一般地你可以把名字列表批量嵌入动态函数const keys [foo, bar, baz]; // 开发者可控的字符串 const fn te.run return function sum(obj) { ${keys.map((k) teconst ${te.identifier(k)} obj.${te.get(k)};).join(\n)} return foo bar baz; }; ; console.log(fn({ foo: 1, bar: 2, baz: 3 })); // 6在这个例子里teconst ${te.identifier(k)} ...生成的代码类似const foo ...;因为identifier返回的是 RAW 节点它被嵌入外层模板后会被当作普通代码文本合并输出tamedevil 的serialize会对 RAW 文本逐字拼接见 utils/tamedevil/src/index.tste.get(k)负责安全的属性访问配合使用即可完全避开dangerouslyIncludeRawCode。如果在keys中混入了非法名字比如null或my-var整个构建过程会立刻抛出Invalid identifier name ...让你在运行生成代码之前就发现错误而不是把隐患带进new Function。六、行为边界与安全注意事项不要用于不可信输入。te.identifier()只做合法性判定不做意图判定——一个合法变量名如果语义上被用于攻击例如拼出恶意表达式上下文tamedevil 无法阻止。它本质上是给开发者自己可控的字符串用的便利方法原文档对此有明确提示。它不是转义器。identifier输出的是变量名本身没有转义逻辑如果名字非法它的处理方式是直接抛错而非转义成安全形式。这与te.substring()转义字符串内容和te.safeKeyOrThrow()校验对象属性键的分工不同后者负责数据前者负责标识符。默认写法优先。只要名字是你在源码里写死的字面量直接使用temyVarNameHere即可te.identifier()是为名字来自字符串变量且需要判定的场景准备的。大小写敏感。校验区分大小写Class非保留字可以通过而class保留字会抛错Async可通过async会抛错。这与 JavaScript 标识符的语义一致。与te.ref(name)的联动。如果你只是想把某个值通过闭包传入动态代码并顺便给它一个可读的变量名应当使用te.ref(value, name)当name非法时它会抛出Invalid variable name ...错误文案与identifier不同但校验规则一致。七、源码与测试佐证速查如果你想深入验证本文结论可以在仓库中按以下路径对照阅读实现源码utils/tamedevil/src/index.tsidentifier、utils/tamedevil/src/index.tsisValidVariableName、utils/tamedevil/src/index.tsmakeRawNode生成 RAW 节点保留字清单utils/tamedevil/src/reservedWords.ts行为测试utils/tamedevil/tests/general.test.ts其中成对验证了te.identifier与te.ref(name)对null、true、false、debugger、undefined的抛错行为配套文档utils/website/tamedevil/api/te-identifier.md本文原始出处、utils/website/tamedevil/importing.md导入方式、utils/website/tamedevil/index.md设计动机。综上te.identifier()是一个小而精的 API它把这个字符串能不能当 JS 变量名这一判断集中到一处让动态代码生成过程中的标识符嵌入既保持逐字输出的效率又不越过保留字与字符集的安全红线。理解它的校验规则与边界是安全使用 tamedevil 动态代码生成能力的重要一环。赞分享后端API网关【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址https://gitcode.com/gh_mirrors/cry/crystal点击查看免费下载相关推荐django-helpdesk未来路线图新功能预测与社区贡献指南django helpdesk未来路线图新功能预测与社区贡献指南 django helpdesk是基于Django框架构建的开源内部帮助台工单管理系统前身为ADK 2.0 Workflow 图Graph完全指南节点、边与九条校验规则ADK 2.0 Workflow 图Graph完全指南节点、边与九条校验规则 ADK 2.0 的 Workflow 把多步骤 Agent 交互抽象成一张有人工智能AI AgentAgent 框架多智能体工具调用RAGyfinance3行Python代码拉取完整的美股价格历史yfinance3行Python代码拉取完整的美股价格历史 你要回测一个策略需要3只股票5年的日线价格手动从网页上逐页复制要几个小时数字还未必对。yfi数据分析金融科技上一篇libcurl CURLINFO_REDIRECT_TIME 详解跨多次重定向的总耗时如何度量、获取与使用下一篇Web-Dev-For-Beginners 第 5 模块实战基于 CO2 Signal API 的 Carbon Trigger 浏览器扩展完整解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表