Files
console-dev/app/lib/ticketAttachments.js
T
cieanyau 651c36367f
前端验证 / verify (push) Failing after 15m2s
接入 ESLint 与 Prettier 并加入 CI 静态门禁
2026-11-07 01:24:36 +08:00

94 lines
2.9 KiB
JavaScript

/** 工单附件展示适配;文件名、存储名与可访问 URL 分开,不把存储键直接当链接。 */
// 允许 HTTP(S) 和显式相对路径,拒绝控制字符、反斜杠及脚本/data 等协议。
function e(e) {
if (
!/^(?:https?:\/\/|\/(?!\/)|\.\.?\/)/i.test(e) ||
// eslint-disable-next-line no-control-regex -- 安全边界:拒绝附件 URL 内的控制字符。
/[\u0000-\u001f\u007f\\]/.test(e)
)
return !1;
try {
let t = new URL(e, `https://attachment.invalid/`);
return t.protocol === `http:` || t.protocol === `https:`;
} catch {
return !1;
}
}
// 仅在地址合法且文件名为支持的位图扩展名时启用图片预览,SVG 不走内嵌预览。
function t(t) {
return (
!!t.href &&
e(t.href) &&
/\.(?:avif|bmp|gif|ico|jpe?g|png|webp)$/i.test(t.name)
);
}
// 历史存储名使用 ^ 分隔前缀,展示时取末段;URI 解码失败仍保留可读的原名。
function n(e, t) {
let n =
e
.split(`/`)
.at(-1)
?.split(/\^|%5e/i)
.at(-1) || t;
try {
n = decodeURIComponent(n);
} catch {}
return n.split(`^`).at(-1) || t;
}
/** 兼容字符串及对象附件;无地址仍保留名称/存储名和明确占位,不伪造下载链接。 */
function r(t) {
return Array.isArray(t)
? t.map((t, r) => {
let i = `附件 ${r + 1}`,
a = t && typeof t == `object` && !Array.isArray(t) ? t : null;
if (
typeof t != `string` &&
(!a ||
![`url`, `name`, `save_name`].some((e) => typeof a[e] == `string`))
)
return {
name: `${i}(格式暂不支持)`,
href: null,
};
let o = typeof t == `string` ? t : a?.url,
s = typeof o == `string` ? o.trim() : ``,
c = typeof a?.name == `string` ? a.name.trim() : ``,
l = typeof a?.save_name == `string` ? a.save_name.trim() : ``,
u = c || (l ? n(l, i) : ``),
d =
l ||
// eslint-disable-next-line no-control-regex -- 安全边界:拒绝附件名中的控制字符。
(typeof o == `string` && !e(o) && !/[\\/:\u0000-\u001f]/.test(o)
? o
: ``),
f = {
name: u || (d ? n(d, i) : `${i}(地址不可用)`),
href: null,
...(d
? {
storageName: d,
}
: {}),
};
if (!e(s)) return f;
try {
let e = new URL(s, `https://attachment.invalid/`);
return e.protocol !== `http:` && e.protocol !== `https:`
? f
: {
name: u || n(e.pathname, i),
href: s,
...(d
? {
storageName: d,
}
: {}),
};
} catch {
return f;
}
})
: [];
}
export { r as n, t };