UNPKG

6.69 kBJavaScriptView Raw
1// Copyright Michael Rhodes. 2017,2018. All Rights Reserved.
2// This file is licensed under the MIT License.
3// License text available at https://opensource.org/licenses/MIT
4
5var express = require('express');
6var cookieParser = require('cookie-parser');
7var uuid = require('uuid');
8var cryptography = require('antisocial-encryption');
9
10
11var app = express();
12
13app.use(express.json());
14app.use(express.urlencoded({
15 extended: false
16}));
17app.use(cookieParser());
18
19
20// mount the friend API under /antisocial
21var antisocial = require('./index');
22
23
24// Example database adaptor for persistant storage of users and friends
25// adapt these abstract methods to your application
26// data storage scheme
27
28function dbHandler() {
29 var self = this;
30
31 self.collections = {
32 'users': {},
33 'friends': {},
34 'invitations': {},
35 'blocks': {}
36 };
37
38 // store an item after assigning an unique id
39 this.newInstance = function (collectionName, data, cb) {
40 data.id = uuid();
41 self.collections[collectionName][data.id] = data;
42 if (cb) {
43 cb(null, data);
44 }
45 else {
46 return data;
47 }
48 };
49
50 // get an item by matching some property
51 this.getInstances = function (collectionName, pairs, cb) {
52 var found = [];
53 for (var item in self.collections[collectionName]) {
54 if (self.collections[collectionName].hasOwnProperty(item)) {
55 var instance = self.collections[collectionName][item];
56
57 var match = 0;
58 for (var i = 0; i < pairs.length; i++) {
59 var prop = pairs[i].property;
60 var value = pairs[i].value;
61 if (instance[prop] === value) {
62 ++match;
63 }
64 }
65
66 if (match == pairs.length) {
67 found.push(instance);
68 }
69 }
70 }
71 if (cb) {
72 cb(null, found);
73 }
74 else {
75 return found;
76 }
77 };
78
79 // update item properties by id
80 this.updateInstance = function (collectionName, id, patch, cb) {
81 var item = self.collections[collectionName][id];
82 for (var prop in patch) {
83 if (patch.hasOwnProperty(prop)) {
84 item[prop] = patch[prop];
85 }
86 }
87 if (cb) {
88 cb(null, item);
89 }
90 else {
91 return item;
92 }
93 };
94
95 this.deleteInstance = function (collectionName, id, cb) {
96 delete self.collections[collectionName][id];
97 if (cb) {
98 cb(null);
99 }
100 };
101}
102
103var db = new dbHandler();
104
105
106/*
107 Example middleware adaptor to get the logged in user.
108 exposes the current user on req.antisocialUser
109 normally this would use a cookie via some sort of token
110 to find the user in this case we use the 'token' property
111 in the users collection
112*/
113
114function getAuthenticatedUser(req, res, next) {
115 var token;
116
117 if (req.cookies && req.cookies.access_token) {
118 token = req.cookies.access_token;
119 }
120
121 if (req.body && req.body.access_token) {
122 token = req.body.access_token;
123 }
124
125 if (!token) {
126 return next();
127 }
128
129 db.getInstances('users', [{
130 'property': 'token',
131 'value': token
132 }], function (err, userInstances) {
133 req.antisocialUser = userInstances[0];
134 next();
135 });
136}
137
138app.db = db;
139
140function setupAntisocialEvents(antisocialApp) {
141 antisocialApp.on('new-friend-request', function (e) {
142 console.log('antisocial new-friend-request %s %j', e.info.user.username, e.info.friend.remoteEndPoint);
143 });
144
145 antisocialApp.on('new-friend', function (e) {
146 console.log('antisocial new-friend %s %j', e.info.user.username, e.info.friend.remoteEndPoint);
147 });
148
149 antisocialApp.on('friend-updated', function (e) {
150 console.log('antisocial friend-updated %s %j', e.info.user.username, e.info.friend.remoteEndPoint);
151 });
152
153 antisocialApp.on('friend-deleted', function (e) {
154 console.log('antisocial friend-deleted %s %j', e.info.user.username, e.info.friend.remoteEndPoint);
155 });
156
157 antisocialApp.on('open-activity-connection', function (e) {
158 var friend = e.info.friend;
159 var user = e.info.user;
160 var socket = e.socket;
161
162 console.log('antisocial new-activity-connection %j', e.info.key);
163
164 // set up data handler. will be called whenever data is received on socket
165 socket.antisocial.setDataHandler(function (data) {
166 console.log('antisocial activity-data from %s to %s %j', friend.remoteName, user.name, data);
167 });
168
169 var data = JSON.stringify({
170 'hello': friend.remoteName
171 });
172
173 var message = cryptography.encrypt(friend.remotePublicKey, friend.keys.private, data);
174
175 e.socket.emit('data', message);
176 });
177
178 antisocialApp.on('activity-backfill', function (e) {
179 var user = e.info.user;
180 var friend = e.info.friend;
181 var socket = e.socket;
182 var highwater = e.highwater;
183 console.log('antisocial activity-backfill user %s friend %s requesting backfill since %s', user.username, friend.remoteEndPoint, highwater);
184 });
185
186 antisocialApp.on('close-activity-connection', function (e) {
187 console.log('antisocial new-activity-connection %j', e.info.key);
188 });
189
190 antisocialApp.on('open-notification-connection', function (e) {
191 console.log('antisocial new-notification-connection %j', e.info.key);
192
193 socket.antisocial.setDataHandler(function (data) {
194 console.log('antisocial notification-data from %s to %s %j', e.info.user.name, data);
195 });
196
197 e.socket.emit('data', {
198 'hello': 'world'
199 });
200 });
201
202 antisocialApp.on('close-notification-connection', function (e) {
203 console.log('antisocial new-notification-connection %j', e.info.key);
204 });
205
206 antisocialApp.on('notification-backfill', function (e) {
207 var user = e.info.user;
208 var socket = e.socket;
209 var highwater = e.highwater;
210 console.log('antisocial notification-backfill user %s requesting backfill since %s', user.username, highwater);
211 });
212}
213
214// user register route for tests
215var router = express.Router();
216router.all('/register', function (req, res) {
217 var params = req.method === 'GET' ? req.query : req.body;
218 app.db.newInstance('users', {
219 'name': params.name,
220 'username': params.username,
221 'token': uuid(),
222 'id': uuid()
223 }, function (err, user) {
224 res.cookie('access_token', user.token).send({
225 'status': 'ok',
226 'result': user
227 });
228 });
229});
230
231app.use(router);
232
233var server = null;
234
235app.start = function (port) {
236 var http = require('http');
237 server = http.createServer(app);
238 var listener = server.listen(port);
239
240
241 var config = {
242 'APIPrefix': '/antisocial',
243 'publicHost': 'http://127.0.0.1:3000',
244 'port': 3000
245 };
246
247 var antisocialApp = antisocial(app, config, db, getAuthenticatedUser, listener);
248
249 setupAntisocialEvents(antisocialApp);
250};
251
252app.stop = function () {
253 server.close();
254};
255
256if (require.main === module) {
257 app.start(3000);
258}
259
260module.exports = app;