Merge pull request #22 from Skylar-Tech/21-global-client

Global access to matrix client so user's can do whatever they want
This commit is contained in:
Skylar Sadlier 2021-09-03 08:51:32 -06:00 committed by GitHub
commit 63728d86a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 176 additions and 19 deletions

View File

@ -30,9 +30,6 @@ The following is supported from this package:
Therefore, you can easily build a bot, chat relay, or administrate your Matrix server from within [Node-RED](https://nodered.org/).
### Usage
We have examples! [Check them out](https://github.com/Skylar-Tech/node-red-contrib-matrix-chat/tree/master/examples#readme)
### Installing
You can either install from within Node-RED by searching for `node-red-contrib-matrix-chat` or run this from within your Node-RED directory:
@ -40,8 +37,16 @@ You can either install from within Node-RED by searching for `node-red-contrib-m
npm install node-red-contrib-matrix-chat
```
### Usage
We have examples! [Check them out](https://github.com/Skylar-Tech/node-red-contrib-matrix-chat/tree/master/examples#readme)
#### Extra functionality
You are not limited by just the nodes we have created. If you turn on global access when setting up your Matrix Client you can access the client directly from any function node to write your own logic.
View an example [here](https://github.com/Skylar-Tech/node-red-contrib-matrix-chat/tree/master/examples#use-function-node-to-run-any-command)
### End-to-End Encryption Notes
Currently this module has no way of getting encryption keys from other devices on the same account. Therefore it is recommended you use the bot exclusively with Node-RED after it's creation. Failure to do so will lead to your bot being unable to receive messages from e2ee rooms it joined from another client. Shared secret registration makes this super easy since it returns a token and device ID.
Currently, this module has no way of getting encryption keys from other devices on the same account. Therefore it is recommended you use the bot exclusively with Node-RED after it's creation. Failure to do so will lead to your bot being unable to receive messages from e2ee rooms it joined from another client. Shared secret registration makes this super easy since it returns a token and device ID.
This module stores a folder in your Node-RED directory called `matrix-client-storage` and is it vital that you periodically back this up if you are using e2ee. This is where the client stores all the keys necessary to decrypt messages and if lost you will lose access to e2e rooms. If you move your client to another NR install make sure to migrate this folder as well (and do not let both the old and new client run at same time).

View File

@ -9,6 +9,7 @@ Build something cool with these nodes? Feel free to submit a pull request to sha
- [Create User with Shared Secret Registration](#create-user-with-shared-secret-registration)
- [Create/Edit Synapse User](#createedit-synapse-user)
- [Use function node to run any command](#use-function-node-to-run-any-command)
- [Respond to "ping" with "pong"](#respond-to-ping-with-pong)
- [Respond to "html" with an HTML message](#respond-to-html-with-an-html-message)
- [Respond to "image" with an uploaded image](#respond-to-image-with-an-uploaded-image)
@ -39,6 +40,18 @@ Allows an administrator to create or modify a user account with a specified `msg
![img.png](add-user-with-admin-user.png)
### Use function node to run any command
[View JSON](custom-redact-function-node.json)
If we do not have a node for something you want to do (such as redacting events/messages) you can do this manually with a function node.
**Note:** You should make sure to catch any errors in your function node otherwise you could cause Node-RED to crash.
To view what sort of functions you have access to check out the `client.ts` file from `matrix-js-sdk` [here](https://github.com/matrix-org/matrix-js-sdk/blob/master/src/client.ts).
![img.png](custom-redact-function-node.png)
### Respond to "ping" with "pong"
[View JSON](respond-to-html-with-html.json)

View File

@ -0,0 +1,113 @@
[
{
"id": "89eed7ddf7a96070",
"type": "function",
"z": "f025a8b9fbd1b054",
"name": "Redact Message",
"func": "let matrixClient = global.get(\"matrixClient['@bot:example.com']\"),\n matrixOnline = global.get(\"matrixClientOnline['@bot:example.com']\");\n\nif(!matrixOnline) {\n msg.error = 'Matrix client not connected.';\n return [null, msg];\n}\n \nmatrixClient.redactEvent(msg.topic, msg.eventId, undefined, {\n reason: 'Redacted, muhahaha!'\n})\n .then(function(e) {\n msg.eventId = e.eventId;\n node.send([msg, null]);\n })\n .catch(function(e){\n node.warn(\"Error sending message \" + e);\n msg.error = e;\n node.send([null, msg]);\n });",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 730,
"y": 1580,
"wires": [
[
"5decd492e2da79d9"
],
[
"fadcf8c32bdfd8be"
]
]
},
{
"id": "5decd492e2da79d9",
"type": "debug",
"z": "f025a8b9fbd1b054",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 890,
"y": 1560,
"wires": []
},
{
"id": "f3636f4221511a81",
"type": "comment",
"z": "f025a8b9fbd1b054",
"name": "If message is \"redact\" then redact the message.",
"info": "",
"x": 420,
"y": 1540,
"wires": []
},
{
"id": "9f777828840bb9a2",
"type": "matrix-receive",
"z": "f025a8b9fbd1b054",
"name": "",
"roomId": "",
"acceptText": true,
"acceptEmotes": false,
"acceptStickers": false,
"acceptReactions": false,
"acceptFiles": false,
"acceptImages": false,
"x": 320,
"y": 1580,
"wires": [
[
"21a00b09f8c85399"
]
]
},
{
"id": "21a00b09f8c85399",
"type": "switch",
"z": "f025a8b9fbd1b054",
"name": "filter on msg.payload",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "redact",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 520,
"y": 1580,
"wires": [
[
"89eed7ddf7a96070"
]
]
},
{
"id": "fadcf8c32bdfd8be",
"type": "debug",
"z": "f025a8b9fbd1b054",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 890,
"y": 1600,
"wires": []
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -11,7 +11,8 @@
defaults: {
name: { value: null },
autoAcceptRoomInvites: { value: true },
enableE2ee: { type: "checkbox", value: true }
enableE2ee: { type: "checkbox", value: true },
global: { type: "checkbox", value: true }
},
icon: "matrix.png",
label: function() {
@ -67,10 +68,24 @@
Enable end-to-end encryption (requires DeviceID)
</label>
</div>
<div class="form-tips" style="margin-bottom: 12px;">
E2ee requires a Device ID to be set.
</div>
<div class="form-row">
<input
type="checkbox"
id="node-config-input-global"
style="width: auto; margin-left: 125px; vertical-align: top"
/>
<label for="node-config-input-global" style="width: auto">
Global access to Matrix Client
</label>
<div class="form-tips" style="margin-bottom: 12px;">
If enabled this allows you to access the matrix client directly with a Function node. This way you can do whatever you want with the client.<br />
Example: <code>let client = global.get("matrixClient['@bot:example.com']")</code>
</div>
</div>
</script>
<script type="text/html" data-help-name="matrix-server-config">

View File

@ -26,7 +26,7 @@ module.exports = function(RED) {
node.setMaxListeners(1000);
this.connected = false;
this.connected = null;
this.name = n.name;
this.userId = this.credentials.userId;
this.deviceId = this.credentials.deviceId || null;
@ -34,6 +34,7 @@ module.exports = function(RED) {
this.autoAcceptRoomInvites = n.autoAcceptRoomInvites;
this.enableE2ee = n.enableE2ee || false;
this.e2ee = (this.enableE2ee && this.deviceId);
this.globalAccess = n.global;
if(!this.credentials.accessToken) {
node.log("Matrix connection failed: missing access token.");
@ -42,6 +43,23 @@ module.exports = function(RED) {
} else if(!this.userId) {
node.log("Matrix connection failed: missing user ID.");
} else {
node.setConnected = function(connected) {
if (node.connected !== connected) {
node.connected = connected;
if (connected) {
node.log("Matrix server connection ready.");
node.emit("connected");
} else {
node.emit("disconnected");
}
if(this.globalAccess) {
this.context().global.set('matrixClientOnline["'+this.userId+'"]', connected);
}
}
};
node.setConnected(false);
let localStorageDir = storageDir + '/' + MatrixFolderNameFromUserId(this.userId);
fs.ensureDirSync(storageDir); // create storage directory if it doesn't exist
@ -56,6 +74,11 @@ module.exports = function(RED) {
deviceId: this.deviceId || undefined,
});
// set globally if configured to do so
if(this.globalAccess) {
this.context().global.set('matrixClient["'+this.userId+'"]', node.matrixClient);
}
node.on('close', function(done) {
if(node.matrixClient) {
node.matrixClient.close();
@ -66,18 +89,6 @@ module.exports = function(RED) {
done();
});
node.setConnected = function(connected) {
if (node.connected !== connected) {
node.connected = connected;
if (connected) {
node.log("Matrix server connection ready.");
node.emit("connected");
} else {
node.emit("disconnected");
}
}
};
node.isConnected = function() {
return node.connected;
};