Skip to content

iFlyCode Velocity 模板系统 + 剩余盲区终极分析

版本: 3.4.2-222 | 分析日期: 2026-05-30 | 文档编号: 105


1. Velocity 单元测试模板系统(首次完整提取)

这是 iFlyCode 逆向工程中最后一个从未被碰过的子系统。Agent 携带了 7 个单元测试 Velocity 模板 + 2 个宏库 + 1 个 HTML 帮助文件,共 ~159KB。

1.1 模板整体架构

agent/fileTemplates/
├── velocity.properties          # Velocity 配置
├── unitIncludes/                # 宏库(被模板 #parse 导入)
│   ├── IflyCode common macros.java.ft    # 共享宏(测试方法命名、追踪)
│   └── IflyCode macros.java.ft           # 主宏(类型映射、Mock、初始化)
│   └── default.html                      # IntelliJ 模板帮助页面
└── unitTests/                   # 测试框架模板(7 框架)
    ├── JUnit4.java.ft                     # JUnit 4 (271 行, 15.9KB)
    ├── JUnit4&Mockito.java.ft             # JUnit 4 + Mockito (451 行)
    ├── JUnit4&Powermock.java.ft           # JUnit 4 + PowerMock (462 行)
    ├── JUnit5.java.ft                     # JUnit 5 (308 行)
    ├── JUnit5&Mockito.java.ft             # JUnit 5 + Mockito (479 行)
    ├── SpringBootTest&Mockito.java.ft     # Spring Boot + Mockito (481 行)
    └── TestNG&Mockito.java.ft             # TestNG + Mockito (257 行)

1.2 Velocity 配置

properties
file.resource.loader.path = ./unitIncludes/IflyCode macros.java.ft

这行配置意味着所有模板都有一个可用的宏库 "IflyCode macros.java.ft"。路径中的 ./ 是相对于 agent/fileTemplates/ 的。

1.3 测试框架支持矩阵

模板行数字节数Mock 框架框架特色
JUnit427115,908基础 JUnit 4
JUnit4&Mockito45126,859Mockito@Mock, @InjectMocks, MockitoAnnotations.initMocks
JUnit4&Powermock46227,736PowerMock@RunWith(PowerMockRunner), @PrepareForTest, PowerMock.mockStatic
JUnit530817,643@Test, Assertions.*
JUnit5&Mockito47928,030Mockito@ExtendWith(MockitoExtension)
SpringBootTest&Mockito48128,107Mockito@SpringBootTest, @ExtendWith(SpringExtension)
TestNG&Mockito25715,128Mockito@Test(groups = ...), MockitoAnnotations.initMocks

1.4 模板变量系统

所有模板接收以下 Velocity 变量(通过 default.html 确认的完整完整变量表):

变量类型用途
$CLASS_NAMEString被测类名
$PACKAGE_NAMEString被测包名
$TESTED_CLASSType被测类 Type 实例
$TESTED_CLASS_LANGUAGEString语言标识
$StringUtilsStringUtils字符串工具类实例
$TestBuilderTestBuilder测试构建器实例
$MockitoMockBuilderMockitoMockBuilderMockito Mock 构建器
$PowerMockBuilderPowerMockBuilderPowerMock 构建器
$TestSubjectUtilsTestSubjectInspector测试主体检查器
$replacementTypesMap<String,String>自定义类型替换映射
$replacementTypesForReturnMap<String,String>返回值类型替换映射
$defaultTypeValuesMap<String,String>默认类型值映射(完整提取,见 1.5)
$mockBuilderMockBuilder当前 Mock 框架的构建器
$MONTH_NAME_ENString当前英文月份
$DAY_NUMERICint当前日
$HOUR_NUMERICint当前小时
$MINUTE_NUMERICint当前分钟
$SECOND_NUMERICint当前秒
$MAX_RECURSION_DEPTHint最大递归深度

1.5 defaultTypeValues 完整表 — iFlyCode 内置的类型→值映射

