ken_nogi/oldCode/LINEWORKS_sendMessage/lwSendMessageBot.js
Kenichiro NOGI 06c28e8b5a oldCode: 旧LINEWORKS/Pleasanter連携コード一式を追加
express/LINEWORKS_Pleasanter/LINEWORKS_sendMessage、いずれも過去の
Express実装。Gitea移行に伴い保管。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 10:42:21 +09:00

143 lines
4.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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`);
});