-
Notifications
You must be signed in to change notification settings - Fork 116
Expand file tree
/
Copy pathtest-webhook.js
More file actions
215 lines (177 loc) · 6.45 KB
/
test-webhook.js
File metadata and controls
215 lines (177 loc) · 6.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#!/usr/bin/env node
/**
* Simple webhook test server for TaskNotes webhook testing
*
* Usage: node test-webhook.js [port]
* Default port: 3000
*
* This server will log all incoming webhook payloads and verify signatures.
*/
const express = require('express');
const crypto = require('crypto');
const app = express();
const PORT = process.argv[2] || 3000;
// Middleware
app.use(express.json());
// CORS middleware
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-TaskNotes-Event, X-TaskNotes-Signature, X-TaskNotes-Delivery-ID');
// Handle preflight requests
if (req.method === 'OPTIONS') {
res.sendStatus(200);
return;
}
next();
});
// Test webhook secret (you should use this when configuring the webhook in TaskNotes)
const WEBHOOK_SECRET = 'test-secret-key-for-tasknotes-webhooks';
console.log('='.repeat(60));
console.log('TaskNotes Webhook Test Server');
console.log('='.repeat(60));
console.log(`Server running on: http://localhost:${PORT}`);
console.log(`Webhook URL: http://localhost:${PORT}/webhook`);
console.log(`Test secret: ${WEBHOOK_SECRET}`);
console.log('='.repeat(60));
/**
* Verify webhook signature
*/
function verifySignature(payload, signature, secret) {
if (!signature) return false;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return signature === expectedSignature;
}
/**
* Main webhook endpoint
*/
app.post('/webhook', (req, res) => {
const timestamp = new Date().toISOString();
const signature = req.headers['x-tasknotes-signature'];
const event = req.headers['x-tasknotes-event'];
const deliveryId = req.headers['x-tasknotes-delivery-id'];
console.log('\n' + '='.repeat(50));
console.log(`📨 Webhook Received [${timestamp}]`);
console.log('='.repeat(50));
// Headers
console.log('📋 Headers:');
console.log(` Event Type: ${event || 'unknown'}`);
console.log(` Delivery ID: ${deliveryId || 'unknown'}`);
console.log(` Signature: ${signature ? signature.substring(0, 16) + '...' : 'missing'}`);
// Signature verification
const isValidSignature = verifySignature(req.body, signature, WEBHOOK_SECRET);
console.log(` Signature Valid: ${isValidSignature ? '✅' : '❌'}`);
if (!isValidSignature) {
console.log('⚠️ WARNING: Invalid signature! Check your webhook secret.');
}
// Payload
console.log('\n📦 Payload:');
console.log(JSON.stringify(req.body, null, 2));
// Event-specific processing
if (req.body.event && req.body.data) {
console.log('\n🔄 Processing Event:');
switch (req.body.event) {
case 'task.created':
console.log(` ➕ New task created: "${req.body.data.task?.title}"`);
if (req.body.data.source === 'nlp') {
console.log(` 💬 Created via NLP from: "${req.body.data.originalText}"`);
}
break;
case 'task.updated':
console.log(` ✏️ Task updated: "${req.body.data.task?.title}"`);
if (req.body.data.previous) {
console.log(` 📊 Changed status: ${req.body.data.previous.status} → ${req.body.data.task?.status}`);
}
break;
case 'task.completed':
console.log(` ✅ Task completed: "${req.body.data.task?.title}"`);
break;
case 'task.deleted':
console.log(` 🗑️ Task deleted: "${req.body.data.task?.title}"`);
break;
case 'task.archived':
console.log(` 📦 Task archived: "${req.body.data.task?.title}"`);
break;
case 'time.started':
console.log(` ⏰ Time tracking started: "${req.body.data.task?.title}"`);
break;
case 'time.stopped':
console.log(` ⏹️ Time tracking stopped: "${req.body.data.task?.title}"`);
break;
case 'reminder.triggered':
console.log(` 🔔 Reminder triggered: "${req.body.data.task?.title}"`);
console.log(` 📝 Message: "${req.body.data.message}"`);
console.log(` 🕐 Notification time: ${req.body.data.notificationTime}`);
break;
default:
console.log(` 🔍 Unknown event: ${req.body.event}`);
}
}
console.log('='.repeat(50));
// Always respond with 200 OK
res.status(200).json({
received: true,
timestamp,
event,
deliveryId,
signatureValid: isValidSignature
});
});
/**
* Health check endpoint
*/
app.get('/health', (req, res) => {
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
message: 'TaskNotes webhook test server is running'
});
});
/**
* Root endpoint with instructions
*/
app.get('/', (req, res) => {
res.send(`
<h1>TaskNotes Webhook Test Server</h1>
<p>This server is ready to receive TaskNotes webhooks!</p>
<h2>Configuration:</h2>
<ul>
<li><strong>Webhook URL:</strong> <code>http://localhost:${PORT}/webhook</code></li>
<li><strong>Secret:</strong> <code>${WEBHOOK_SECRET}</code></li>
</ul>
<h2>Setup Instructions:</h2>
<ol>
<li>Open TaskNotes Settings → HTTP API tab</li>
<li>Enable HTTP API if not already enabled</li>
<li>Click "Add Webhook" in the Webhook Settings section</li>
<li>Enter URL: <code>http://localhost:${PORT}/webhook</code></li>
<li>Select the events you want to test</li>
<li>The secret will be auto-generated - replace it with: <code>${WEBHOOK_SECRET}</code></li>
<li>Save the webhook configuration</li>
<li>Perform actions in TaskNotes to trigger webhook events!</li>
</ol>
<p>Check the console output to see webhook payloads as they arrive.</p>
`);
});
// Error handling
app.use((error, req, res, next) => {
console.error('❌ Server Error:', error);
res.status(500).json({ error: 'Internal server error' });
});
// Start server
app.listen(PORT, () => {
console.log(`\n🚀 Ready to receive webhooks!`);
console.log(`\nTo test:`);
console.log(`1. Add webhook URL: http://localhost:${PORT}/webhook`);
console.log(`2. Use secret: ${WEBHOOK_SECRET}`);
console.log(`3. Perform actions in TaskNotes`);
console.log(`4. Watch the console for webhook events!\n`);
});
// Handle graceful shutdown
process.on('SIGINT', () => {
console.log('\n👋 Shutting down webhook test server...');
process.exit(0);
});