diff --git a/sync-server/docker-compose.caddy.yml b/sync-server/docker-compose.caddy.yml index 0fa4f4b..5370f13 100644 --- a/sync-server/docker-compose.caddy.yml +++ b/sync-server/docker-compose.caddy.yml @@ -19,8 +19,9 @@ services: - ../app/server:/app/app-server:ro # 命令层整目录挂载(避免单文件嵌套遮蔽的不可靠行为) environment: - REGISTER_ENABLED=true - # - LSKY_API=https://img.linyux.cn/api/v1 # 兰空图床(对接 COS):填入后附件自动直传对象存储 - # - LSKY_TOKEN= # 兰空 个人中心 → API 令牌 + # - LSKY_API=https://img.linyux.cn/api/v1 # 兰空图床(已对接 COS):填入后附件自动直传对象存储 + # - LSKY_TOKEN=1|xxxxxxxx # 兰空 个人中心 → API 接口 → 复制 Token + # - LSKY_STRATEGY_ID=2 # 存储策略 ID(2=COS 策略) - INVITE_CODE=please-change-me # 多用户:注册须携带此邀请码(留空则不校验) - MAX_USERS=20 # 用户数上限,0=不限 restart: unless-stopped diff --git a/sync-server/src/index.mjs b/sync-server/src/index.mjs index 3211196..ea233e3 100644 --- a/sync-server/src/index.mjs +++ b/sync-server/src/index.mjs @@ -6,9 +6,16 @@ import zlib from 'node:zlib'; // 图床网关:Lsky Pro(已对接 COS),附件直传对象存储,应用服务器不做搬运工 const LSKY_API = (process.env.LSKY_API || '').replace(/\/$/, ''); const LSKY_TOKEN = process.env.LSKY_TOKEN || ''; +const LSKY_STRATEGY_ID = process.env.LSKY_STRATEGY_ID || ''; // 存储策略(如 2=COS),不填用默认策略 +function sanitizeImageUrl(u) { + // 裸 IP:port 的 http 地址在 HTTPS 站点会被拦截;域名地址统一切 https + if (!u) return u; + return /^http:\/\/\d+\./.test(u) ? u : u.replace(/^http:\/\//, 'https://'); +} async function lskyUpload(buf, fileName, mime) { const fd = new FormData(); fd.append('file', new Blob([buf], { type: mime || 'application/octet-stream' }), fileName); + if (LSKY_STRATEGY_ID) fd.append('strategy_id', LSKY_STRATEGY_ID); const r = await fetch(LSKY_API + '/upload', { method: 'POST', headers: { authorization: 'Bearer ' + LSKY_TOKEN, accept: 'application/json' }, @@ -16,8 +23,9 @@ async function lskyUpload(buf, fileName, mime) { signal: AbortSignal.timeout(60_000), }); const j = await r.json().catch(() => null); - if (!j || j.status !== true || !j.data?.url) throw new Error('LSKY ' + r.status + ': ' + (j?.message || 'no url')); - return j.data; + const url = sanitizeImageUrl(j?.data?.links?.url || j?.data?.url); + if (!j || j.status !== true || !url) throw new Error('LSKY ' + r.status + ': ' + (j?.message || 'no url')); + return { url, thumb_url: sanitizeImageUrl(j?.data?.thumbnail_url) || undefined, key: j.data.key }; } import path from 'node:path'; import { fileURLToPath } from 'node:url';