Compare commits

..

27 Commits

Author SHA1 Message Date
skylord123 0e755bc350 - Remove console.log usage 2023-10-14 23:22:38 -06:00
skylord123 c920dd12cb - Fix error with matrix-synapse-register node
- Ensure matrix-server-config's register/deregister methods are always available
2023-10-14 22:26:29 -06:00
bvmensvoort 9661922f78 Pass msg object where possible
As described on https://nodered.org/docs/user-guide/writing-functions#handling-errors
2023-10-14 21:32:46 -06:00
bvmensvoort 20c7182511 Make errors catchable and (de)register at config node of all nodes 2023-10-14 21:32:46 -06:00
bvmensvoort f48ba74a72 Make errors of config node catchable via a catch node 2023-10-14 21:32:46 -06:00
bvmensvoort 124a0cba34 (de)Register consumer nodes at config node
In order for error messages to be catchable
2023-10-14 21:32:46 -06:00
bvmensvoort 8ca11f36d8 Make errors of nodes catchable by a catch node 2023-10-14 21:32:46 -06:00
skylord123 8a7fba39e8 Merge pull request #95 from Skylar-Tech/dev
Release v0.7.1
2023-09-05 11:22:48 -06:00
skylord123 c61eadd05d Release 0.7.1
- Upgrade matrix-js-sdk from 22.0.0 to 28.0.0
- Upgrade olm from v3.2.13 to v3.2.15
2023-09-05 11:22:00 -06:00
skylord123 78f8ab7abb Merge pull request #74 from Skylar-Tech/dev
v0.7.0
2022-12-06 22:15:49 -07:00
skylord123 ce8be4a30f Update readme 2022-12-06 22:10:26 -07:00
skylord123 3e808cabec - Set version to 0.7.0 2022-12-06 21:53:30 -07:00
skylord123 2fdc7482ce - Add back in persistent storage
- Receive node now accepts video files
2022-12-06 21:49:05 -07:00
skylord123 c7f9d56df2 - Updated code for new authedRequest argument format
- matrix-js-sdk updated to 22.0.0
- fs-extra updated to 11.1.0
- minimum version set to 14.14
2022-12-06 18:47:41 -07:00
skylord123 3c042ae47d - rename "Invite Room" node to "Invite to Room" to distinguish from new node
- new node "Invite Room" for receiving room invites
- new node "Leave Room" for leaving a room
- updated examples with new nodes
2022-12-05 23:40:05 -07:00
skylord123 0a34870fa3 Merge pull request #71 from jacotec/master
Pass invites to the receive object
2022-12-05 21:20:11 -07:00
skylord123 768a1c8ce0 Merge pull request #73 from WesleyE/master
Verify login on the relative matrix-chat/login URI
2022-12-05 21:19:03 -07:00
skylord123 22dd9b4ca3 - matrix-js-sdk updated to v21.2.0
- added node-fetch polyfill for older nodejs versions
- added abort-controller polyfill for older nodejs versions
2022-12-05 21:18:16 -07:00
skylord123 462f9670c2 - matrix-js-sdk updated to v20.0.0
- olm updated to v3.2.13 https://gitlab.matrix.org/matrix-org/olm/-/packages/136
- console messages now only appear if Node-RED's settings.js `logging.console.level` is info, debug, or trace
2022-12-05 19:49:55 -07:00
Wesley Elfring e4b01c40c2 Verify login on the relative matrix-chat/login URI 2022-11-30 13:11:33 +01:00
Marco Jakobs 908d60835d Pass invites to the receive object
This commit passes a room invite to the receive node, so you can react to it.

Sample invitation:

