UNPKG

4.6 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 fixIfBehindProxy = require('../lib/utilities').fixIfBehindProxy;
6var debug = require('debug')('antisocial-friends');
7var VError = require('verror').VError;
8var WError = require('verror').WError;
9var async = require('async');
10var request = require('request');
11var _ = require('lodash');
12
13module.exports = function mountFriendUpdate(antisocialApp) {
14
15 var router = antisocialApp.router;
16 var config = antisocialApp.config;
17 var db = antisocialApp.db;
18 var authUserMiddleware = antisocialApp.authUserMiddleware;
19
20 var updateRegex = /^\/([a-zA-Z0-9\-.]+)\/friend-update$/;
21
22 debug('mounting GET /username/friend-update', updateRegex);
23
24 router.post(updateRegex, authUserMiddleware, function handleFriendUpdate(req, res) {
25 var matches = req.path.match(updateRegex);
26 var username = matches[1];
27
28 var endpoint = req.body.endpoint;
29
30 if (!endpoint) {
31 debug('endpoint not supplied');
32 return res.status(400).send('endpoint not supplied');
33 }
34
35 if (!endpoint.match(/(^|\s)((https?:\/\/)?[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?)/gi)) {
36 debug('endpoint not a valid url');
37 return res.status(400).send('endpoint not a valid url');
38 }
39
40 // must be a logged in user
41 var currentUser = req.antisocialUser;
42 if (!currentUser) {
43 debug('not logged in');
44 return res.sendStatus(401);
45 }
46
47 // by convention expects user to match username
48 if (currentUser.username !== username) {
49 debug('username mismatch');
50 return res.status(400).send('username mismatch');
51 }
52
53 var newStatus = req.body.status;
54 var newAudiences = req.body.audiences;
55
56 async.waterfall([
57 function findFriend(cb) {
58 debug('/friend-update findFriend');
59 db.getInstances('friends', [{
60 'property': 'userId',
61 'value': currentUser.id
62 }, {
63 'property': 'remoteEndPoint',
64 'value': req.body.endpoint
65 }], function (err, friendInstances) {
66 if (err) {
67 return cb(new VError(err, 'error reading friends'));
68 }
69
70 if (friendInstances.length !== 1) {
71 return cb(new VError(err, 'friend request not found'));
72 }
73
74 cb(null, friendInstances[0]);
75 });
76 },
77 function callWebHook(friend, cb) {
78 debug('/friend-update callWebhook');
79
80 var payload = {
81 'accessToken': friend.remoteAccessToken,
82 'action': 'friend-update'
83 };
84
85 if (newStatus === 'delete' || newStatus === 'block') {
86 payload.action = 'friend-delete';
87 }
88
89 var options = {
90 'url': fixIfBehindProxy(friend.remoteEndPoint + '/friend-webhook'),
91 'form': payload,
92 'json': true
93 };
94
95 request.post(options, function (err, response, body) {
96 if (err) {
97 return cb(new VError(err, '/friend-update callWebhook failed'));
98 }
99 if (response.statusCode !== 200) {
100 return cb(new VError('/friend-update callWebhook http error ' + response.statusCode));
101 }
102 if (_.get(body, 'status') !== 'ok') {
103 return cb(new VError('/friend-update callWebhook unexpected result %j' + body));
104 }
105
106 cb(null, friend);
107 });
108 },
109 function createBlock(friend, cb) {
110 if (newStatus !== 'block') {
111 return async.setImmediate(function () {
112 cb(null, friend);
113 });
114 }
115
116 // create a block entry
117 db.newInstance('blocks', {
118 'remoteEndPoint': friend.remoteEndPoint,
119 'userId': currentUser.id
120 }, function (err, block) {
121 cb(null, friend);
122 });
123 },
124 function updateFriend(friend, cb) {
125
126 if (newStatus === 'delete' || newStatus === 'block') {
127
128 antisocialApp.emit('friend-deleted', currentUser, JSON.parse(JSON.stringify(friend)));
129
130 db.deleteInstance('friends', friend.id, function (err) {
131 if (err) {
132 var e = new VError(err, '/friend-update updateFriend error');
133 return cb(e);
134 }
135
136 cb(null);
137 });
138 }
139 else {
140 friend.audiences.push('friends');
141
142 var update = {
143 'audiences': newAudiences
144 };
145
146 db.updateInstance('friends', friend.id, update, function (err, friend) {
147 if (err) {
148 var e = new VError(err, '/friend-update updateFriend error');
149 return cb(e);
150 }
151
152 antisocialApp.emit('friend-updated', currentUser, friend);
153
154 cb(null);
155 });
156 }
157 }
158 ], function (err) {
159 if (err) {
160 var e = new WError(err, '/friend-update failed');
161 return res.send({
162 'status': 'error',
163 'reason': e.message,
164 'details': e.cause().message
165 });
166 }
167
168 res.send({
169 'status': 'ok'
170 });
171 });
172
173 });
174};