106 lines
3.0 KiB
JavaScript
106 lines
3.0 KiB
JavaScript
const { fetchWithAuth } = require('../feishu-common/index.js');
|
|
|
|
// Security: scan for potential secrets before sending
|
|
var SECRET_PATTERNS = [
|
|
/sk-ant-api03-[a-zA-Z0-9\-_]{20,}/,
|
|
/ghp_[a-zA-Z0-9]{10,}/,
|
|
/xox[baprs]-[a-zA-Z0-9]{10,}/,
|
|
/-----BEGIN [A-Z]+ PRIVATE KEY-----/
|
|
];
|
|
|
|
function scanForSecrets(content) {
|
|
if (!content) return;
|
|
for (var i = 0; i < SECRET_PATTERNS.length; i++) {
|
|
if (SECRET_PATTERNS[i].test(content)) {
|
|
throw new Error('Aborted send to prevent secret leakage.');
|
|
}
|
|
}
|
|
}
|
|
|
|
async function sendCard({ target, title, text, color, note, cardData }) {
|
|
// INNOVATION: Smart fallback for target (Cycle #3315)
|
|
// If target is missing, try to use the Master ID from environment.
|
|
if (!target && process.env.OPENCLAW_MASTER_ID) {
|
|
target = process.env.OPENCLAW_MASTER_ID;
|
|
}
|
|
|
|
if (!target) {
|
|
throw new Error("Target ID is required (and OPENCLAW_MASTER_ID env var is not set)");
|
|
}
|
|
|
|
// Receive ID type detection (aligned with feishu-card/send.js)
|
|
var receiveIdType = 'open_id';
|
|
if (target.startsWith('oc_')) receiveIdType = 'chat_id';
|
|
else if (target.startsWith('ou_')) receiveIdType = 'open_id';
|
|
else if (target.includes('@')) receiveIdType = 'email';
|
|
|
|
// Handle escaped newlines from CLI arguments
|
|
var processedText = (text || '').replace(/\\n/g, '\n');
|
|
|
|
scanForSecrets(processedText);
|
|
|
|
// Build elements array (same pattern as feishu-card/send.js)
|
|
var elements = [];
|
|
|
|
if (processedText) {
|
|
elements.push({
|
|
tag: 'markdown',
|
|
content: processedText
|
|
});
|
|
}
|
|
|
|
// Note element (footer small text) -- Feishu native card component
|
|
if (note) {
|
|
elements.push({
|
|
tag: 'note',
|
|
elements: [
|
|
{ tag: 'plain_text', content: String(note) }
|
|
]
|
|
});
|
|
}
|
|
|
|
// Build card object (aligned with feishu-card/send.js buildCardContent)
|
|
var card = {
|
|
config: { wide_screen_mode: true },
|
|
elements: elements
|
|
};
|
|
|
|
if (title) {
|
|
card.header = {
|
|
title: { tag: 'plain_text', content: title },
|
|
template: color || 'blue'
|
|
};
|
|
} else if (cardData && cardData.header) {
|
|
// Allow pre-built header from dashboard
|
|
card.header = cardData.header;
|
|
}
|
|
|
|
// Allow passing raw 'elements' array via cardData
|
|
if (cardData && cardData.elements) {
|
|
card.elements = cardData.elements;
|
|
}
|
|
|
|
var payload = {
|
|
receive_id: target,
|
|
msg_type: 'interactive',
|
|
content: JSON.stringify(card)
|
|
};
|
|
|
|
var res = await fetchWithAuth(
|
|
'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=' + receiveIdType,
|
|
{
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload)
|
|
}
|
|
);
|
|
|
|
var data = await res.json();
|
|
if (data.code !== 0) {
|
|
throw new Error('Feishu API Error: ' + data.msg);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
module.exports = { sendCard };
|