// Node.jsでLINE WORKSのBot APIを使って特定ユーザーにメッセージを送信するサンプル(HTTPS対応) const express = require('express'); const bodyParser = require('body-parser'); const fetch = require('node-fetch'); const jwt = require('jsonwebtoken'); const fs = require('fs'); const https = require('https'); const cors = require('cors'); // 追加 const app = express(); app.use(cors({ origin: [ 'https://neo999.next-hd.net', 'https://nextoffice.next-hd.co.jp', ], // 許可するオリジン optionsSuccessStatus: 200 })); //app.use(bodyParser.json()); const API_KEY = 'pgqhLFWbDFu4Byz#4afNYX2F6Fa1&$KPjved$8%sUdTQV52caip#EpIKxYUkdd4S'; // 任意のAPIキーを設定 // アクセストークン取得 async function getAccessToken() { const clientId = 'V58hNobcAqRcQPerySMz'; const clientSecret = 'gJ84XQtigD'; const serviceAccount = 'x94xh.serviceaccount@works-nextgroup2'; const privateKey = fs.readFileSync('./private_20250530180606.key', 'utf8'); const apiUrl = 'https://auth.worksmobile.com/oauth2/v2.0/token'; const now = Math.floor(Date.now() / 1000); // JWT生成 const payload = { 'iss': clientId, 'sub': serviceAccount, 'iat': now, 'exp': now + 60 * 5, 'aud': apiUrl }; const assertion = jwt.sign(payload, privateKey, { 'algorithm': 'RS256' }); const body = new URLSearchParams({ 'assertion': assertion, 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'client_id': clientId, 'client_secret': clientSecret, 'scope': 'bot' }); const response = await fetch(apiUrl, { 'method': 'POST', 'headers': { 'Content-Type': 'application/x-www-form-urlencoded' }, 'body': body.toString() }); if (response.ok) { const data = await response.json(); return data.access_token; } else { console.error('アクセストークン取得失敗:', await response.text()); return null; } } // メッセージ送信 async function sendLineworksMessage(botId, userId, messageText) { const accessToken = await getAccessToken(); if (!accessToken) return; const apiUrl = `https://www.worksapis.com/v1.0/bots/${botId}/users/${userId}/messages`; const body = { 'content': { 'type': 'text', 'text': messageText } }; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json;charset=UTF-8', 'Authorization': `Bearer ${accessToken}` }, body: JSON.stringify(body) }); if (response.ok) { console.log('送信成功'); } else { console.error('送信失敗', await response.text()); } } // APIエンドポイント app.post('/lwSendMessage', async (req, res) => { let rawBody = ''; req.on('data', (chunk) => { rawBody += chunk; // リクエストデータをそのまま取得 }); req.on('end', () => { // APIキーの検証 const apiKey = req.headers['x-api-key']; if (!apiKey || apiKey !== API_KEY) { return res.status(401).json({ error: 'APIキーが不正です' }); } // botIdとuserIdをヘッダーから取得 const botId = req.headers['x-bot-id']; const userId = req.headers['x-user-id']; if (!botId || !userId) { return res.status(400).json({ error: 'x-bot-id, x-user-idは必須です' }); } // リクエストボディ全体をmessageTextとして使用 const messageText = rawBody; console.log('messageText:', messageText); if (!messageText) { return res.status(400).json({ error: 'messageTextは必須です' }); } try { sendLineworksMessage(botId, userId, messageText); res.json({ result: 'ok' }); } catch (e) { res.status(500).json({ error: e.message }); } }); }); // HTTPSサーバー起動 const PORT = 30309; const sslOptions = { cert: fs.readFileSync('/etc/letsencrypt/live/neo999.next-hd.net/fullchain.pem'), key: fs.readFileSync('/etc/letsencrypt/live/neo999.next-hd.net/privkey.pem') }; https.createServer(sslOptions, app).listen(PORT, () => { console.log(`APIサーバー起動: https://neo999.next-hd.net:${PORT}/lwSendMessage`); });