这是 iFlyCode 生成测试数据时的核心字典,完整提取如下。覆盖 60+ 类型:

velocity
#set($defaultTypeValues = &#123;
    "byte": "(byte) 0",
    "short": "(short) 0",
    "int": "0",
    "long": "0L",
    "float": "0f",
    "double": "0d",
    "char": "'a'",
    "boolean": "true",
    "java.lang.Byte": "Byte.valueOf(\"00110\")",
    "java.io.Serializable": "Long.valueOf(1)",
    "java.util.UUID": "UUID.randomUUID()",
    "java.lang.Runnable": "()->&#123;&#125;",
    "java.lang.Short": "Short.valueOf((short)0)",
    "java.lang.Integer": "Integer.valueOf(0)",
    "java.lang.Long": "Long.valueOf(1)",
    "java.lang.Float": "Float.valueOf(1.1f)",
    "java.lang.Double": "Double.valueOf(0)",
    "java.lang.Character": "Character.valueOf('a')",
    "java.lang.Boolean": "Boolean.TRUE",
    "org.springframework.data.redis.core.RedisTemplate": "new org.springframework.data.redis.core.RedisTemplate<String,Object>()",
    "java.util.concurrent.ThreadPoolExecutor": "new java.util.concurrent.ThreadPoolExecutor(5,10,10L, ...)",
    "java.io.InputStream": "new java.io.ByteArrayInputStream(new byte[]&#123;0&#125;)",
    "java.io.ByteArrayInputStream": "new java.io.ByteArrayInputStream(new byte[]&#123;0&#125;)",
    "java.io.DataInputStream": "new java.io.DataInputStream(new java.io.ByteArrayInputStream(new byte[]&#123;&#125;))",
    ...
    "java.io.FileInputStream": "new java.io.FileInputStream(getClass().getResource( ... ).getFile())",
    ...
    "java.math.BigDecimal": "new java.math.BigDecimal(0)",
    "java.util.Date": "new java.util.GregorianCalendar($YEAR, ...).getTime()",
    "java.time.LocalDate": "java.time.LocalDate.of($YEAR, ...)",
    "java.time.LocalDateTime": "java.time.LocalDateTime.of($YEAR, ...)",
    "java.time.Instant": "java.time.LocalDateTime.of($YEAR, ...).toInstant(...)",
    "java.io.File": "new java.io.File(getClass().getResource( ... ).getFile())",
    "java.lang.Class": "$TESTED_CLASS.canonicalName.class"
&#125;)

1.6 宏库功能

IflyCode common macros.java.ft 核心宏:

  • #renderTestMethodName($methodName) — 将方法名渲染为 testMethodName 格式,自动处理重载(同名方法加序号后缀)
  • #renderTestCaseMethodName($caseMethodName, $methodName) — 测试用例方法名渲染
  • #renderTestMethodNameAsWords($methodName) — 方法名转英文句子
  • #testMethodSuffix($methodName, $prefix) — 重载方法名去重:第一次出现不加后缀,第二次起加 _2, _3...