HDsvcHGiTYFxxxxxxx:mydomain.de : msg : Object
object
type: "r.invite"
payload: "Invitation"
userId: "@relay:mydomain.de"
topic: "!HDsvcHGiTYFxxxxxxx:mydomain.de"
_msgid: "ef1fd7f3c8ae82e6"
2022-11-25 20:56:06 +01:00
skylord123 4c17a21008 Merge pull request #63 from Skylar-Tech/dev
Version 0.6.1
2022-04-19 13:03:47 -06:00
skylord123 bd4f6ea486 Update version to 0.6.1
- Fix: Error thrown in folder migration if new and old path are same
2022-04-19 13:01:00 -06:00
skylord123 5ef0b6a11f Fix: Error thrown in folder migration if new and old path are same 2022-04-19 12:58:52 -06:00
skylord123 97f27e61c6 Merge pull request #62 from Skylar-Tech/61-audio-messages
61 audio messages
2022-03-28 00:45:22 -06:00
skylord123 7bdadc0fe9 Closes #209
- Can now receive audio files
- Can now receive locations
- Readme updated
2022-03-28 00:42:52 -06:00
skylord123 5f129560aa Couple of little changes:
- Fix matrix-receive message types displaying in uppercase when it should be lowercase
- Readme updated with some extra things that are now possible since last release
- Link to matrix.org project in our README.md
2022-03-28 00:42:19 -06:00
36 changed files with 15569 additions and 8515 deletions
Binary file not shown.
+5 -5
View File
@@ -1,5 +1,5 @@
# node-red-contrib-matrix-chat # node-red-contrib-matrix-chat
Matrix chat server client for [Node-RED](https://nodered.org/) [Matrix](https://matrix.org/) chat server client for [Node-RED](https://nodered.org/)
***Currently we are in beta. We ask that you open any issues you have on our repository to help us reach a stable well tested version. Things may change & break before our first release so check changelog before updating.*** ***Currently we are in beta. We ask that you open any issues you have on our repository to help us reach a stable well tested version. Things may change & break before our first release so check changelog before updating.***
@@ -11,8 +11,10 @@ The following is supported from this package:
- End-to-end encryption - End-to-end encryption
- [Currently a WIP](#end-to-end-encryption-notes) - [Currently a WIP](#end-to-end-encryption-notes)
- Receive events from a room (messages, reactions, images, and files) whether encrypted or not - Receive events from a room (messages, reactions, images, audio, locations, and files) whether encrypted or not
- Send Images/Files (sending files to e2ee room doesn't currently encrypt them yet) - Send Images/Files (sending files to e2ee room doesn't currently encrypt them yet)
- Edit messages
- Delete events (messages, reactions, etc)
- Decrypt files in e2ee rooms - Decrypt files in e2ee rooms
- Send HTML/Plain Text Message/Notice - Send HTML/Plain Text Message/Notice
- React to messages - React to messages
@@ -24,9 +26,7 @@ The following is supported from this package:
- Get a user list from a room - Get a user list from a room
- Kick user from room - Kick user from room
- Ban user from room - Ban user from room
- Join a room - Join, Create, Invite, and Leave rooms
- Create a room
- Invite to a room
- Synapse admin API to force add user to room (requires bot to be in same room already) - Synapse admin API to force add user to room (requires bot to be in same room already)
+22
View File
@@ -15,6 +15,8 @@ Build something cool with these nodes? Feel free to submit a pull request to sha
- [Respond to "image" with an uploaded image](#respond-to-image-with-an-uploaded-image) - [Respond to "image" with an uploaded image](#respond-to-image-with-an-uploaded-image)
- [Respond to "file" with an uploaded file](#respond-to-file-with-an-uploaded-file) - [Respond to "file" with an uploaded file](#respond-to-file-with-an-uploaded-file)
- [Respond to "react" with a reaction](#respond-to-react-with-a-reaction) - [Respond to "react" with a reaction](#respond-to-react-with-a-reaction)
- [Accept room invites from specific user](#accept-room-invites-from-specific-user)
- [Leave room when someone says "bye"](#leave-room-when-someone-says-bye)
- [Remove messages containing "delete"](#remove-messages-containing-delete) - [Remove messages containing "delete"](#remove-messages-containing-delete)
- [Respond to "users" with full list of server users](#respond-to-users-with-full-list-of-server-users) - [Respond to "users" with full list of server users](#respond-to-users-with-full-list-of-server-users)
- [Respond to "newroom" by creating new room and inviting user](#respond-to-newroom-by-creating-new-room-and-inviting-user) - [Respond to "newroom" by creating new room and inviting user](#respond-to-newroom-by-creating-new-room-and-inviting-user)
@@ -113,6 +115,26 @@ Give a 👍 reaction when someone says "react"
### Accept room invites from specific user
[View JSON](accept-room-invites.json)
Accept room invites from specific user.
![accept-room-invites.png](accept-room-invites.png)
### Leave room when someone says bye
[View JSON](leave-room-bye.json)
Leave room when someone says "bye".
![leave-room-bye.png](leave-room-bye.png)
### Remove messages containing "delete" ### Remove messages containing "delete"
[View JSON](delete-event.json) [View JSON](delete-event.json)
+94
View File
@@ -0,0 +1,94 @@
[
{
"id": "64f76474ff7a3727",
"type": "matrix-room-invite",
"z": "f025a8b9fbd1b054",
"name": "",
"server": "8da0ef83f77f8e24",
"roomId": null,
"x": 270,
"y": 2380,
"wires": [
[
"22f6056fa5bc5bd0"
]
]
},
{
"id": "6d6f304a0a6342b8",
"type": "matrix-join-room",
"z": "f025a8b9fbd1b054",
"name": "",
"server": "8da0ef83f77f8e24",
"x": 770,
"y": 2380,
"wires": [
[
"1409ebb4a0e65663"
],
[
"1409ebb4a0e65663"
]
]
},
{
"id": "22f6056fa5bc5bd0",
"type": "switch",
"z": "f025a8b9fbd1b054",
"name": "msg.userId == @skylord123:skylar.tech",
"property": "userId",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "@skylord123:skylar.tech",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 520,
"y": 2380,
"wires": [
[
"6d6f304a0a6342b8"
]
]
},
{
"id": "043f74e6d76b1eb0",
"type": "comment",
"z": "f025a8b9fbd1b054",
"name": "Only accept room invites from specific user",
"info": "",
"x": 360,
"y": 2340,
"wires": []
},
{
"id": "1409ebb4a0e65663",
"type": "debug",
"z": "f025a8b9fbd1b054",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 910,
"y": 2380,
"wires": []
},
{
"id": "8da0ef83f77f8e24",
"type": "matrix-server-config",
"name": null,
"autoAcceptRoomInvites": false,
"enableE2ee": true,
"global": true
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+103
View File
@@ -0,0 +1,103 @@
[
{
"id": "997c354038202dba",
"type": "comment",
"z": "f025a8b9fbd1b054",
"name": "Leave room when someone says \"bye\"",
"info": "",
"x": 350,
"y": 2520,
"wires": []
},
{
"id": "69c4ea189be94feb",
"type": "matrix-receive",
"z": "f025a8b9fbd1b054",
"name": "",
"server": "8da0ef83f77f8e24",
"roomId": "",
"acceptText": true,
"acceptEmotes": true,
"acceptStickers": true,
"acceptReactions": true,
"acceptFiles": true,
"acceptAudio": true,
"acceptImages": true,
"acceptLocations": true,
"x": 280,
"y": 2560,
"wires": [
[
"19e1d64b63ae8a1f"
]
]
},
{
"id": "19e1d64b63ae8a1f",
"type": "switch",
"z": "f025a8b9fbd1b054",
"name": "msg.payload == bye",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "bye",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 480,
"y": 2560,
"wires": [
[
"db0e51f8e7793f92"
]
]
},
{
"id": "db0e51f8e7793f92",
"type": "matrix-leave-room",
"z": "f025a8b9fbd1b054",
"name": "",
"server": "8da0ef83f77f8e24",
"roomId": null,
"x": 670,
"y": 2560,
"wires": [
[
"3791f551bf0e4fc4"
],
[
"3791f551bf0e4fc4"
]
]
},
{
"id": "3791f551bf0e4fc4",
"type": "debug",
"z": "f025a8b9fbd1b054",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 810,
"y": 2560,
"wires": []
},
{
"id": "8da0ef83f77f8e24",
"type": "matrix-server-config",
"name": null,
"autoAcceptRoomInvites": false,
"enableE2ee": true,
"global": true
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+14736 -8392
View File
File diff suppressed because it is too large Load Diff
+12 -7
View File
@@ -1,14 +1,17 @@
{ {
"name": "node-red-contrib-matrix-chat", "name": "node-red-contrib-matrix-chat",
"version": "0.5.8", "version": "0.7.1",
"description": "Matrix chat server client for Node-RED", "description": "Matrix chat server client for Node-RED",
"dependencies": { "dependencies": {
"fs-extra": "^10.0.1", "abort-controller": "^3.0.0",
"fs-extra": "^11.1.0",
"got": "^12.0.2", "got": "^12.0.2",
"isomorphic-webcrypto": "^2.3.8", "isomorphic-webcrypto": "^2.3.8",
"matrix-js-sdk": "^16.0.0", "matrix-js-sdk": "^28.0.0",
"node-fetch": "^3.3.0",
"node-localstorage": "^2.2.1", "node-localstorage": "^2.2.1",
"olm": "https://gitlab.matrix.org/matrix-org/olm/-/package_files/271/download", "olm": "https://gitlab.matrix.org/matrix-org/olm/-/package_files/2572/download",
"request": "^2.88.2",
"utf8": "^3.0.0" "utf8": "^3.0.0"
}, },
"node-red": { "node-red": {
@@ -23,7 +26,9 @@
"matrix-react": "src/matrix-react.js", "matrix-react": "src/matrix-react.js",
"matrix-create-room": "src/matrix-create-room.js", "matrix-create-room": "src/matrix-create-room.js",
"matrix-invite-room": "src/matrix-invite-room.js", "matrix-invite-room": "src/matrix-invite-room.js",
"matrix-room-invite": "src/matrix-room-invite.js",
"matrix-join-room": "src/matrix-join-room.js", "matrix-join-room": "src/matrix-join-room.js",
"matrix-leave-room": "src/matrix-leave-room.js",
"matrix-crypt-file": "src/matrix-crypt-file.js", "matrix-crypt-file": "src/matrix-crypt-file.js",
"matrix-room-kick": "src/matrix-room-kick.js", "matrix-room-kick": "src/matrix-room-kick.js",
"matrix-room-ban": "src/matrix-room-ban.js", "matrix-room-ban": "src/matrix-room-ban.js",
@@ -42,9 +47,9 @@
"keywords": [ "keywords": [
"node-red", "node-red",
"matrix", "matrix",
"support", "chat",
"bot", "chatbot",
"chat" "federated"
], ],
"repository": { "repository": {
"type": "git", "type": "git",
+7 -2
View File
@@ -8,9 +8,10 @@ module.exports = function(RED) {
this.server = RED.nodes.getNode(n.server); this.server = RED.nodes.getNode(n.server);
if(!this.server) { if(!this.server) {
node.error('Server must be configured on the node.'); node.error('Server must be configured on the node.', {});
return; return;
} }
node.server.register(node);
this.encodeUri = function(pathTemplate, variables) { this.encodeUri = function(pathTemplate, variables) {
for (const key in variables) { for (const key in variables) {
@@ -41,7 +42,7 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
@@ -64,6 +65,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-create-room", MatrixCreateRoom); RED.nodes.registerType("matrix-create-room", MatrixCreateRoom);
} }
+4 -4
View File
@@ -12,22 +12,22 @@ module.exports = function(RED) {
const { got } = await import('got'); const { got } = await import('got');
if(!msg.type) { if(!msg.type) {
node.error('msg.type is required.'); node.error('msg.type is required.', msg);
return; return;
} }
if(!msg.content) { if(!msg.content) {
node.error('msg.content is required.'); node.error('msg.content is required.', msg);
return; return;
} }
if(!msg.content.file) { if(!msg.content.file) {
node.error('msg.content.file is required.'); node.error('msg.content.file is required.', msg);
return; return;
} }
if(!msg.url) { if(!msg.url) {
node.error('msg.url is required.'); node.error('msg.url is required.', msg);
return; return;
} }
+7 -2
View File
@@ -13,6 +13,7 @@ module.exports = function(RED) {
node.warn("No configuration node"); node.warn("No configuration node");
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -27,7 +28,7 @@ module.exports = function(RED) {
node.on('input', function(msg) { node.on('input', function(msg) {
if(!msg.eventId) { if(!msg.eventId) {
node.error("eventId is missing"); node.error("eventId is missing", msg);
node.send([null, msg]) node.send([null, msg])
return; return;
} }
@@ -38,7 +39,7 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return; return;
} }
@@ -70,6 +71,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-delete-event",MatrixDeleteEvent); RED.nodes.registerType("matrix-delete-event",MatrixDeleteEvent);
} }
+2 -2
View File
@@ -12,9 +12,9 @@
roomId: { value: null }, roomId: { value: null },
}, },
label: function() { label: function() {
return this.name || "Room Invite"; return this.name || "Invite to Room";
}, },
paletteLabel: 'Room Invite' paletteLabel: 'Invite to Room'
}); });
</script> </script>
+9 -4
View File
@@ -9,9 +9,10 @@ module.exports = function(RED) {
this.roomId = n.roomId; this.roomId = n.roomId;
if(!this.server) { if(!this.server) {
node.error('Server must be configured on the node.'); node.error('Server must be configured on the node.', {});
return; return;
} }
node.server.register(node);
this.encodeUri = function(pathTemplate, variables) { this.encodeUri = function(pathTemplate, variables) {
for (const key in variables) { for (const key in variables) {
@@ -37,18 +38,18 @@ module.exports = function(RED) {
node.on("input", function (msg) { node.on("input", function (msg) {
if (! node.server || ! node.server.matrixClient) { if (! node.server || ! node.server.matrixClient) {
node.error("No matrix server selected"); node.error("No matrix server selected", msg);
return; return;
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;
if(!msg.topic) { if(!msg.topic) {
node.error("room must be defined in either msg.topic or in node config"); node.error("room must be defined in either msg.topic or in node config", msg);
return; return;
} }
@@ -64,6 +65,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-invite-room", MatrixInviteRoom); RED.nodes.registerType("matrix-invite-room", MatrixInviteRoom);
} }
+9 -4
View File
@@ -11,6 +11,7 @@ module.exports = function(RED) {
node.warn("No configuration node"); node.warn("No configuration node");
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -24,17 +25,17 @@ module.exports = function(RED) {
node.on("input", function (msg) { node.on("input", function (msg) {
if (! node.server || ! node.server.matrixClient) { if (! node.server || ! node.server.matrixClient) {
node.error("No matrix server selected"); node.error("No matrix server selected", msg);
return; return;
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
if(!msg.topic) { if(!msg.topic) {
node.error("Room must be specified in msg.topic"); node.error("Room must be specified in msg.topic", msg);
return; return;
} }
@@ -46,11 +47,15 @@ module.exports = function(RED) {
node.send([msg, null]); node.send([msg, null]);
}) })
.catch(function(e){ .catch(function(e){
node.error("Error trying to join room " + msg.topic + ":" + e); node.error("Error trying to join room " + msg.topic + ":" + e, msg);
msg.error = e; msg.error = e;
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-join-room", MatrixJoinRoom); RED.nodes.registerType("matrix-join-room", MatrixJoinRoom);
} }
+63
View File
@@ -0,0 +1,63 @@
<script type="text/javascript">
RED.nodes.registerType('matrix-leave-room', {
category: 'matrix',
color: '#00b7ca',
icon: "matrix.png",
outputLabels: ["success", "error"],
inputs: 1,
outputs: 2,
defaults: {
name: { value: null },
server: { value: "", type: "matrix-server-config" },
roomId: { value: null },
},
label: function() {
return this.name || "Leave Room";
},
paletteLabel: 'Leave Room'
});
</script>
<script type="text/html" data-template-name="matrix-leave-room">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-server"><i class="fa fa-user"></i> Matrix Server Config</label>
<input type="text" id="node-input-server">
</div>
</script>
<script type="text/html" data-help-name="matrix-leave-room">
<h3>Details</h3>
<p>
This node leaves a room
</p>
<h3>Inputs</h3>
<dl class="message-properties">
<dt>msg.topic
<span class="property-type">string</span>
</dt>
<dd> The room identifier to leave: for example, <code>!h8zld9j31:example.com</code>.</dd>
</dl>
<h3>Outputs</h3>
<ol class="node-ports">
<li>Success
<dl class="message-properties">
<dt>msg.payload <span class="property-type">object</span></dt>
<dd>Returns the same message that was received</dd>
</dl>
</li>
<li>Error
<dl class="message-properties">
<dt>msg.error <span class="property-type">string</span></dt>
<dd>the error that occurred.</dd>
</dl>
</li>
</ol>
</script>
+59
View File
@@ -0,0 +1,59 @@
module.exports = function(RED) {
function MatrixLeaveRoom(n) {
RED.nodes.createNode(this, n);
let node = this;
this.name = n.name;
this.server = RED.nodes.getNode(n.server);
this.roomId = n.roomId;
node.status({ fill: "red", shape: "ring", text: "disconnected" });
if (!node.server) {
node.error("No configuration node", {});
return;
}
node.server.register(node);
node.server.on("disconnected", function(){
node.status({ fill: "red", shape: "ring", text: "disconnected" });
});
node.server.on("connected", function() {
node.status({ fill: "green", shape: "ring", text: "connected" });
});
node.on('input', function(msg) {
if (! node.server || ! node.server.matrixClient) {
node.error("No matrix server selected", msg);
return;
}
if(!msg.topic) {
node.error('No room provided in msg.topic', msg);
return;
}
if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]);
}
try {
node.log("Leaving room " + msg.topic);
node.server.matrixClient.leave(msg.topic);
node.send([msg, null]);
} catch(e) {
node.error("Failed to leave room " + msg.topic + ": " + e, msg);
msg.payload = e;
node.send([null, msg]);
}
});
node.on("close", function() {
node.server.deregister(node);
});
}
RED.nodes.registerType("matrix-leave-room", MatrixLeaveRoom);
}
+10 -5
View File
@@ -13,6 +13,7 @@ module.exports = function(RED) {
node.warn("No configuration node"); node.warn("No configuration node");
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -26,30 +27,30 @@ module.exports = function(RED) {
node.on("input", function (msg) { node.on("input", function (msg) {
if (!node.server || !node.server.matrixClient) { if (!node.server || !node.server.matrixClient) {
node.error("No matrix server selected"); node.error("No matrix server selected", msg);
return; return;
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;
if(!msg.topic) { if(!msg.topic) {
node.error("Room must be specified in msg.topic or in configuration"); node.error("Room must be specified in msg.topic or in configuration", msg);
return; return;
} }
let payload = n.reaction || msg.payload; let payload = n.reaction || msg.payload;
if(!payload) { if(!payload) {
node.error('msg.payload must be defined or the reaction configured on the node.'); node.error('msg.payload must be defined or the reaction configured on the node.', msg);
return; return;
} }
let eventId = msg.referenceEventId || msg.eventId; let eventId = msg.referenceEventId || msg.eventId;
if(!eventId) { if(!eventId) {
node.error('Either msg.referenceEventId or msg.eventId must be defined to react to a message.'); node.error('Either msg.referenceEventId or msg.eventId must be defined to react to a message.', msg);
return; return;
} }
@@ -75,6 +76,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-react", MatrixReact); RED.nodes.registerType("matrix-react", MatrixReact);
} }
+78 -6
View File
@@ -15,7 +15,10 @@
acceptStickers: {"value": true}, acceptStickers: {"value": true},
acceptReactions: {"value": true}, acceptReactions: {"value": true},
acceptFiles: {"value": true}, acceptFiles: {"value": true},
acceptAudio: {"value": true},
acceptImages: {"value": true}, acceptImages: {"value": true},
acceptVideos: {"value": true},
acceptLocations: {"value": true},
}, },
label: function() { label: function() {
return this.name || "Matrix Receive"; return this.name || "Matrix Receive";
@@ -49,7 +52,7 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptText" style="width: auto"> <label for="node-input-acceptText" style="width: auto">
Accept text <code>m.text</code> Accept text <code style="text-transform: none;">m.text</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -59,7 +62,7 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptEmotes" style="width: auto"> <label for="node-input-acceptEmotes" style="width: auto">
Accept emotes <code>m.emote</code> Accept emotes <code style="text-transform: none;">m.emote</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -69,7 +72,7 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptStickers" style="width: auto"> <label for="node-input-acceptStickers" style="width: auto">
Accept stickers <code>m.sticker</code> Accept stickers <code style="text-transform: none;">m.sticker</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -79,7 +82,7 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptReactions" style="width: auto"> <label for="node-input-acceptReactions" style="width: auto">
Accept reactions <code>m.reaction</code> Accept reactions <code style="text-transform: none;">m.reaction</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -89,7 +92,17 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptFiles" style="width: auto"> <label for="node-input-acceptFiles" style="width: auto">
Accept files <code>m.file</code> Accept files <code style="text-transform: none;">m.file</code>
</label>
</div>
<div class="form-row">
<input
type="checkbox"
id="node-input-acceptAudio"
style="width: auto; margin-left: 125px; vertical-align: top"
/>
<label for="node-input-acceptAudio" style="width: auto">
Accept files <code style="text-transform: none;">m.audio</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -99,7 +112,27 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptImages" style="width: auto"> <label for="node-input-acceptImages" style="width: auto">
Accept images <code>m.image</code> Accept images <code style="text-transform: none;">m.image</code>
</label>
</div>
<div class="form-row">
<input
type="checkbox"
id="node-input-acceptVideos"
style="width: auto; margin-left: 125px; vertical-align: top"
/>
<label for="node-input-acceptVideos" style="width: auto">
Accept videos <code style="text-transform: none;">m.video</code>
</label>
</div>
<div class="form-row">
<input
type="checkbox"
id="node-input-acceptLocations"
style="width: auto; margin-left: 125px; vertical-align: top"
/>
<label for="node-input-acceptLocations" style="width: auto">
Accept locations <code style="text-transform: none;">m.location</code>
</label> </label>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
@@ -237,6 +270,38 @@
</dl> </dl>
</li> </li>
<li><code>msg.type</code> == '<strong>m.audio</strong>'
<dl class="message-properties">
<dt>msg.filename <span class="property-type">string</span></dt>
<dd>the image's parsed filename</dd>
</dl>
<dl class="message-properties">
<dt>msg.mimetype <span class="property-type">string</span></dt>
<dd>audio file mimetype (ex: audio/ogg)</dd>
</dl>
<dl class="message-properties">
<dt>msg.url <span class="property-type">string</span></dt>
<dd>the file's URL</dd>
</dl>
<dl class="message-properties">
<dt>msg.mxc_url <span class="property-type">string</span></dt>
<dd>the file's Matrix URL</dd>
</dl>
<dl class="message-properties">
<dt>msg.duration <span class="property-type">integer</span></dt>
<dd>duration of audio file in milliseconds</dd>
</dl>
<dl class="message-properties">
<dt>msg.waveform <span class="property-type">array[int]</span></dt>
<dd>waveform of the audio clip</dd>
</dl>
</li>
<li><code>msg.type</code> == '<strong>m.image</strong>' <li><code>msg.type</code> == '<strong>m.image</strong>'
<dl class="message-properties"> <dl class="message-properties">
<dt>msg.filename <span class="property-type">string</span></dt> <dt>msg.filename <span class="property-type">string</span></dt>
@@ -263,5 +328,12 @@
<dd>the image's thumbnail Matrix URL</dd> <dd>the image's thumbnail Matrix URL</dd>
</dl> </dl>
</li> </li>
<li><code>msg.type</code> == '<strong>m.location</strong>'
<dl class="message-properties">
<dt>msg.geo_uri <span class="property-type">string</span></dt>
<dd>URI format of the geolocation</dd>
</dl>
</li>
</ul> </ul>
</script> </script>
+53 -1
View File
@@ -11,16 +11,20 @@ module.exports = function(RED) {
this.acceptStickers = n.acceptStickers; this.acceptStickers = n.acceptStickers;
this.acceptReactions = n.acceptReactions; this.acceptReactions = n.acceptReactions;
this.acceptFiles = n.acceptFiles; this.acceptFiles = n.acceptFiles;
this.acceptAudio = n.acceptAudio;
this.acceptImages = n.acceptImages; this.acceptImages = n.acceptImages;
this.acceptVideos = n.acceptVideos;
this.acceptLocations = n.acceptLocations;
this.roomId = n.roomId; this.roomId = n.roomId;
this.roomIds = this.roomId ? this.roomId.split(',') : []; this.roomIds = this.roomId ? this.roomId.split(',') : [];
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
if (!node.server) { if (!node.server) {
node.error("No configuration node"); node.error("No configuration node", {});
return; return;
} }
node.server.register(node);
node.server.on("disconnected", function(){ node.server.on("disconnected", function(){
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -72,6 +76,27 @@ module.exports = function(RED) {
} }
break; break;
case 'm.audio':
if(!node.acceptAudio) return;
if(msg.encrypted) {
msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.file.url);
msg.mxc_url = msg.content.file.url;
} else {
msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url);
msg.mxc_url = msg.content.url;
}
if('org.matrix.msc1767.file' in msg.content) {
msg.filename = msg.content['org.matrix.msc1767.file'].name;
msg.mimetype = msg.content['org.matrix.msc1767.file'].mimetype;
}
if('org.matrix.msc1767.audio' in msg.content) {
msg.duration = msg.content['org.matrix.msc1767.audio'].duration;
msg.waveform = msg.content['org.matrix.msc1767.audio'].waveform;
}
break;
case 'm.image': case 'm.image':
if(!node.acceptImages) return; if(!node.acceptImages) return;
msg.filename = msg.content.filename || msg.content.body; msg.filename = msg.content.filename || msg.content.body;
@@ -88,6 +113,29 @@ module.exports = function(RED) {
} }
break; break;
case 'm.video':
if(!node.acceptVideos) return;
msg.filename = msg.content.filename || msg.content.body;
if(msg.encrypted) {
msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.file.url);
msg.mxc_url = msg.content.file.url;
msg.thumbnail_url = node.server.matrixClient.mxcUrlToHttp(msg.content.info.thumbnail_file.url);
msg.thumbnail_mxc_url = msg.content.info.thumbnail_file.url;
} else {
msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url);
msg.mxc_url = msg.content.url;
msg.thumbnail_url = node.server.matrixClient.mxcUrlToHttp(msg.content.info.thumbnail_url);
msg.thumbnail_mxc_url = msg.content.info.thumbnail_url;
}
break;
case 'm.location':
if(!node.acceptLocations) return;
msg.geo_uri = msg.content.geo_uri;
msg.payload = msg.content.body;
break;
case 'm.reaction': case 'm.reaction':
if(!node.acceptReactions) return; if(!node.acceptReactions) return;
msg.info = msg.content["m.relates_to"].info; msg.info = msg.content["m.relates_to"].info;
@@ -102,6 +150,10 @@ module.exports = function(RED) {
node.send(msg); node.send(msg);
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-receive", MatrixReceiveMessage); RED.nodes.registerType("matrix-receive", MatrixReceiveMessage);
} }
+10 -5
View File
@@ -13,6 +13,7 @@ module.exports = function(RED) {
node.warn("No configuration node"); node.warn("No configuration node");
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -26,23 +27,23 @@ module.exports = function(RED) {
node.on("input", function (msg) { node.on("input", function (msg) {
if (! node.server || ! node.server.matrixClient) { if (! node.server || ! node.server.matrixClient) {
node.error("No matrix server selected"); node.error("No matrix server selected", msg);
return; return;
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;
if(!msg.topic) { if(!msg.topic) {
node.error("Room must be specified in msg.topic or in configuration"); node.error("Room must be specified in msg.topic or in configuration", msg);
return; return;
} }
if(!msg.userId) { if(!msg.userId) {
node.error("msg.userId was not set."); node.error("msg.userId was not set.", msg);
return; return;
} }
@@ -53,11 +54,15 @@ module.exports = function(RED) {
node.send([msg, null]); node.send([msg, null]);
}) })
.catch(function(e){ .catch(function(e){
node.error("Error trying to ban " + msg.userId + " from " + msg.topic); node.error("Error trying to ban " + msg.userId + " from " + msg.topic, msg);
msg.error = e; msg.error = e;
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-room-ban", MatrixBan); RED.nodes.registerType("matrix-room-ban", MatrixBan);
} }
+80
View File
@@ -0,0 +1,80 @@
<script type="text/javascript">
RED.nodes.registerType('matrix-room-invite', {
category: 'matrix',
color: '#00b7ca',
icon: "matrix.png",
outputLabels: ["success", "error"],
inputs: 0,
outputs: 1,
defaults: {
name: { value: null },
server: { value: "", type: "matrix-server-config" },
roomId: { value: null },
},
label: function() {
return this.name || "Room Invite";
},
paletteLabel: 'Room Invite'
});
</script>
<script type="text/html" data-template-name="matrix-room-invite">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-server"><i class="fa fa-user"></i> Matrix Server Config</label>
<input type="text" id="node-input-server">
</div>
</script>
<script type="text/html" data-help-name="matrix-room-invite">
<h3>Details</h3>
<p>
This node receives room invites.
</p>
<h3>Outputs</h3>
<ol class="node-ports">
<li>Success
<dl class="message-properties">
<dt>msg.type <span class="property-type">string</span></dt>
<dd>Always <code>m.room.member</code></dd>
</dl>
<dl class="message-properties">
<dt>msg.userId <span class="property-type">string</span></dt>
<dd>ID of the user the invite is from</dd>
</dl>
<dl class="message-properties">
<dt>msg.topic <span class="property-type">string</span></dt>
<dd>The room identifier for the invite: for example, <code>!h8zld9j31:example.com</code>.</dd>
</dl>
<dl class="message-properties">
<dt>msg.topicName <span class="property-type">string</span></dt>
<dd>The invited room name.</dd>
</dl>
<dl class="message-properties">
<dt>msg.event <span class="property-type">object</span></dt>
<dd>The event object for this invite to get extra details.</dd>
</dl>
<dl class="message-properties">
<dt>msg.eventId <span class="property-type">object</span></dt>
<dd>The ID of the event for this invite.</dd>
</dl>
</li>
<li>Error
<dl class="message-properties">
<dt>msg.error <span class="property-type">string</span></dt>
<dd>the error that occurred.</dd>
</dl>
</li>
</ol>
</script>
+36
View File
@@ -0,0 +1,36 @@
module.exports = function(RED) {
function MatrixRoomInvite(n) {
RED.nodes.createNode(this, n);
let node = this;
this.name = n.name;
this.server = RED.nodes.getNode(n.server);
this.roomId = n.roomId;
if(!this.server) {
node.error('Server must be configured on the node.', {});
return;
}
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" });
node.server.on("disconnected", function(){
node.status({ fill: "red", shape: "ring", text: "disconnected" });
});
node.server.on("connected", function() {
node.status({ fill: "green", shape: "ring", text: "connected" });
});
node.server.on("Room.invite", async function(msg) {
node.send(msg);
});
node.on("close", function() {
node.server.deregister(node);
});
}
RED.nodes.registerType("matrix-room-invite", MatrixRoomInvite);
}
+10 -5
View File
@@ -13,6 +13,7 @@ module.exports = function(RED) {
node.warn("No configuration node"); node.warn("No configuration node");
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -26,23 +27,23 @@ module.exports = function(RED) {
node.on("input", function (msg) { node.on("input", function (msg) {
if (! node.server || ! node.server.matrixClient) { if (! node.server || ! node.server.matrixClient) {
node.error("No matrix server selected"); node.error("No matrix server selected", msg);
return; return;
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;
if(!msg.topic) { if(!msg.topic) {
node.error("Room must be specified in msg.topic or in configuration"); node.error("Room must be specified in msg.topic or in configuration", msg);
return; return;
} }
if(!msg.userId) { if(!msg.userId) {
node.error("msg.userId was not set."); node.error("msg.userId was not set.", msg);
return; return;
} }
@@ -53,11 +54,15 @@ module.exports = function(RED) {
node.send([msg, null]); node.send([msg, null]);
}) })
.catch(function(e){ .catch(function(e){
node.error("Error trying to kick " + msg.userId + " from " + msg.topic); node.error("Error trying to kick " + msg.userId + " from " + msg.topic, msg);
msg.error = e; msg.error = e;
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-room-kick", MatrixKick); RED.nodes.registerType("matrix-room-kick", MatrixKick);
} }
+7 -2
View File
@@ -13,6 +13,7 @@ module.exports = function(RED) {
node.warn("No configuration node"); node.warn("No configuration node");
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -31,13 +32,13 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
let roomId = node.roomId || msg.topic; let roomId = node.roomId || msg.topic;
if(!roomId) { if(!roomId) {
node.error("msg.topic is required. Specify in the input or configure the room ID on the node."); node.error("msg.topic is required. Specify in the input or configure the room ID on the node.", msg);
return; return;
} }
@@ -65,6 +66,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-room-users", MatrixRoomUsers); RED.nodes.registerType("matrix-room-users", MatrixRoomUsers);
} }
+7 -2
View File
@@ -13,6 +13,7 @@ module.exports = function(RED) {
node.warn("No configuration node"); node.warn("No configuration node");
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -31,7 +32,7 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
@@ -57,7 +58,7 @@ module.exports = function(RED) {
} }
if(!msg.payload) { if(!msg.payload) {
node.error('msg.payload is required'); node.error('msg.payload is required', msg);
return; return;
} }
@@ -94,6 +95,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-send-file", MatrixSendFile); RED.nodes.registerType("matrix-send-file", MatrixSendFile);
} }
+7 -2
View File
@@ -13,6 +13,7 @@ module.exports = function(RED) {
node.warn("No configuration node"); node.warn("No configuration node");
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -31,7 +32,7 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
@@ -57,7 +58,7 @@ module.exports = function(RED) {
} }
if(!msg.payload) { if(!msg.payload) {
node.error('msg.payload is required'); node.error('msg.payload is required', msg);
return; return;
} }
@@ -98,6 +99,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-send-image", MatrixSendImage); RED.nodes.registerType("matrix-send-image", MatrixSendImage);
} }
+9 -4
View File
@@ -54,6 +54,7 @@ module.exports = function(RED) {
node.warn("No configuration node"); node.warn("No configuration node");
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
@@ -71,7 +72,7 @@ module.exports = function(RED) {
if(msgType === 'msg.type') { if(msgType === 'msg.type') {
if(!msg.type) { if(!msg.type) {
node.error("msg.type type is set to be passed in via msg.type but was not defined"); node.error("msg.type type is set to be passed in via msg.type but was not defined", msg);
return; return;
} }
msgType = msg.type; msgType = msg.type;
@@ -79,7 +80,7 @@ module.exports = function(RED) {
if(msgFormat === 'msg.format') { if(msgFormat === 'msg.format') {
if(!msg.format) { if(!msg.format) {
node.error("Message format is set to be passed in via msg.format but was not defined"); node.error("Message format is set to be passed in via msg.format but was not defined", msg);
return; return;
} }
msgFormat = msg.format; msgFormat = msg.format;
@@ -91,7 +92,7 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return; return;
} }
@@ -104,7 +105,7 @@ module.exports = function(RED) {
let payload = n.message || msg.payload; let payload = n.message || msg.payload;
if(!payload) { if(!payload) {
node.error('msg.payload must be defined or the message configured on the node.'); node.error('msg.payload must be defined or the message configured on the node.', msg);
return; return;
} }
@@ -152,6 +153,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-send-message", MatrixSendImage); RED.nodes.registerType("matrix-send-message", MatrixSendImage);
} }
+2 -2
View File
@@ -162,7 +162,7 @@
$("#matrix-access-token-loader").show(); $("#matrix-access-token-loader").show();
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/matrix-chat/login', url: 'matrix-chat/login',
dataType: 'json', dataType: 'json',
data: { data: {
'userId': userId, 'userId': userId,
@@ -214,4 +214,4 @@
<p>If this is a server you do not administrate/have access to follow these instructions:</p> <p>If this is a server you do not administrate/have access to follow these instructions:</p>
<ol><li>In a private/incognito browser window, open Element.</li><li>Log in to the account you want to get the access token for, such as the bot's account. <strong>Do not setup key storage</strong>.</li><li>Click on the bot's name in the top left corner then "Settings".</li><li>(Optional) Set your bot's display name and avatar.</li><li>Click the "Help &amp; About" tab (left side of the dialog).</li><li>Scroll to the bottom and click the <code>&lt;click to reveal&gt;</code> part of <code>Access Token: &lt;click to reveal&gt;</code>.</li><li>Copy your access token to a safe place, like the bot's configuration file.</li><li><strong>Do not log out.</strong> Instead, just close the window. If you used a private browsing session, you should be able to still use Element for your own account. Logging out deletes the access token from the server, making the bot unable to use it.</li></ol> <ol><li>In a private/incognito browser window, open Element.</li><li>Log in to the account you want to get the access token for, such as the bot's account. <strong>Do not setup key storage</strong>.</li><li>Click on the bot's name in the top left corner then "Settings".</li><li>(Optional) Set your bot's display name and avatar.</li><li>Click the "Help &amp; About" tab (left side of the dialog).</li><li>Scroll to the bottom and click the <code>&lt;click to reveal&gt;</code> part of <code>Access Token: &lt;click to reveal&gt;</code>.</li><li>Copy your access token to a safe place, like the bot's configuration file.</li><li><strong>Do not log out.</strong> Instead, just close the window. If you used a private browsing session, you should be able to still use Element for your own account. Logging out deletes the access token from the server, making the bot unable to use it.</li></ol>
</div> </div>
</script> </script>
+72 -27
View File
@@ -4,11 +4,30 @@ const sdk = require("matrix-js-sdk");
const { resolve } = require('path'); const { resolve } = require('path');
const { LocalStorage } = require('node-localstorage'); const { LocalStorage } = require('node-localstorage');
const { LocalStorageCryptoStore } = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store'); const { LocalStorageCryptoStore } = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store');
const {RoomEvent, RoomMemberEvent, HttpApiEvent, ClientEvent} = require("matrix-js-sdk"); const {RoomEvent, RoomMemberEvent, HttpApiEvent, ClientEvent, MemoryStore} = require("matrix-js-sdk");
const {deriveKey} = require("matrix-js-sdk/lib/crypto/key_passphrase"); const request = require("request");
const {encryptAES} = require("matrix-js-sdk/lib/crypto/aes"); require("abort-controller/polyfill"); // polyfill abort-controller if we don't have it
if (!globalThis.fetch) {
// polyfill fetch if we don't have it
if (!globalThis.fetch) {
import('node-fetch').then(({ default: fetch, Headers, Request, Response }) => {
Object.assign(globalThis, { fetch, Headers, Request, Response })
})
}
}
module.exports = function(RED) { module.exports = function(RED) {
// disable logging if set to "off"
let loggingSettings = RED.settings.get('logging');
if(
typeof loggingSettings.console !== 'undefined' &&
typeof loggingSettings.console.level !== 'undefined' &&
['info','debug','trace'].indexOf(loggingSettings.console.level.toLowerCase()) >= 0
) {
const { logger } = require('matrix-js-sdk/lib/logger');
logger.disableAll();
}
function MatrixFolderNameFromUserId(name) { function MatrixFolderNameFromUserId(name) {
return name.replace(/[^a-z0-9]/gi, '_').toLowerCase(); return name.replace(/[^a-z0-9]/gi, '_').toLowerCase();
} }
@@ -25,6 +44,7 @@ module.exports = function(RED) {
this.credentials = {}; this.credentials = {};
} }
this.users = {};
this.connected = null; this.connected = null;
this.name = n.name; this.name = n.name;
this.userId = this.credentials.userId; this.userId = this.credentials.userId;
@@ -36,6 +56,14 @@ module.exports = function(RED) {
this.globalAccess = n.global; this.globalAccess = n.global;
this.initializedAt = new Date(); this.initializedAt = new Date();
// Keep track of all consumers of this node to be able to catch errors
node.register = function(consumerNode) {
node.users[consumerNode.id] = consumerNode;
};
node.deregister = function(consumerNode) {
delete node.users[consumerNode.id];
};
if(!this.userId) { if(!this.userId) {
node.log("Matrix connection failed: missing user ID in configuration."); node.log("Matrix connection failed: missing user ID in configuration.");
@@ -49,9 +77,9 @@ module.exports = function(RED) {
let retryStartTimeout = null; let retryStartTimeout = null;
if(!this.credentials.accessToken) { if(!this.credentials.accessToken) {
node.error("Matrix connection failed: missing access token in configuration."); node.error("Matrix connection failed: missing access token in configuration.", {});
} else if(!this.url) { } else if(!this.url) {
node.error("Matrix connection failed: missing server URL in configuration."); node.error("Matrix connection failed: missing server URL in configuration.", {});
} else { } else {
node.setConnected = async function(connected, cb) { node.setConnected = async function(connected, cb) {
if (node.connected !== connected) { if (node.connected !== connected) {
@@ -69,7 +97,7 @@ module.exports = function(RED) {
device_id = this.matrixClient.getDeviceId(); device_id = this.matrixClient.getDeviceId();
if(!device_id && node.enableE2ee) { if(!device_id && node.enableE2ee) {
node.error("Failed to auto detect deviceId for this auth token. You will need to manually specify one. You may need to login to create a new deviceId.") node.error("Failed to auto detect deviceId for this auth token. You will need to manually specify one. You may need to login to create a new deviceId.", {})
} else { } else {
if(!stored_device_id || stored_device_id !== device_id) { if(!stored_device_id || stored_device_id !== device_id) {
node.log(`Saving Device ID (old:${stored_device_id} new:${device_id})`); node.log(`Saving Device ID (old:${stored_device_id} new:${device_id})`);
@@ -88,13 +116,13 @@ module.exports = function(RED) {
}).then( }).then(
function(response) {}, function(response) {},
function(error) { function(error) {
node.error("Failed to set device label: " + error); node.error("Failed to set device label: " + error, {});
} }
); );
} }
}, },
function(error) { function(error) {
node.error("Failed to fetch device: " + error); node.error("Failed to fetch device: " + error, {});
} }
); );
} }
@@ -118,10 +146,13 @@ module.exports = function(RED) {
node.matrixClient = sdk.createClient({ node.matrixClient = sdk.createClient({
baseUrl: this.url, baseUrl: this.url,
accessToken: this.credentials.accessToken, accessToken: this.credentials.accessToken,
sessionStore: new sdk.WebStorageSessionStore(localStorage),
cryptoStore: new LocalStorageCryptoStore(localStorage), cryptoStore: new LocalStorageCryptoStore(localStorage),
store: new MemoryStore({
localStorage: localStorage,
}),
userId: this.userId, userId: this.userId,
deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined, deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined,
request
// verificationMethods: ["m.sas.v1"] // verificationMethods: ["m.sas.v1"]
}); });
@@ -167,7 +198,7 @@ module.exports = function(RED) {
try { try {
await node.matrixClient.decryptEventIfNeeded(event); await node.matrixClient.decryptEventIfNeeded(event);
} catch (error) { } catch (error) {
node.error(error); node.error(error, {});
return; return;
} }
@@ -232,16 +263,29 @@ module.exports = function(RED) {
// handle auto-joining rooms // handle auto-joining rooms
node.matrixClient.on(RoomMemberEvent.Membership, async function(event, member) { node.matrixClient.on(RoomMemberEvent.Membership, async function(event, member) {
if(node.initializedAt > event.getDate()) {
return; // skip events that occurred before our client initialized
}
if (member.membership === "invite" && member.userId === node.userId) { if (member.membership === "invite" && member.userId === node.userId) {
node.log("Got invite to join room " + member.roomId);
if(node.autoAcceptRoomInvites) { if(node.autoAcceptRoomInvites) {
node.matrixClient.joinRoom(member.roomId).then(function() { node.matrixClient.joinRoom(member.roomId).then(function() {
node.log("Automatically accepted invitation to join room " + member.roomId); node.log("Automatically accepted invitation to join room " + member.roomId);
}).catch(function(e) { }).catch(function(e) {
node.warn("Cannot join room (could be from being kicked/banned) " + member.roomId + ": " + e); node.warn("Cannot join room (could be from being kicked/banned) " + member.roomId + ": " + e);
}); });
} else {
node.log("Got invite to join room " + member.roomId);
} }
let room = node.matrixClient.getRoom(event.getRoomId());
node.emit("Room.invite", {
type : 'm.room.member',
userId : event.getSender(),
topic : event.getRoomId(),
topicName : (room ? room.name : null) || null,
event : event,
eventId : event.getId(),
});
} }
}); });
@@ -256,7 +300,7 @@ module.exports = function(RED) {
} else if(prevState === null && state === "ERROR") { } else if(prevState === null && state === "ERROR") {
// Occurs when the initial sync failed first time. // Occurs when the initial sync failed first time.
node.setConnected(false, function(){ node.setConnected(false, function(){
node.error("Failed to connect to Matrix server"); node.error("Failed to connect to Matrix server", {});
}); });
} else if(prevState === "ERROR" && state === "PREPARED") { } else if(prevState === "ERROR" && state === "PREPARED") {
// Occurs when the initial sync succeeds // Occurs when the initial sync succeeds
@@ -273,18 +317,18 @@ module.exports = function(RED) {
} else if(prevState === "SYNCING" && state === "RECONNECTING") { } else if(prevState === "SYNCING" && state === "RECONNECTING") {
// Occurs when the live update fails. // Occurs when the live update fails.
node.setConnected(false, function(){ node.setConnected(false, function(){
node.error("Connection to Matrix server lost"); node.error("Connection to Matrix server lost", {});
}); });
} else if(prevState === "RECONNECTING" && state === "RECONNECTING") { } else if(prevState === "RECONNECTING" && state === "RECONNECTING") {
// Can occur if the update calls continue to fail, // Can occur if the update calls continue to fail,
// but the keepalive calls (to /versions) succeed. // but the keepalive calls (to /versions) succeed.
node.setConnected(false, function(){ node.setConnected(false, function(){
node.error("Connection to Matrix server lost"); node.error("Connection to Matrix server lost", {});
}); });
} else if(prevState === "RECONNECTING" && state === "ERROR") { } else if(prevState === "RECONNECTING" && state === "ERROR") {
// Occurs when the keepalive call also fails // Occurs when the keepalive call also fails
node.setConnected(false, function(){ node.setConnected(false, function(){
node.error("Connection to Matrix server lost"); node.error("Connection to Matrix server lost", {});
}); });
} else if(prevState === "ERROR" && state === "SYNCING") { } else if(prevState === "ERROR" && state === "SYNCING") {
// Occurs when the client has performed a // Occurs when the client has performed a
@@ -296,7 +340,7 @@ module.exports = function(RED) {
// Occurs when the client has failed to // Occurs when the client has failed to
// keepalive for a second time or more. // keepalive for a second time or more.
node.setConnected(false, function(){ node.setConnected(false, function(){
node.error("Connection to Matrix server lost"); node.error("Connection to Matrix server lost", {});
}); });
} else if(prevState === "SYNCING" && state === "SYNCING") { } else if(prevState === "SYNCING" && state === "SYNCING") {
// Occurs when the client has performed a live update. // Occurs when the client has performed a live update.
@@ -308,7 +352,7 @@ module.exports = function(RED) {
// Occurs once the client has stopped syncing or // Occurs once the client has stopped syncing or
// trying to sync after stopClient has been called. // trying to sync after stopClient has been called.
node.setConnected(false, function(){ node.setConnected(false, function(){
node.error("Connection to Matrix server lost"); node.error("Connection to Matrix server lost", {});
}); });
} }
}); });
@@ -326,7 +370,7 @@ module.exports = function(RED) {
// httpStatus: 401 // httpStatus: 401
// } // }
node.error("Authentication failure: " + errorObj); node.error("Authentication failure: " + errorObj, {});
stopClient(); stopClient();
}); });
@@ -342,7 +386,7 @@ module.exports = function(RED) {
initialSyncLimit: 8 initialSyncLimit: 8
}); });
} catch(error) { } catch(error) {
node.error(error); node.error(error, {});
} }
} }
@@ -363,7 +407,7 @@ module.exports = function(RED) {
.then( .then(
function(data) { function(data) {
if((typeof data['device_id'] === undefined || !data['device_id']) && !node.deviceId && !getStoredDeviceId(localStorage)) { if((typeof data['device_id'] === undefined || !data['device_id']) && !node.deviceId && !getStoredDeviceId(localStorage)) {
node.error("/whoami request did not return device_id. You will need to manually set one in your configuration because this cannot be automatically fetched."); node.error("/whoami request did not return device_id. You will need to manually set one in your configuration because this cannot be automatically fetched.", {});
} }
if('device_id' in data && data['device_id'] && !node.deviceId) { if('device_id' in data && data['device_id'] && !node.deviceId) {
// if we have no device_id configured lets use the one // if we have no device_id configured lets use the one
@@ -373,7 +417,7 @@ module.exports = function(RED) {
// make sure our userId matches the access token's // make sure our userId matches the access token's
if(data['user_id'].toLowerCase() !== node.userId.toLowerCase()) { if(data['user_id'].toLowerCase() !== node.userId.toLowerCase()) {
node.error(`User ID provided is ${node.userId} but token belongs to ${data['user_id']}`); node.error(`User ID provided is ${node.userId} but token belongs to ${data['user_id']}`, {});
return; return;
} }
run().catch((error) => node.error(error)); run().catch((error) => node.error(error));
@@ -382,7 +426,7 @@ module.exports = function(RED) {
// if the error isn't authentication related retry in a little bit // if the error isn't authentication related retry in a little bit
if(err.code !== "M_UNKNOWN_TOKEN") { if(err.code !== "M_UNKNOWN_TOKEN") {
retryStartTimeout = setTimeout(checkAuthTokenThenStart, 15000); retryStartTimeout = setTimeout(checkAuthTokenThenStart, 15000);
node.error("Auth check failed: " + err); node.error("Auth check failed: " + err, {});
} }
} }
) )
@@ -413,7 +457,8 @@ module.exports = function(RED) {
const matrixClient = sdk.createClient({ const matrixClient = sdk.createClient({
baseUrl: baseUrl, baseUrl: baseUrl,
deviceId: deviceId, deviceId: deviceId,
localTimeoutMs: '30000' localTimeoutMs: '30000',
request
}); });
matrixClient.login( matrixClient.login(
@@ -444,7 +489,7 @@ module.exports = function(RED) {
let oldStorageDir = './matrix-local-storage', let oldStorageDir = './matrix-local-storage',
oldStorageDir2 = './matrix-client-storage'; oldStorageDir2 = './matrix-client-storage';
// if the old storage location exists lets move it to it's new location // if the old storage location exists lets move it to the new location
if(fs.pathExistsSync(oldStorageDir)){ if(fs.pathExistsSync(oldStorageDir)){
RED.nodes.eachNode(function(n){ RED.nodes.eachNode(function(n){
try { try {
@@ -457,7 +502,7 @@ module.exports = function(RED) {
fs.copySync(oldStorageDir, dir); fs.copySync(oldStorageDir, dir);
} }
} catch (err) { } catch (err) {
console.error(err) node.error(err, {});
} }
}); });
@@ -466,7 +511,7 @@ module.exports = function(RED) {
fs.renameSync(oldStorageDir, oldStorageDir + "-backup"); fs.renameSync(oldStorageDir, oldStorageDir + "-backup");
} }
if(RED.settings.userDir !== resolve('./')) { if(RED.settings.userDir !== resolve('./') && resolve(oldStorageDir2) !== resolve(storageDir)) {
// user directory does not match running directory // user directory does not match running directory
// check if we stored stuff in wrong directory and move it // check if we stored stuff in wrong directory and move it
if(fs.pathExistsSync(oldStorageDir2)){ if(fs.pathExistsSync(oldStorageDir2)){
+15 -11
View File
@@ -8,9 +8,10 @@ module.exports = function(RED) {
this.server = RED.nodes.getNode(n.server); this.server = RED.nodes.getNode(n.server);
if(!this.server) { if(!this.server) {
node.error('Server must be configured on the node.'); node.error('Server must be configured on the node.', {});
return; return;
} }
node.server.register(node);
this.encodeUri = function(pathTemplate, variables) { this.encodeUri = function(pathTemplate, variables) {
for (const key in variables) { for (const key in variables) {
@@ -41,18 +42,17 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
if(!msg.userId) { if(!msg.userId) {
node.error("msg.userId must be set to edit/create a user (ex: @user:server.com)"); node.error("msg.userId must be set to edit/create a user (ex: @user:server.com)", msg);
return; return;
} }
node.server.matrixClient.http node.server.matrixClient.http
.authedRequest( .authedRequest(
undefined,
'PUT', 'PUT',
node.encodeUri( node.encodeUri(
"/_synapse/admin/v2/users/$userId", "/_synapse/admin/v2/users/$userId",
@@ -62,13 +62,17 @@ module.exports = function(RED) {
msg.payload, msg.payload,
{ prefix: '' } { prefix: '' }
).then(function(e){ ).then(function(e){
msg.payload = e; msg.payload = e;
node.send([msg, null]); node.send([msg, null]);
}).catch(function(e){ }).catch(function(e){
node.warn("Error creating/editing user " + e); node.warn("Error creating/editing user " + e);
msg.error = e; msg.error = e;
node.send([null, msg]); node.send([null, msg]);
}); });
});
node.on("close", function() {
node.server.deregister(node);
}); });
} }
RED.nodes.registerType("matrix-synapse-create-edit-user", MatrixSynapseCreateEditUser); RED.nodes.registerType("matrix-synapse-create-edit-user", MatrixSynapseCreateEditUser);
+8 -4
View File
@@ -8,9 +8,10 @@ module.exports = function(RED) {
this.server = RED.nodes.getNode(n.server); this.server = RED.nodes.getNode(n.server);
if(!this.server) { if(!this.server) {
node.error('Server must be configured on the node.'); node.error('Server must be configured on the node.', {});
return; return;
} }
node.server.register(node);
this.encodeUri = function(pathTemplate, variables) { this.encodeUri = function(pathTemplate, variables) {
for (const key in variables) { for (const key in variables) {
@@ -41,12 +42,12 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
if(!msg.userId) { if(!msg.userId) {
node.error("msg.userId must be set to edit/create a user (ex: @user:server.com)"); node.error("msg.userId must be set to edit/create a user (ex: @user:server.com)", msg);
return; return;
} }
@@ -56,7 +57,6 @@ module.exports = function(RED) {
); );
node.server.matrixClient.http node.server.matrixClient.http
.authedRequest( .authedRequest(
undefined,
'POST', 'POST',
path, path,
undefined, undefined,
@@ -71,6 +71,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-synapse-deactivate-user", MatrixSynapseDeactivateUser); RED.nodes.registerType("matrix-synapse-deactivate-user", MatrixSynapseDeactivateUser);
} }
+8 -6
View File
@@ -9,10 +9,9 @@ module.exports = function(RED) {
this.roomId = n.roomId; this.roomId = n.roomId;
if(!this.server) { if(!this.server) {
node.error('Server must be configured on the node.'); node.error('Server must be configured on the node.', {});
return; return;
} }
this.encodeUri = function(pathTemplate, variables) { this.encodeUri = function(pathTemplate, variables) {
for (const key in variables) { for (const key in variables) {
if (!variables.hasOwnProperty(key)) { if (!variables.hasOwnProperty(key)) {
@@ -42,25 +41,24 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;
if(!msg.topic) { if(!msg.topic) {
node.error("room must be defined in either msg.topic or in node config"); node.error("room must be defined in either msg.topic or in node config", msg);
return; return;
} }
if(!msg.userId) { if(!msg.userId) {
node.error("msg.userId is required to set user into a room"); node.error("msg.userId is required to set user into a room", msg);
return; return;
} }
// we need the status code, so set onlydata to false for this request // we need the status code, so set onlydata to false for this request
node.server.matrixClient.http node.server.matrixClient.http
.authedRequest( .authedRequest(
undefined,
'POST', 'POST',
node.encodeUri( node.encodeUri(
"/_synapse/admin/v1/join/$room_id_or_alias", "/_synapse/admin/v1/join/$room_id_or_alias",
@@ -78,6 +76,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-synapse-join-room", MatrixJoinRoom); RED.nodes.registerType("matrix-synapse-join-room", MatrixJoinRoom);
} }
+9 -5
View File
@@ -12,12 +12,12 @@ module.exports = function(RED) {
this.sharedSecret = this.credentials.sharedSecret; this.sharedSecret = this.credentials.sharedSecret;
if(!this.server) { if(!this.server) {
node.error('Server URL must be configured on the node.'); node.error('Server URL must be configured on the node.', {});
return; return;
} }
if(!this.sharedSecret) { if(!this.sharedSecret) {
node.error('Shared registration secret must be configured on the node.'); node.error('Shared registration secret must be configured on the node.', {});
return; return;
} }
@@ -25,12 +25,12 @@ module.exports = function(RED) {
const { got } = await import('got'); const { got } = await import('got');
if(!msg.payload.username) { if(!msg.payload.username) {
node.error("msg.payload.username is required"); node.error("msg.payload.username is required", msg);
return; return;
} }
if(!msg.payload.password) { if(!msg.payload.password) {
node.error("msg.payload.password is required"); node.error("msg.payload.password is required", msg);
return; return;
} }
@@ -50,7 +50,7 @@ module.exports = function(RED) {
var nonce = response.body.nonce; var nonce = response.body.nonce;
if(!nonce) { if(!nonce) {
node.error('Could not get nonce from /_synapse/admin/v1/register'); node.error('Could not get nonce from /_synapse/admin/v1/register', msg);
return; return;
} }
@@ -96,6 +96,10 @@ module.exports = function(RED) {
node.send(msg); node.send(msg);
})(); })();
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-synapse-register", MatrixSynapseRegister, { RED.nodes.registerType("matrix-synapse-register", MatrixSynapseRegister, {
credentials: { credentials: {
+7 -2
View File
@@ -12,6 +12,8 @@ module.exports = function(RED) {
return; return;
} }
node.server.register(node);
node.status({ fill: "red", shape: "ring", text: "disconnected" }); node.status({ fill: "red", shape: "ring", text: "disconnected" });
node.server.on("disconnected", function(){ node.server.on("disconnected", function(){
@@ -29,7 +31,7 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
@@ -48,7 +50,6 @@ module.exports = function(RED) {
node.server.matrixClient.http node.server.matrixClient.http
.authedRequest( .authedRequest(
undefined,
'GET', 'GET',
"/_synapse/admin/v2/users", "/_synapse/admin/v2/users",
queryParams, queryParams,
@@ -63,6 +64,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-synapse-users", MatrixSynapseUsers); RED.nodes.registerType("matrix-synapse-users", MatrixSynapseUsers);
} }
+9 -4
View File
@@ -8,10 +8,12 @@ module.exports = function(RED) {
this.server = RED.nodes.getNode(n.server); this.server = RED.nodes.getNode(n.server);
if(!this.server) { if(!this.server) {
node.error('Server must be configured on the node.'); node.error('Server must be configured on the node.', {});
return; return;
} }
node.server.register(node);
this.encodeUri = function(pathTemplate, variables) { this.encodeUri = function(pathTemplate, variables) {
for (const key in variables) { for (const key in variables) {
if (!variables.hasOwnProperty(key)) { if (!variables.hasOwnProperty(key)) {
@@ -41,19 +43,18 @@ module.exports = function(RED) {
} }
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed"); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
} }
if(!msg.userId) { if(!msg.userId) {
node.error("msg.userId must be set to get user whois data"); node.error("msg.userId must be set to get user whois data", msg);
return; return;
} }
// we need the status code, so set onlydata to false for this request // we need the status code, so set onlydata to false for this request
node.server.matrixClient.http node.server.matrixClient.http
.authedRequest( .authedRequest(
undefined,
'GET', 'GET',
node.encodeUri( node.encodeUri(
"/_matrix/client/r0/admin/whois/$userId", "/_matrix/client/r0/admin/whois/$userId",
@@ -71,6 +72,10 @@ module.exports = function(RED) {
node.send([null, msg]); node.send([null, msg]);
}); });
}); });
node.on("close", function() {
node.server.deregister(node);
});
} }
RED.nodes.registerType("matrix-whois-user", MatrixWhoIsUser); RED.nodes.registerType("matrix-whois-user", MatrixWhoIsUser);
} }