-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
170 lines (145 loc) · 4.95 KB
/
index.js
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
/**
* Module dependencies.
*/
const express = require('express');
const { Deta } = require('deta'); // import Deta
var app = module.exports = express();
app.use(express.json());
var path = require('path');
/**
* Deta variables.
*/
const myDataKey = process.env.DETA_PROJECT_KEY;
const deta = Deta(myDataKey);
// Deta database name
const db = deta.Base('HookStack');
// create an error with .status. to use in our custom error handler
function error(status, msg) {
var err = new Error(msg);
err.status = status;
return err;
}
// the following, accepts http get requests and provides
// a simple help guide or introduction
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, '/frontend/index.html'));
});
// the following, accepts any http posts that contains data
// and then saves it to a database using the source parameter
// for the system-id field and saving the body as a JSON object
app.post('/p/', function(req, res){
// Set system variable
var source = req.query['source'];
if (source === undefined) {
var source = 'unknown';
};
var timeKey = Date.now();
// Check Post Length
// post is empty - send error
if (Object.keys(req.body).length <= 0) {
res.status(200);
res.set('Cache-control', `no-store`)
console.log('received empty request');
res.send({ result: "no data" });
} else {
// post is not empty - record to Deta base
console.log('receiving data from ' + source + ' at ' + timeKey);
db.put({ key: timeKey.toString(), body: req.body, source });
res.status(200);
res.set('Cache-control', `no-store`)
res.send({ success: "data received", key: timeKey, body: req.body, source });
console.log('data received and processed');
}
});
// here we validate the API key
app.use('/', function(req, res, next){
var key = req.query['api-key'];
// key isn't present
if (!key) return next(error(400, 'api key required'));
// key is invalid
if (key !== apiKeys) return next(error(401, 'invalid api key'));
// all good, store req.key for route access
req.key = key;
next();
});
// valid api key
// api keys do_not_serve as authentication, merely to
// help prevent malicious behavior etc.
var apiKeys = process.env.API_KEY;
// we now can assume the api key is valid,
// and simply expose the data
// get all records for source provided in URL
// then delete all retrieved records
app.get('/webhooks/:source', async (req, res) => {
// Get source from URL parameter
const { source } = req.params
console.log('Retrieving items for source: ' + source);
// START NEW PART
let resA = await db.fetch([{"source":source}]);
let items = resA.items;
// continue fetching until last is not seen
while (resA.last){
resA = await db.fetch([{"source":source}], {last: resA.last});
items = items.concat(resA.items);
}
console.log('Retrieved ' + items.length + ' items');
// END NEW PART
// Create response
res.set('Cache-control', `no-store`)
res.setHeader("Content-Count", items.length);
res.json({ items: items });
// Delete retrieved records
for (const element of items) {
console.log('Deleting: ' + element.key)
db.delete(element.key)
console.log('Deleted: ' + element.key);
}
});
// get all records for source unknown
// then delete all retrieved records
app.get('/webhooks/', async (req, res) => {
// set source to unknown as not provided in URL
var source = "unknown";
console.log('Retrieving items for unknown source');
// START NEW PART
let resA = await db.fetch([{"source":source}]);
let items = resA.items;
// continue fetching until last is not seen
while (resA.last){
resA = await db.fetch([{"source":source}], {last: resA.last});
items = items.concat(resA.items);
}
console.log('Retrieved ' + items.length + ' items');
// END NEW PART
// Create response
res.set('Cache-control', `no-store`)
res.setHeader("Content-Count", items.length);
res.json({ items: items });
// Delete retrieved records
for (const element of items) {
console.log('Deleting: ' + element.key)
db.delete(element.key)
console.log('Deleted: ' + element.key);
}
});
// error handling middleware. When you next(err) it will
// be passed through the defined middleware in order
app.use(function(err, req, res, next){
res.status(err.status || 500);
res.set('Cache-control', `no-store`)
res.send({ error: err.message });
});
// our custom JSON 404 middleware. Since it's placed last
// it will be the last middleware called, if all others
// invoke next() and do not respond.
app.use(function(req, res){
res.status(404);
res.set('Cache-control', `no-store`)
res.send({ error: "can't find that" });
});
// Port is required by Deta Space
const port = parseInt(process.env.PORT || 443);
app.listen(port, () => {
console.log(`HookStack: listening on port ${port}`);
console.log(`Version 0.1.0`);
});