#!/usr/bin/env node 'use strict'; /** * 把 LibreDesk 的 app.root_url 设置为公网 HTTPS 地址(WhatsApp webhook 必须)。 * 用法:node scripts/set-public-url.js https://xxx.trycloudflare.com */ const fs = require('fs'); const path = require('path'); const ROOT = path.resolve(__dirname, '..'); const publicURL = String(process.argv[2] || '').trim().replace(/\/+$/, ''); if (!/^https:\/\//.test(publicURL)) { console.error('用法: node scripts/set-public-url.js https://'); process.exit(1); } function loadEnv(file) { const out = {}; for (const line of fs.readFileSync(file, 'utf8').split('\n')) { const t = line.trim(); if (!t || t.startsWith('#')) continue; const eq = t.indexOf('='); if (eq < 0) continue; let v = t.slice(eq + 1).trim(); if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1); out[t.slice(0, eq).trim()] = v; } return out; } async function main() { const env = loadEnv(path.join(ROOT, '.env')); const base = (env.LIBREDESK_BASE_URL || 'http://192.168.31.61:9000').replace(/\/+$/, ''); const login = await fetch(base + '/api/v1/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: env.LIBREDESK_SYSTEM_EMAIL || 'System', password: env.LIBREDESK_SYSTEM_USER_PASSWORD }), }); if (!login.ok) throw new Error(`login failed: HTTP ${login.status}`); const cookies = login.headers.getSetCookie().map((c) => c.split(';')[0]); const csrfCookie = cookies.find((c) => c.startsWith('csrf_token=')); const csrf = csrfCookie.slice(csrfCookie.indexOf('=') + 1); const keys = [ 'app.site_name', 'app.lang', 'app.max_file_upload_size', 'app.favicon_url', 'app.logo_url', 'app.root_url', 'app.allowed_file_upload_extensions', 'app.timezone', 'app.business_hours_id', 'app.show_conversation_subject', ]; const currentRes = await fetch(base + '/api/v1/settings/general', { headers: { Cookie: cookies.join('; ') } }); const currentText = await currentRes.text(); let current = {}; try { current = JSON.parse(currentText).data || JSON.parse(currentText); } catch { /* ignore */ } const body = {}; for (const k of keys) if (k in current) body[k] = current[k]; body['app.root_url'] = publicURL; const res = await fetch(base + '/api/v1/settings/general', { method: 'PUT', headers: { Cookie: cookies.join('; '), 'Content-Type': 'application/json', 'X-CSRFTOKEN': csrf }, body: JSON.stringify(body), }); const text = await res.text(); if (!res.ok) throw new Error(`update failed: HTTP ${res.status} ${text.slice(0, 200)}`); console.log(`root_url 已设置为: ${publicURL}`); } main().catch((err) => { console.error('[set-public-url]', err.message); process.exit(1); });