@sockethub/platform-xmpp 5.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@sockethub/platform-xmpp",
3
+ "description": "A sockethub platform module implementing XMPP functionality",
4
+ "version": "5.0.0-alpha.3",
5
+ "private": false,
6
+ "author": "Nick Jennings <nick@silverbucket.net>",
7
+ "license": "LGPL-3.0+",
8
+ "main": "src/index.js",
9
+ "keywords": [
10
+ "sockethub",
11
+ "messaging",
12
+ "activitystreams",
13
+ "activity",
14
+ "streams",
15
+ "protocol",
16
+ "xmpp"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/sockethub/sockethub.git",
21
+ "directory": "packages/platform-xmpp"
22
+ },
23
+ "homepage": "https://github.com/sockethub/sockethub/tree/master/packages/platform-xmpp",
24
+ "dependencies": {
25
+ "@xmpp/client": "^0.13.0",
26
+ "c8": "7.11.0"
27
+ },
28
+ "devDependencies": {
29
+ "@sockethub/schemas": "^3.0.0-alpha.3",
30
+ "chai": "4.3.6",
31
+ "eslint": "8.9.0",
32
+ "jsdoc-to-markdown": "7.1.1",
33
+ "mocha": "9.2.1",
34
+ "proxyquire": "2.1.3",
35
+ "sinon": "13.0.1"
36
+ },
37
+ "peerDependencies": {
38
+ "@sockethub/server": ">=5.0.0-alpha.2"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "@sockethub/server": {
42
+ "optional": true
43
+ }
44
+ },
45
+ "scripts": {
46
+ "build": "yarn run doc",
47
+ "clean": "npx rimraf coverage",
48
+ "clean:deps": "npx rimraf node_modules",
49
+ "compliance": "yarn run test && yarn run coverage",
50
+ "test": "c8 mocha **/*.test.js",
51
+ "lint": "eslint \"**/*.js\"",
52
+ "lint:fix": "eslint --fix \"**/*.js\"",
53
+ "coverage": "c8 check-coverage --statements 85 --branches 80 --functions 70 --lines 85",
54
+ "doc": "jsdoc2md --no-gfm --heading-depth 1 src/index.js > API.md"
55
+ },
56
+ "gitHead": "f02238a478b7ffd3f31d8deea292eb67e630a86b"
57
+ }
@@ -0,0 +1,194 @@
1
+ module.exports = [
2
+ [
3
+ `presence error 1`,
4
+ `<presence type="error" to="hermes@5apps.com/hyperchannel" from="xmpp.5apps.com/#watercooler" xmlns:stream="http://etherx.jabber.org/streams"><error type="cancel"> <remote-server-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></presence>`,
5
+ {context: 'xmpp', type: 'join', actor: {id: 'xmpp.5apps.com/#watercooler', 'type': 'room'},
6
+ error: 'remote server not found xmpp.5apps.com/#watercooler',
7
+ target: {id: 'hermes@5apps.com/hyperchannel', type: 'person'}}
8
+ ],
9
+ [
10
+ `presence error 2`,
11
+ `<presence type="error" to="hermes@5apps.com/hyperchannel" from="xmpp.5apps.com/#watercooler" xmlns:stream="http://etherx.jabber.org/streams"><error type="cancel"><not-allowed xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/><text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Communication with remote domains is not enabled</text></error></presence>`,
12
+ {context: 'xmpp', type: 'update', actor: {id: 'xmpp.5apps.com/#watercooler', 'type': 'room'},
13
+ error: '<error type="cancel"><not-allowed xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>' +
14
+ '<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Communication with remote domains is not enabled</text>' +
15
+ '</error>',
16
+ target: {id: 'hermes@5apps.com/hyperchannel', type: 'person'}}
17
+ ],
18
+ [
19
+ `initial presence`,
20
+ `<presence to="foo@bar.org" from="baz@bag.org"></presence>`,
21
+ {context: 'xmpp', type: 'update', actor: { id: "baz@bag.org", type: "person" },
22
+ target: { id: "foo@bar.org", type: 'person' }, object: {type: 'presence', presence: "online"}}
23
+ ],
24
+ [
25
+ `presence body`,
26
+ `<presence to="foo@bar.org" from="baz@bag.org"><show>online</show> <status>away message!</status></presence>`,
27
+ {context: 'xmpp', type: 'update', actor: { id: "baz@bag.org", type: "person" },
28
+ target: { id: "foo@bar.org", type: 'person' }, object: {type: 'presence', content: "away message!",
29
+ presence: "online"}}
30
+ ],
31
+ [
32
+ `presence unavailable`,
33
+ `<presence to="foo@bar.org/hyperchannel" from="baz@bag.org/yarg" type="unavailable"><x xmlns="http://jabber.org/protocol/muc#user"><item affiliation="owner" role="none"></item></x></presence>`,
34
+ { context: 'xmpp', type: "update", actor: { type: "person", id: "baz@bag.org/yarg" },
35
+ target: { id: "foo@bar.org/hyperchannel", type: 'person' },
36
+ object: { type: "presence", presence: "offline" },
37
+ }
38
+ ],
39
+ [
40
+ `presence away`,
41
+ `<presence to="foo@bar.org/hyperchannel" from="baz@bag.org/yarg" type="available"><show>away</show><x xmlns="http://jabber.org/protocol/muc#user"><item affiliation="owner" role="none"></item></x></presence>`,
42
+ { context: 'xmpp', type: "update", actor: { type: "person", id: "baz@bag.org/yarg" },
43
+ target: { id: "foo@bar.org/hyperchannel", type: 'person' },
44
+ object: { type: "presence", presence: "away" },
45
+ }
46
+ ],
47
+ [
48
+ 'attendance',
49
+ `<iq id="muc_id" type="result" to="ernie@jabber.net/Home" from="PartyChatRoom@jabber.net" xmlns:stream="http://etherx.jabber.org/streams"> <query xmlns="http://jabber.org/protocol/disco#items"> <item jid="PartyChatRoom@jabber.net/ernie" name="ernie"/> <item jid="PartyChatRoom@jabber.net/bert" name="bert"/><item jid="PartyChatRoom@jabber.net/oscar" name="oscar"/> <item jid="PartyChatRoom@jabber.net/big_bird" name="big_bird"/> <item jid="PartyChatRoom@jabber.net/elmo" name="elmo"/></query></iq>`,
50
+ {context: 'xmpp', type: 'query', actor: {id: 'PartyChatRoom@jabber.net', 'type': 'room'},
51
+ target: {id: 'ernie@jabber.net/Home', type: 'person'}, object: {'type': 'attendance',
52
+ members: ['ernie', 'bert', 'oscar', 'big_bird', 'elmo']}}
53
+ ],
54
+ [
55
+ 'message',
56
+ `<message from="radical@example.org/thinkpad" to="user@jabber.org" type="chat" id="purple9840c15f" xmlns:stream="http://etherx.jabber.org/streams">
57
+ <active xmlns="http://jabber.org/protocol/chatstates" />
58
+ <stanza-id xmlns="urn:xmpp:sid:0" id="123456789" />
59
+ <body>ohai</body>
60
+ </message>`,
61
+ {
62
+ context: 'xmpp',
63
+ type: 'send',
64
+ actor: { type: 'person', id: 'radical@example.org/thinkpad' },
65
+ target: { type: 'person', id: 'user@jabber.org' },
66
+ object: { type: 'message', content: 'ohai',
67
+ id: 'purple9840c15f', 'xmpp:stanza-id': '123456789' }
68
+ }
69
+ ],
70
+ [
71
+ 'message with delay (e.g. offline message)',
72
+ `<message from="radical@example.org/thinkpad" to="user@jabber.org" type="chat" id="purple9840c15f" xmlns:stream="http://etherx.jabber.org/streams">
73
+ <active xmlns="http://jabber.org/protocol/chatstates" />
74
+ <stanza-id xmlns="urn:xmpp:sid:0" id="123456789" />
75
+ <delay xmlns="urn:xmpp:delay" from="jabber.org" stamp="2021-04-17T18:50:25Z">Offline Storage</delay>
76
+ <body>ohai</body>
77
+ </message>`,
78
+ {
79
+ context: 'xmpp',
80
+ type: 'send',
81
+ published: '2021-04-17T18:50:25Z',
82
+ actor: { type: 'person', id: 'radical@example.org/thinkpad' },
83
+ target: { type: 'person', id: 'user@jabber.org' },
84
+ object: { type: 'message', content: 'ohai',
85
+ id: 'purple9840c15f', 'xmpp:stanza-id': '123456789' }
86
+ }
87
+ ],
88
+ [
89
+ 'message correction (XEP-0308)',
90
+ `<message from="radical@example.org/thinkpad" to="user@jabber.org" type="chat" id="purple9840c15f" xmlns:stream="http://etherx.jabber.org/streams">
91
+ <active xmlns="http://jabber.org/protocol/chatstates" />
92
+ <stanza-id xmlns="urn:xmpp:sid:0" id="123456789" />
93
+ <replace id="purple1234c15f" />
94
+ <body>oh hey</body>
95
+ </message>`,
96
+ {
97
+ context: 'xmpp',
98
+ type: 'send',
99
+ actor: { type: 'person', id: 'radical@example.org/thinkpad' },
100
+ target: { type: 'person', id: 'user@jabber.org' },
101
+ object: { type: 'message', content: 'oh hey',
102
+ id: 'purple9840c15f', 'xmpp:stanza-id': '123456789',
103
+ 'xmpp:replace': { id: 'purple1234c15f' } }
104
+ }
105
+ ],
106
+ [
107
+ 'group presence',
108
+ `<presence from='room@xmpp.example.org/speedboat'><show>chat</show> <status>brrroom!</status></presence>`,
109
+ {context: 'xmpp', type: 'update', actor: {id: 'room@xmpp.example.org/speedboat', 'type': 'person',
110
+ name: 'speedboat'}, object: {type: 'presence', content: 'brrroom!',
111
+ presence: 'chat' }}
112
+ ],
113
+ [
114
+ 'group message',
115
+ `<message from='coven@chat.shakespeare.lit/thirdwitch' id='hysf1v37' to='crone1@shakespeare.lit/desktop' type='groupchat'>
116
+ <stanza-id id="123456789" />
117
+ <body>Thrice the brinded cat hath mew'd.</body>
118
+ </message>`,
119
+ {
120
+ context: 'xmpp',
121
+ type: 'send',
122
+ actor: { type: 'person', id: 'coven@chat.shakespeare.lit/thirdwitch', name: 'thirdwitch' },
123
+ target: { type: 'room', id: 'coven@chat.shakespeare.lit' },
124
+ object: { id: 'hysf1v37', type: 'message', content: 'Thrice the brinded cat hath mew\'d.',
125
+ 'xmpp:stanza-id': '123456789'}
126
+ }
127
+ ],
128
+ // [
129
+ // 'subscribe',
130
+ // `<presence from=’user1@example.com’ to=’user2@example.com’ type=’subscribe’></presence>`,
131
+ // {}
132
+ // ],
133
+ // [
134
+ // 'subscribed',
135
+ // `<presence from=’user2@example.com’ to=’user1@example.com’ type=’subscribed’></presence>`,
136
+ // {}
137
+ // ],
138
+ // [
139
+ // 'status',
140
+ // `<presence><show>away</show><status>feeding the chickens</status></presence>`,
141
+ // {}
142
+ // ],
143
+ // [
144
+ // 'request roster',
145
+ // `<iq from=’abc@example.com’ type=’get’ id=’xyz123’>
146
+ // <query xmlns=’jabber:iq:roster’/> </iq>`,
147
+ // {}
148
+ // ],
149
+ // [
150
+ // 'present roster',
151
+ // `<iq to=’abc@example.com’ type=’result’ id=’xyz123’> <query xmlns=’jabber:iq:roster’>
152
+ // <item jid=’efg@example.com’ name=’EFG’/> <item jid=’hij’@ example.com’ name=’HIJ’/>
153
+ // </query> </iq>`,
154
+ // {}
155
+ // ],
156
+ // [
157
+ // 'join room',
158
+ // `<presence from='hav66@shakespeare.lit/pda' id='n13mt3l'
159
+ // to='coven@chat.shakespeare.lit/thirdwitch'>
160
+ // <x xmlns='http://jabber.org/protocol/muc'/> </presence>`,
161
+ // {}
162
+ // ],
163
+ [
164
+ 'JID malformed',
165
+ `<presence from='coven@chat.shakespeare.lit' id='273hs51g' to='hag66@shakespeare.lit/pda' type='error'> <error by='coven@chat.shakespeare.lit' type='modify'> <jid-malformed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence>`,
166
+ {context: 'xmpp', type: "update", actor: {id: "coven@chat.shakespeare.lit", type: "room"},
167
+ error: `<error by="coven@chat.shakespeare.lit" type="modify"> <jid-malformed xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/> </error>`,
168
+ target: {id: "hag66@shakespeare.lit/pda", type: "person"} },
169
+ ]
170
+ // [
171
+ // 'presence affiliation owner',
172
+ // `<presence from='coven@chat.shakespeare.lit/firstwitch'
173
+ // id='3DCB0401-D7CF-4E31-BE05-EDF8D057BFBD' to='hag66@shakespeare.lit/pda'>
174
+ // <x xmlns='http://jabber.org/protocol/muc#user'> <item affiliation='owner'
175
+ // role='moderator'/> </x> </presence>`,
176
+ // {}
177
+ // ],
178
+ // [
179
+ // 'presence affiliation member',
180
+ // `<presence from='coven@chat.shakespeare.lit/thirdwitch'
181
+ // id='27C55F89-1C6A-459A-9EB5-77690145D624' to='crone1@shakespeare.lit/desktop'>
182
+ // <x xmlns='http://jabber.org/protocol/muc#user'> <item affiliation='member'
183
+ // role='participant'/> </x> </presence>`,
184
+ // {}
185
+ // ],
186
+ // [
187
+ // 'presence affiliation none',
188
+ // `<presence from='coven@chat.shakespeare.lit/thirdwitch'
189
+ // id='17232D15-134F-43C8-9A29-61C20A64B236' to='crone1@shakespeare.lit/desktop'>
190
+ // <x xmlns='http://jabber.org/protocol/muc#user'> <item affiliation='none'
191
+ // jid='hag66@shakespeare.lit/pda' role='participant'/> </x> </presence>`,
192
+ // {}
193
+ // ]
194
+ ];
@@ -0,0 +1,309 @@
1
+ function getMessageBody(stanza) {
2
+ for (let elem of stanza.children) {
3
+ if (elem.name === 'body') {
4
+ return elem.children.join(' ');
5
+ }
6
+ }
7
+ }
8
+
9
+ function getMessageTimestamp(stanza) {
10
+ try {
11
+ const delay = stanza.children.find(c => c.name === 'delay');
12
+ return delay.attrs.stamp;
13
+ } catch (e) {
14
+ // no timestamp
15
+ return null;
16
+ }
17
+ }
18
+
19
+ function getMessageId(stanza) {
20
+ try {
21
+ return stanza.attrs.id;
22
+ } catch (e) {
23
+ // no message id
24
+ return null;
25
+ }
26
+ }
27
+
28
+ function getMessageStanzaId(stanza) {
29
+ try {
30
+ const stanzaId = stanza.children.find(c => c.name === 'stanza-id');
31
+ return stanzaId.attrs.id;
32
+ } catch (e) {
33
+ // no stanza id
34
+ return null;
35
+ }
36
+ }
37
+
38
+ function getMessageReplaceId(stanza) {
39
+ try {
40
+ const replaceEl = stanza.children.find(c => c.name === 'replace');
41
+ return replaceEl.attrs.id;
42
+ } catch (e) {
43
+ // no origin id
44
+ return null;
45
+ }
46
+ }
47
+
48
+ class IncomingHandlers {
49
+ constructor(session) {
50
+ this.session = session;
51
+ }
52
+
53
+ close() {
54
+ this.session.debug('received close event with no handler specified');
55
+ this.session.sendToClient({
56
+ context: 'xmpp',
57
+ type: 'close',
58
+ actor: this.session.actor,
59
+ target: this.session.actor
60
+ });
61
+ this.session.debug('**** xmpp this.session.for ' + this.session.actor['id'] + ' closed');
62
+ this.session.connection.disconnect();
63
+ }
64
+
65
+ error(err) {
66
+ try {
67
+ this.session.sendToClient({
68
+ context: 'xmpp',
69
+ type: 'error',
70
+ error: err.text || err.toString(),
71
+ object: {
72
+ type: 'message',
73
+ condition: err.condition || 'unknown'
74
+ }
75
+ });
76
+ } catch (e) {
77
+ this.session.debug('*** XMPP ERROR (rl catch): ', e);
78
+ }
79
+ }
80
+
81
+ presence(stanza) {
82
+ const obj = {
83
+ context: 'xmpp',
84
+ type: 'update',
85
+ actor: {
86
+ type: 'person',
87
+ id: stanza.attrs.from,
88
+ },
89
+ object: {
90
+ type: 'presence'
91
+ }
92
+ };
93
+ if (stanza.getChildText('status')) {
94
+ obj.object.content = stanza.getChildText('status');
95
+ }
96
+ if (stanza.getChild('show')) {
97
+ obj.object.presence = stanza.getChild('show').getText();
98
+ } else {
99
+ obj.object.presence = stanza.attrs.type === "unavailable" ? "offline" : "online";
100
+ }
101
+ if (stanza.attrs.to) {
102
+ obj.target = {id: stanza.attrs.to, type: 'person'};
103
+ } else {
104
+ obj.actor.name = stanza.attrs.from.split('/')[1];
105
+ }
106
+ this.session.debug('received contact presence update from ' + stanza.attrs.from);
107
+ this.session.sendToClient(obj);
108
+ }
109
+
110
+ subscribe(to, from, name) {
111
+ this.session.debug('received subscribe request from ' + from);
112
+ const actor = { id: from, type: 'person' };
113
+ if (name) {
114
+ actor.name = name;
115
+ }
116
+ this.session.sendToClient({
117
+ context: 'xmpp',
118
+ type: "request-friend",
119
+ actor: actor,
120
+ target: to
121
+ });
122
+ }
123
+
124
+ // unsubscribe(from) {
125
+ // this.session.debug('received unsubscribe request from ' + from);
126
+ // this.session.sendToClient({
127
+ // type: "remove-friend",
128
+ // actor: { id: from },
129
+ // target: this.session.actor
130
+ // });
131
+ // }
132
+
133
+ notifyChatMessage(stanza) {
134
+ const message = getMessageBody(stanza);
135
+ if (!message) { return; }
136
+ const from = stanza.attrs.from;
137
+ const timestamp = getMessageTimestamp(stanza);
138
+ const messageId = getMessageId(stanza);
139
+ const type = stanza.attrs.type === 'groupchat' ? 'room' : 'person';
140
+
141
+ const activity = {
142
+ context: 'xmpp',
143
+ type: 'send',
144
+ actor: {
145
+ type: 'person',
146
+ id: from,
147
+ },
148
+ target: {
149
+ type: type,
150
+ id: stanza.attrs.to,
151
+ },
152
+ object: {
153
+ type: 'message',
154
+ id: messageId,
155
+ content: message,
156
+ }
157
+ };
158
+
159
+ const messageStanzaId = getMessageStanzaId(stanza);
160
+ if (messageStanzaId) { activity.object['xmpp:stanza-id'] = messageStanzaId; }
161
+
162
+ const messageReplaceId = getMessageReplaceId(stanza);
163
+ if (messageReplaceId) {
164
+ activity.object['xmpp:replace'] = { id: messageReplaceId };
165
+ }
166
+
167
+ if (type === 'room') {
168
+ [activity.target['id'], activity.actor.name] = from.split('/');
169
+ }
170
+
171
+ if (timestamp) { activity.published = timestamp; }
172
+
173
+ this.session.sendToClient(activity);
174
+ }
175
+
176
+ notifyError(stanza) {
177
+ const error = stanza.getChild('error');
178
+ let message = stanza.toString();
179
+ let type = 'message';
180
+ if (stanza.is('presence')) {
181
+ type = 'update';
182
+ }
183
+
184
+ if (error) {
185
+ message = error.toString();
186
+ if (error.getChild('remote-server-not-found')) {
187
+ // when we get this.session.type of return message, we know it was a response from a join
188
+ type = 'join';
189
+ message = 'remote server not found ' + stanza.attrs.from;
190
+ }
191
+ }
192
+
193
+ this.session.sendToClient({
194
+ context: 'xmpp',
195
+ type: type,
196
+ actor: {
197
+ id: stanza.attrs.from,
198
+ type: 'room'
199
+ },
200
+ error: message,
201
+ target: {
202
+ id: stanza.attrs.to,
203
+ type: 'person'
204
+ }
205
+ });
206
+ }
207
+
208
+ notifyRoomAttendance(stanza) {
209
+ const query = stanza.getChild('query');
210
+ if (query) {
211
+ let members = [];
212
+ const entries = query.getChildren('item');
213
+ for (let e in entries) {
214
+ if (!entries.hasOwnProperty(e)) {
215
+ continue;
216
+ }
217
+ members.push(entries[e].attrs.name);
218
+ }
219
+
220
+ this.session.sendToClient({
221
+ context: 'xmpp',
222
+ type: 'query',
223
+ actor: {
224
+ id: stanza.attrs.from,
225
+ type: 'room'
226
+ },
227
+ target: {
228
+ id: stanza.attrs.to,
229
+ type: 'person'
230
+ },
231
+ object: {
232
+ type: 'attendance',
233
+ members: members
234
+ }
235
+ });
236
+ }
237
+ }
238
+
239
+ online() {
240
+ this.session.debug('online');
241
+ }
242
+
243
+ /**
244
+ * Handles all unknown conditions that we don't have an explicit handler for
245
+ **/
246
+ stanza(stanza) {
247
+ // console.log("incoming stanza ", stanza);
248
+ if ((stanza.attrs.type === 'error')) {
249
+ this.notifyError(stanza);
250
+ } else if (stanza.is('message')) {
251
+ this.notifyChatMessage(stanza);
252
+ } else if (stanza.is('presence')) {
253
+ this.presence(stanza);
254
+ } else if (stanza.is('iq')) {
255
+ if (stanza.attrs.id === 'muc_id' && stanza.attrs.type === 'result') {
256
+ this.session.debug('got room attendance list');
257
+ return this.notifyRoomAttendance(stanza);
258
+ }
259
+
260
+ // todo: clean up this area, unsure of what these are
261
+ const query = stanza.getChild('query');
262
+ if (query) {
263
+ const entries = query.getChildren('item');
264
+ for (let e in entries) {
265
+ if (! entries.hasOwnProperty(e)) {
266
+ continue;
267
+ }
268
+ this.session.debug('STANZA ATTRS: ', entries[e].attrs);
269
+ if (entries[e].attrs.subscription === 'both') {
270
+ this.session.sendToClient({
271
+ context: 'xmpp',
272
+ type: 'update',
273
+ actor: { id: entries[e].attrs.jid, name: entries[e].attrs.name },
274
+ target: this.session.actor,
275
+ object: {
276
+ type: 'presence',
277
+ status: '',
278
+ presence: state
279
+ }
280
+ });
281
+ } else if ((entries[e].attrs.subscription === 'from') &&
282
+ (entries[e].attrs.ask) && (entries[e].attrs.ask === 'subscribe')) {
283
+ this.session.sendToClient({
284
+ context: 'xmpp',
285
+ type: 'update',
286
+ actor: { id: entries[e].attrs.jid, name: entries[e].attrs.name },
287
+ target: this.session.actor,
288
+ object: {
289
+ type: 'presence',
290
+ statusText: '',
291
+ presence: 'notauthorized'
292
+ }
293
+ });
294
+ } else {
295
+ /**
296
+ * can't figure out how to know if one of these query stanzas are from
297
+ * added contacts or pending requests
298
+ */
299
+ this.subscribe(this.session.actor, entries[e].attrs.jid, entries[e].attrs.name);
300
+ }
301
+ }
302
+ }
303
+ } else {
304
+ this.session.debug("got XMPP unknown stanza... " + stanza);
305
+ }
306
+ }
307
+ }
308
+
309
+ module.exports = IncomingHandlers;
@@ -0,0 +1,35 @@
1
+ const sinon = require('sinon');
2
+ const chai = require('chai');
3
+ const expect = chai.expect;
4
+ const IncomingHandler = require('./incoming-handlers');
5
+ const parse = require('@xmpp/xml/lib/parse');
6
+ const schemas = require('@sockethub/schemas').default;
7
+
8
+ const stanzas = require('./incoming-handlers.data');
9
+ const {os} = require("yarn/lib/cli");
10
+
11
+ describe('Incoming handlers', () => {
12
+ describe('XML stanzas result in the expected AS objects', () => {
13
+ let ih, sendToClient;
14
+
15
+ beforeEach(() => {
16
+ sendToClient = sinon.fake();
17
+ ih = new IncomingHandler({
18
+ sendToClient: sendToClient,
19
+ debug: sinon.fake()
20
+ });
21
+ });
22
+
23
+ stanzas.forEach(([name, stanza, asobject]) => {
24
+ it(name, () => {
25
+ const xmlObj = parse(stanza);
26
+ ih.stanza(xmlObj);
27
+ sinon.assert.calledWith(sendToClient, asobject);
28
+ });
29
+
30
+ it(`${name} - passes @sockethub/schemas validator`, () => {
31
+ expect(schemas.validateActivityStream(asobject)).to.equal("");
32
+ });
33
+ });
34
+ });
35
+ });