mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
chore: rewrite feishu tool guard card comments as functional descriptions; remove unused wecom media helpers
This commit is contained in:
parent
be836b6f0a
commit
2405c7f3d6
@ -284,8 +284,8 @@ public class ToolGuardCardHandler implements FeishuCardHandler {
|
||||
// Schema 2.0 body works fine on cardkit/v1 card.create and on
|
||||
// im/v1 message.create msg_type=interactive. Two different
|
||||
// server-side validators, only one of which has been upgraded
|
||||
// for Schema 2.0. QwenPaw's production Feishu adapter uses the
|
||||
// same type="raw" approach for callback updates.
|
||||
// for Schema 2.0, so callback updates must go through
|
||||
// type="raw" with a Schema 1.0 body.
|
||||
cb.setType("raw");
|
||||
cb.setData(cardJson);
|
||||
return cb;
|
||||
|
||||
@ -74,8 +74,7 @@ public class ToolGuardCardRenderer implements FeishuCardRenderer {
|
||||
// mismatch error. Schema 2.0 is supported by im/v1/message.create
|
||||
// BUT the callback response validator only accepts Schema 1.0
|
||||
// inline (type="raw") — once we commit to Schema 1.0 here the
|
||||
// resolved-state card update lands cleanly. QwenPaw's
|
||||
// production Feishu integration uses the same Schema 1.0 path.
|
||||
// resolved-state card update lands cleanly.
|
||||
Map<String, Object> approveBtn = new LinkedHashMap<>();
|
||||
approveBtn.put("tag", "button");
|
||||
approveBtn.put("text", plainText("批准"));
|
||||
@ -116,8 +115,7 @@ public class ToolGuardCardRenderer implements FeishuCardRenderer {
|
||||
* {@code cardkit/v1 card.create}, both of which DO accept Schema
|
||||
* 2.0. So we keep the original approval card (sent via message
|
||||
* create) in Schema 2.0 for the column_set button layout, but the
|
||||
* resolved-state update has to be Schema 1.0. QwenPaw's production
|
||||
* Feishu integration uses the same split.
|
||||
* resolved-state update has to be Schema 1.0.
|
||||
*
|
||||
* <p>Caller passes the resulting Map to a {@code CallBackCard}
|
||||
* with {@code type="raw"} (NOT {@code card_json}).
|
||||
|
||||
@ -3243,63 +3243,12 @@ public class WeComChannelAdapter extends AbstractChannelAdapter implements Strea
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载并解密企业微信媒体文件(旧版本,保留给 outbound / 其他场景使用)
|
||||
* AES-256-CBC decryption for WeCom media payloads.
|
||||
* <p>
|
||||
* AES-256-CBC 解密:base64 decode aesKey → IV = 前 16 字节 → PKCS#7 去填充
|
||||
*
|
||||
* @param url 文件下载 URL
|
||||
* @param aesKey Base64 编码的 AES-256 密钥
|
||||
* @param msgId 消息 ID(用于生成文件名)
|
||||
* @param fileNameHint 文件名提示
|
||||
* @return 本地文件路径,失败返回 null
|
||||
*/
|
||||
private String downloadAndDecryptMedia(String url, String aesKey, String msgId, String fileNameHint) {
|
||||
try {
|
||||
String mediaDir = getConfigString("media_dir", "data/media");
|
||||
Path mediaDirPath = Path.of(mediaDir);
|
||||
Files.createDirectories(mediaDirPath);
|
||||
|
||||
// 1. HTTP GET 下载文件
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.timeout(Duration.ofSeconds(30))
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
byte[] encryptedData = response.body().readAllBytes();
|
||||
|
||||
byte[] fileData;
|
||||
// 2. AES 解密(如果提供了 aesKey)
|
||||
if (aesKey != null && !aesKey.isBlank()) {
|
||||
fileData = decryptAes256Cbc(encryptedData, aesKey);
|
||||
} else {
|
||||
fileData = encryptedData;
|
||||
}
|
||||
|
||||
// 3. 保存到本地
|
||||
String urlHash = md5Hex(url).substring(0, 8);
|
||||
String safeName = fileNameHint.replaceAll("[^a-zA-Z0-9._-]", "_");
|
||||
if (safeName.isBlank()) safeName = "media";
|
||||
Path filePath = mediaDirPath.resolve("wecom_" + urlHash + "_" + safeName);
|
||||
Files.write(filePath, fileData);
|
||||
|
||||
log.info("[wecom] Media downloaded: {} ({} bytes)", filePath, fileData.length);
|
||||
return filePath.toAbsolutePath().toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[wecom] Failed to download media: {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AES-256-CBC 解密(对齐 wecom-aibot-python-sdk crypto_utils.py)
|
||||
* <p>
|
||||
* 1. Base64 decode aesKey(自动补齐 padding)
|
||||
* 2. IV = decoded key 前 16 字节
|
||||
* 3. AES-256-CBC 解密
|
||||
* 4. PKCS#7 去填充
|
||||
* 1. Base64 decode aesKey (auto-fix missing padding)
|
||||
* 2. IV = first 16 bytes of the decoded key
|
||||
* 3. AES-256-CBC decrypt
|
||||
* 4. Strip PKCS#7 padding
|
||||
*/
|
||||
private byte[] decryptAes256Cbc(byte[] encryptedData, String aesKeyBase64) throws Exception {
|
||||
// 补齐 Base64 padding
|
||||
@ -3377,19 +3326,6 @@ public class WeComChannelAdapter extends AbstractChannelAdapter implements Strea
|
||||
return prefix + "_" + System.currentTimeMillis() + "_" + reqIdCounter.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 哈希(hex 字符串)
|
||||
*/
|
||||
private String md5Hex(String input) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] hash = md.digest(input.getBytes());
|
||||
return bytesToHex(hash);
|
||||
} catch (Exception e) {
|
||||
return Integer.toHexString(input.hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 哈希(字节数组输入)
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user