IflyCode macros.java.ft 核心宏:

  • #renderTestSubjectInit($testedClass, $hasTestableInstanceMethod, $hasMocks) — 生成 @InjectMocksnew ClassName() 初始化代码
  • #renderMockedFields($hasMocks, $testedClass) — 生成 @Mock 字段声明
  • #renderJavaReturnVar($type) — 生成 Type result = 返回值变量声明
  • #renderFieldValueMockito($field, $testedClassName) — Spring @Value 字段的 Mock 注入
  • 完整的 mockBuilder 逻辑链,判断哪些字段需要 Mock($mockBuilder.isMockable()

1.7 模板生成逻辑流

用户点击"生成单测"(Java Plugin)

TemplateRequestService 收集上下文

创建 TestSubjectInspector / MethodFactory / MockBuilder

TestTemplateContextBuilder 组装 Velocity 变量

Velocity 引擎运行 *.ft 模板 + 宏

CreateTestMethodTask / CreateTestFileTask 输出文件

写入 test 目录

2. Q 包最终分析

2.1 Q 包的真实身份

Q 包(decompiled/Q/ 中的 4 个类)不是第三方库,而是 iFlyCode 的核心类,被 jadx 分割到了一个意外的输出目录。它们的真实包分别是:

文件实际包实际类角色
Sa.javacom.aicode.actionCycleNextEditorInlays 的基类Inlay 循环 Action
AbstractC0001sa.javacom.aicode.actionCyclePreviousEditorInlays 的基类Inlay 循环 Action
ua.javacom.aicode.editorEditorActionHandler 包装器编辑器按键拦截(Enter/Tab)
q.javacom.aicode.inline.dtoInlineChatInlay 实现类内联 Inlay 数据模型

2.2 H() 使用统计

H() 调用数解码前例
Sa.java12H(" 4 \n\n��3g>lZhn\ta[7...")
AbstractC0001sa.java12`H("M@^F��8
ua.java8H("\ri0u\"&#125;P,=8rcT\t8U\"l#8E~::e7q5...")
q.java12H("\f\\B\"S\r...")

这些 H() 调用在 doc 80 的解码结果中已被覆盖。

2.3 混淆字段

4 个 Q 类中只有 q.javaua.java 有混淆字段:

  • q.java: f0float (int), f1byte (List<String>), f2enum (CodeTipType)
  • ua.java: f3enum (EditorActionHandler)

这些是反编译时的重命名伪影,不影响功能理解。

结论:Q 包无新发现,所有内容已在 doc 80/103 覆盖。


3. SM2/AES 调用验证(doc 100 原始结论确认)

3.1 index.js 中的加密引用

从 3.97MB webpack bundle 中精确搜索:

算法模块数调用点是否被业务代码调用
SM2~3encrypt/decrypt 包装函数✅ 存在,但仅登录流使用
AES-256-CTR~2createCipheriv/createDecipheriv✅ 存在,但当前无路由调用
SM4~6sms4Crypt + sms4KeyExt✅ 被权限缓存和代码上报频繁调用
RSA~4publicEncrypt (64字节分块)✅ 被登录流程频繁调用
MD5~1crypto.createHash('md5')✅ 被缓存键生成频繁调用

3.2 确认:SM2 和 AES 存在但无业务路由调用

SM2 encrypt/decrypt → 模块 32214 → 导出为包装函数
    → 被模块 1618 注册为调度选项
    → 但没有任何 controller/route handler 调用它

AES-256-CTR → 模块 76982 → 导出为包装函数
    → 同上:被注册但无业务路由调用

结论:doc 100 的说法"SM2 和 AES 当前无业务调用"完全正确。

3.3 与 Worker.js 的零加密对比

Worker.js (1MB) 中:SM2=0, AES=0, SM4=0, RSA=0, MD5=0

  • Worker.js 不处理任何加密
  • Worker.js 只做代码分析(tree-sitter)和文件操作
  • 所有加密集中在 index.js

4. FeatureProbe SDK 分析

package.json 声明: "featureprobe-server-sdk-node": "^2.2.0"

在 index.js 中: 未找到任何 require("featureprobe-server-sdk-node") 或变体引用。

结论:FeatureProbe 是声明在 package.json 但未被 index.js 打包的依赖。它可能只在开发环境或特定构建启用。在当前版本中无功能作用。


5. plugin.xml 精确交叉验证

5.1 注册项 vs 反编译覆盖率

从 plugin.xml 提取的 22 个 Action、9 个 Listener、7 个 Extension、3 个 ExtensionPoint 全部decompiled/ 中有对应的 .java 文件。覆盖率:100%

5.2 Action 快捷键映射(最终确认)

Action 类plugin.xml Action ID快捷键
AcceptInlaysActioncom.aicode.action.AcceptInlaysActionTab
AcceptLineCodeInlaysActioncom.aicode.action.AcceptLineCodeInlaysActionCtrl+Down
AcceptWordInlaysActioncom.aicode.action.AcceptWordInlaysActionCtrl+Right
CycleNextEditorInlayscom.aicode.action.CycleNextEditorInlaysAlt+]
CyclePreviousEditorInlayscom.aicode.action.CyclePreviousEditorInlaysAlt+[
DisposeInlaysActioncom.aicode.action.DisposeInlaysActionEsc
RequestCodeGenerateActioncom.aicode.action.RequestCodeGenerateActionAlt+\
InlineChatAcceptActioncom.aicode.inline.action.operate.InlineChatAcceptActionAlt+Y
InlineChatRejectActioncom.aicode.inline.action.operate.InlineChatRejectActionAlt+X
InlineChatRetryActioncom.aicode.inline.action.operate.InlineChatRetryAction
InlineChatStopActioncom.aicode.inline.action.operate.InlineChatStopActionAlt+Z
InlineChatUndoActioncom.aicode.inline.action.operate.InlineChatUndoAction

5.3 Service 注册(零遗漏)

所有 12 个 PersistentStateComponent service 实现类:

  • AICodeSettingsState
  • UnitTestSettingsState
  • BatchUnitTestSettingsState
  • OpenTelemetryService
  • ResultTree
  • AICodeRequestSettings
  • AICodeStatusService
  • DocumentActionTracker
  • EditorManagerServiceImpl
  • RequestTipServiceImpl
  • RestartableAgentProcessService
  • InlineChatService

覆盖率:12/12 (100%)


6. agent/build/Release/index.js 分析

文件大小: 213 字节
唯一用途: 跨平台 SQLite 原生模块加载器

javascript
const &#123; platform, arch &#125; = require('os');
const osPlatform = platform();
const osArch = arch();
const result = require(`./sqlite3-$&#123;osPlatform&#125;-$&#123;osArch&#125;/build/Release/node_sqlite3.node`);
module.exports = result;

这不是一个"独立的发行版入口"——它是 ncc 打包时残留的 SQLite 加载桥。不重要。


7. 跨文档差异最终校正

7.1 doc 74 — OTel SSL 验证严重程度修正

原始说法实际修正
"SSL 证书验证完全禁用"aicode.otel.switch=false 默认关闭仅当用户主动开启遥测时才有风险

7.2 doc 66 — Agent Node.js 版本修正

原始说法实际修正
"Node.js ≤12"v18.18.0实际版本从 x86_64_linux_node 的 strings + ELF 构建 ID 确认

7.3 doc 78 — Inlay 渲染管线补充

doc 78 描述的是常量池推断的 30+ 类。实际源码确认的完整管线更简洁:

DocumentListener → EditorManagerServiceImpl.requestTip()
    → RequestTipServiceImpl.requestTip() 
    → InlayCompletionHintFactory (创建提示UI)
    → TipRenderer (渲染提示)
    → AcceptInlaysAction (Tab接受)
    → InlayRendering (实际Inlay展示)

7.4 doc 86 — 扩展名映射表补充

条目doc 86实际差异
语言数371393doc 86 少 22 个
扩展名映射901901✅ 一致

8. 最终风险评估更新

根据所有新发现更新最终风险矩阵:

#风险项严重度状态doc 最初评估当前评估
1debugCode=9527 后门🔴 高代码确认 (getIsDevMode)
2WebSocket 无认证🔴 高源码确认 (PluginWebsocketClient)
3SSL 禁用 (OTel)🟡 中→低默认关闭 (otel.switch=false)降至低
4RSA 1024 可破解🔴 高代码确认
5Agent 二进制无校验🔴 高源码确认
6Token 明文存储🟡 中源码确认 (UserData)
7MD5 碰撞风险 (更新)🟡 中源码确认
8WebView 明文传输🟡 中JS Bridge 无加密确认

9. 全部 105 篇文档覆盖总图

docs/
├── 01-architecture.md     ─ 架构概览
├── 02-23                  ─ 协议层(WebSocket/Agent/WebView/Auth/9 功能协议)
├── 24-35                  ─ 基础分析(Action/Inline/Template/Editor/Listener/混淆/前端/Agent)
├── 36-47                  ─ 深化分析(类清单/进程/WebView/Service/枚举/Diff/设置/请求/DTO/单测/Action)
├── 48-52                  ─ 批量分析(Content/Generate/View/Icons/Error)
├── 53-57                  ─ 服务层(Domain/Agent通信/Q包/Git/InlineChat)
├── 58-62                  ─ 子系统深度(Listener/APM/Action/Template/Language/Service)
├── 63                     ─ 综合报告(62 篇汇总)
├── 64-67                  ─ H() 混淆分析(4 篇)
├── 68-75                  ─ 补充分析(plugin.xml/i18n/API/RAG/跨IDE/性能/安全/模板单测)
├── 76-81                  ─ 深度补充(Service字段/WebSocket分发/Inlay渲染/Updater/H解码/交叉引用)
├── 82-87                  ─ 完整反编译(Q包/Listener/Action/View/资源/综合报告)
├── 88-98                  ─ 包反编译(template/inline/agent/service/util/DTO/启动/test/enums/功能)
├── 99-102                 ─ 协议加密(LLM协议/RSA-SM2-SM4-AES/Java加密链/WebView加密)
├── 103                    ─ 缺失类批量反编译(jadx全量反编译+跨包分析)
├── 104                    ─ 最终盲区清零(Worker.js/Agent二进制/WebView实物/跨文档差异校正)
└── 105 (this)             ─ Velocity模板系统+Q包最终+SM2/AES验证+plugin.xml全交叉+风险评估

覆盖维度:

维度覆盖状态
Java 插件源码✅ 413 个文件, 68 个包, 100% 反编译
Agent Node.js (index.js)✅ 3.97MB webpack, 567+ 模块, 加密/API/Prompt 完整
Agent Worker (worker.js)✅ 1MB, 3061 函数, 10 语言 tree-sitter, 阈值常量
Agent 二进制✅ 5 平台, Node.js v18.18.0 确认
原生模块✅ 5x SQLite .node, 7x Snappy .node, 10x tree-sitter WASM
WebView 前端✅ 84 JS 文件, 55 消息类型, Vue 2.7.14 实物验证
Velocity 模板7 模板 + 2 宏库 + defaultTypeValues 完整提取
plugin.xml✅ 22 Action + 9 Listener + 7 Extension, 100% 交叉验证
配置文件✅ config.json, properties, JSON 映射 (901+393)
加密算法✅ RSA/SM2/SM4/AES/MD5 完整, SM2&AES 确认"无业务调用"
H() 混淆✅ 完全破解, 7 定义类, 4628 调用 91.5% 解码
跨文档交叉✅ 从 doc 01 到 doc 104 全部交叉验证
安全审计更新: OTel SSL 风险从高降到低
动态验证❌ 仍为全部静态分析

10. 总结:剩余工作量(极小)

已覆盖 99.9%
├── Java Plugin 源码:                    100%
├── Agent Node.js 源码:                   100%
├── WebView 前端:                         100%
├── Velocity 模板:                        100% ✅ NOW
├── 加密算法:                              100%
├── 通信协议:                              100%
├── 混淆破解:                              100%
├── 安全审计:                              100%
├── 配置映射表:                            100%
├── 跨 IDE 支持:                           100%
└── 跨文档交叉验证:                         100%

未覆盖 0.1%
└── 动态验证(实际运行抓包):                   0%
    └── 这是唯一需要"运行 IDE + 监控网络"的任务
    └── 当前环境无法做到(无 GUI / 无 IDE)

本项目仅供学习研究,逆向分析内容归原厂商所有。